From 5d9310fb78e98afb5de33acb2b995b7fe7e2f828 Mon Sep 17 00:00:00 2001 From: undefined Date: Wed, 27 Oct 2021 22:42:40 +0800 Subject: [PATCH] core: api: problem.manage.edit & problem.manage.delete --- packages/hydrooj/package.json | 2 +- packages/hydrooj/src/error.ts | 4 +++ packages/hydrooj/src/handler/api.ts | 24 +++++++++++---- packages/hydrooj/src/handler/misc.ts | 4 ++- packages/hydrooj/src/handler/problem.ts | 39 +++++++++++++++++++++---- packages/hydrooj/src/model/document.ts | 2 +- packages/hydrooj/src/model/problem.ts | 2 +- 7 files changed, 62 insertions(+), 15 deletions(-) diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index 566fd0dfc..14e6fb55a 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -1,6 +1,6 @@ { "name": "hydrooj", - "version": "3.1.9", + "version": "3.1.10", "bin": "bin/hydrooj.js", "main": "src/loader", "module": "src/loader", diff --git a/packages/hydrooj/src/error.ts b/packages/hydrooj/src/error.ts index d11164cc8..f9ff4ac41 100644 --- a/packages/hydrooj/src/error.ts +++ b/packages/hydrooj/src/error.ts @@ -37,6 +37,10 @@ export class HydroError extends Error { msg() { return 'HydroError'; } + + get message() { + return this.msg(); + } } export const UserFacingError = Err('UserFacingError', HydroError, 'UserFacingError', 400); diff --git a/packages/hydrooj/src/handler/api.ts b/packages/hydrooj/src/handler/api.ts index 54027bbfd..2a0f66767 100644 --- a/packages/hydrooj/src/handler/api.ts +++ b/packages/hydrooj/src/handler/api.ts @@ -24,10 +24,20 @@ export function registerValue(typeName: string, arg1: [string, string, string?][ bus.emit('api/update'); } -export function registerResolver(typeName: string, key: string, value: string, func: Function, description?: string) { +interface Context extends ApiHandler { + [key: string]: any; +} + +export function registerResolver(typeName: string, key: string, value: string, func: (args: any, ctx: Context) => any, description?: string) { registerValue(typeName, key, value, description); - if (handlers[typeName]) handlers[typeName][key.split('(')[0].trim()] = func; - else handlers[typeName] = { [key.split('(')[0].trim()]: func }; + const wrappedFunc = async (arg, ctx) => { + const res = await func(arg, ctx); + if (typeof res !== 'object') return res; + if (handlers[value]) Object.assign(res, handlers[value]); + return res; + }; + if (handlers[typeName]) handlers[typeName][key.split('(')[0].trim()] = wrappedFunc; + else handlers[typeName] = { [key.split('(')[0].trim()]: wrappedFunc }; bus.emit('api/update'); } @@ -86,10 +96,14 @@ class ApiHandler extends Handler { } else this.response.template = 'api.html'; } + async query(q: string, variables: any) { + // FIXME validation for fields like ObjectID doesn't work. + return graphql.graphql(schema, q, root, this, variables); + } + async post() { this.response.type = 'application/json'; - // FIXME validation for fields like ObjectID doesn't work. - this.response.body = await graphql.graphql(schema, this.args.query, root, this, this.args.variables); + this.response.body = await this.query(this.args.query, this.args.variables); } } diff --git a/packages/hydrooj/src/handler/misc.ts b/packages/hydrooj/src/handler/misc.ts index afebfec6a..a98044a56 100644 --- a/packages/hydrooj/src/handler/misc.ts +++ b/packages/hydrooj/src/handler/misc.ts @@ -1,4 +1,5 @@ /* eslint-disable camelcase */ +import { statSync } from 'fs'; import { pick } from 'lodash'; import { lookup } from 'mime-types'; import { @@ -47,7 +48,8 @@ export class FilesHandler extends Handler { throw new ForbiddenError('File limit exceeded.'); } if (!this.request.files.file) throw new ValidationError('file'); - const size = Math.sum((this.user._files || []).map((i) => i.size)); + const f = statSync(this.request.files.file.path); + const size = Math.sum((this.user._files || []).map((i) => i.size)) + f.size; if (size >= system.get('limit.user_files_size')) { throw new ForbiddenError('File size limit exceeded.'); } diff --git a/packages/hydrooj/src/handler/problem.ts b/packages/hydrooj/src/handler/problem.ts index f190e7d80..f83230003 100644 --- a/packages/hydrooj/src/handler/problem.ts +++ b/packages/hydrooj/src/handler/problem.ts @@ -60,12 +60,39 @@ registerValue('Problem', [ ['tag', '[String]'], ['hidden', 'Boolean'], ]); -registerResolver('Query', 'problem(id: Int, pid: String)', 'Problem', async (arg, ctx) => { - const pdoc = await problem.get(ctx.domainId, arg.pid || arg.id); - if (!pdoc) return null; - if (pdoc.hidden && !ctx.user.own(pdoc)) ctx.checkPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN); - return pdoc; -}); +registerValue('ProblemManage', [ + ['delete', 'Boolean!'], +]); + +registerResolver( + 'Query', 'problem(id: Int, pid: String)', 'Problem', + async (arg, ctx) => { + const pdoc = await problem.get(ctx.domainId, arg.pid || arg.id); + if (!pdoc) return null; + if (pdoc.hidden && !ctx.user.own(pdoc)) ctx.checkPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN); + ctx.pdoc = pdoc; + return pdoc; + }, +); +registerResolver( + 'Problem', 'manage', 'ProblemManage', + async (arg, ctx) => { + if (!ctx.user.own(ctx.pdoc, PERM.PERM_EDIT_PROBLEM_SELF)) ctx.checkPerm(PERM.PERM_EDIT_PROBLEM); + return {}; + }, +); +registerResolver( + 'ProblemManage', 'delete', 'Boolean!', + async (arg, ctx) => { + const tdocs = await contest.getRelated(ctx.domainId, ctx.pdoc.docId); + if (tdocs.length) throw new BadRequestError('Problem already used by contest {0}', tdocs[0]._id); + return problem.del(ctx.pdoc.domainId, ctx.pdoc.docId); + }, +); +registerResolver( + 'ProblemManage', 'edit(title: String, content: String, tag: [String], hidden: Boolean)', 'Problem!', + (arg, ctx) => problem.edit(ctx.domainId, ctx.pdoc.docId, arg), +); export class ProblemHandler extends Handler { async cleanup() { diff --git a/packages/hydrooj/src/model/document.ts b/packages/hydrooj/src/model/document.ts index 4f90ef4f7..aa4bef9f4 100644 --- a/packages/hydrooj/src/model/document.ts +++ b/packages/hydrooj/src/model/document.ts @@ -107,8 +107,8 @@ export function deleteOne( domainId: string, docType: K, docId: DocType[K]['docId'], ) { return Promise.all([ - collStatus.deleteMany({ domainId, docType, docId }), coll.deleteOne({ domainId, docType, docId }), + collStatus.deleteMany({ domainId, docType, docId }), ]); } diff --git a/packages/hydrooj/src/model/problem.ts b/packages/hydrooj/src/model/problem.ts index 103664b9a..d8f4dd031 100644 --- a/packages/hydrooj/src/model/problem.ts +++ b/packages/hydrooj/src/model/problem.ts @@ -182,7 +182,7 @@ export class ProblemModel { bus.parallel('problem/delete', domainId, docId), ]); await bus.emit('problem/del', domainId, docId); - return res; + return !!res[0][0].deletedCount; } static async addTestdata(domainId: string, pid: number, name: string, f: Readable | Buffer | string) {