diff --git a/packages/hydrooj/src/handler/contest.ts b/packages/hydrooj/src/handler/contest.ts index b076955de..060e9f292 100644 --- a/packages/hydrooj/src/handler/contest.ts +++ b/packages/hydrooj/src/handler/contest.ts @@ -115,7 +115,7 @@ class ContestBoardcastHandler extends ContestHandler { } @param('tid', Types.ObjectID) - @param('content', Types.String, isContent) + @param('content', Types.Content) async post(domainId: string, tid: ObjectID, content: string) { const tdoc = await contest.get(domainId, tid); if (tdoc.owner !== this.user._id) throw new PermissionError('Boardcast Message'); @@ -202,10 +202,10 @@ class ContestEditHandler extends ContestHandler { @param('beginAtDate', Types.Date) @param('beginAtTime', Types.Time) @param('duration', Types.Float) - @param('title', Types.String, isTitle) - @param('content', Types.String, isContent) + @param('content', Types.Title) + @param('content', Types.Content) @param('rule', Types.Range(contest.RULES)) - @param('pids', Types.String) + @param('pids', Types.Content) @param('rated', Types.Boolean) async post( domainId: string, beginAtDate: string, beginAtTime: string, duration: number, @@ -284,7 +284,7 @@ class ContestProblemHandler extends ContestHandler { export class ContestProblemFileDownloadHandler extends ContestProblemHandler { @query('type', Types.Range(['additional_file', 'testdata']), true) - @param('filename', Types.String) + @param('filename', Types.Name) @param('noDisposition', Types.Boolean) async get(domainId: string, type = 'additional_file', filename: string, noDisposition = false) { if (type === 'testdata' && this.user._id !== this.pdoc.owner) this.checkPerm(PERM.PERM_READ_PROBLEM_DATA); @@ -327,8 +327,8 @@ class ContestDetailProblemSubmitHandler extends ContestProblemHandler { } @param('tid', Types.ObjectID) - @param('lang', Types.String) - @param('code', Types.String) + @param('lang', Types.Name) + @param('code', Types.Content) async post(domainId: string, tid: ObjectID, lang: string, code: string) { await this.limitRate('add_record', 60, 10); const rid = await record.add(domainId, this.pdoc.docId, this.user._id, lang, code, true, { @@ -406,10 +406,10 @@ class ContestCreateHandler extends ContestHandler { @param('beginAtDate', Types.Date) @param('beginAtTime', Types.Time) @param('duration', Types.Float) - @param('title', Types.String, isTitle) - @param('content', Types.String, isContent) - @param('rule', Types.String) - @param('pids', Types.String) + @param('content', Types.Title) + @param('content', Types.Content) + @param('rule', Types.Name) + @param('pids', Types.Content) @param('rated', Types.Boolean) async post( domainId: string, beginAtDate: string, beginAtTime: string, duration: number, diff --git a/packages/hydrooj/src/handler/discussion.ts b/packages/hydrooj/src/handler/discussion.ts index 27c679965..d4fde2afc 100644 --- a/packages/hydrooj/src/handler/discussion.ts +++ b/packages/hydrooj/src/handler/discussion.ts @@ -32,8 +32,8 @@ class DiscussionHandler extends Handler { drrdoc?: Drrdoc; vnode?: any; - @param('type', Types.String, true) - @param('name', Types.String, true) + @param('type', Types.Name, true) + @param('name', Types.Name, true) @param('did', Types.ObjectID, true) @param('drid', Types.ObjectID, true) @param('drrid', Types.ObjectID, true) @@ -97,8 +97,8 @@ class DiscussionMainHandler extends Handler { } class DiscussionNodeHandler extends DiscussionHandler { - @param('type', Types.String) - @param('name', Types.String) + @param('type', Types.Name) + @param('name', Types.Name) @param('page', Types.PositiveInt, true) async get(domainId: string, type: string, _name: string, page = 1) { let name: ObjectID | string | number; @@ -149,10 +149,10 @@ class DiscussionCreateHandler extends DiscussionHandler { this.response.body = { path, vnode: this.vnode }; } - @param('type', Types.String) - @param('name', Types.String) - @param('title', Types.String, isTitle) - @param('content', Types.String, isContent) + @param('type', Types.Name) + @param('name', Types.Name) + @param('content', Types.Title) + @param('content', Types.Content) @param('highlight', Types.Boolean) @param('pin', Types.Boolean) async post( @@ -166,11 +166,6 @@ class DiscussionCreateHandler extends DiscussionHandler { else name = _name; if (highlight) this.checkPerm(PERM.PERM_HIGHLIGHT_DISCUSSION); if (pin) this.checkPerm(PERM.PERM_PIN_DISCUSSION); - await bus.serial( - 'discussion/before-add', - domainId, typeMapper[type], name, this.user._id, - title, content, this.request.ip, highlight, pin, - ); const did = await discussion.add( domainId, typeMapper[type], name, this.user._id, title, content, this.request.ip, highlight, pin, @@ -217,7 +212,7 @@ class DiscussionDetailHandler extends DiscussionHandler { } @param('did', Types.ObjectID) - @param('content', Types.String, isContent) + @param('content', Types.Content) async postReply(domainId: string, did: ObjectID, content: string) { this.checkPerm(PERM.PERM_REPLY_DISCUSSION); await this.limitRate('add_discussion', 3600, 60); @@ -236,7 +231,7 @@ class DiscussionDetailHandler extends DiscussionHandler { } @param('drid', Types.ObjectID) - @param('content', Types.String, isContent) + @param('content', Types.Content) async postTailReply(domainId: string, drid: ObjectID, content: string) { this.checkPerm(PERM.PERM_REPLY_DISCUSSION); await this.limitRate('add_discussion', 3600, 60); @@ -245,7 +240,7 @@ class DiscussionDetailHandler extends DiscussionHandler { } @param('drid', Types.ObjectID) - @param('content', Types.String, isContent) + @param('content', Types.Content) async postEditReply(domainId: string, drid: ObjectID, content: string) { this.checkPerm(PERM.PERM_EDIT_DISCUSSION_REPLY_SELF); if (this.drdoc.owner !== this.user._id) throw new PermissionError(PERM.PERM_EDIT_DISCUSSION_REPLY_SELF); @@ -268,7 +263,7 @@ class DiscussionDetailHandler extends DiscussionHandler { @param('drid', Types.ObjectID) @param('drrid', Types.ObjectID) - @param('content', Types.String, isContent) + @param('content', Types.Content) async postEditTailReply(domainId: string, drid: ObjectID, drrid: ObjectID, content: string) { this.checkPerm(PERM.PERM_EDIT_DISCUSSION_REPLY_SELF); if (this.drdoc.owner !== this.user._id) throw new PermissionError(PERM.PERM_EDIT_DISCUSSION_REPLY_SELF); @@ -333,8 +328,8 @@ class DiscussionEditHandler extends DiscussionHandler { } @param('did', Types.ObjectID) - @param('title', Types.String, isTitle) - @param('content', Types.String, isContent) + @param('content', Types.Title) + @param('content', Types.Content) @param('highlight', Types.Boolean) @param('pin', Types.Boolean) async postUpdate( diff --git a/packages/hydrooj/src/handler/domain.ts b/packages/hydrooj/src/handler/domain.ts index 872bb9b3f..a7abc5da3 100644 --- a/packages/hydrooj/src/handler/domain.ts +++ b/packages/hydrooj/src/handler/domain.ts @@ -130,14 +130,14 @@ class DomainUserHandler extends ManageHandler { } @post('uid', Types.Int) - @post('role', Types.String) + @post('role', Types.Name) async postSetUser(domainId: string, uid: number, role: string) { await domain.setUserRole(domainId, uid, role); this.back(); } @param('uid', Types.NumericArray) - @param('role', Types.String) + @param('role', Types.Name) async postSetUsers(domainId: string, uid: number[], role: string) { await domain.setUserRole(domainId, uid, role); this.back(); @@ -187,7 +187,7 @@ class DomainRoleHandler extends ManageHandler { this.response.body = { roles, domain: this.domain, path }; } - @param('role', Types.String) + @param('role', Types.Name) async postAdd(domainId: string, role: string) { const roles = await domain.getRoles(this.domain); const rdict: Dictionary = {}; @@ -229,9 +229,9 @@ class DomainJoinApplicationsHandler extends ManageHandler { } @post('method', Types.Range([domain.JOIN_METHOD_NONE, domain.JOIN_METHOD_ALL, domain.JOIN_METHOD_CODE])) - @post('role', Types.String, true) + @post('role', Types.Name, true) @post('expire', Types.Int, true) - @post('invitationCode', Types.String, true) + @post('invitationCode', Types.Content, true) async post(domainId: string, method: number, role: string, expire: number, invitationCode = '') { const r = await domain.getRoles(this.domain); const roles = r.map((rl) => rl._id); @@ -269,7 +269,7 @@ class DomainJoinHandler extends Handler { if (this.user.role !== 'default') throw new DomainJoinAlreadyMemberError(this.domain._id, this.user._id); } - @param('code', Types.String, true) + @param('code', Types.Content, true) async get(domainId: string, code: string) { this.response.template = 'domain_join.html'; this.response.body.joinSettings = this.joinSettings; @@ -280,7 +280,7 @@ class DomainJoinHandler extends Handler { ]; } - @param('code', Types.String, true) + @param('code', Types.Content, true) async post(domainId: string, code: string) { if (this.joinSettings.method === domain.JOIN_METHOD_CODE) { if (this.joinSettings.code !== code) { @@ -293,7 +293,7 @@ class DomainJoinHandler extends Handler { } class DomainSearchHandler extends Handler { - @param('q', Types.String) + @param('q', Types.Content) async get(domainId: string, q: string) { const ddocs = await domain.getPrefixSearch(q, 20); for (let i = 0; i < ddocs.length; i++) { diff --git a/packages/hydrooj/src/handler/home.ts b/packages/hydrooj/src/handler/home.ts index 4436abe98..4b3ec8dcc 100644 --- a/packages/hydrooj/src/handler/home.ts +++ b/packages/hydrooj/src/handler/home.ts @@ -151,7 +151,7 @@ class HomeSecurityHandler extends Handler { } @param('currentPassword', Types.String) - @param('mail', Types.String, isEmail) + @param('mail', Types.Name, isEmail) async postChangeMail(domainId: string, current: string, email: string) { await this.limitRate('send_mail', 3600, 30); this.user.checkPassword(current); @@ -191,7 +191,7 @@ class HomeSecurityHandler extends Handler { } class HomeSettingsHandler extends Handler { - @param('category', Types.String) + @param('category', Types.Name) async get(domainId: string, category: string) { const path = [ ['Hydro', 'homepage'], @@ -287,10 +287,10 @@ class HomeDomainCreateHandler extends Handler { this.response.template = 'domain_create.html'; } - @param('id', Types.String) - @param('name', Types.String, isTitle) - @param('bulletin', Types.String, isContent) - @param('gravatar', Types.String, true, isEmail) + @param('id', Types.Name) + @param('name', Types.Title) + @param('bulletin', Types.Content) + @param('gravatar', Types.Content, true, isEmail) async post(_: string, id: string, name: string, bulletin: string, gravatar: string) { const doc = await domain.get(id); if (doc) throw new DomainAlreadyExistsError(id); @@ -335,7 +335,7 @@ class HomeMessagesHandler extends Handler { } @param('uid', Types.Int) - @param('content', Types.String, isContent) + @param('content', Types.Content) async postSend(domainId: string, uid: number, content: string) { const udoc = await user.getById('system', uid); if (!udoc) throw new UserNotFoundError(uid); diff --git a/packages/hydrooj/src/handler/homework.ts b/packages/hydrooj/src/handler/homework.ts index 6763fd8a3..4c6f4c83c 100644 --- a/packages/hydrooj/src/handler/homework.ts +++ b/packages/hydrooj/src/handler/homework.ts @@ -174,8 +174,8 @@ class HomeworkDetailProblemSubmitHandler extends HomeworkDetailProblemHandler { @param('tid', Types.ObjectID) @param('pid', Types.UnsignedInt) - @param('code', Types.String) - @param('lang', Types.String) + @param('code', Types.Content) + @param('lang', Types.Name) async post(domainId: string, tid: ObjectID, pid: number, code: string, lang: string) { await this.limitRate('add_record', 60, 5); const tsdoc = await contest.getStatus(domainId, tid, this.user._id, document.TYPE_HOMEWORK); @@ -227,10 +227,10 @@ class HomeworkCreateHandler extends HomeworkHandler { @param('penaltySinceDate', Types.Date) @param('penaltySinceTime', Types.Time) @param('extensionDays', Types.Float) - @param('penaltyRules', Types.String, validatePenaltyRules, convertPenaltyRules) - @param('title', Types.String, isTitle) - @param('content', Types.String, isContent) - @param('pids', Types.String) + @param('penaltyRules', Types.Content, validatePenaltyRules, convertPenaltyRules) + @param('content', Types.Title) + @param('content', Types.Content) + @param('pids', Types.Content) @param('rated', Types.Boolean) async post( domainId: string, beginAtDate: string, beginAtTime: string, @@ -294,10 +294,10 @@ class HomeworkEditHandler extends HomeworkHandler { @param('penaltySinceDate', Types.Date) @param('penaltySinceTime', Types.Time) @param('extensionDays', Types.Float) - @param('penaltyRules', Types.String, validatePenaltyRules, convertPenaltyRules) - @param('title', Types.String, isTitle) - @param('content', Types.String, isContent) - @param('pids', Types.String) + @param('penaltyRules', Types.Content, validatePenaltyRules, convertPenaltyRules) + @param('content', Types.Title) + @param('content', Types.Content) + @param('pids', Types.Content) @param('rated', Types.Boolean) async post( domainId: string, tid: ObjectID, beginAtDate: string, beginAtTime: string, @@ -364,7 +364,7 @@ class HomeworkScoreboardHandler extends HomeworkHandler { class HomeworkScoreboardDownloadHandler extends HomeworkHandler { @param('tid', Types.ObjectID) - @param('ext', Types.String) + @param('ext', Types.Name) async get(domainId: string, tid: ObjectID, ext: string) { const getContent = { csv: (rows) => `\uFEFF${rows.map((c) => (c.map((i) => i.value).join(','))).join('\n')}`, diff --git a/packages/hydrooj/src/handler/import.syzoj.ts b/packages/hydrooj/src/handler/import.syzoj.ts index eb43f6b1e..d06f6be78 100644 --- a/packages/hydrooj/src/handler/import.syzoj.ts +++ b/packages/hydrooj/src/handler/import.syzoj.ts @@ -220,10 +220,10 @@ class ProblemImportSYZOJHandler extends Handler { return docId; } - @post('url', Types.String, true) - @post('pid', Types.String, true, isPid) + @post('url', Types.Content, true) + @post('pid', Types.Name, true, isPid) @post('hidden', Types.Boolean) - @post('prefix', Types.String, true) + @post('prefix', Types.Name, true) @post('start', Types.UnsignedInt, true) @post('end', Types.UnsignedInt, true) async post( diff --git a/packages/hydrooj/src/handler/manage.ts b/packages/hydrooj/src/handler/manage.ts index 6c23807cc..6bef43af3 100644 --- a/packages/hydrooj/src/handler/manage.ts +++ b/packages/hydrooj/src/handler/manage.ts @@ -102,8 +102,8 @@ class SystemScriptHandler extends SystemHandler { this.response.body.path.push(['manage_script', null]); } - @param('id', Types.String) - @param('args', Types.String, true) + @param('id', Types.Name) + @param('args', Types.Content, true) async post(domainId: string, id: string, raw = '{}') { if (!global.Hydro.script[id]) throw new ValidationError('id'); const args = JSON.parse(raw); @@ -189,7 +189,7 @@ class SystemUserImportHandler extends SystemHandler { this.response.template = 'manage_user_import.html'; } - @param('users', Types.String) + @param('users', Types.Content) @param('draft', Types.Boolean) async post(domainId: string, _users: string, draft: boolean) { const users = _users.split('\n'); diff --git a/packages/hydrooj/src/handler/misc.ts b/packages/hydrooj/src/handler/misc.ts index 8a7b5217f..ba42112db 100644 --- a/packages/hydrooj/src/handler/misc.ts +++ b/packages/hydrooj/src/handler/misc.ts @@ -36,7 +36,7 @@ class CheckInHandler extends Handler { } class SwitchLanguageHandler extends Handler { - @param('lang', Types.String) + @param('lang', Types.Name) async get(domainId: string, lang: string) { if (this.user.hasPriv(PRIV.PRIV_USER_PROFILE)) { this.session.viewLang = lang; diff --git a/packages/hydrooj/src/handler/problem.ts b/packages/hydrooj/src/handler/problem.ts index de62c4bad..8e83e7ffa 100644 --- a/packages/hydrooj/src/handler/problem.ts +++ b/packages/hydrooj/src/handler/problem.ts @@ -53,7 +53,7 @@ export class ProblemHandler extends Handler { export class ProblemMainHandler extends ProblemHandler { @param('page', Types.PositiveInt, true) - @param('q', Types.String, true) + @param('q', Types.Content, true) async get(domainId: string, page = 1, q = '') { this.response.template = 'problem_main.html'; // eslint-disable-next-line @typescript-eslint/no-shadow @@ -112,7 +112,7 @@ export class ProblemMainHandler extends ProblemHandler { export class ProblemCategoryHandler extends ProblemHandler { @param('page', Types.PositiveInt, true) - @param('category', Types.String, null, parseCategory) + @param('category', Types.Name, null, parseCategory) async get(domainId: string, page = 1, category: string[]) { this.response.template = 'problem_main.html'; const q: any = { $and: [] }; @@ -143,7 +143,7 @@ export class ProblemCategoryHandler extends ProblemHandler { } export class ProblemRandomHandler extends ProblemHandler { - @param('category', Types.String, true, null, parseCategory) + @param('category', Types.Name, true, null, parseCategory) async get(domainId: string, category: string[] = []) { const q: FilterQuery = category.length ? { $and: [] } : {}; for (const tag of category) q.$and.push({ tag }); @@ -160,7 +160,7 @@ export class ProblemDetailHandler extends ProblemHandler { pdoc: Pdoc; udoc: User; - @route('pid', Types.String, true, null, parsePid) + @route('pid', Types.Name, true, null, parsePid) async _prepare(domainId: string, pid: number | string) { this.response.template = 'problem_detail.html'; this.pdoc = await problem.get(domainId, pid, this.user._id); @@ -210,7 +210,7 @@ export class ProblemDetailHandler extends ProblemHandler { } export class ProblemSubmitHandler extends ProblemDetailHandler { - @param('pid', Types.String, null, parsePid) + @param('pid', Types.Name, null, parsePid) async get(domainId: string, pid: string | number) { this.response.template = 'problem_submit.html'; const rdocs = await record @@ -232,8 +232,8 @@ export class ProblemSubmitHandler extends ProblemDetailHandler { }; } - @param('lang', Types.String) - @param('code', Types.String) + @param('lang', Types.Name) + @param('code', Types.Content) async post(domainId: string, lang: string, code: string) { await this.limitRate('add_record', 60, 5); const rid = await record.add(domainId, this.pdoc.docId, this.user._id, lang, code, true); @@ -250,9 +250,9 @@ export class ProblemSubmitHandler extends ProblemDetailHandler { } export class ProblemPretestHandler extends ProblemDetailHandler { - @param('lang', Types.String) - @param('code', Types.String) - @param('input', Types.String, true) + @param('lang', Types.Name) + @param('code', Types.Content) + @param('input', Types.Content, true) async post(domainId: string, lang: string, code: string, input = '') { await this.limitRate('add_record', 60, 5); const rid = await record.add( @@ -270,7 +270,7 @@ export class ProblemPretestConnectionHandler extends ConnectionHandler { domainId: string; dispose: bus.Disposable; - @param('pid', Types.String) + @param('pid', Types.Name) async prepare(domainId: string, pid: string) { const pdoc = await problem.get(domainId, pid); if (!pdoc) throw new ProblemNotFoundError(domainId, pid); @@ -327,12 +327,12 @@ export class ProblemEditHandler extends ProblemManageHandler { ]; } - @route('pid', Types.String, null, parsePid) - @post('title', Types.String, isTitle) - @post('content', Types.String, isContent) - @post('pid', Types.String, isPid, true) + @route('pid', Types.Name, null, parsePid) + @post('content', Types.Title) + @post('content', Types.Content) + @post('pid', Types.Name, isPid, true) @post('hidden', Types.Boolean) - @post('tag', Types.String, true, null, parseCategory) + @post('tag', Types.Content, true, null, parseCategory) async post( domainId: string, pid: string | number, title: string, content: string, newPid: string = '', hidden = false, tag: string[] = [], @@ -375,8 +375,8 @@ export class ProblemFilesHandler extends ProblemDetailHandler { this.response.body.links = links; } - @post('filename', Types.String) - @post('type', Types.String, true) + @post('filename', Types.Name) + @post('type', Types.Content, true) async postUploadFile(domainId: string, filename: string, type = 'testdata') { if (!this.request.files.file) throw new ValidationError('file'); if (this.pdoc.owner !== this.user._id) this.checkPerm(PERM.PERM_EDIT_PROBLEM); @@ -413,7 +413,7 @@ export class ProblemFilesHandler extends ProblemDetailHandler { export class ProblemFileDownloadHandler extends ProblemDetailHandler { @query('type', Types.Range(['additional_file', 'testdata']), true) - @param('filename', Types.String) + @param('filename', Types.Name) @param('noDisposition', Types.Boolean) async get(domainId: string, type = 'additional_file', filename: string, noDisposition = false) { if (type === 'testdata' && this.user._id !== this.pdoc.owner) this.checkPerm(PERM.PERM_READ_PROBLEM_DATA); @@ -456,14 +456,14 @@ export class ProblemSolutionHandler extends ProblemDetailHandler { await bus.serial('handler/solution/get', this); } - @param('content', Types.String, isContent) + @param('content', Types.Content) 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(); } - @param('content', Types.String, isContent) + @param('content', Types.Content) @param('psid', Types.ObjectID) async postEditSolution(domainId: string, content: string, psid: ObjectID) { let psdoc = await solution.get(domainId, psid); @@ -483,7 +483,7 @@ export class ProblemSolutionHandler extends ProblemDetailHandler { } @param('psid', Types.ObjectID) - @param('content', Types.String, isContent) + @param('content', Types.Content) async postReply(domainId: string, psid: ObjectID, content: string) { this.checkPerm(PERM.PERM_REPLY_PROBLEM_SOLUTION); const psdoc = await solution.get(domainId, psid); @@ -493,7 +493,7 @@ export class ProblemSolutionHandler extends ProblemDetailHandler { @param('psid', Types.ObjectID) @param('psrid', Types.ObjectID) - @param('content', Types.String, isContent) + @param('content', Types.Content) 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); @@ -561,11 +561,11 @@ export class ProblemCreateHandler extends Handler { }; } - @post('title', Types.String, isTitle) - @post('content', Types.String, isContent) - @post('pid', Types.String, true, isPid) + @post('content', Types.Title) + @post('content', Types.Content) + @post('pid', Types.Name, true, isPid) @post('hidden', Types.Boolean) - @post('tag', Types.String, true, null, parseCategory) + @post('tag', Types.Content, true, null, parseCategory) async post(domainId: string, title: string, content: string, pid: string, hidden = false, tag: string[] = []) { if (pid && await problem.get(domainId, pid)) throw new BadRequestError('invalid pid'); const docId = await problem.add(domainId, pid, title, content, this.user._id, tag ?? [], hidden); diff --git a/packages/hydrooj/src/handler/record.ts b/packages/hydrooj/src/handler/record.ts index 6b30042da..f3c91782d 100644 --- a/packages/hydrooj/src/handler/record.ts +++ b/packages/hydrooj/src/handler/record.ts @@ -18,9 +18,9 @@ const RecordHandler = contest.ContestHandlerMixin(Handler); class RecordListHandler extends RecordHandler { @param('page', Types.PositiveInt, true) - @param('pid', Types.String, true) + @param('pid', Types.Name, true) @param('tid', Types.ObjectID, true) - @param('uidOrName', Types.String, true) + @param('uidOrName', Types.Name, true) @param('allDomain', Types.Boolean, true) async get(domainId: string, page = 1, pid?: string, tid?: ObjectID, uidOrName?: string, all = false) { this.response.template = 'record_main.html'; diff --git a/packages/hydrooj/src/handler/remote.ts b/packages/hydrooj/src/handler/remote.ts index 6df671289..ad521437b 100644 --- a/packages/hydrooj/src/handler/remote.ts +++ b/packages/hydrooj/src/handler/remote.ts @@ -50,7 +50,7 @@ export class ProblemSendHandler extends Handler { this.back(); } - @post('token', Types.String) + @post('token', Types.Content) async postInfo(domainId: string, tokenId: string) { const data = await token.get(tokenId, token.TYPE_EXPORT); if (!data) throw new InvalidTokenError(tokenId); @@ -60,7 +60,7 @@ export class ProblemSendHandler extends Handler { this.response.body = { pdocs: r, pids: data.pids }; } - @post('token', Types.String, true) + @post('token', Types.Content, true) @post('pids', Types.Array) async postFetch(domainId: string, tokenId: string, pids: number[]) { pids = pids.map((i) => (+i ? +i : i)); diff --git a/packages/hydrooj/src/handler/training.ts b/packages/hydrooj/src/handler/training.ts index 443cfa279..c78017ded 100644 --- a/packages/hydrooj/src/handler/training.ts +++ b/packages/hydrooj/src/handler/training.ts @@ -178,8 +178,8 @@ class TrainingCreateHandler extends Handler { this.response.body = { page_name: 'training_create', path }; } - @param('title', Types.String, isTitle) - @param('content', Types.String, isContent) + @param('content', Types.Title) + @param('content', Types.Content) @param('dag', Types.String, isContent) @param('description', Types.String, isDescription) async post( @@ -224,8 +224,8 @@ class TrainingEditHandler extends Handler { } @param('tid', Types.ObjectID) - @param('title', Types.String, isTitle) - @param('content', Types.String, isContent) + @param('content', Types.Title) + @param('content', Types.Content) @param('dag', Types.String, isContent) @param('description', Types.String, isDescription) async post( diff --git a/packages/hydrooj/src/model/discussion.ts b/packages/hydrooj/src/model/discussion.ts index 8ce83d393..24492fee1 100644 --- a/packages/hydrooj/src/model/discussion.ts +++ b/packages/hydrooj/src/model/discussion.ts @@ -1,4 +1,5 @@ import { FilterQuery, ObjectID } from 'mongodb'; +import { omit } from 'lodash'; import problem from './problem'; import * as contest from './contest'; import * as training from './training'; @@ -63,24 +64,33 @@ export const typeDisplay = { [document.TYPE_HOMEWORK]: 'homework', }; -export function add( +export async function add( domainId: string, parentType: number, parentId: ObjectID | number | string, owner: number, title: string, content: string, ip: string | null = null, highlight: boolean, pin: boolean, ): Promise { - return document.add( - domainId, content, owner, document.TYPE_DISCUSSION, - null, parentType, parentId, - { - title, - ip, - nReply: 0, - highlight, - pin, - updateAt: new Date(), - views: 0, - }, + const payload: Partial = { + domainId, + content, + owner, + parentType, + parentId, + title, + ip, + nReply: 0, + highlight, + pin, + updateAt: new Date(), + views: 0, + }; + await bus.serial('discussion/before-add', payload); + const res = await document.add( + payload.domainId, payload.content, payload.owner, document.TYPE_DISCUSSION, + null, payload.parentType, payload.parentId, omit(payload, ['domainId', 'content', 'owner', 'parentType', 'parentId']), ); + payload.docId = res; + await bus.emit('discussion/add', payload); + return payload.docId; } // FIXME typings doesn't work diff --git a/packages/hydrooj/src/service/bus.ts b/packages/hydrooj/src/service/bus.ts index 863e20e44..b51e08c8a 100644 --- a/packages/hydrooj/src/service/bus.ts +++ b/packages/hydrooj/src/service/bus.ts @@ -9,7 +9,7 @@ import { Logger } from '../logger'; import type { Mdoc, Pdoc, Rdoc, TrainingDoc, User, } from '../interface'; -import type { DomainDoc } from '../loader'; +import type { Ddoc, DomainDoc } from '../loader'; import type { DocType } from '../model/document'; import type { ProblemSolutionHandler } from '../handler/problem'; import type { UserRegisterHandler } from '../handler/user'; @@ -70,11 +70,8 @@ export interface EventMap extends Record { 'handler/finish/UserRegister': (thisArg: UserRegisterHandler) => VoidReturn 'handler/solution/get': (thisArg: ProblemSolutionHandler) => VoidReturn - 'discussion/before-add': ( - domainId: string, parentType: number, parentId: ObjectID | number | string, - owner: number, title: string, content: string, - ip: string | null, highlight: boolean, pin: boolean - ) => VoidReturn + 'discussion/before-add': (payload: Partial) => VoidReturn + 'discussion/add': (payload: Partial) => VoidReturn 'problem/before-add': (doc: Partial) => VoidReturn 'problem/add': (doc: Partial, docId: number) => VoidReturn diff --git a/packages/hydrooj/src/service/server.ts b/packages/hydrooj/src/service/server.ts index 36b5e05aa..dd46f37cc 100644 --- a/packages/hydrooj/src/service/server.ts +++ b/packages/hydrooj/src/service/server.ts @@ -30,6 +30,7 @@ import { NotFoundError, HydroError, } from '../error'; import * as misc from '../lib/misc'; +import { isContent, isName, isTitle } from '../lib/validator'; import user from '../model/user'; import domain from '../model/domain'; import * as system from '../model/system'; @@ -57,6 +58,9 @@ interface ParamOption { type Type = [Converter, Validator, boolean?]; export interface Types { + Content: Type, + Name: Type, + Title: Type, String: Type, Int: Type, UnsignedInt: Type, @@ -73,6 +77,9 @@ export interface Types { } export const Types: Types = { + Content: [(v) => v.toString(), isContent], + Name: [(v) => v.toString(), isName], + Title: [(v) => v.toString(), isTitle], String: [(v) => v.toString(), null], Int: [(v) => parseInt(v, 10), (v) => isSafeInteger(parseInt(v, 10))], UnsignedInt: [(v) => parseInt(v, 10), (v) => parseInt(v, 10) >= 0],