修复一些错误

This commit is contained in:
masnn committed 2020-05-19 12:46:00 +08:00
1 parent 747cb1b9b5
commit b19f948fdd
30 files changed
+306 -132

No files matched your search

+24 -1
View File
@@ -12,6 +12,7 @@ const system = require('../model/system');
const { Route, Handler } = require('../service/server');
const ContestHandler = contest.ContestHandlerMixin(Handler);
class ContestListHandler extends ContestHandler {
async get({ rule = 0, page = 1 }) {
this.response.template = 'contest_main.html';
@@ -31,11 +32,16 @@ class ContestListHandler extends ContestHandler {
const tids = [];
for (const tdoc of tdocs) tids.push(tdoc._id);
const tsdict = await contest.getListStatus(this.user._id, tids);
const path = [
['Hydro', '/'],
['contest_main', null],
];
this.response.body = {
page, tpcount, qs, rule, tdocs, tsdict,
page, tpcount, qs, rule, tdocs, tsdict, path,
};
}
}
class ContestDetailHandler extends ContestHandler {
async _prepare({ tid }) {
this.tdoc = await contest.get(tid);
@@ -62,6 +68,7 @@ class ContestDetailHandler extends ContestHandler {
} else attended = false;
const udict = await user.getList([this.tdoc.owner]);
const path = [
['Hydro', '/'],
['contest_main', '/c'],
[this.tdoc.title, null, true],
];
@@ -76,10 +83,12 @@ class ContestDetailHandler extends ContestHandler {
this.back();
}
}
class ContestScoreboardHandler extends ContestDetailHandler {
async get({ tid }) {
const [tdoc, rows, udict] = await this.getScoreboard(tid);
const path = [
['Hydro', '/'],
['contest_main', '/c'],
[tdoc.title, `/c/${tid}`, true],
['contest_scoreboard', null],
@@ -90,6 +99,7 @@ class ContestScoreboardHandler extends ContestDetailHandler {
};
}
}
class ContestScoreboardDownloadHandler extends ContestDetailHandler {
async get({ tid, ext }) {
const getContent = {
@@ -101,6 +111,7 @@ class ContestScoreboardDownloadHandler extends ContestDetailHandler {
this.binary(await getContent[ext](rows), `${this.tdoc.title}.${ext}`);
}
}
class ContestEditHandler extends ContestDetailHandler {
async prepare({ tid }) {
const tdoc = await contest.get(tid);
@@ -113,6 +124,7 @@ class ContestEditHandler extends ContestDetailHandler {
for (const i in contest.RULES) { rules[i] = contest.RULES[i].TEXT; }
const duration = (this.tdoc.endAt.getTime() - this.tdoc.beginAt.getTime()) / 3600 / 1000;
const path = [
['Hydro', '/'],
['contest_main', '/c'],
[this.tdoc.title, `/c/${this.tdoc._id}`, true],
['contest_edit', null],
@@ -151,6 +163,7 @@ class ContestEditHandler extends ContestDetailHandler {
else this.response.redirect = `/c/${this.tdoc._id}`;
}
}
class ContestProblemHandler extends ContestDetailHandler {
async prepare({ tid, pid }) {
[this.tdoc, this.pdoc] = await Promise.all([
@@ -175,6 +188,7 @@ class ContestProblemHandler extends ContestDetailHandler {
async get({ tid }) {
const path = [
['Hydro', '/'],
['contest_main', '/c'],
[this.tdoc.title, `/c/${tid}`, true],
[this.pdoc.title, null, true],
@@ -189,6 +203,7 @@ class ContestProblemHandler extends ContestDetailHandler {
};
}
}
class ContestProblemSubmitHandler extends ContestProblemHandler {
async get({ tid, pid }) {
let rdocs = [];
@@ -198,6 +213,7 @@ class ContestProblemSubmitHandler extends ContestProblemHandler {
}
this.response.template = 'problem_submit.html';
const path = [
['Hydro', '/'],
['contest_main', '/c'],
[this.tdoc.title, `/c/${tid}`, true],
[this.pdoc.title, `/c/${tid}/p/${pid}`, true],
@@ -229,6 +245,7 @@ class ContestProblemSubmitHandler extends ContestProblemHandler {
}
}
}
class ContestCreateHandler extends ContestHandler {
async prepare() {
this.checkPerm(PERM_CREATE_CONTEST);
@@ -242,8 +259,14 @@ class ContestCreateHandler extends ContestHandler {
let ts = now.getTime();
ts = ts - (ts % (15 * 60 * 1000)) + 15 * 60 * 1000;
const dt = new Date(ts);
const path = [
['Hydro', '/'],
['contest_main', '/c'],
['contest_create', null],
];
this.response.body = {
rules,
path,
page_name: 'contest_create',
date_text: `${dt.getFullYear()}-${dt.getMonth() + 1}-${dt.getDate()}`,
time_text: `${dt.getHours()}:${dt.getMinutes()}`,
+12 -2
View File
@@ -88,6 +88,7 @@ class DiscussionNodeHandler extends DiscussionHandler {
);
const udict = await user.getList(ddocs.map((ddoc) => ddoc.owner));
const path = [
['Hydro', '/'],
['discussion_main', '/discuss'],
[this.vnode.title, null, true],
];
@@ -112,6 +113,7 @@ class DiscussionCreateHandler extends DiscussionHandler {
async get({ type, docId }) {
const path = [
['Hydro', '/'],
['discussion_main', '/discuss'],
[this.vnode.title, `/discuss/${type}/${docId}`, true],
['discussion_create', null],
@@ -155,8 +157,9 @@ class DiscussionDetailHandler extends DiscussionHandler {
}
const udict = await user.getList(uids);
const path = [
['Hydro', '/'],
['discussion_main', '/discuss'],
[this.vnode.title, '/discuss/{type}', true],
[this.vnode.title, `/discuss/${this.ddoc.parentType}`, true],
[this.ddoc.title, null, true],
];
this.response.template = 'discussion_detail.html';
@@ -243,8 +246,15 @@ class DiscussionTailReplyRawHandler extends DiscussionHandler {
class DiscussionEditHandler extends DiscussionHandler {
async get() {
if (this.ddoc.owner !== this.user._id) this.checkPerm(PERM_EDIT_DISCUSSION);
const path = [
['Hydro', '/'],
['discussion_main', '/discuss'],
[this.vnode.title, `/discuss/${this.ddoc.parentType}`, true],
[this.ddoc.title, `/discuss/${this.ddoc._id}`, true],
['discussion_edit', null],
];
this.response.template = 'discussion_edit.html';
this.response.body = { ddoc: this.ddoc };
this.response.body = { ddoc: this.ddoc, path };
}
async post({
+41 -7
View File
@@ -20,15 +20,25 @@ class ManageMainHandler extends ManageHandler {
class ManageDashboardHandler extends ManageHandler {
async get() {
const path = [
['Hydro', '/'],
['manage', '/manage'],
['manage_dashboard', null],
];
this.response.template = 'manage_dashboard.html';
this.response.body = { system: this.system };
this.response.body = { system: this.system, path };
}
}
class ManageEditHandler extends ManageHandler {
async get() {
const path = [
['Hydro', '/'],
['manage', '/manage'],
['manage_edit', null],
];
this.response.template = 'manage_edit.html';
this.response.body = { system: this.system };
this.response.body = { system: this.system, path };
}
async post({ uname, gravatar, bio }) {
@@ -56,9 +66,14 @@ class ManageUserHandler extends ManageHandler {
}
const rolesSelect = roles.map((role) => [role._id, role._id]);
const udict = await user.getList(uids);
const path = [
['Hydro', '/'],
['manage', '/manage'],
['manage_user', null],
];
this.response.template = 'manage_user.html';
this.response.body = {
roles, rolesSelect, rudocs, udict, system,
roles, rolesSelect, rudocs, udict, system, path,
};
}
@@ -74,8 +89,13 @@ class ManagePermissionHandler extends ManageHandler {
user.getRoles(),
user.getById(0),
]);
const path = [
['Hydro', '/'],
['manage', '/manage'],
['manage_permission', null],
];
this.response.template = 'manage_permission.html';
this.response.body = { roles, system };
this.response.body = { roles, system, path };
}
async post({ roles }) {
@@ -97,8 +117,13 @@ class ManageRoleHandler extends ManageHandler {
user.getRoles(),
user.getById(0),
]);
const path = [
['Hydro', '/'],
['manage', '/manage'],
['manage_role', null],
];
this.response.template = 'manage_role.html';
this.response.body = { roles, system };
this.response.body = { roles, system, path };
}
async postAdd({ role }) {
@@ -125,11 +150,20 @@ class ManageRoleHandler extends ManageHandler {
class ManageModuleHandler extends ManageHandler {
async get() {
const installed = await hpm.getInstalled();
const active = loader.active.map((module) => module.id);
this.response.body = { installed, active };
const path = [
['Hydro', '/'],
['manage', '/manage'],
['manage_module', null],
];
this.response.body = { installed, active: loader.active, path };
this.response.template = 'manage_module.html';
}
async postInstall({ url, id }) {
await hpm.install(url, id);
this.back();
}
async postDelete({ id }) {
await hpm.del(id);
this.back();
+53 -1
View File
@@ -32,7 +32,7 @@ class ProblemHandler extends Handler {
this.response.template = 'problem_main.html';
const q = {};
let psdict = {};
if (category) q.category = category;
if (category) q.$or = [{ category }, { tag: category }];
if (!this.user.hasPerm(PERM_VIEW_PROBLEM_HIDDEN)) q.hidden = false;
const [pdocs, ppcount, pcount] = await paginate(
problem.getMulti(q).sort({ pid: 1 }),
@@ -50,6 +50,55 @@ class ProblemHandler extends Handler {
path, page, pcount, ppcount, pdocs, psdict, category,
};
}
async cleanup() {
if (this.response.template === 'problem_main.html' && this.preferJson) {
const {
path, page, pcount, ppcount, pdocs, psdict, category,
} = this.response.body;
this.response.body = {
title: this.renderTitle(category),
fragments: (await Promise.all([
this.renderHTML('partials/problem_list.html', {
page, ppcount, pcount, pdocs, psdict,
}),
this.renderHTML('partials/problem_stat.html', { pcount }),
this.renderHTML('partials/problem_lucky.html', { category }),
this.renderHTML('partials/path.html', { path }),
])).map((i) => ({ html: i })),
raw: {
path, page, pcount, ppcount, pdocs, psdict, category,
},
};
}
}
}
class ProblemCategoryHandler extends ProblemHandler {
async get({ page = 1, category }) {
this.response.template = 'problem_main.html';
const q = {
$or: [{ category }, { tag: category }],
};
let psdict = {};
if (!this.user.hasPerm(PERM_VIEW_PROBLEM_HIDDEN)) q.hidden = false;
const [pdocs, ppcount, pcount] = await paginate(
problem.getMulti(q).sort({ pid: 1 }),
page,
await system.get('PROBLEM_PER_PAGE'),
);
if (this.user.hasPerm(PERM_LOGGEDIN)) {
psdict = await problem.getListStatus(this.user._id, pdocs.map((pdoc) => pdoc._id));
}
const path = [
['Hydro', '/'],
['problem_main', '/p'],
[category, null, true],
];
this.response.body = {
path, page, pcount, ppcount, pdocs, psdict, category,
};
}
}
class ProblemRandomHandler extends ProblemHandler {
@@ -59,6 +108,7 @@ class ProblemRandomHandler extends ProblemHandler {
const pid = await problem.random(q);
if (!pid) throw new NoProblemError();
this.response.body = { pid };
this.response.redirect = `/p/${pid}`;
}
}
@@ -380,6 +430,7 @@ class ProblemCreateHandler extends Handler {
async function apply() {
Route('/p', module.exports.ProblemHandler);
Route('/p/category/:category', module.exports.ProblemCategoryHandler);
Route('/problem/random', module.exports.ProblemRandomHandler);
Route('/p/:pid', module.exports.ProblemDetailHandler);
Route('/p/:pid/submit', module.exports.ProblemSubmitHandler);
@@ -398,6 +449,7 @@ async function apply() {
global.Hydro.handler.problem = module.exports = {
ProblemHandler,
ProblemCategoryHandler,
ProblemRandomHandler,
ProblemDetailHandler,
ProblemSubmitHandler,
+36 -14
View File
@@ -2,6 +2,7 @@
/* eslint-disable no-await-in-loop */
/* eslint-disable no-eval */
const fs = require('fs');
const os = require('os');
const zlib = require('zlib');
const path = require('path');
const yaml = require('js-yaml');
@@ -11,29 +12,50 @@ function root(name) {
return path.resolve(process.cwd(), name);
}
const moduleRoots = [
root('.build/module'),
root('module'),
root(path.resolve(os.homedir(), '.hydro', 'module')),
root('.'),
];
let moduleRoot;
for (const i of moduleRoots) {
if (fs.existsSync(i) && fs.statSync(i).isDirectory()) {
moduleRoot = i;
break;
}
}
async function getInstalled() {
const files = fs.readdirSync(root('.build/module'));
const installed = [];
const modules = [];
const files = fs.readdirSync(moduleRoot);
for (const file of files) {
if (file.endsWith('.hydro')) {
const f = fs.readFileSync(root(`.build/module/${file}`));
const s = fs.statSync(root(`.build/module/${file}`));
installed.push({
...yaml.safeLoad(zlib.gunzipSync(f)),
id: file.split('.')[0],
size: s.size,
});
try {
const f = fs.readFileSync(root(`${moduleRoot}/${file}`));
const s = fs.statSync(root(`${moduleRoot}/${file}`));
const m = {
...yaml.safeLoad(zlib.gunzipSync(f)),
filename: file.split('.')[0],
size: s.size,
};
modules.push(m);
} catch (e) {
if (e.code === 'Z_DATA_ERROR') {
console.error(`Module Load Fail: ${file} (File Corrupted)`);
} else console.error(`Module Load Fail: ${file} ${e}`);
}
}
}
return installed;
return modules;
}
async function del(id) {
fs.unlinkSync(root(`.build/module/${id}.hydro`));
fs.unlinkSync(root(`${moduleRoot}/${id}.hydro`));
}
async function install(id, url) {
await download(url, root(`module/${id}.hydro`));
async function install(url) {
await download(url, root(`${moduleRoot}/${String.random(16)}.hydro`));
}
module.exports = { getInstalled, del, install };
global.Hydro.lib.hpm = module.exports = { getInstalled, del, install };
+20 -52
View File
@@ -19,6 +19,7 @@ function ensureDir(dir) {
}
}
let pending = [];
const active = [];
const fail = [];
try {
@@ -26,39 +27,13 @@ try {
// eslint-disable-next-line import/no-unresolved
const f = require('../.build/builtin.json');
const m = { ...yaml.safeLoad(zlib.gunzipSync(f.data)), id: 'builtin' };
active.push(m);
pending.push(m);
} catch (e) {
// Builtin module is in the module directory
}
const moduleRoots = [
root('.build/module'),
root('module'),
root(path.resolve(os.homedir(), '.hydro', 'module')),
root('.'),
];
let moduleRoot;
for (const i of moduleRoots) {
if (fs.existsSync(i) && fs.statSync(i).isDirectory()) {
moduleRoot = i;
break;
}
}
async function preload() {
const files = fs.readdirSync(moduleRoot);
for (const file of files) {
if (file.endsWith('.hydro')) {
try {
const f = fs.readFileSync(root(`${moduleRoot}/${file}`));
const m = { ...yaml.safeLoad(zlib.gunzipSync(f)), id: file.split('.')[0] };
active.push(m);
} catch (e) {
console.error(`Module Load Fail: ${file}`);
}
}
}
for (const i of active) {
for (const i of pending) {
try {
if (i.os) {
if (!i.os.includes(os.platform().toLowerCase())) throw new Error('Unsupported OS');
@@ -86,14 +61,11 @@ async function preload() {
}
async function handler() {
for (const i of active) {
for (const i of pending) {
if (i.handler && !i.fail) {
try {
console.log(`Handler init: ${i.id}`);
console.time(`Handler init: ${i.id}`);
const exports = {};
// eslint-disable-next-line no-unused-vars
const module = { exports, file: i.files || {} };
eval(i.handler);
console.timeEnd(`Handler init: ${i.id}`);
} catch (e) {
@@ -106,7 +78,7 @@ async function handler() {
}
async function locale() {
for (const i of active) {
for (const i of pending) {
if (i.locale && !i.fail) {
try {
global.Hydro.lib.i18n(i.locale);
@@ -121,7 +93,7 @@ async function locale() {
}
async function template() {
for (const i of active) {
for (const i of pending) {
if (i.template && !i.fail) {
try {
Object.assign(global.Hydro.template, i.template);
@@ -136,15 +108,13 @@ async function template() {
}
async function model() {
for (const i of active) {
for (const i of pending) {
if (i.model && !i.fail) {
try {
console.log(`Model init: ${i.id}`);
console.time(`Model init: ${i.id}`);
const exports = {};
const module = { exports, file: i.files || {} };
eval(i.model);
if ((module.exports || {}).index) await module.exports.index();
const m = eval(i.model);
if ((m || {}).index) await m.index();
console.timeEnd(`Model init: ${i.id}`);
} catch (e) {
i.fail = true;
@@ -156,14 +126,11 @@ async function model() {
}
async function lib() {
for (const i of active) {
for (const i of pending) {
if (i.lib && !i.fail) {
try {
console.log(`Lib init: ${i.id}`);
console.time(`Lib init: ${i.id}`);
const exports = {};
// eslint-disable-next-line no-unused-vars
const module = { exports, file: i.files || {} };
eval(i.lib);
console.timeEnd(`Lib init: ${i.id}`);
} catch (e) {
@@ -176,14 +143,12 @@ async function lib() {
}
async function service() {
for (const i of active) {
for (const i of pending) {
if (i.service && !i.fail) {
try {
console.time(`Service init: ${i.id}`);
const exports = {}; // eslint-disable-line no-unused-vars
const module = { exports };
eval(i.service);
if ((module.exports || {}).init) await module.exports.init();
const m = eval(i.service);
if ((m || {}).init) await m.init();
console.timeEnd(`Service init: ${i.id}`);
} catch (e) {
i.fail = true;
@@ -196,12 +161,10 @@ async function service() {
}
async function script() {
for (const i of active) {
for (const i of pending) {
if (i.script && !i.fail) {
try {
console.time(`Script init: ${i.id}`);
const exports = {};
const module = { exports }; // eslint-disable-line no-unused-vars
eval(i.script);
console.timeEnd(`Script init: ${i.id}`);
} catch (e) {
@@ -211,6 +174,7 @@ async function script() {
console.error(e);
}
}
if (!i.fail) active.push(i.name);
}
}
@@ -235,6 +199,7 @@ async function load() {
template: {},
ui: {},
};
pending.push(...await require('./lib/hpm').getInstalled());
await preload();
require('./lib/i18n');
require('./utils');
@@ -299,7 +264,10 @@ async function load() {
if (global.Hydro.service[i].postInit) await global.Hydro.service[i].postInit();
}
await script();
pending = [];
await server.start();
}
module.exports = { load, active, fail };
module.exports = {
load, pending, active, fail,
};
+4 -4
View File
@@ -123,11 +123,11 @@ function count(query) {
return coll.find(query).count();
}
async function random(query) {
const pdocs = coll.find(query);
const pcount = await pdocs.count();
const cursor = coll.find(query);
const pcount = await cursor.count();
if (pcount) {
const pdoc = await pdocs.skip(Math.floor(Math.random() * pcount)).limit(1).toArray()[0];
return pdoc.pid;
const pdoc = await cursor.skip(Math.floor(Math.random() * pcount)).limit(1).toArray();
return pdoc[0].pid;
} return null;
}
async function getList(pids) {
+1 -1
View File
@@ -242,7 +242,7 @@ class Handler {
}
}
const check = ['tid', 'rid', 'did', 'drid', 'drrid', 'psid', 'psrid', 'docId'];
const check = ['tid', 'rid', 'did', 'drid', 'drrid', 'psid', 'psrid', 'docId', 'mongoId'];
function Route(route, RouteHandler) {
router.all(route, async (ctx) => {