mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-19 01:38:19 +08:00
优化结构
This commit is contained in:
1 parent
75ebc1a746
commit
2554cf660a
34 files changed
+401
-150
No files matched your search
@@ -26,5 +26,6 @@ module.exports = {
|
||||
"no-param-reassign": "off",
|
||||
"global-require": "off",
|
||||
"no-nested-ternary": "off",
|
||||
"no-multi-assign": "off",
|
||||
},
|
||||
};
|
||||
@@ -14,8 +14,7 @@ jobs:
|
||||
node_version: '13.x'
|
||||
- run: |
|
||||
yarn
|
||||
yarn add webpack webpack-cli -D
|
||||
yarn build
|
||||
yarn build:production
|
||||
- uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: hydro
|
||||
@@ -23,8 +22,7 @@ jobs:
|
||||
- run: |
|
||||
cd ui
|
||||
yarn
|
||||
yarn add webpack webpack-cli -D
|
||||
yarn build
|
||||
yarn build:production
|
||||
cd ..
|
||||
- uses: actions/upload-artifact@v1
|
||||
with:
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
FROM mhart/alpine-node:slim-10
|
||||
WORKDIR /app
|
||||
ADD .uibuild dist locales templates /app/
|
||||
ADD .uibuild .build /app/
|
||||
RUN mkdir /config
|
||||
VOLUME [ "/config" ]
|
||||
EXPOSE 8888
|
||||
CMD ["node", "dist/development.js"]
|
||||
CMD ["node", ".build/development.js"]
|
||||
+10
-8
@@ -1,7 +1,9 @@
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
const fs = require('fs');
|
||||
const webpack = require('webpack');
|
||||
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin');
|
||||
const root = require('./root');
|
||||
|
||||
const exist = (name) => {
|
||||
try {
|
||||
fs.statSync(root(name));
|
||||
@@ -9,24 +11,24 @@ const exist = (name) => {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
const build = async () => {
|
||||
};
|
||||
const build = async (type) => {
|
||||
const modules = fs.readdirSync(root('module'));
|
||||
const config = {
|
||||
mode: 'production',
|
||||
mode: type,
|
||||
entry: {},
|
||||
output: {
|
||||
filename: 'module/[name].js',
|
||||
path: root('.build')
|
||||
path: root('.build'),
|
||||
},
|
||||
target: 'node',
|
||||
module: {},
|
||||
plugins: [
|
||||
new webpack.ProgressPlugin(),
|
||||
new FriendlyErrorsPlugin(),
|
||||
]
|
||||
],
|
||||
};
|
||||
for (let i of modules) {
|
||||
for (const i of modules) {
|
||||
if (!i.startsWith('.')) {
|
||||
if (exist(`module/${i}/model.js`)) {
|
||||
config.entry[`${i}/model`] = root(`module/${i}/model.js`);
|
||||
@@ -47,7 +49,7 @@ const build = async () => {
|
||||
if (stats.hasErrors()) process.exitCode = 1;
|
||||
resolve();
|
||||
});
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = build;
|
||||
@@ -0,0 +1,45 @@
|
||||
const fs = require('fs');
|
||||
const yaml = require('js-yaml');
|
||||
const root = require('./root');
|
||||
|
||||
function getFiles(folder) {
|
||||
const files = [];
|
||||
const f = fs.readdirSync(root(folder));
|
||||
for (const i of f) {
|
||||
if (!i.startsWith('.')) {
|
||||
if (fs.statSync(root(`${folder}/${i}`)).isDirectory()) {
|
||||
const g = getFiles(`${folder}/${i}`);
|
||||
for (const j of g) files.push(`${i}/${j}`);
|
||||
} else files.push(i);
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
const build = async () => {
|
||||
const files = getFiles('templates');
|
||||
const exclude = ['partials/training_default.json', 'partials/problem_default.md'];
|
||||
const templates = {};
|
||||
for (const i of files) {
|
||||
let template = fs.readFileSync(root(`templates/${i}`)).toString();
|
||||
if (!exclude.includes(i)) {
|
||||
template = template
|
||||
.trim()
|
||||
.replace(/ *\n */gmi, ' ')
|
||||
.replace(/, /gmi, ',')
|
||||
.replace(/%} {%/gmi, '%}{%')
|
||||
.replace(/ %}/gmi, '%}')
|
||||
.replace(/{% /gmi, '{%')
|
||||
.replace(/> </gmi, '><')
|
||||
.replace(/}} </gmi, '}}<')
|
||||
.replace(/> {{/gmi, '>{{')
|
||||
.replace(/{{ /gmi, '{{')
|
||||
.replace(/ }}/gmi, '}}')
|
||||
.trim();
|
||||
}
|
||||
templates[i] = template;
|
||||
}
|
||||
fs.writeFileSync(root('.build/template.yaml'), yaml.safeDump(templates));
|
||||
};
|
||||
|
||||
module.exports = build;
|
||||
@@ -0,0 +1,3 @@
|
||||
require('./index.js')('development').catch((e) => {
|
||||
console.error(e);
|
||||
});
|
||||
+22
-7
@@ -1,9 +1,24 @@
|
||||
const fs = require('fs');
|
||||
const root = require('./root');
|
||||
try {
|
||||
fs.rmdirSync(root('.build'));
|
||||
} catch (e) { }
|
||||
fs.mkdirSync(root('.build'));
|
||||
require('./locales')();
|
||||
require('./buildModule')();
|
||||
require('./webpack')();
|
||||
|
||||
async function build(type) {
|
||||
if (!['development', 'production'].includes(type)) throw new Error('Unknown type: ' + type);
|
||||
try {
|
||||
fs.rmdirSync(root('.build'));
|
||||
} catch (e) { }
|
||||
fs.mkdirSync(root('.build'));
|
||||
await Promise.all([
|
||||
require('./locales')(type),
|
||||
require('./buildModule')(type),
|
||||
require('./buildTemplate')(type),
|
||||
require('./webpack')(type),
|
||||
]);
|
||||
}
|
||||
|
||||
module.exports = build;
|
||||
|
||||
if (!module.parent) {
|
||||
build('development').catch((e) => {
|
||||
console.error(e);
|
||||
});
|
||||
}
|
||||
+5
-4
@@ -1,13 +1,14 @@
|
||||
const yaml = require('js-yaml');
|
||||
const fs = require('fs');
|
||||
const root = require('./root');
|
||||
|
||||
const build = async () => {
|
||||
let langs = fs.readdirSync(root('locales'));
|
||||
let lang = {};
|
||||
for (let i of langs) {
|
||||
const langs = fs.readdirSync(root('locales'));
|
||||
const lang = {};
|
||||
for (const i of langs) {
|
||||
const content = fs.readFileSync(root(`locales/${i}`)).toString();
|
||||
lang[i.split('.')[0]] = yaml.safeLoad(content);
|
||||
}
|
||||
fs.writeFileSync(root('.build/locales.json'), JSON.stringify(lang));
|
||||
}
|
||||
};
|
||||
module.exports = build;
|
||||
@@ -0,0 +1,3 @@
|
||||
require('./index.js')('production').catch((e) => {
|
||||
console.error(e);
|
||||
});
|
||||
@@ -1,4 +1,5 @@
|
||||
const path = require('path');
|
||||
|
||||
function root(name) {
|
||||
return path.resolve(__dirname, '..', name);
|
||||
}
|
||||
|
||||
+11
-9
@@ -1,11 +1,13 @@
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
const fs = require('fs');
|
||||
const webpack = require('webpack');
|
||||
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin');
|
||||
const root = require('./root');
|
||||
const build = async () => {
|
||||
|
||||
const build = async (type) => {
|
||||
function hackNodeModuleFormidable() {
|
||||
const tasks = ['incoming_form', 'file', 'json_parser', 'querystring_parser'];
|
||||
for (let task of tasks) {
|
||||
for (const task of tasks) {
|
||||
let file = fs.readFileSync(root(`node_modules/formidable/lib/${task}.js`)).toString();
|
||||
if (file.startsWith('if (global.GENTLY) require = GENTLY.hijack(require);')) {
|
||||
file = file.split('\n');
|
||||
@@ -18,22 +20,22 @@ const build = async () => {
|
||||
hackNodeModuleFormidable();
|
||||
|
||||
const config = {
|
||||
mode: 'development',
|
||||
mode: type,
|
||||
entry: {
|
||||
development: root('hydro/development.js'),
|
||||
install: root('hydro/install.js'),
|
||||
uninstall: root('hydro/uninstall.js')
|
||||
uninstall: root('hydro/uninstall.js'),
|
||||
},
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
path: root('.build')
|
||||
path: root('.build'),
|
||||
},
|
||||
target: 'node',
|
||||
module: {},
|
||||
plugins: [
|
||||
new webpack.ProgressPlugin(),
|
||||
new FriendlyErrorsPlugin(),
|
||||
]
|
||||
],
|
||||
};
|
||||
const compiler = webpack(config);
|
||||
await new Promise((resolve, reject) => {
|
||||
@@ -41,12 +43,12 @@ const build = async () => {
|
||||
if (err) {
|
||||
console.error(err.stack || err);
|
||||
if (err.details) console.error(err.details);
|
||||
reject(1);
|
||||
reject();
|
||||
}
|
||||
if (stats.hasErrors()) process.exitCode = 1;
|
||||
resolve();
|
||||
});
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = build;
|
||||
+14
-14
@@ -9,7 +9,10 @@ process.stdin.on('data', async (input) => {
|
||||
}
|
||||
});
|
||||
|
||||
global.Hydro = {};
|
||||
global.Hydro = {
|
||||
handler: {},
|
||||
template: {}
|
||||
};
|
||||
|
||||
require('./lib/i18n');
|
||||
require('./utils');
|
||||
@@ -31,21 +34,18 @@ async function run() {
|
||||
require('./service/gridfs');
|
||||
require('./service/queue');
|
||||
const server = require('./service/server');
|
||||
const HandlerHome = require('./handler/home');
|
||||
const HandlerProblem = require('./handler/problem');
|
||||
const HandlerRecord = require('./handler/record');
|
||||
const HandlerJudge = require('./handler/judge');
|
||||
const HandlerUser = require('./handler/user');
|
||||
const HandlerContest = require('./handler/contest');
|
||||
const HandlerTraining = require('./handler/training');
|
||||
const HandlerDiscussion = require('./handler/discussion');
|
||||
const HandlerManage = require('./handler/manage');
|
||||
const HandlerImport = require('./handler/import');
|
||||
const builtinHandler = [
|
||||
'home', 'problem', 'record', 'judge', 'user',
|
||||
'contest', 'training', 'discussion', 'manage', 'import',
|
||||
];
|
||||
for (const i of builtinHandler) require(`./handler/${i}`);
|
||||
await loader.model();
|
||||
await loader.handler();
|
||||
HandlerContest.apply();
|
||||
HandlerDiscussion.apply();
|
||||
HandlerImport.apply();
|
||||
for (const i in global.Hydro.handler) {
|
||||
await global.Hydro.handler[i].apply();
|
||||
}
|
||||
const notfound = require(`./handler/notfound`);
|
||||
await notfound.apply();
|
||||
server.start();
|
||||
}
|
||||
run().catch((e) => {
|
||||
|
||||
@@ -267,7 +267,7 @@ class ContestCreateHandler extends ContestHandler {
|
||||
}
|
||||
}
|
||||
|
||||
function apply() {
|
||||
async function apply() {
|
||||
Route('/c', module.exports.ContestListHandler);
|
||||
Route('/c/:tid', module.exports.ContestDetailHandler);
|
||||
Route('/c/:tid/edit', module.exports.ContestEditHandler);
|
||||
@@ -278,7 +278,7 @@ function apply() {
|
||||
Route('/contest/create', module.exports.ContestCreateHandler);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
global.Hydro.handler.contest = module.exports = {
|
||||
ContestListHandler,
|
||||
ContestDetailHandler,
|
||||
ContestEditHandler,
|
||||
|
||||
+15
-10
@@ -34,7 +34,9 @@ class DiscussionHandler extends Handler {
|
||||
if (drrid) {
|
||||
[, this.drrdoc] = await discussion.getTailReply(drid, drrid);
|
||||
if (!this.drrdoc) throw new DiscussionNotFoundError(drrid);
|
||||
if (this.drrdoc.parent !== this.drdoc._id) throw new DocumentNotFoundError(drid);
|
||||
if (this.drrdoc.parent !== this.drdoc._id) {
|
||||
throw new DocumentNotFoundError(drid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,7 +62,11 @@ class DiscussionHandler extends Handler {
|
||||
|
||||
class DiscussionMainHandler extends DiscussionHandler {
|
||||
async get({ page = 1 }) {
|
||||
const [ddocs, dpcount] = await paginate(discussion.getMulti(), page, constants.DISCUSSION_PER_PAGE);
|
||||
const [ddocs, dpcount] = await paginate(
|
||||
discussion.getMulti(),
|
||||
page,
|
||||
constants.DISCUSSION_PER_PAGE,
|
||||
);
|
||||
const udict = await user.getList(ddocs.map((ddoc) => ddoc.owner));
|
||||
this.response.template = 'discussion_main_or_node.html';
|
||||
this.response.body = {
|
||||
@@ -114,12 +120,11 @@ class DiscussionCreateHandler extends DiscussionHandler {
|
||||
type, docId, title, content, highlight,
|
||||
}) {
|
||||
this.limitRate('add_discussion', 3600, 30);
|
||||
const flags = {};
|
||||
if (highlight) {
|
||||
this.checkPerm(PERM_HIGHLIGHT_DISCUSSION);
|
||||
flags.highlight = true;
|
||||
}
|
||||
const did = await discussion.add(type, docId, this.user._id, title, content, this.request.ip, flags);
|
||||
if (highlight) this.checkPerm(PERM_HIGHLIGHT_DISCUSSION);
|
||||
const did = await discussion.add(
|
||||
type, docId, this.user._id,
|
||||
title, content, this.request.ip, highlight,
|
||||
);
|
||||
this.response.body = { did };
|
||||
this.response.redirect = `/discuss/${did}`;
|
||||
}
|
||||
@@ -257,7 +262,7 @@ class DiscussionEditHandler extends DiscussionHandler {
|
||||
}
|
||||
}
|
||||
|
||||
function apply() {
|
||||
async function apply() {
|
||||
Route('/discuss', module.exports.DiscussionMainHandler);
|
||||
Route('/discuss/:did', module.exports.DiscussionDetailHandler);
|
||||
Route('/discuss/:did/edit', module.exports.DiscussionEditHandler);
|
||||
@@ -268,7 +273,7 @@ function apply() {
|
||||
Route('/discuss/:type/:docId/create', module.exports.DiscussionCreateHandler);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
global.Hydro.handler.discussion = module.exports = {
|
||||
DiscussionMainHandler,
|
||||
DiscussionDetailHandler,
|
||||
DiscussionEditHandler,
|
||||
|
||||
@@ -171,11 +171,16 @@ class UserChangemailWithCodeHandler extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
Route('/', HomeHandler);
|
||||
Route('/home/security', HomeSecurityHandler);
|
||||
Route('/home/changeMail/:code', UserChangemailWithCodeHandler);
|
||||
Route('/home/settings/:category', HomeSettingsHandler);
|
||||
async function apply() {
|
||||
Route('/', module.exports.HomeHandler);
|
||||
Route('/home/security', module.exports.HomeSecurityHandler);
|
||||
Route('/home/changeMail/:code', module.exports.UserChangemailWithCodeHandler);
|
||||
Route('/home/settings/:category', module.exports.HomeSettingsHandler);
|
||||
}
|
||||
|
||||
global.Hydro.handler.home = module.exports = {
|
||||
HomeHandler, HomeSecurityHandler, HomeSettingsHandler, UserChangemailWithCodeHandler, apply,
|
||||
};
|
||||
/*
|
||||
@app.route('/home/messages', 'home_messages', global_route=True)
|
||||
class HomeMessagesHandler(base.OperationHandler):
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
const problem = require('../model/problem');
|
||||
const { Route, Handler } = require('../service/server');
|
||||
const { PERM_CREATE_PROBLEM } = require('../permission');
|
||||
@@ -23,8 +22,10 @@ class ProblemImportHandler extends Handler {
|
||||
async post({
|
||||
url, pid, hidden, remoteType,
|
||||
}) {
|
||||
if (remoteType !== 'syzoj') throw new ValidationError('remoteType');
|
||||
const [pdoc, testdata] = await this.syzoj(url);
|
||||
if (typeof this[`from_${remoteType}`] !== 'function') {
|
||||
throw new ValidationError('remoteType');
|
||||
}
|
||||
const [pdoc, testdata] = await this[`from_${remoteType}`](url);
|
||||
if (pid) pdoc.pid = pid;
|
||||
if (hidden) pdoc.hidden = true;
|
||||
const _id = await problem.add(pdoc);
|
||||
@@ -39,6 +40,6 @@ async function apply() {
|
||||
Route('/problem/import', module.exports.ProblemImportHandler);
|
||||
}
|
||||
|
||||
global.Hydro['handler.import'] = module.exports = {
|
||||
global.Hydro.handler.import = module.exports = {
|
||||
ProblemImportHandler, apply,
|
||||
};
|
||||
@@ -183,5 +183,11 @@ class JudgeConnectionHandler extends ConnectionHandler {
|
||||
}
|
||||
}
|
||||
|
||||
Route('/judge', JudgeHandler);
|
||||
Connection('/judge/conn', JudgeConnectionHandler);
|
||||
async function apply() {
|
||||
Route('/judge', module.exports.JudgeHandler);
|
||||
Connection('/judge/conn', module.exports.JudgeConnectionHandler);
|
||||
}
|
||||
|
||||
global.Hydro.handler.judge = module.exports = {
|
||||
JudgeHandler, JudgeConnectionHandler, apply,
|
||||
};
|
||||
+18
-6
@@ -120,9 +120,21 @@ class ManageRoleHandler extends ManageHandler {
|
||||
}
|
||||
}
|
||||
|
||||
Route('/manage', ManageMainHandler);
|
||||
Route('/manage/dashboard', ManageDashboardHandler);
|
||||
Route('/manage/edit', ManageEditHandler);
|
||||
Route('/manage/user', ManageUserHandler);
|
||||
Route('/manage/permission', ManagePermissionHandler);
|
||||
Route('/manage/role', ManageRoleHandler);
|
||||
async function apply() {
|
||||
Route('/manage', module.exports.ManageMainHandler);
|
||||
Route('/manage/dashboard', module.exports.ManageDashboardHandler);
|
||||
Route('/manage/edit', module.exports.ManageEditHandler);
|
||||
Route('/manage/user', module.exports.ManageUserHandler);
|
||||
Route('/manage/permission', module.exports.ManagePermissionHandler);
|
||||
Route('/manage/role', module.exports.ManageRoleHandler);
|
||||
}
|
||||
|
||||
global.Hydro.handler.manage = module.exports = {
|
||||
ManageMainHandler,
|
||||
ManageDashboardHandler,
|
||||
ManageEditHandler,
|
||||
ManageUserHandler,
|
||||
ManagePermissionHandler,
|
||||
ManageRoleHandler,
|
||||
apply,
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
const { Route, Handler } = require('../service/server');
|
||||
const { NotFoundError } = require('../error');
|
||||
|
||||
class NotFoundHandler extends Handler {
|
||||
async prepare() {
|
||||
throw new NotFoundError();
|
||||
}
|
||||
}
|
||||
|
||||
async function apply() {
|
||||
Route('/:param1', module.exports.NotFoundHandler);
|
||||
Route('/:param1/:param2', module.exports.NotFoundHandler);
|
||||
Route('/:param1/:param2/:param3', module.exports.NotFoundHandler);
|
||||
Route('/:param1/:param2/:param3/:param4', module.exports.NotFoundHandler);
|
||||
}
|
||||
|
||||
global.Hydro.handler.notfound = module.exports = {
|
||||
NotFoundHandler, apply,
|
||||
};
|
||||
+39
-16
@@ -71,7 +71,9 @@ class ProblemDetailHandler extends ProblemHandler {
|
||||
this.uid = this.user._id;
|
||||
this.pid = pid;
|
||||
if (pid) this.pdoc = await problem.get(pid, this.uid);
|
||||
if (this.pdoc.hidden && this.pdoc.owner !== this.uid) this.checkPerm(PERM_VIEW_PROBLEM_HIDDEN);
|
||||
if (this.pdoc.hidden && this.pdoc.owner !== this.uid) {
|
||||
this.checkPerm(PERM_VIEW_PROBLEM_HIDDEN);
|
||||
}
|
||||
if (this.pdoc) this.udoc = await user.getById(this.pdoc.owner);
|
||||
this.response.body = {
|
||||
pdoc: this.pdoc,
|
||||
@@ -376,18 +378,39 @@ class ProblemCreateHandler extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
Route('/p', ProblemHandler);
|
||||
Route('/problem/random', ProblemRandomHandler);
|
||||
Route('/p/:pid', ProblemDetailHandler);
|
||||
Route('/p/:pid/submit', ProblemSubmitHandler);
|
||||
Route('/p/:pid/pretest', ProblemPretestHandler);
|
||||
Route('/p/:pid/settings', ProblemSettingsHandler);
|
||||
Route('/p/:pid/statistics', ProblemStatisticsHandler);
|
||||
Route('/p/:pid/edit', ProblemEditHandler);
|
||||
Route('/p/:pid/upload', ProblemDataUploadHandler);
|
||||
Route('/p/:pid/data', ProblemDataDownloadHandler);
|
||||
Route('/p/:pid/solution', ProblemSolutionHandler);
|
||||
Route('/p/:pid/solution/:psid/raw', ProblemSolutionRawHandler);
|
||||
Route('/p/:pid/solution/:psid/:psrid/raw', ProblemSolutionReplyRawHandler);
|
||||
Route('/problem/create', ProblemCreateHandler);
|
||||
Connection('/p/:pid/pretest-conn', ProblemPretestConnectionHandler);
|
||||
async function apply() {
|
||||
Route('/p', module.exports.ProblemHandler);
|
||||
Route('/problem/random', module.exports.ProblemRandomHandler);
|
||||
Route('/p/:pid', module.exports.ProblemDetailHandler);
|
||||
Route('/p/:pid/submit', module.exports.ProblemSubmitHandler);
|
||||
Route('/p/:pid/pretest', module.exports.ProblemPretestHandler);
|
||||
Route('/p/:pid/settings', module.exports.ProblemSettingsHandler);
|
||||
Route('/p/:pid/statistics', module.exports.ProblemStatisticsHandler);
|
||||
Route('/p/:pid/edit', module.exports.ProblemEditHandler);
|
||||
Route('/p/:pid/upload', module.exports.ProblemDataUploadHandler);
|
||||
Route('/p/:pid/data', module.exports.ProblemDataDownloadHandler);
|
||||
Route('/p/:pid/solution', module.exports.ProblemSolutionHandler);
|
||||
Route('/p/:pid/solution/:psid/raw', module.exports.ProblemSolutionRawHandler);
|
||||
Route('/p/:pid/solution/:psid/:psrid/raw', module.exports.ProblemSolutionReplyRawHandler);
|
||||
Route('/problem/create', module.exports.ProblemCreateHandler);
|
||||
Connection('/p/:pid/pretest-conn', module.exports.ProblemPretestConnectionHandler);
|
||||
}
|
||||
|
||||
global.Hydro.handler.problem = module.exports = {
|
||||
ProblemHandler,
|
||||
ProblemRandomHandler,
|
||||
ProblemDetailHandler,
|
||||
ProblemSubmitHandler,
|
||||
ProblemPretestHandler,
|
||||
ProblemSettingsHandler,
|
||||
ProblemStatisticsHandler,
|
||||
ProblemEditHandler,
|
||||
ProblemDataUploadHandler,
|
||||
ProblemDataDownloadHandler,
|
||||
ProblemSolutionHandler,
|
||||
ProblemSolutionRawHandler,
|
||||
ProblemSolutionReplyRawHandler,
|
||||
ProblemCreateHandler,
|
||||
ProblemPretestConnectionHandler,
|
||||
apply,
|
||||
};
|
||||
+25
-13
@@ -34,18 +34,16 @@ class RecordListHandler extends Handler {
|
||||
for (const pdoc of plist) {
|
||||
pdict[pdoc._id] = pdoc;
|
||||
}
|
||||
const path = [
|
||||
['Hydro', '/'],
|
||||
['record_main', null],
|
||||
];
|
||||
this.response.body = {
|
||||
path: [
|
||||
['Hydro', '/'],
|
||||
['record_main', null],
|
||||
],
|
||||
page,
|
||||
rdocs,
|
||||
pdict,
|
||||
udict,
|
||||
path, page, rdocs, pdict, udict,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class RecordDetailHandler extends Handler {
|
||||
async get({ rid }) {
|
||||
this.response.template = 'record_detail.html';
|
||||
@@ -66,6 +64,7 @@ class RecordDetailHandler extends Handler {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class RecordRejudgeHandler extends Handler {
|
||||
async post({ rid }) {
|
||||
this.checkPerm(PERM_REJUDGE);
|
||||
@@ -77,6 +76,7 @@ class RecordRejudgeHandler extends Handler {
|
||||
this.back();
|
||||
}
|
||||
}
|
||||
|
||||
class RecordConnectionHandler extends ConnectionHandler {
|
||||
async prepare() {
|
||||
bus.subscribe(['record_change'], this.onRecordChange);
|
||||
@@ -102,6 +102,7 @@ class RecordConnectionHandler extends ConnectionHandler {
|
||||
this.send({ html: await this.renderHTML('record_main_tr.html', { rdoc, udoc, pdoc }) });
|
||||
}
|
||||
}
|
||||
|
||||
class RecordDetailConnectionHandler extends contest.ContestHandlerMixin(ConnectionHandler) {
|
||||
async prepare({ rid }) {
|
||||
const rdoc = await record.get(rid);
|
||||
@@ -131,8 +132,19 @@ class RecordDetailConnectionHandler extends contest.ContestHandlerMixin(Connecti
|
||||
}
|
||||
}
|
||||
|
||||
Route('/r', RecordListHandler);
|
||||
Route('/r/:rid', RecordDetailHandler);
|
||||
Route('/r/:rid/rejudge', RecordRejudgeHandler);
|
||||
Connection('/record-conn', RecordConnectionHandler);
|
||||
Connection('/record-detail-conn', RecordDetailConnectionHandler);
|
||||
async function apply() {
|
||||
Route('/r', module.exports.RecordListHandler);
|
||||
Route('/r/:rid', module.exports.RecordDetailHandler);
|
||||
Route('/r/:rid/rejudge', module.exports.RecordRejudgeHandler);
|
||||
Connection('/record-conn', module.exports.RecordConnectionHandler);
|
||||
Connection('/record-detail-conn', module.exports.RecordDetailConnectionHandler);
|
||||
}
|
||||
|
||||
global.Hydro.handler.record = module.exports = {
|
||||
RecordListHandler,
|
||||
RecordDetailHandler,
|
||||
RecordRejudgeHandler,
|
||||
RecordConnectionHandler,
|
||||
RecordDetailConnectionHandler,
|
||||
apply,
|
||||
};
|
||||
@@ -237,7 +237,17 @@ class TrainingEditHandler extends TrainingHandler {
|
||||
}
|
||||
}
|
||||
|
||||
Route('/t', TrainingMainHandler);
|
||||
Route('/t/:tid', TrainingDetailHandler);
|
||||
Route('/t/:tid/edit', TrainingEditHandler);
|
||||
Route('/training/create', TrainingCreateHandler);
|
||||
async function apply() {
|
||||
Route('/t', module.exports.TrainingMainHandler);
|
||||
Route('/t/:tid', module.exports.TrainingDetailHandler);
|
||||
Route('/t/:tid/edit', module.exports.TrainingEditHandler);
|
||||
Route('/training/create', module.exports.TrainingCreateHandler);
|
||||
}
|
||||
|
||||
global.Hydro.handler.training = module.exports = {
|
||||
TrainingMainHandler,
|
||||
TrainingDetailHandler,
|
||||
TrainingEditHandler,
|
||||
TrainingCreateHandler,
|
||||
apply,
|
||||
};
|
||||
+22
-8
@@ -181,11 +181,25 @@ class UserSearchHandler extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
Route('/login', UserLoginHandler);
|
||||
Route('/register', UserRegisterHandler);
|
||||
Route('/register/:code', UserRegisterWithCodeHandler);
|
||||
Route('/logout', UserLogoutHandler);
|
||||
Route('/lostpass', UserLostPassHandler);
|
||||
Route('/lostpass/:code', UserLostPassWithCodeHandler);
|
||||
Route('/user/search', UserSearchHandler);
|
||||
Route('/user/:uid', UserDetailHandler);
|
||||
async function apply() {
|
||||
Route('/login', module.exports.UserLoginHandler);
|
||||
Route('/register', module.exports.UserRegisterHandler);
|
||||
Route('/register/:code', module.exports.UserRegisterWithCodeHandler);
|
||||
Route('/logout', module.exports.UserLogoutHandler);
|
||||
Route('/lostpass', module.exports.UserLostPassHandler);
|
||||
Route('/lostpass/:code', module.exports.UserLostPassWithCodeHandler);
|
||||
Route('/user/search', module.exports.UserSearchHandler);
|
||||
Route('/user/:uid', module.exports.UserDetailHandler);
|
||||
}
|
||||
|
||||
global.Hydro.handler.user = module.exports = {
|
||||
UserLoginHandler,
|
||||
UserRegisterHandler,
|
||||
UserRegisterWithCodeHandler,
|
||||
UserLogoutHandler,
|
||||
UserLostPassHandler,
|
||||
UserLostPassWithCodeHandler,
|
||||
UserSearchHandler,
|
||||
UserDetailHandler,
|
||||
apply,
|
||||
};
|
||||
+11
-5
@@ -14,9 +14,15 @@ function exist(name) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const superRequire = (name) => (__non_webpack_require__
|
||||
? __non_webpack_require__(root(name))
|
||||
: require(root(name)));
|
||||
const superRequire = (name) => {
|
||||
let m;
|
||||
try {
|
||||
m = require(root(name)); // eslint-disable-line import/no-dynamic-require
|
||||
} catch (e) {
|
||||
m = __non_webpack_require__(root(name)); // eslint-disable-line no-undef
|
||||
}
|
||||
return m;
|
||||
};
|
||||
|
||||
async function prepare() {
|
||||
installed = fs.readdirSync(root('.build/module'));
|
||||
@@ -26,8 +32,8 @@ async function handler() {
|
||||
for (const i of installed) {
|
||||
if (exist(`.build/module/${i}/handler.js`)) {
|
||||
superRequire(`.build/module/${i}/handler.js`);
|
||||
console.log(`Handler init: ${i}`);
|
||||
}
|
||||
console.log(`Handler init: ${i}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +41,8 @@ async function model() {
|
||||
for (const i of installed) {
|
||||
if (exist(`.build/module/${i}/model.js`)) {
|
||||
superRequire(`.build/module/${i}/model.js`);
|
||||
console.log(`Model init: ${i}`);
|
||||
}
|
||||
console.log(`Model init: ${i}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,11 @@ async function edit(tid, $set) {
|
||||
if ($set.title) validator.checkTitle($set.title);
|
||||
if ($set.content) validator.checkIntro($set.content);
|
||||
if ($set.rule) { if (!this.RULES[$set.rule]) throw new ValidationError('rule'); }
|
||||
if ($set.beginAt && $set.endAt) if ($set.beginAt >= $set.endAt) throw new ValidationError('beginAt', 'endAt');
|
||||
if ($set.beginAt && $set.endAt) {
|
||||
if ($set.beginAt >= $set.endAt) {
|
||||
throw new ValidationError('beginAt', 'endAt');
|
||||
}
|
||||
}
|
||||
const tdoc = await coll.findOne({ tid });
|
||||
if (!tdoc) throw new ContestNotFoundError(tid);
|
||||
this.RULES[$set.rule || tdoc.rule].check(Object.assign(tdoc, $set));
|
||||
@@ -84,7 +88,8 @@ function getStatus(tid, uid) {
|
||||
}
|
||||
async function getListStatus(uid, tids) {
|
||||
const r = {};
|
||||
for (const tid of tids) r[tid] = await getStatus(tid, uid); // eslint-disable-line no-await-in-loop
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
for (const tid of tids) r[tid] = await getStatus(tid, uid);
|
||||
return r;
|
||||
}
|
||||
async function attend(tid, uid) {
|
||||
|
||||
@@ -65,7 +65,7 @@ function editReply(drid, content) {
|
||||
async function delReply(drid) {
|
||||
const drdoc = await getReply(drid);
|
||||
if (!drdoc) throw new DocumentNotFoundError(drid);
|
||||
return await Promise.all([
|
||||
return await Promise.all([ // eslint-disable-line no-return-await
|
||||
collReply.deleteOne({ _id: drid }),
|
||||
coll.updateOne({ _id: drdoc.did }, { $inc: { nReply: -1 } }),
|
||||
]);
|
||||
@@ -112,6 +112,7 @@ async function editTailReply(drid, drrid, content) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line no-return-await
|
||||
return await collReply.findOneAndUpdate({ _id: drdoc._id }, { $set: { reply } });
|
||||
}
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ async function setTestdata(_id, readStream) {
|
||||
f.once('error', reject);
|
||||
});
|
||||
if (pdoc.data && typeof pdoc.data === 'object') gridfs.delete(this.pdoc.data);
|
||||
return await edit(_id, { data: f.id });
|
||||
return await edit(_id, { data: f.id }); // eslint-disable-line no-return-await
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -28,13 +28,14 @@ async function get(psid) {
|
||||
}
|
||||
|
||||
function getMany(query, sort, page, limit) {
|
||||
return coll.find(query).sort(sort).skip((page - 1) * limit).limit(limit)
|
||||
return coll.find(query).sort(sort)
|
||||
.skip((page - 1) * limit).limit(limit)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
async function edit(_id, content) {
|
||||
validator.checkContent(content);
|
||||
await coll.findOneAndUpdate({ _id }, { $set: { content } });
|
||||
await coll.updateOne({ _id }, { $set: { content } });
|
||||
const psdoc = await get(_id);
|
||||
if (!psdoc) throw new SolutionNotFoundError(_id);
|
||||
return psdoc;
|
||||
@@ -79,7 +80,8 @@ async function editReply(psid, psrid, content) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return await coll.findOneAndUpdate({ _id: psdoc._id }, { $set: { reply } });
|
||||
// eslint-disable-next-line no-return-await
|
||||
return await coll.updateOne({ _id: psdoc._id }, { $set: { reply } });
|
||||
}
|
||||
|
||||
function delReply(psid, psrid) {
|
||||
@@ -91,7 +93,7 @@ async function vote(psid, uid, value) {
|
||||
if (pssdoc) await collStatus.deleteOne({ psid, uid });
|
||||
await collStatus.insertOne({ psid, uid, vote: value });
|
||||
if (pssdoc) value += -pssdoc.vote;
|
||||
await coll.findOneAndUpdate({ _id: psid }, { $inc: { vote: value } });
|
||||
await coll.updateOne({ _id: psid }, { $inc: { vote: value } });
|
||||
pssdoc = await collStatus.findOne({ psid, uid });
|
||||
const psdoc = await coll.findOne({ _id: psid });
|
||||
return [psdoc, pssdoc];
|
||||
|
||||
@@ -27,12 +27,12 @@ async function enroll(tid, uid) {
|
||||
} catch (e) {
|
||||
throw new TrainingAlreadyEnrollError(tid, uid);
|
||||
}
|
||||
await coll.findOneAndUpdate({ _id: tid }, { $inc: { enroll: 1 } });
|
||||
await coll.updateOne({ _id: tid }, { $inc: { enroll: 1 } });
|
||||
}
|
||||
|
||||
async function setStatus(tid, uid, $set) {
|
||||
await collStatus.findOneAndUpdate({ tid, uid }, { $set });
|
||||
return await collStatus.findOne({ tid, uid });
|
||||
await collStatus.updateOne({ tid, uid }, { $set });
|
||||
return await collStatus.findOne({ tid, uid }); // eslint-disable-line no-return-await
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
const { defaults } = require('lodash');
|
||||
const db = require('../service/db');
|
||||
const builtin = require('../model/builtin');
|
||||
const pwhash = require('../lib/pwhash');
|
||||
const { udoc } = require('../interface');
|
||||
|
||||
async function run() {
|
||||
const collUser = db.collection('user');
|
||||
const collRole = db.collection('role');
|
||||
const collBlacklist = db.collection('blacklist');
|
||||
const collToken = db.collection('token');
|
||||
async function createUser() {
|
||||
const salt = pwhash.salt();
|
||||
await collUser.insertMany([
|
||||
defaults({
|
||||
_id: 0,
|
||||
uname: 'Hydro',
|
||||
unameLower: 'hydro',
|
||||
mail: 'hydro@hydro',
|
||||
mailLower: 'hydro@hydro',
|
||||
role: 'guest',
|
||||
}, udoc),
|
||||
defaults({
|
||||
_id: 1,
|
||||
mail: 'guest@hydro',
|
||||
mailLower: 'guest@hydro',
|
||||
uname: 'Guest',
|
||||
unameLower: 'guest',
|
||||
role: 'guest',
|
||||
}, udoc),
|
||||
defaults({
|
||||
_id: -1,
|
||||
mail: 'root@hydro',
|
||||
mailLower: 'root@hydro',
|
||||
uname: 'Root',
|
||||
unameLower: 'root',
|
||||
hash: pwhash.hash('rootroot', salt),
|
||||
salt,
|
||||
gravatar: 'root@hydro',
|
||||
role: 'root',
|
||||
}, udoc),
|
||||
]);
|
||||
}
|
||||
await collUser.createIndex('unameLower', { unique: true });
|
||||
await collUser.createIndex('mailLower', { sparse: true });
|
||||
await collRole.insertMany(builtin.BUILTIN_ROLES);
|
||||
await collBlacklist.createIndex('expireAt', { expireAfterSeconds: 0 });
|
||||
await collToken.createIndex([{ uid: 1 }, { tokenType: 1 }, { updateAt: -1 }], { sparse: true });
|
||||
await collToken.createIndex('expireAt', { expireAfterSeconds: 0 });
|
||||
await createUser();
|
||||
console.log('Installed');
|
||||
}
|
||||
|
||||
module.exports = { run };
|
||||
@@ -0,0 +1,8 @@
|
||||
const db = require('../service/db.js');
|
||||
|
||||
async function run() {
|
||||
await db.dropDatabase();
|
||||
console.log('Dropped');
|
||||
}
|
||||
|
||||
module.exports = { run };
|
||||
+8
-14
@@ -17,7 +17,7 @@ const token = require('../model/token');
|
||||
const opcount = require('../model/opcount');
|
||||
const {
|
||||
UserNotFoundError, BlacklistedError, PermissionError,
|
||||
NotFoundError, UserFacingError, ValidationError,
|
||||
UserFacingError, ValidationError,
|
||||
} = require('../error');
|
||||
|
||||
const app = new Koa();
|
||||
@@ -166,19 +166,13 @@ class Handler {
|
||||
}
|
||||
|
||||
async renderBody() {
|
||||
if (!this.response.redirect) {
|
||||
if (!(this.response.body || this.response.template)) {
|
||||
this.response.body = { error: new NotFoundError() };
|
||||
this.response.template = 'error.html';
|
||||
}
|
||||
if (!this.preferJson) {
|
||||
if (this.response.body || this.response.template) {
|
||||
if (this.request.query.noTemplate || this.preferJson) return;
|
||||
const templateName = this.request.query.template || this.response.template;
|
||||
if (templateName) {
|
||||
this.response.body = this.response.body || {};
|
||||
await this.render(templateName, this.response.body);
|
||||
}
|
||||
if (!this.response.redirect && !this.preferJson) {
|
||||
if (this.response.body || this.response.template) {
|
||||
if (this.request.query.noTemplate || this.preferJson) return;
|
||||
const templateName = this.request.query.template || this.response.template;
|
||||
if (templateName) {
|
||||
this.response.body = this.response.body || {};
|
||||
await this.render(templateName, this.response.body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-2
@@ -26,12 +26,16 @@
|
||||
"devDependencies": {
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-airbnb-base": "^14.1.0",
|
||||
"eslint-plugin-import": "^2.20.2"
|
||||
"eslint-plugin-import": "^2.20.2",
|
||||
"friendly-errors-webpack-plugin": "^1.7.0",
|
||||
"webpack": "^4.42.1"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "node build/index.js",
|
||||
"build:development": "node build/development.js",
|
||||
"build:production": "node build/production.js",
|
||||
"pack": "pkg .",
|
||||
"lint": "eslint hydro module --fix"
|
||||
"lint": "eslint build hydro module --fix"
|
||||
},
|
||||
"pkg": {
|
||||
"scripts": [
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
Reference in new issue
Block a user