mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 17:36:08 +08:00
core: api: problem.manage.edit & problem.manage.delete
This commit is contained in:
1 parent
a75804362d
commit
5d9310fb78
7 files changed
+62
-15
No files matched your search
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hydrooj",
|
||||
"version": "3.1.9",
|
||||
"version": "3.1.10",
|
||||
"bin": "bin/hydrooj.js",
|
||||
"main": "src/loader",
|
||||
"module": "src/loader",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.');
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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 }),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in new issue
Block a user