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
a248425db6
commit
441eeadaf3
23 files changed
+158
-97
No files matched your search
+17
-2
@@ -14,6 +14,7 @@ const document = require('../model/document');
|
||||
const system = require('../model/system');
|
||||
const user = require('../model/user');
|
||||
const setting = require('../model/setting');
|
||||
const domain = require('../model/domain');
|
||||
const discussion = require('../model/discussion');
|
||||
const token = require('../model/token');
|
||||
const training = require('../model/training');
|
||||
@@ -87,10 +88,24 @@ class HomeHandler extends Handler {
|
||||
this.homework(domainId), this.contest(domainId),
|
||||
this.training(domainId), this.discussion(domainId),
|
||||
]);
|
||||
const udict = await user.getList(domainId, ddocs.map((ddoc) => ddoc.owner));
|
||||
const [udict, dodoc, vnodes] = await Promise.all([
|
||||
user.getList(domainId, ddocs.map((ddoc) => ddoc.owner)),
|
||||
domain.get(domainId),
|
||||
discussion.getNodes(domainId),
|
||||
]);
|
||||
this.response.template = 'main.html';
|
||||
this.response.body = {
|
||||
htdocs, htsdict, tdocs, tsdict, trdocs, trsdict, ddocs, vndict, udict,
|
||||
htdocs,
|
||||
htsdict,
|
||||
tdocs,
|
||||
tsdict,
|
||||
trdocs,
|
||||
trsdict,
|
||||
ddocs,
|
||||
vndict,
|
||||
udict,
|
||||
domain: dodoc,
|
||||
vnodes,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+11
-9
@@ -32,16 +32,18 @@ class ProblemImportHandler extends Handler {
|
||||
if (pid) pdoc.pid = pid;
|
||||
if (hidden) pdoc.hidden = true;
|
||||
const docId = await problem.add(domainId, pdoc.title, pdoc.content, this.user._id, pdoc);
|
||||
const file = path.resolve(os.tmpdir(), 'hydro', `import_${domainId}_${pid}.zip`);
|
||||
const w = fs.createWriteStream(file);
|
||||
await new Promise((resolve, reject) => {
|
||||
w.on('finish', resolve);
|
||||
w.on('error', reject);
|
||||
testdata.pipe(w);
|
||||
});
|
||||
await problem.setTestdata(domainId, docId, file);
|
||||
if (testdata) {
|
||||
const file = path.resolve(os.tmpdir(), 'hydro', `import_${domainId}_${pid || pdoc.pid || docId}.zip`);
|
||||
const w = fs.createWriteStream(file);
|
||||
await new Promise((resolve, reject) => {
|
||||
w.on('finish', resolve);
|
||||
w.on('error', reject);
|
||||
testdata.pipe(w);
|
||||
});
|
||||
await problem.setTestdata(domainId, docId, file);
|
||||
}
|
||||
this.response.body = { pid: pid || docId };
|
||||
this.response.redirect = `/p/${pid || docId}/settings`;
|
||||
this.response.redirect = this.url('problem_settings', { pid: pid || docId });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+25
-10
@@ -27,14 +27,23 @@ class ProblemHandler extends Handler {
|
||||
this.checkPerm(PERM_VIEW_PROBLEM);
|
||||
}
|
||||
|
||||
async get({ domainId, page = 1, category = '' }) {
|
||||
async get({ domainId, page = 1, q = '' }) {
|
||||
this.response.template = 'problem_main.html';
|
||||
const q = {};
|
||||
const query = {};
|
||||
let psdict = {};
|
||||
if (category) q.$or = [{ category }, { tag: category }];
|
||||
if (!this.user.hasPerm(PERM_VIEW_PROBLEM_HIDDEN)) q.hidden = false;
|
||||
const path = [
|
||||
['Hydro', 'homepage'],
|
||||
['problem_main', null],
|
||||
];
|
||||
if (q) {
|
||||
q = q.toLowerCase();
|
||||
const $regex = new RegExp(`\\A\\Q${q.replace(/\\E/gmi, /\\E\\E\\Q/gmi)}\\E`, 'gmi');
|
||||
query.title = { $regex };
|
||||
path.push([q, null, null, true]);
|
||||
}
|
||||
if (!this.user.hasPerm(PERM_VIEW_PROBLEM_HIDDEN)) query.hidden = false;
|
||||
const [pdocs, ppcount, pcount] = await paginate(
|
||||
problem.getMulti(domainId, q).sort({ pid: 1 }),
|
||||
problem.getMulti(domainId, query).sort({ pid: 1 }),
|
||||
page,
|
||||
await system.get('PROBLEM_PER_PAGE'),
|
||||
);
|
||||
@@ -43,15 +52,21 @@ class ProblemHandler extends Handler {
|
||||
domainId, this.user._id, pdocs.map((pdoc) => pdoc.docId),
|
||||
);
|
||||
}
|
||||
const path = [
|
||||
['Hydro', 'homepage'],
|
||||
['problem_main', null],
|
||||
];
|
||||
this.response.body = {
|
||||
path, page, pcount, ppcount, pdocs, psdict, category,
|
||||
path, page, pcount, ppcount, pdocs, psdict, category: q,
|
||||
};
|
||||
}
|
||||
|
||||
async postStar({ domainId, pid }) {
|
||||
await problem.setStar(domainId, pid, this.user._id, true);
|
||||
this.back({ star: true });
|
||||
}
|
||||
|
||||
async postUnstar({ domainId, pid }) {
|
||||
await problem.setStar(domainId, pid, this.user._id, false);
|
||||
this.back({ star: false });
|
||||
}
|
||||
|
||||
async cleanup() {
|
||||
if (this.response.template === 'problem_main.html' && this.preferJson) {
|
||||
const {
|
||||
|
||||
@@ -102,7 +102,7 @@ class TrainingDetailHandler extends TrainingHandler {
|
||||
const tdoc = await training.get(domainId, tid);
|
||||
const pids = training.getPids(tdoc);
|
||||
const f = this.user.hasPerm(PERM_VIEW_PROBLEM_HIDDEN) ? {} : { hidden: false };
|
||||
const [udoc, pdict] = await Promise.all([
|
||||
const [owner, pdict] = await Promise.all([
|
||||
user.getById(domainId, tdoc.owner),
|
||||
problem.getList(domainId, pids, f),
|
||||
]);
|
||||
@@ -146,7 +146,7 @@ class TrainingDetailHandler extends TrainingHandler {
|
||||
];
|
||||
this.response.template = 'training_detail.html';
|
||||
this.response.body = {
|
||||
path, tdoc, tsdoc, pids, pdict, psdict, ndict, nsdict, udoc,
|
||||
path, tdoc, tsdoc, pids, pdict, psdict, ndict, nsdict, owner,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ class TrainingCreateHandler extends TrainingHandler {
|
||||
}
|
||||
const tid = await training.add(domainId, title, content, this.user._id, dag, description);
|
||||
this.response.body = { tid };
|
||||
this.response.redirect = `/t/${tid}`;
|
||||
this.response.redirect = this.url('training_detail', { tid });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ class TrainingEditHandler extends TrainingHandler {
|
||||
title, content, dag, description,
|
||||
});
|
||||
this.response.body = { tid };
|
||||
this.response.redirect = `/t/${tid}`;
|
||||
this.response.redirect = this.url('training_detail', { tid });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
-11
@@ -1,17 +1,19 @@
|
||||
const superagent = require('superagent');
|
||||
const fs = require('fs');
|
||||
|
||||
async function download(url, path, retry = 3) {
|
||||
if (path) {
|
||||
const w = await fs.createWriteStream(path);
|
||||
await superagent.get(url).retry(retry).pipe(w);
|
||||
await new Promise((resolve, reject) => {
|
||||
w.on('finish', resolve);
|
||||
w.on('error', reject);
|
||||
});
|
||||
return path;
|
||||
}
|
||||
return superagent.get(url);
|
||||
async function _download(url, path, retry) {
|
||||
const w = fs.createWriteStream(path);
|
||||
await superagent.get(url).retry(retry).pipe(w);
|
||||
await new Promise((resolve, reject) => {
|
||||
w.on('finish', resolve);
|
||||
w.on('error', reject);
|
||||
});
|
||||
return path;
|
||||
}
|
||||
|
||||
function download(url, path, retry = 3) {
|
||||
if (path) return _download(url, path, retry);
|
||||
return superagent.get(url).retry(retry);
|
||||
}
|
||||
|
||||
global.Hydro.lib.download = module.exports = download;
|
||||
+2
-2
@@ -60,8 +60,8 @@ async function del(id) {
|
||||
fs.unlinkSync(root(`${moduleRoot}/${id}.hydro`));
|
||||
}
|
||||
|
||||
async function install(url) {
|
||||
await download(url, root(`${moduleRoot}/${String.random(16)}.hydro`));
|
||||
function install(url) {
|
||||
return download(url, root(`${moduleRoot}/${String.random(16)}.hydro`));
|
||||
}
|
||||
|
||||
global.Hydro.lib.hpm = module.exports = {
|
||||
|
||||
@@ -123,8 +123,11 @@ function getStatus(domainId, did, uid) {
|
||||
return document.getStatus(domainId, document.TYPE_DISCUSSION, did, uid);
|
||||
}
|
||||
|
||||
function addNode(domainId, _id, category) {
|
||||
return document.add(domainId, category, 1, document.TYPE_DISCUSSION_NODE, _id);
|
||||
function addNode(domainId, _id, category, args) {
|
||||
return document.add(
|
||||
domainId, category, 1, document.TYPE_DISCUSSION_NODE,
|
||||
_id, null, null, args,
|
||||
);
|
||||
}
|
||||
|
||||
function getNode(domainId, _id) {
|
||||
@@ -166,6 +169,10 @@ async function getVnode(domainId, ddoc, handler) {
|
||||
};
|
||||
}
|
||||
|
||||
function getNodes(domainId) {
|
||||
return document.getMulti(domainId, document.TYPE_DISCUSSION_NODE).toArray();
|
||||
}
|
||||
|
||||
async function getListVnodes(domainId, ddocs, handler) {
|
||||
const tasks = [];
|
||||
const res = {};
|
||||
@@ -201,6 +208,7 @@ global.Hydro.model.discussion = module.exports = {
|
||||
setStar,
|
||||
getStatus,
|
||||
addNode,
|
||||
getNodes,
|
||||
getVnode,
|
||||
getListVnodes,
|
||||
};
|
||||
+1
-1
@@ -15,7 +15,7 @@ function _timestamp() {
|
||||
async function add(streamOrPath, filename, meta = {}) {
|
||||
if (typeof streamOrPath === 'string') streamOrPath = fs.createReadStream(streamOrPath);
|
||||
const w = gridfs.openUploadStream(filename);
|
||||
await coll.insertOne({ ...meta, _id: w.id });
|
||||
await coll.insertOne({ ...meta, _id: w.id, secret: String.random(32) });
|
||||
await new Promise((resolve, reject) => {
|
||||
w.on('error', reject);
|
||||
w.on('finish', resolve);
|
||||
|
||||
@@ -31,7 +31,6 @@ async function add(domainId, title, content, owner, {
|
||||
}) {
|
||||
const d = await domain.inc(domainId, 'pidCounter', 1);
|
||||
if (!pid) pid = d.pidCounter.toString();
|
||||
// eslint-disable-next-line no-return-await
|
||||
return await document.add(
|
||||
domainId, content, owner, document.TYPE_PROBLEM, d.pidCounter, null, null,
|
||||
{
|
||||
@@ -47,6 +46,7 @@ async function add(domainId, title, content, owner, {
|
||||
* @returns {Promise<Pdoc>}
|
||||
*/
|
||||
async function get(domainId, pid, uid = null, doThrow = true) {
|
||||
if (!Number.isNaN(parseInt(pid, 10))) pid = parseInt(pid, 10);
|
||||
const pdoc = Number.isInteger(pid)
|
||||
? await document.get(domainId, document.TYPE_PROBLEM, pid)
|
||||
: (await document.getMulti(domainId, document.TYPE_PROBLEM, { pid }).toArray())[0];
|
||||
@@ -95,7 +95,7 @@ function getMultiStatus(domainId, query) {
|
||||
* @param {string} domainId
|
||||
* @param {ObjectID} _id
|
||||
* @param {object} query
|
||||
* @returns {Pdoc}
|
||||
* @returns {Promise<Pdoc>}
|
||||
*/
|
||||
function edit(domainId, _id, $set) {
|
||||
return document.set(domainId, document.TYPE_PROBLEM, _id, $set);
|
||||
@@ -156,6 +156,10 @@ async function updateStatus(domainId, pid, uid, rid, status) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function setStar(domainId, pid, uid, star) {
|
||||
return document.setStatus(domainId, document.TYPE_PROBLEM, pid, uid, { star });
|
||||
}
|
||||
|
||||
async function setTestdata(domainId, _id, filePath) {
|
||||
const pdoc = await get(domainId, _id);
|
||||
const config = await readConfig(filePath);
|
||||
@@ -176,6 +180,7 @@ global.Hydro.model.problem = module.exports = {
|
||||
getList,
|
||||
getListStatus,
|
||||
getMultiStatus,
|
||||
setStar,
|
||||
setTestdata,
|
||||
updateStatus,
|
||||
};
|
||||
@@ -102,6 +102,7 @@ SystemSetting(
|
||||
Setting('setting_server', 'server.host', null, null, 'text', 'Server Host'),
|
||||
Setting('setting_server', 'server.url', null, null, 'text', 'Server BaseURL'),
|
||||
Setting('setting_server', 'server.port', null, 8888, 'number', 'Server Port'),
|
||||
Setting('setting_server', 'server.log', null, false, 'checkbox', 'Disable Access Log'),
|
||||
Setting('setting_oauth', 'oauth.githubappid', null, null, 'text', 'Github Oauth AppID'),
|
||||
Setting('setting_oauth', 'oauth.githubsecret', null, null, 'text', 'Github Oauth Secret'),
|
||||
Setting('setting_oauth', 'oauth.googleappid', null, null, 'text', 'Google Oauth ClientID'),
|
||||
|
||||
+10
-4
@@ -23,6 +23,8 @@ const {
|
||||
UserFacingError, ValidationError,
|
||||
} = require('../error');
|
||||
|
||||
let enableLog = true;
|
||||
|
||||
const app = new Koa();
|
||||
let server;
|
||||
const router = new Router();
|
||||
@@ -153,7 +155,7 @@ class Handler {
|
||||
}
|
||||
|
||||
async renderHTML(name, context) {
|
||||
console.time(name);
|
||||
if (enableLog) console.time(name);
|
||||
this.hasPerm = (perm) => this.user.hasPerm(perm);
|
||||
const res = await template.render(name, Object.assign(context, {
|
||||
handler: this,
|
||||
@@ -161,7 +163,7 @@ class Handler {
|
||||
_: (str) => (str ? str.toString().translate(this.user.viewLang || this.session.viewLang) : ''),
|
||||
user: this.user,
|
||||
}));
|
||||
console.timeEnd(name);
|
||||
if (enableLog) console.timeEnd(name);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -266,6 +268,7 @@ class Handler {
|
||||
try {
|
||||
await this.renderBody();
|
||||
} catch (error) {
|
||||
this.response.status = error instanceof UserFacingError ? error.code : 500;
|
||||
if (this.preferJson) this.response.body = { error };
|
||||
else await this.render(error instanceof UserFacingError ? 'error.html' : 'bsod.html', { error });
|
||||
}
|
||||
@@ -342,6 +345,7 @@ class Handler {
|
||||
async onerror(error) {
|
||||
console.error(error.message, error.params);
|
||||
console.error(error.stack);
|
||||
this.response.status = error instanceof UserFacingError ? error.code : 500;
|
||||
this.response.template = error instanceof UserFacingError ? 'error.html' : 'bsod.html';
|
||||
this.response.body = {
|
||||
error: { message: error.message, params: error.params, stack: error.stack },
|
||||
@@ -526,10 +530,12 @@ function Validate(key, func) {
|
||||
}
|
||||
|
||||
async function start() {
|
||||
app.use(morgan(':method :url :status :res[content-length] - :response-time ms'));
|
||||
const [disableLog, port] = await system.getMany(['server.log', 'server.port']);
|
||||
if (!disableLog) {
|
||||
app.use(morgan(':method :url :status :res[content-length] - :response-time ms'));
|
||||
} else enableLog = false;
|
||||
app.use(router.routes()).use(router.allowedMethods());
|
||||
Route('notfound_handler', '*', Handler);
|
||||
const port = await system.get('server.port');
|
||||
server.listen(port);
|
||||
console.log('Server listening at: %s', port);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user