core: api: problem.manage.edit & problem.manage.delete

This commit is contained in:
undefined committed 2021-10-27 22:42:40 +08:00
1 parent a75804362d
commit 5d9310fb78
7 files changed
+62 -15

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "hydrooj",
"version": "3.1.9",
"version": "3.1.10",
"bin": "bin/hydrooj.js",
"main": "src/loader",
"module": "src/loader",
+4
View File
@@ -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);
+19 -5
View File
@@ -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);
}
}
+3 -1
View File
@@ -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.');
}
+33 -6
View File
@@ -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() {
+1 -1
View File
@@ -107,8 +107,8 @@ export function deleteOne<K extends keyof DocType>(
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 }),
]);
}
+1 -1
View File
@@ -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) {