mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-19 17:38:19 +08:00
使用 @param 验证接口
This commit is contained in:
1 parent
4e85b696c0
commit
19cf1a5304
22 files changed
+657
-393
No files matched your search
+118
-70
@@ -1,5 +1,9 @@
|
||||
import { isSafeInteger, flatten } from 'lodash';
|
||||
import { ObjectID } from 'mongodb';
|
||||
import paginate from '../lib/paginate';
|
||||
import * as validator from '../lib/validator';
|
||||
import {
|
||||
checkPid, isTitle, isContent, isPid,
|
||||
} from '../lib/validator';
|
||||
import * as file from '../model/file';
|
||||
import * as problem from '../model/problem';
|
||||
import * as record from '../model/record';
|
||||
@@ -9,19 +13,48 @@ import * as system from '../model/system';
|
||||
import { PERM, PRIV } from '../model/builtin';
|
||||
import * as bus from '../service/bus';
|
||||
import {
|
||||
Route, Connection, Handler, ConnectionHandler,
|
||||
Route, Connection, Handler, ConnectionHandler, Types, param,
|
||||
} from '../service/server';
|
||||
import {
|
||||
NoProblemError, ProblemDataNotFoundError, BadRequestError,
|
||||
SolutionNotFoundError,
|
||||
} from '../error';
|
||||
|
||||
const parseCategory = (value: string) => flatten(value.split('+').map((e) => e.split(','))).map((e) => e.trim());
|
||||
const parsePid = (value: string) => (isSafeInteger(value) ? parseInt(value, 10) : value);
|
||||
|
||||
class ProblemHandler extends Handler {
|
||||
async __prepare() {
|
||||
this.checkPerm(PERM.PERM_VIEW_PROBLEM);
|
||||
}
|
||||
|
||||
async get({ domainId, page = 1, q = '' }) {
|
||||
async cleanup() {
|
||||
if (this.response.template === 'problem_main.html' && this.request.json) {
|
||||
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 ProblemMainHandler extends ProblemHandler {
|
||||
@param('page', Types.UnsignedInt, true)
|
||||
@param('q', Types.String, true)
|
||||
async get(domainId: string, page = 1, q = '') {
|
||||
this.response.template = 'problem_main.html';
|
||||
const query: any = {};
|
||||
let psdict = {};
|
||||
@@ -51,41 +84,23 @@ class ProblemHandler extends Handler {
|
||||
};
|
||||
}
|
||||
|
||||
async postStar({ domainId, pid }) {
|
||||
@param('pid', Types.UnsignedInt)
|
||||
async postStar(domainId: string, pid: number) {
|
||||
await problem.setStar(domainId, pid, this.user._id, true);
|
||||
this.back({ star: true });
|
||||
}
|
||||
|
||||
async postUnstar({ domainId, pid }) {
|
||||
@param('pid', Types.UnsignedInt)
|
||||
async postUnstar(domainId: string, pid: number) {
|
||||
await problem.setStar(domainId, pid, this.user._id, false);
|
||||
this.back({ star: false });
|
||||
}
|
||||
|
||||
async cleanup() {
|
||||
if (this.response.template === 'problem_main.html' && this.request.json) {
|
||||
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({ domainId, page = 1, category }) {
|
||||
@param('page', Types.UnsignedInt, true)
|
||||
@param('category', Types.String, parseCategory)
|
||||
async get(domainId: string, page = 1, category: string[]) {
|
||||
this.response.template = 'problem_main.html';
|
||||
const q: any = { $and: [] };
|
||||
for (const name of category) {
|
||||
@@ -120,8 +135,9 @@ class ProblemCategoryHandler extends ProblemHandler {
|
||||
}
|
||||
|
||||
class ProblemRandomHandler extends ProblemHandler {
|
||||
async get({ domainId, category }) {
|
||||
const q: any = category[0] ? { $and: [] } : {};
|
||||
@param('category', Types.String, true, null, parseCategory)
|
||||
async get(domainId: string, category: string[]) {
|
||||
const q: any = category.length ? { $and: [] } : {};
|
||||
for (const name of category) {
|
||||
if (name) {
|
||||
q.$and.push({
|
||||
@@ -141,7 +157,8 @@ class ProblemRandomHandler extends ProblemHandler {
|
||||
}
|
||||
|
||||
class ProblemDetailHandler extends ProblemHandler {
|
||||
async _prepare({ domainId, pid }) {
|
||||
@param('pid', Types.String, null, parsePid)
|
||||
async _prepare(domainId: string, pid: number | string) {
|
||||
this.response.template = 'problem_detail.html';
|
||||
if (pid) {
|
||||
this.pdoc = await problem.get(domainId, pid, this.user._id);
|
||||
@@ -158,7 +175,7 @@ class ProblemDetailHandler extends ProblemHandler {
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async get(args: any) {
|
||||
async get(...args: any) {
|
||||
this.response.body.path = [
|
||||
['Hydro', 'homepage'],
|
||||
['problem_main', 'problem_main'],
|
||||
@@ -168,9 +185,11 @@ class ProblemDetailHandler extends ProblemHandler {
|
||||
}
|
||||
|
||||
class ProblemSubmitHandler extends ProblemDetailHandler {
|
||||
async get({ domainId, pid }) {
|
||||
@param('pid', Types.String, null, parsePid)
|
||||
async get(domainId: string, pid: string | number) {
|
||||
this.response.template = 'problem_submit.html';
|
||||
const rdocs = await record.getUserInProblemMulti(domainId, this.user._id, this.pdoc.docId)
|
||||
const rdocs = await record
|
||||
.getUserInProblemMulti(domainId, this.user._id, this.pdoc.docId)
|
||||
.sort({ _id: -1 })
|
||||
.limit(10)
|
||||
.toArray();
|
||||
@@ -188,8 +207,9 @@ class ProblemSubmitHandler extends ProblemDetailHandler {
|
||||
};
|
||||
}
|
||||
|
||||
async post({ domainId }) {
|
||||
const { lang, code } = this.request.body;
|
||||
@param('lang', Types.String)
|
||||
@param('code', Types.String)
|
||||
async post(domainId: string, lang: string, code: string) {
|
||||
const rid = await record.add(domainId, {
|
||||
uid: this.user._id, lang, code, pid: this.pdoc.docId,
|
||||
}, true);
|
||||
@@ -200,9 +220,10 @@ class ProblemSubmitHandler extends ProblemDetailHandler {
|
||||
}
|
||||
|
||||
class ProblemPretestHandler extends ProblemDetailHandler {
|
||||
async post({
|
||||
domainId, lang, code, input,
|
||||
}) {
|
||||
@param('lang', Types.String)
|
||||
@param('code', Types.String)
|
||||
@param('input', Types.String)
|
||||
async post(domainId: string, lang: string, code: string, input: string) {
|
||||
this.limitRate('add_record', 60, 100);
|
||||
const rid = await record.add(domainId, {
|
||||
uid: this.user._id, lang, code, pid: this.pdoc.docId, input,
|
||||
@@ -213,8 +234,9 @@ class ProblemPretestHandler extends ProblemDetailHandler {
|
||||
}
|
||||
|
||||
class ProblemPretestConnectionHandler extends ConnectionHandler {
|
||||
async prepare({ domainId, pid }) {
|
||||
this.pid = pid.toString();
|
||||
@param('pid', Types.String)
|
||||
async prepare(domainId: string, pid: string) {
|
||||
this.pid = pid;
|
||||
this.domainId = domainId;
|
||||
bus.subscribe(['record_change'], this, 'onRecordChange');
|
||||
}
|
||||
@@ -236,7 +258,7 @@ class ProblemPretestConnectionHandler extends ConnectionHandler {
|
||||
}
|
||||
|
||||
class ProblemStatisticsHandler extends ProblemDetailHandler {
|
||||
async get({ domainId }) {
|
||||
async get(domainId: string) {
|
||||
const udoc = await user.getById(domainId, this.pdoc.owner);
|
||||
const path = [
|
||||
['problem_main', 'problem_main'],
|
||||
@@ -256,7 +278,8 @@ class ProblemManageHandler extends ProblemDetailHandler {
|
||||
}
|
||||
|
||||
class ProblemSettingsHandler extends ProblemManageHandler {
|
||||
async get({ pid }) {
|
||||
@param('pid', Types.String)
|
||||
async get(domainId: string, pid: string) {
|
||||
this.response.template = 'problem_settings.html';
|
||||
this.response.body.path = [
|
||||
['Hydro', 'homepage'],
|
||||
@@ -266,15 +289,24 @@ class ProblemSettingsHandler extends ProblemManageHandler {
|
||||
];
|
||||
}
|
||||
|
||||
async postConfig({ domainId, pid, yaml }) {
|
||||
await problem.edit(domainId, pid, { config: yaml });
|
||||
@param('pid', Types.String, null, parsePid)
|
||||
@param('yaml', Types.String)
|
||||
async postConfig(domainId: string, pid: string | number, yaml: string) {
|
||||
const pdoc = await problem.get(domainId, pid);
|
||||
await problem.edit(domainId, pdoc.docId, { config: yaml });
|
||||
this.back();
|
||||
}
|
||||
|
||||
async postSetting({
|
||||
domainId, pid, hidden = false, category, tag,
|
||||
}) {
|
||||
await problem.edit(domainId, pid, { hidden, category, tag });
|
||||
@param('pid', Types.String, null, parsePid)
|
||||
@param('hidden', Types.Boolean)
|
||||
@param('category', Types.String, null, parseCategory)
|
||||
@param('tag', Types.String, null, parseCategory)
|
||||
async postSetting(
|
||||
domainId: string, pid: string | number, hidden = false,
|
||||
category: string[], tag: string[],
|
||||
) {
|
||||
const pdoc = await problem.get(domainId, pid);
|
||||
await problem.edit(domainId, pdoc.docId, { hidden, category, tag });
|
||||
this.back();
|
||||
}
|
||||
}
|
||||
@@ -291,8 +323,10 @@ class ProblemEditHandler extends ProblemManageHandler {
|
||||
this.response.body.page_name = 'problem_edit';
|
||||
}
|
||||
|
||||
async post({ domainId, title, content }) {
|
||||
const pid = validator.checkPid(this.request.body.pid);
|
||||
@param('title', Types.String, isTitle)
|
||||
@param('content', Types.String, isContent)
|
||||
async post(domainId: string, title: string, content: string) {
|
||||
const pid = checkPid(this.request.body.pid);
|
||||
const pdoc = await problem.get(domainId, this.request.params.pid);
|
||||
await problem.edit(domainId, pdoc.docId, { title, content, pid });
|
||||
this.back();
|
||||
@@ -314,7 +348,9 @@ class ProblemDataUploadHandler extends ProblemManageHandler {
|
||||
|
||||
async post({ domainId }) {
|
||||
if (!this.request.files.file) throw new BadRequestError();
|
||||
await problem.setTestdata(domainId, this.pdoc.docId, this.request.files.file.path);
|
||||
await problem.setTestdata(
|
||||
domainId, this.pdoc.docId, this.request.files.file.path,
|
||||
);
|
||||
if (this.pdoc.data && typeof this.pdoc.data === 'object') {
|
||||
const f = await file.getMeta(this.pdoc.data);
|
||||
this.md5 = f.md5;
|
||||
@@ -337,7 +373,8 @@ class ProblemDataDownloadHandler extends ProblemDetailHandler {
|
||||
}
|
||||
|
||||
class ProblemSolutionHandler extends ProblemDetailHandler {
|
||||
async get({ domainId, page = 1 }) {
|
||||
@param('page', Types.UnsignedInt, true)
|
||||
async get(domainId: string, page = 1) {
|
||||
this.response.template = 'problem_solution.html';
|
||||
this.checkPerm(PERM.PERM_VIEW_PROBLEM_SOLUTION);
|
||||
const [psdocs, pcount, pscount] = await paginate(
|
||||
@@ -367,21 +404,22 @@ class ProblemSolutionHandler extends ProblemDetailHandler {
|
||||
}
|
||||
|
||||
async post({ domainId, psid }) {
|
||||
if (psid) this.psdoc = await solution.get(domainId, psid);
|
||||
if (psid) this.psdoc = await solution.get(domainId, new ObjectID(psid));
|
||||
}
|
||||
|
||||
async postSubmit({ domainId, content }) {
|
||||
@param('content', Types.String, isContent)
|
||||
async postSubmit(domainId: string, content: string) {
|
||||
this.checkPerm(PERM.PERM_CREATE_PROBLEM_SOLUTION);
|
||||
await solution.add(domainId, this.pdoc.docId, this.user._id, content);
|
||||
this.back();
|
||||
}
|
||||
|
||||
async postEditSolution({ domainId, content }) {
|
||||
@param('content', Types.String, isContent)
|
||||
async postEditSolution(domainId: string, content: string) {
|
||||
if (this.psdoc.owner !== this.user._id) this.checkPerm(PERM.PERM_EDIT_PROBLEM_SOLUTION);
|
||||
else this.checkPerm(PERM.PERM_EDIT_PROBLEM_SOLUTION_SELF);
|
||||
this.psdoc = await solution.edit(domainId, this.psdoc.docId, content);
|
||||
this.ctx.body.psdoc = this.psdoc;
|
||||
this.back();
|
||||
const psdoc = await solution.edit(domainId, this.psdoc.docId, content);
|
||||
this.back({ psdoc });
|
||||
}
|
||||
|
||||
async postDeleteSolution({ domainId }) {
|
||||
@@ -391,16 +429,19 @@ class ProblemSolutionHandler extends ProblemDetailHandler {
|
||||
this.back();
|
||||
}
|
||||
|
||||
async postReply({ domainId, psid, content }) {
|
||||
@param('psid', Types.ObjectID)
|
||||
@param('content', Types.String, isContent)
|
||||
async postReply(domainId: string, psid: ObjectID, content: string) {
|
||||
this.checkPerm(PERM.PERM_REPLY_PROBLEM_SOLUTION);
|
||||
const psdoc = await solution.get(domainId, psid);
|
||||
await solution.reply(domainId, psdoc.docId, this.user._id, content);
|
||||
this.back();
|
||||
}
|
||||
|
||||
async postEditReply({
|
||||
domainId, content, psid, psrid,
|
||||
}) {
|
||||
@param('psid', Types.ObjectID)
|
||||
@param('psrid', Types.ObjectID)
|
||||
@param('content', Types.String, isContent)
|
||||
async postEditReply(domainId: string, psid: ObjectID, psrid: ObjectID, content: string) {
|
||||
const [psdoc, psrdoc] = await solution.getReply(domainId, psid, psrid);
|
||||
if ((!psdoc) || psdoc.pid !== this.pdoc.docId) throw new SolutionNotFoundError(psid);
|
||||
if (!(psdoc.owner === this.user._id
|
||||
@@ -414,7 +455,9 @@ class ProblemSolutionHandler extends ProblemDetailHandler {
|
||||
this.back();
|
||||
}
|
||||
|
||||
async postDeleteReply({ domainId, psid, psrid }) {
|
||||
@param('psid', Types.ObjectID)
|
||||
@param('psrid', Types.ObjectID)
|
||||
async postDeleteReply(domainId: string, psid: ObjectID, psrid: ObjectID) {
|
||||
const [psdoc, psrdoc] = await solution.getReply(domainId, psid, psrid);
|
||||
if ((!psdoc) || psdoc.pid !== this.pdoc.docId) throw new SolutionNotFoundError(psid);
|
||||
if (!(psdoc.owner === this.user._id
|
||||
@@ -442,7 +485,8 @@ class ProblemSolutionHandler extends ProblemDetailHandler {
|
||||
}
|
||||
|
||||
class ProblemSolutionRawHandler extends ProblemDetailHandler {
|
||||
async get({ domainId, psid }) {
|
||||
@param('psid', Types.ObjectID)
|
||||
async get(domainId: string, psid: ObjectID) {
|
||||
this.checkPerm(PERM.PERM_VIEW_PROBLEM_SOLUTION);
|
||||
const psdoc = await solution.get(domainId, psid);
|
||||
this.response.type = 'text/markdown';
|
||||
@@ -451,7 +495,9 @@ class ProblemSolutionRawHandler extends ProblemDetailHandler {
|
||||
}
|
||||
|
||||
class ProblemSolutionReplyRawHandler extends ProblemDetailHandler {
|
||||
async get({ domainId, psid, psrid }) {
|
||||
@param('psid', Types.ObjectID)
|
||||
@param('psrid', Types.ObjectID)
|
||||
async get(domainId: string, psid: ObjectID, psrid: ObjectID) {
|
||||
this.checkPerm(PERM.PERM_VIEW_PROBLEM_SOLUTION);
|
||||
const [psdoc, psrdoc] = await solution.getReply(domainId, psid, psrid);
|
||||
if ((!psdoc) || psdoc.pid !== this.pdoc.docId) throw new SolutionNotFoundError(psid, psrid);
|
||||
@@ -474,9 +520,11 @@ class ProblemCreateHandler extends Handler {
|
||||
};
|
||||
}
|
||||
|
||||
async post({
|
||||
domainId, title, pid, content, hidden,
|
||||
}) {
|
||||
@param('title', Types.String, isTitle)
|
||||
@param('pid', Types.String, isPid)
|
||||
@param('content', Types.String, isContent)
|
||||
@param('hidden', Types.Boolean)
|
||||
async post(domainId: string, title: string, pid: string, content: string, hidden = false) {
|
||||
pid = await problem.add(domainId, title, content, this.user._id, {
|
||||
pid, hidden,
|
||||
});
|
||||
@@ -486,7 +534,7 @@ class ProblemCreateHandler extends Handler {
|
||||
}
|
||||
|
||||
export async function apply() {
|
||||
Route('problem_main', '/p', ProblemHandler);
|
||||
Route('problem_main', '/p', ProblemMainHandler);
|
||||
Route('problem_category', '/p/category/:category', ProblemCategoryHandler);
|
||||
Route('problem_random', '/problem/random', ProblemRandomHandler);
|
||||
Route('problem_detail', '/p/:pid', ProblemDetailHandler);
|
||||
|
||||
Reference in new issue
Block a user