mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
core: api: problem.manage.edit & problem.manage.delete
This commit is contained in:
1 parent
a75804362d
commit
5d9310fb78
7 files changed
+58
-11
No files matched your search
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hydrooj",
|
"name": "hydrooj",
|
||||||
"version": "3.1.9",
|
"version": "3.1.10",
|
||||||
"bin": "bin/hydrooj.js",
|
"bin": "bin/hydrooj.js",
|
||||||
"main": "src/loader",
|
"main": "src/loader",
|
||||||
"module": "src/loader",
|
"module": "src/loader",
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ export class HydroError extends Error {
|
|||||||
msg() {
|
msg() {
|
||||||
return 'HydroError';
|
return 'HydroError';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get message() {
|
||||||
|
return this.msg();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UserFacingError = Err('UserFacingError', HydroError, 'UserFacingError', 400);
|
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');
|
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);
|
registerValue(typeName, key, value, description);
|
||||||
if (handlers[typeName]) handlers[typeName][key.split('(')[0].trim()] = func;
|
const wrappedFunc = async (arg, ctx) => {
|
||||||
else handlers[typeName] = { [key.split('(')[0].trim()]: func };
|
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');
|
bus.emit('api/update');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,10 +96,14 @@ class ApiHandler extends Handler {
|
|||||||
} else this.response.template = 'api.html';
|
} 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() {
|
async post() {
|
||||||
this.response.type = 'application/json';
|
this.response.type = 'application/json';
|
||||||
// FIXME validation for fields like ObjectID doesn't work.
|
this.response.body = await this.query(this.args.query, this.args.variables);
|
||||||
this.response.body = await graphql.graphql(schema, this.args.query, root, this, this.args.variables);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
|
import { statSync } from 'fs';
|
||||||
import { pick } from 'lodash';
|
import { pick } from 'lodash';
|
||||||
import { lookup } from 'mime-types';
|
import { lookup } from 'mime-types';
|
||||||
import {
|
import {
|
||||||
@@ -47,7 +48,8 @@ export class FilesHandler extends Handler {
|
|||||||
throw new ForbiddenError('File limit exceeded.');
|
throw new ForbiddenError('File limit exceeded.');
|
||||||
}
|
}
|
||||||
if (!this.request.files.file) throw new ValidationError('file');
|
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')) {
|
if (size >= system.get('limit.user_files_size')) {
|
||||||
throw new ForbiddenError('File size limit exceeded.');
|
throw new ForbiddenError('File size limit exceeded.');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,12 +60,39 @@ registerValue('Problem', [
|
|||||||
['tag', '[String]'],
|
['tag', '[String]'],
|
||||||
['hidden', 'Boolean'],
|
['hidden', 'Boolean'],
|
||||||
]);
|
]);
|
||||||
registerResolver('Query', 'problem(id: Int, pid: String)', 'Problem', async (arg, ctx) => {
|
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);
|
const pdoc = await problem.get(ctx.domainId, arg.pid || arg.id);
|
||||||
if (!pdoc) return null;
|
if (!pdoc) return null;
|
||||||
if (pdoc.hidden && !ctx.user.own(pdoc)) ctx.checkPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN);
|
if (pdoc.hidden && !ctx.user.own(pdoc)) ctx.checkPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN);
|
||||||
|
ctx.pdoc = pdoc;
|
||||||
return 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 {
|
export class ProblemHandler extends Handler {
|
||||||
async cleanup() {
|
async cleanup() {
|
||||||
|
|||||||
@@ -107,8 +107,8 @@ export function deleteOne<K extends keyof DocType>(
|
|||||||
domainId: string, docType: K, docId: DocType[K]['docId'],
|
domainId: string, docType: K, docId: DocType[K]['docId'],
|
||||||
) {
|
) {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
collStatus.deleteMany({ domainId, docType, docId }),
|
|
||||||
coll.deleteOne({ 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),
|
bus.parallel('problem/delete', domainId, docId),
|
||||||
]);
|
]);
|
||||||
await bus.emit('problem/del', 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) {
|
static async addTestdata(domainId: string, pid: number, name: string, f: Readable | Buffer | string) {
|
||||||
|
|||||||
Reference in new issue
Block a user