mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
record_detail autoupdate
This commit is contained in:
1 parent
3a90e2893f
commit
c68953c59f
17 files changed
+209
-278
No files matched your search
@@ -69,4 +69,4 @@ MIDDLEWARE(async (ctx, next) => {
|
||||
console.error(e.stack);
|
||||
ctx.body = { error: { message: e.message, params: e.params, stack: e.stack } };
|
||||
}
|
||||
});
|
||||
}, true);
|
||||
@@ -1,9 +1,10 @@
|
||||
const
|
||||
{ GET, POST } = require('../service/server'),
|
||||
queue = require('../service/queue'),
|
||||
record = require('../model/record'),
|
||||
{ requirePerm } = require('./tools'),
|
||||
{ PERM_JUDGE } = require('../permission');
|
||||
{ PERM_JUDGE } = require('../permission'),
|
||||
record = require('../model/record'),
|
||||
bus = require('../service/bus'),
|
||||
queue = require('../service/queue'),
|
||||
{ GET, POST } = require('../service/server');
|
||||
|
||||
queue.assert('judge');
|
||||
|
||||
@@ -46,7 +47,8 @@ POST('/judge/next', requirePerm(PERM_JUDGE), async ctx => {
|
||||
if (body.score) $set.score = body.score;
|
||||
if (body.time_ms) $set.time = body.time_ms;
|
||||
if (body.memory_kb) $set.memory = body.memory_kb;
|
||||
await record.update(body.rid, $set);
|
||||
rdoc = await record.update(body.rid, $set);
|
||||
bus.publish('record_change', rdoc);
|
||||
ctx.body = {};
|
||||
});
|
||||
POST('/judge/end', requirePerm(PERM_JUDGE), async ctx => {
|
||||
@@ -71,6 +73,7 @@ POST('/judge/end', requirePerm(PERM_JUDGE), async ctx => {
|
||||
if (body.memory_kb) $set.memory = body.memory_kb;
|
||||
$set.judgeAt = new Date();
|
||||
$set.judger = ctx.state.user._id;
|
||||
await record.update(body.rid, $set);
|
||||
rdoc = await record.update(body.rid, $set);
|
||||
bus.publish('record_change', rdoc);
|
||||
ctx.body = {};
|
||||
});
|
||||
+50
-6
@@ -1,26 +1,49 @@
|
||||
const
|
||||
bson = require('bson'),
|
||||
{ constants } = require('../options'),
|
||||
{ GET, POST } = require('../service/server'),
|
||||
{ PERM_READ_RECORD_CODE, PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD,
|
||||
PERM_REJUDGE, PERM_VIEW_PROBLEM_HIDDEN } = require('../permission'),
|
||||
{ requirePerm } = require('../handler/tools'),
|
||||
queue = require('../service/queue'),
|
||||
problem = require('../model/problem'),
|
||||
record = require('../model/record'),
|
||||
user = require('../model/user'),
|
||||
problem = require('../model/problem'),
|
||||
{ PERM_READ_RECORD_CODE, PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD, PERM_REJUDGE } = require('../permission');
|
||||
bus = require('../service/bus'),
|
||||
queue = require('../service/queue'),
|
||||
{ GET, POST, SOCKET } = require('../service/server');
|
||||
|
||||
GET('/r', async ctx => {
|
||||
ctx.templateName = 'record_main.html';
|
||||
let q = {},
|
||||
page = ctx.query.page || 1;
|
||||
let rdocs = await record.getMany(q, { rid: 1 }, page, constants.RECORD_PER_PAGE);
|
||||
let pdict, udict;
|
||||
for (let rdoc in rdocs) {
|
||||
let pdict = {}, udict = {};
|
||||
for (let rdoc of rdocs) {
|
||||
udict[rdoc.uid] = await user.getById(rdoc.uid);
|
||||
pdict[rdoc.pid] = await problem.get({ pid: rdoc.pid, uid: ctx.state.user._id });
|
||||
}
|
||||
ctx.body = { page, rdocs, pdict, udict };
|
||||
});
|
||||
SOCKET('/record-conn', class RecordConnHandler {
|
||||
constructor(conn) {
|
||||
this.tid = null;
|
||||
this.h = async data => {
|
||||
let rdoc = data.value;
|
||||
if (rdoc.tid && rdoc.tid != this.tid.toString()) return;
|
||||
let [udoc, pdoc] = await Promise.all([user.getById(rdoc.uid), problem.get({ pid: rdoc.pid })]);
|
||||
if (pdoc.hidden && !conn.state.user.hasPerm(PERM_VIEW_PROBLEM_HIDDEN)) pdoc = null;
|
||||
conn.send({ html: await conn.renderHTML('record_main_tr.html', { rdoc, udoc, pdoc }) });
|
||||
};
|
||||
}
|
||||
onOpen() {
|
||||
bus.subscribe(['record_change'], this.h);
|
||||
}
|
||||
onMessage(data) {
|
||||
if (data.tid) this.tid = data.tid;
|
||||
}
|
||||
onClose() {
|
||||
bus.unsubscribe(['record_change'], this.h);
|
||||
}
|
||||
});
|
||||
GET('/r/:rid', async ctx => {
|
||||
ctx.templateName = 'record_detail.html';
|
||||
let uid = ctx.state.user._id, rid = new bson.ObjectID(ctx.params.rid);
|
||||
@@ -29,6 +52,27 @@ GET('/r/:rid', async ctx => {
|
||||
if (rdoc.uid != uid && !ctx.state.user.hasPerm(PERM_READ_RECORD_CODE)) rdoc.code = null;
|
||||
ctx.body = { rdoc, show_status: true };
|
||||
});
|
||||
SOCKET('/record-detail-conn', class RecordDetailConnHandler {
|
||||
constructor(conn) {
|
||||
this.rid = conn.params.rid;
|
||||
this.h = async data => {
|
||||
let rdoc = data.value;
|
||||
if (rdoc.rid.toString() != this.rid) return;
|
||||
let [udoc, pdoc] = await Promise.all([user.getById(rdoc.uid), problem.get({ pid: rdoc.pid })]);
|
||||
if (pdoc.hidden && !conn.state.user.hasPerm(PERM_VIEW_PROBLEM_HIDDEN)) pdoc = null;
|
||||
conn.send({ html: await conn.renderHTML('record_main_tr.html', { rdoc, udoc, pdoc }) });
|
||||
};
|
||||
}
|
||||
async onOpen() {
|
||||
bus.subscribe(['record_change'], this.h);
|
||||
}
|
||||
onMessage(data) {
|
||||
if (data.rid) this.rid = data.rid;
|
||||
}
|
||||
onClose() {
|
||||
bus.unsubscribe(['record_change'], this.h);
|
||||
}
|
||||
});
|
||||
POST('/r/:rid/rejudge', requirePerm(PERM_REJUDGE), async ctx => {
|
||||
ctx.templateName = 'record_detail.html';
|
||||
let uid = ctx.state.user._id, rid = new bson.ObjectID(ctx.params.rid);
|
||||
|
||||
+13
-6
@@ -30,10 +30,11 @@ class Markdown extends MarkdownIt {
|
||||
}
|
||||
const md = new Markdown();
|
||||
function datetime_span(dt, { relative = true } = {}) {
|
||||
dt = new Date(dt);
|
||||
if (dt.generationTime) dt = new Date(dt.generationTime * 1000);
|
||||
else if (typeof dt == 'number' || typeof dt == 'string') dt = new Date(dt);
|
||||
return '<span class="time{0}" data-timestamp="{1}">{2}</span>'.format(
|
||||
relative ? ' relative' : '',
|
||||
dt.getTime(),
|
||||
dt.getTime() / 1000,
|
||||
dt.toLocaleString()
|
||||
);
|
||||
}
|
||||
@@ -93,14 +94,14 @@ MIDDLEWARE(async (ctx, next) => {
|
||||
url_prefix: '/'
|
||||
};
|
||||
ctx.preferJson = (ctx.request.headers['accept'] || '').includes('application/json');
|
||||
ctx.render = async (name, context) => {
|
||||
ctx.renderHTML = (name, context) => {
|
||||
ctx.user = ctx.state.user;
|
||||
ctx.translate = str => {
|
||||
if (!str) return '';
|
||||
return str.toString().translate(ctx.state.user.language);
|
||||
};
|
||||
ctx.has_perm = perm => ctx.state.user.hasPerm(perm);
|
||||
ctx.body = await new Promise((resolve, reject) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
env.render(name, Object.assign(ctx.state, context, {
|
||||
handler: ctx,
|
||||
_: ctx.translate,
|
||||
@@ -110,6 +111,9 @@ MIDDLEWARE(async (ctx, next) => {
|
||||
else resolve(res);
|
||||
});
|
||||
});
|
||||
};
|
||||
ctx.render = async (name, context) => {
|
||||
ctx.body = await ctx.renderHTML(name, context);
|
||||
ctx.response.type = 'text/html';
|
||||
};
|
||||
try {
|
||||
@@ -125,8 +129,11 @@ MIDDLEWARE(async (ctx, next) => {
|
||||
ctx.response.type = 'application/octet-stream';
|
||||
ctx.redirect(ctx.setRedirect);
|
||||
}
|
||||
} else throw new NotFoundError();
|
||||
} else {
|
||||
throw new NotFoundError();
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof NotFoundError) ctx.status = 404;
|
||||
if (error.toString().startsWith('NotFoundError')) console.log(error);
|
||||
if (error.toString().startsWith('Template render error')) throw error;
|
||||
if (ctx.preferJson) ctx.body = { error };
|
||||
@@ -136,4 +143,4 @@ MIDDLEWARE(async (ctx, next) => {
|
||||
if (ctx.preferJson) ctx.body = { error };
|
||||
else await ctx.render('bsod.html', { error });
|
||||
}
|
||||
});
|
||||
}, true);
|
||||
@@ -14,6 +14,9 @@ class USER {
|
||||
this.salt = user.salt;
|
||||
this.hash = user.hash;
|
||||
this.perm = user.perm;
|
||||
this.lang = user.language || 'zh_CN';
|
||||
this.codeLang = user.codeLang || 'c';
|
||||
this.codeTemplate = user.codeTemplate || '';
|
||||
}
|
||||
hasPerm(perm) {
|
||||
return this.perm == '-' || (this.perm || '').includes(perm);
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
const EventEmitter = require('events').EventEmitter;
|
||||
const bus = new EventEmitter();
|
||||
module.exports = {
|
||||
subscribe(events, handler) {
|
||||
for (let event of events)
|
||||
bus.on(event, handler);
|
||||
},
|
||||
unsubscribe(events, handler) {
|
||||
for (let event of events)
|
||||
bus.off(event, handler);
|
||||
},
|
||||
publish(event, data) {
|
||||
bus.emit(event, { value: data, event });
|
||||
}
|
||||
};
|
||||
+51
-6
@@ -3,14 +3,13 @@ const
|
||||
morgan = require('koa-morgan'),
|
||||
Body = require('koa-body'),
|
||||
Router = require('koa-router'),
|
||||
SocketIO = require('socket.io');
|
||||
sockjs = require('sockjs');
|
||||
|
||||
const options = require('../options');
|
||||
|
||||
let http = options.listen.https ? require('https') : require('http');
|
||||
let app = new Koa();
|
||||
let server = http.createServer(app.callback());
|
||||
let io = SocketIO(server);
|
||||
app.keys = options.session.keys;
|
||||
app.use(Body({
|
||||
multipart: true,
|
||||
@@ -19,12 +18,14 @@ app.use(Body({
|
||||
}
|
||||
}));
|
||||
let router = new Router();
|
||||
|
||||
let m = [];
|
||||
/**
|
||||
* @param {import('koa').Middleware} middleware
|
||||
* @param {boolean} installForSocket
|
||||
*/
|
||||
function MIDDLEWARE(middleware) {
|
||||
function MIDDLEWARE(middleware, installForSocket = false) {
|
||||
app.use(middleware);
|
||||
if (installForSocket) m.push(middleware);
|
||||
}
|
||||
/**
|
||||
* @param {string} route
|
||||
@@ -44,13 +45,57 @@ function POST(route, ...handler) {
|
||||
* @callback SocketIOHandler
|
||||
* @param {import('socket.io').Socket} socket
|
||||
*/
|
||||
/**
|
||||
* @callback SockJSHandler
|
||||
* @param {import('sockjs').Connection} conn
|
||||
*/
|
||||
/**
|
||||
* @param {string} prefix
|
||||
* @param {SocketIOHandler} handler
|
||||
*/
|
||||
function SOCKET(prefix, handler) {
|
||||
io.of(prefix).on('connection', handler);
|
||||
const sock = sockjs.createServer({ prefix });
|
||||
sock.on('connection', async conn => {
|
||||
conn.cookies = {
|
||||
get(name) {
|
||||
return conn.cookies[name];
|
||||
},
|
||||
set() { }
|
||||
};
|
||||
conn.state = {};
|
||||
conn.params = {};
|
||||
conn.request = {
|
||||
headers: conn.headers
|
||||
};
|
||||
let p = conn.url.split('?')[1].split('&');
|
||||
for (let i in p) p[i] = p[i].split('=');
|
||||
for (let i in p) conn.params[p[i][0]] = decodeURIComponent(p[i][1]);
|
||||
await new Promise((resolve, reject) => {
|
||||
conn.once('data', msg => {
|
||||
for (let i of msg.split(';')) {
|
||||
i = i.trim().split('=');
|
||||
conn.cookies[i[0]] = i[1];
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
setTimeout(reject, 5000);
|
||||
});
|
||||
for (let i of m) {
|
||||
await new Promise((resolve, reject) => {
|
||||
i(conn, resolve).catch(reject);
|
||||
});
|
||||
}
|
||||
conn.send = data => {
|
||||
conn.write(JSON.stringify(data));
|
||||
};
|
||||
let h = new handler(conn);
|
||||
if (h.onOpen) conn.on('open', h.onOpen);
|
||||
if (h.onClose) conn.on('close', h.onClose);
|
||||
if (h.onMessage) conn.on('data', h.onMessage);
|
||||
});
|
||||
sock.installHandlers(server);
|
||||
}
|
||||
|
||||
exports.MIDDLEWARE = MIDDLEWARE;
|
||||
exports.GET = GET;
|
||||
exports.POST = POST;
|
||||
@@ -58,6 +103,6 @@ exports.SOCKET = SOCKET;
|
||||
exports.start = function start() {
|
||||
app.use(morgan(':method :url :status :res[content-length] - :response-time ms'));
|
||||
app.use(router.routes()).use(router.allowedMethods());
|
||||
app.listen(options.listen.port);
|
||||
server.listen(options.listen.port);
|
||||
console.log('Server listening at: %s', options.listen.port);
|
||||
};
|
||||
Reference in new issue
Block a user