mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
题目编辑,测试数据上传,评测记录
This commit is contained in:
1 parent
6e28dd868e
commit
f055d79fef
9 files changed
+76
-32
No files matched your search
@@ -1,7 +1,6 @@
|
|||||||
class UserFacingError extends Error {
|
class UserFacingError extends Error {
|
||||||
constructor(type) {
|
constructor(type) {
|
||||||
super(type);
|
super(type);
|
||||||
this.template = 'error';
|
|
||||||
this.code = 500;
|
this.code = 500;
|
||||||
//this.stack = '';
|
//this.stack = '';
|
||||||
this.params = [];
|
this.params = [];
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ const
|
|||||||
{ requirePerm } = require('./tools'),
|
{ requirePerm } = require('./tools'),
|
||||||
{ PERM_JUDGE } = require('../permission'),
|
{ PERM_JUDGE } = require('../permission'),
|
||||||
record = require('../model/record'),
|
record = require('../model/record'),
|
||||||
|
problem = require('../model/problem'),
|
||||||
bus = require('../service/bus'),
|
bus = require('../service/bus'),
|
||||||
queue = require('../service/queue'),
|
queue = require('../service/queue'),
|
||||||
{ GET, POST } = require('../service/server');
|
{ GET, POST } = require('../service/server');
|
||||||
@@ -15,11 +16,12 @@ GET('/judge/fetch', requirePerm(PERM_JUDGE), async ctx => {
|
|||||||
let rid = await queue.get('judge', false);
|
let rid = await queue.get('judge', false);
|
||||||
if (rid) {
|
if (rid) {
|
||||||
let rdoc = await record.get(rid);
|
let rdoc = await record.get(rid);
|
||||||
|
let pdoc = await problem.getById(rdoc.pid);
|
||||||
let task = {
|
let task = {
|
||||||
event: 'judge',
|
event: 'judge',
|
||||||
rid, type: 0,
|
rid, type: 0,
|
||||||
pid: rdoc.pid,
|
pid: rdoc.pid,
|
||||||
data: rdoc.data,
|
data: pdoc.data,
|
||||||
lang: rdoc.lang,
|
lang: rdoc.lang,
|
||||||
code: rdoc.code
|
code: rdoc.code
|
||||||
};
|
};
|
||||||
@@ -28,6 +30,7 @@ GET('/judge/fetch', requirePerm(PERM_JUDGE), async ctx => {
|
|||||||
else ctx.body = {};
|
else ctx.body = {};
|
||||||
});
|
});
|
||||||
POST('/judge/next', requirePerm(PERM_JUDGE), async ctx => {
|
POST('/judge/next', requirePerm(PERM_JUDGE), async ctx => {
|
||||||
|
console.log(ctx.request.body);
|
||||||
let body = ctx.request.body;
|
let body = ctx.request.body;
|
||||||
let rdoc = await record.get(body.rid);
|
let rdoc = await record.get(body.rid);
|
||||||
let $set = {};
|
let $set = {};
|
||||||
@@ -40,7 +43,7 @@ POST('/judge/next', requirePerm(PERM_JUDGE), async ctx => {
|
|||||||
$set.judgeTexts = rdoc.judgeTexts;
|
$set.judgeTexts = rdoc.judgeTexts;
|
||||||
}
|
}
|
||||||
if (body.compiler_text) {
|
if (body.compiler_text) {
|
||||||
rdoc.compilerTexts.push(body.compilerTexts);
|
rdoc.compilerTexts.push(body.compiler_text);
|
||||||
$set.compilerTexts = rdoc.compilerTexts;
|
$set.compilerTexts = rdoc.compilerTexts;
|
||||||
}
|
}
|
||||||
if (body.status) $set.status = body.status;
|
if (body.status) $set.status = body.status;
|
||||||
|
|||||||
@@ -80,11 +80,12 @@ GET('/p/:pid/submit', requirePerm(PERM_SUBMIT_PROBLEM), async ctx => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
POST('/p/:pid/submit', requirePerm(PERM_SUBMIT_PROBLEM), async ctx => {
|
POST('/p/:pid/submit', requirePerm(PERM_SUBMIT_PROBLEM), async ctx => {
|
||||||
|
let pdoc = await problem.get({ pid: ctx.params.pid });
|
||||||
let rid = await record.add({
|
let rid = await record.add({
|
||||||
uid: ctx.state.user._id,
|
uid: ctx.state.user._id,
|
||||||
lang: ctx.request.body.lang,
|
lang: ctx.request.body.lang,
|
||||||
code: ctx.request.body.code,
|
code: ctx.request.body.code,
|
||||||
pid: ctx.params.pid
|
pid: pdoc._id
|
||||||
});
|
});
|
||||||
await queue.push('judge', rid);
|
await queue.push('judge', rid);
|
||||||
ctx.state.user.nSubmit++;
|
ctx.state.user.nSubmit++;
|
||||||
@@ -94,7 +95,7 @@ POST('/p/:pid/submit', requirePerm(PERM_SUBMIT_PROBLEM), async ctx => {
|
|||||||
GET('/p/:pid/settings', async ctx => {
|
GET('/p/:pid/settings', async ctx => {
|
||||||
ctx.templateName = 'problem_settings.html';
|
ctx.templateName = 'problem_settings.html';
|
||||||
let pdoc = await problem.get({ pid: ctx.params.pid, uid: ctx.state.user._id });
|
let pdoc = await problem.get({ pid: ctx.params.pid, uid: ctx.state.user._id });
|
||||||
if (pdoc.hidden) ctx.checkPerm(PERM_VIEW_PROBLEM_HIDDEN);
|
if (pdoc.owner != ctx.state.user._id) ctx.checkPerm(PERM_EDIT_PROBLEM);
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
path: [
|
path: [
|
||||||
['Hydro', '/'],
|
['Hydro', '/'],
|
||||||
@@ -109,12 +110,36 @@ POST('/p/:pid/settings', async ctx => {
|
|||||||
// TODO(masnn)
|
// TODO(masnn)
|
||||||
ctx.back();
|
ctx.back();
|
||||||
});
|
});
|
||||||
|
GET('/p/:pid/edit', async ctx => {
|
||||||
|
ctx.templateName = 'problem_edit.html';
|
||||||
|
let pdoc = await problem.get({ pid: ctx.params.pid, uid: ctx.state.user._id });
|
||||||
|
if (pdoc.owner != ctx.state.user._id) ctx.checkPerm(PERM_EDIT_PROBLEM);
|
||||||
|
ctx.body = {
|
||||||
|
path: [
|
||||||
|
['Hydro', '/'],
|
||||||
|
['problem_main', '/p'],
|
||||||
|
[pdoc.title, `/p/${ctx.params.pid}`, true],
|
||||||
|
['problem_edit', null]
|
||||||
|
],
|
||||||
|
pdoc, page_name: 'problem_edit'
|
||||||
|
};
|
||||||
|
});
|
||||||
|
POST('/p/:pid/edit', async ctx => {
|
||||||
|
let title = validator.checkTitle(ctx.request.body.title);
|
||||||
|
let content = validator.checkContent(ctx.request.body.content);
|
||||||
|
let pid = validator.checkPid(ctx.request.body.pid);
|
||||||
|
let pdoc = await problem.get({ pid: ctx.params.pid });
|
||||||
|
await problem.edit(pdoc._id, {
|
||||||
|
title, content, pid
|
||||||
|
});
|
||||||
|
ctx.setRedirect = `/p/${pid}`;
|
||||||
|
});
|
||||||
GET('/p/:pid/upload', async ctx => {
|
GET('/p/:pid/upload', async ctx => {
|
||||||
ctx.templateName = 'problem_upload.html';
|
ctx.templateName = 'problem_upload.html';
|
||||||
let pdoc = await problem.get({ pid: ctx.params.pid, uid: ctx.state.user._id });
|
let pdoc = await problem.get({ pid: ctx.params.pid, uid: ctx.state.user._id });
|
||||||
if (pdoc.owner != ctx.state.user._id) ctx.checkPerm(PERM_EDIT_PROBLEM);
|
if (pdoc.owner != ctx.state.user._id) ctx.checkPerm(PERM_EDIT_PROBLEM);
|
||||||
let md5;
|
let md5;
|
||||||
if (typeof pdoc.data == 'object') {
|
if (pdoc.data && typeof pdoc.data == 'object') {
|
||||||
let files = await gridfs.find({ _id: pdoc.data }).toArray();
|
let files = await gridfs.find({ _id: pdoc.data }).toArray();
|
||||||
md5 = files[0].md5;
|
md5 = files[0].md5;
|
||||||
}
|
}
|
||||||
@@ -133,11 +158,14 @@ POST('/p/:pid/upload', async ctx => {
|
|||||||
f.once('error', reject);
|
f.once('error', reject);
|
||||||
});
|
});
|
||||||
let md5;
|
let md5;
|
||||||
if (typeof pdoc.data == 'object') {
|
if (pdoc.data && typeof pdoc.data == 'object') {
|
||||||
|
gridfs.delete(pdoc.data);
|
||||||
|
}
|
||||||
|
pdoc = await problem.edit(pdoc._id, { data: f.id });
|
||||||
|
if (pdoc.data && typeof pdoc.data == 'object') {
|
||||||
let files = await gridfs.find({ _id: pdoc.data }).toArray();
|
let files = await gridfs.find({ _id: pdoc.data }).toArray();
|
||||||
md5 = files[0].md5;
|
md5 = files[0].md5;
|
||||||
}
|
}
|
||||||
pdoc = await problem.edit(ctx.params.pid, { data: f.id });
|
|
||||||
ctx.body = { pdoc, md5 };
|
ctx.body = { pdoc, md5 };
|
||||||
});
|
});
|
||||||
GET('/p/:pid/data', async ctx => {
|
GET('/p/:pid/data', async ctx => {
|
||||||
|
|||||||
+4
-1
@@ -128,7 +128,10 @@ MIDDLEWARE(async (ctx, next) => {
|
|||||||
} else {
|
} else {
|
||||||
throw new NotFoundError();
|
throw new NotFoundError();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (e) {
|
||||||
|
let error;
|
||||||
|
if (ctx.body && ctx.body.error) error = ctx.body.error;
|
||||||
|
else error = e;
|
||||||
if (error instanceof NotFoundError) ctx.status = 404;
|
if (error instanceof NotFoundError) ctx.status = 404;
|
||||||
if (error.toString().startsWith('NotFoundError')) console.log(error);
|
if (error.toString().startsWith('NotFoundError')) console.log(error);
|
||||||
if (error.toString().startsWith('Template render error')) throw error;
|
if (error.toString().startsWith('Template render error')) throw error;
|
||||||
|
|||||||
@@ -7,21 +7,21 @@ const
|
|||||||
|
|
||||||
const
|
const
|
||||||
isTitle = s => s && s.length < 64,
|
isTitle = s => s && s.length < 64,
|
||||||
checkTitle = s => { if (!isTitle(s)) throw new ValidationError('title'); },
|
checkTitle = s => { if (!isTitle(s)) throw new ValidationError('title'); else return s; },
|
||||||
isUid = s => RE_UID.test(s),
|
isUid = s => RE_UID.test(s),
|
||||||
checkUid = s => { if (!isUid(s)) throw new ValidationError('uid'); },
|
checkUid = s => { if (!isUid(s)) throw new ValidationError('uid'); else return s; },
|
||||||
isUname = s => RE_UNAME.test(s),
|
isUname = s => RE_UNAME.test(s),
|
||||||
checkUname = s => { if (!isUname(s)) throw new ValidationError('uname'); },
|
checkUname = s => { if (!isUname(s)) throw new ValidationError('uname'); else return s; },
|
||||||
isPassword = s => s.length >= 5,
|
isPassword = s => s.length >= 5,
|
||||||
checkPassword = s => { if (!isPassword(s)) throw new ValidationError('password'); },
|
checkPassword = s => { if (!isPassword(s)) throw new ValidationError('password'); else return s; },
|
||||||
isEmail = s => RE_MAIL.test(s),
|
isEmail = s => RE_MAIL.test(s),
|
||||||
checkEmail = s => { if (!isEmail(s)) throw new ValidationError('mail'); },
|
checkEmail = s => { if (!isEmail(s)) throw new ValidationError('mail'); else return s; },
|
||||||
isContent = s => s && s.length < 65536,
|
isContent = s => s && s.length < 65536,
|
||||||
checkContent = s => { if (!isContent(s)) throw new ValidationError('content'); },
|
checkContent = s => { if (!isContent(s)) throw new ValidationError('content'); else return s; },
|
||||||
isName = s => s && s.length < 256,
|
isName = s => s && s.length < 256,
|
||||||
checkName = s => { if (!isName(s)) throw new ValidationError('name'); },
|
checkName = s => { if (!isName(s)) throw new ValidationError('name'); else return s; },
|
||||||
isPid = s => RE_PID.test(s.toString()),
|
isPid = s => RE_PID.test(s.toString()),
|
||||||
checkPid = s => { if (!RE_PID.test(s)) throw new ValidationError('pid'); };
|
checkPid = s => { if (!RE_PID.test(s)) throw new ValidationError('pid'); else return s; };
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
isTitle, checkTitle,
|
isTitle, checkTitle,
|
||||||
|
|||||||
+22
-11
@@ -1,6 +1,7 @@
|
|||||||
const
|
const
|
||||||
validator = require('../lib/validator'),
|
{ ObjectID } = require('bson'),
|
||||||
{ ProblemNotFoundError } = require('../error'),
|
{ ProblemNotFoundError } = require('../error'),
|
||||||
|
validator = require('../lib/validator'),
|
||||||
db = require('../service/db.js'),
|
db = require('../service/db.js'),
|
||||||
coll = db.collection('problem'),
|
coll = db.collection('problem'),
|
||||||
coll_status = db.collection('problem.status');
|
coll_status = db.collection('problem.status');
|
||||||
@@ -42,23 +43,32 @@ async function add({
|
|||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
async function get({ pid, uid }) {
|
async function get({ pid, uid }) {
|
||||||
pid = parseInt(pid) || pid;
|
let query = {};
|
||||||
let pdoc = await coll.findOne({ pid });
|
if (pid.generationTime || pid.length == 24) query = { _id: new ObjectID(pid) };
|
||||||
|
else query = { pid: parseInt(pid) || pid };
|
||||||
|
let pdoc = await coll.findOne(query);
|
||||||
if (!pdoc) throw new ProblemNotFoundError(pid);
|
if (!pdoc) throw new ProblemNotFoundError(pid);
|
||||||
pdoc.psdoc = uid ?
|
if (uid) {
|
||||||
await coll_status.findOne({ pid, uid }) :
|
query.uid = uid;
|
||||||
null;
|
pdoc.psdoc = await coll_status.findOne(query);
|
||||||
|
}
|
||||||
|
return pdoc;
|
||||||
|
}
|
||||||
|
async function getById(_id) {
|
||||||
|
_id = new ObjectID(_id);
|
||||||
|
let pdoc = await coll.findOne({ _id });
|
||||||
|
if (!pdoc) throw new ProblemNotFoundError(_id);
|
||||||
return pdoc;
|
return pdoc;
|
||||||
}
|
}
|
||||||
async function getMany(query, sort, page, limit) {
|
async function getMany(query, sort, page, limit) {
|
||||||
return await coll.find(query).sort(sort).skip((page - 1) * limit).limit(limit).toArray();
|
return await coll.find(query).sort(sort).skip((page - 1) * limit).limit(limit).toArray();
|
||||||
}
|
}
|
||||||
async function edit(pid, $set) {
|
async function edit(_id, $set) {
|
||||||
if ($set.title) validator.checkTitle($set.title);
|
if ($set.title) validator.checkTitle($set.title);
|
||||||
if ($set.content) validator.checkContent($set.content);
|
if ($set.content) validator.checkContent($set.content);
|
||||||
await coll.findOneAndUpdate({ pid }, { $set });
|
await coll.findOneAndUpdate({ _id }, { $set });
|
||||||
let pdoc = await coll.findOne({ pid });
|
let pdoc = await getById(_id);
|
||||||
if (!pdoc) throw new ProblemNotFoundError(pid);
|
if (!pdoc) throw new ProblemNotFoundError(_id);
|
||||||
return pdoc;
|
return pdoc;
|
||||||
}
|
}
|
||||||
async function count(query) {
|
async function count(query) {
|
||||||
@@ -80,5 +90,6 @@ module.exports = {
|
|||||||
getMany,
|
getMany,
|
||||||
edit,
|
edit,
|
||||||
count,
|
count,
|
||||||
random
|
random,
|
||||||
|
getById
|
||||||
};
|
};
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
/ {% if c[1] %}<a href="{{ c[1] }}">{{ c[0] if c[2] else _(c[0]) }}</a>{% endif %}
|
/ {% if c[1] %}<a href="{{ c[1] }}">{{ c[0] if c[2] else _(c[0]) }}</a>{% endif %}
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
</div>
|
</div>
|
||||||
<h1 class="location-current" data-emoji-enabled>{{ path[path.length - 1][0] if path[path.length - 1][0] else _(path[path.length - 1][0]) }}</h1>
|
<h1 class="location-current" data-emoji-enabled>{{ path[path.length - 1][0] if path[path.length - 1][2] else _(path[path.length - 1][0]) }}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="media__right">
|
<div class="media__right">
|
||||||
{% include "partials/hamburger.html" %}
|
{% include "partials/hamburger.html" %}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
{% import "components/problem.html" as problem with context %}
|
{% import "components/problem.html" as problem with context %}
|
||||||
{% import "components/nothing.html" as nothing with context %}
|
{% import "components/nothing.html" as nothing with context %}
|
||||||
<div data-fragment-id="problem_list">
|
<div data-fragment-id="problem_list">
|
||||||
{% if not pdocs %}
|
{% if not pdocs.length %}
|
||||||
{{ nothing.render('Sorry, there is no problem in the problem set') }}
|
{{ nothing.render('Sorry, there is no problem in the problem set') }}
|
||||||
{% else %}
|
{% else %}
|
||||||
<table class="data-table">
|
<table class="data-table">
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
{% if (typeof(pdoc.data) == 'string') %}
|
{% if (typeof(pdoc.data) == 'string') %}
|
||||||
<p><b>{{ _('Current dataset comes from') }} <a href="{{ pdoc.data.split('from:')[1] }}" target="_blank">{{ pdoc.data.split('from:')[1] }}</a></b></p>
|
<p><b>{{ _('Current dataset comes from') }} <a href="{{ pdoc.data.split('from:')[1] }}" target="_blank">{{ pdoc.data.split('from:')[1] }}</a></b></p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>{{ _('Current dataset: {0}').format(pdoc['data'].toString()|default(_('(None)'))) }}</p>
|
<p>{{ _('Current dataset: {0}').format((pdoc['data'] or _('(None)')).toString()) }}</p>
|
||||||
<p>{{ _('MD5: {0}').format(md5|default(_('(None)'))) }}</p>
|
<p>{{ _('MD5: {0}').format(md5 or _('(None)')) }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p>{{ _('New dataset') }}:
|
<p>{{ _('New dataset') }}:
|
||||||
<input type="hidden" name="csrf_token" value="{{ handler.csrf_token }}">
|
<input type="hidden" name="csrf_token" value="{{ handler.csrf_token }}">
|
||||||
|
|||||||
Reference in new issue
Block a user