core: make API a service

This commit is contained in:
undefined committed 2024-05-25 02:14:07 +08:00
1 parent f48f8fe5f7
commit d4116c502e
8 files changed
+388 -357

No files matched your search

+63 -63
View File
@@ -8,6 +8,7 @@ import { nanoid } from 'nanoid';
import sanitize from 'sanitize-filename';
import parser from '@hydrooj/utils/lib/search';
import { sortFiles, streamToBuffer } from '@hydrooj/utils/lib/utils';
import type { Context } from '../context';
import {
BadRequestError, ContestNotAttendedError, ContestNotEndedError, ContestNotFoundError, ContestNotLiveError,
FileLimitExceededError, HackFailedError, NoProblemError, NotFoundError,
@@ -34,72 +35,10 @@ import {
Handler, param, post, query, route, Types,
} from '../service/server';
import { buildProjection } from '../utils';
import { registerResolver, registerValue } from './api';
import { ContestDetailBaseHandler } from './contest';
export const parseCategory = (value: string) => value.replace(/,/g, ',').split(',').map((e) => e.trim());
registerValue('FileInfo', [
['_id', 'String!'],
['name', 'String!'],
['size', 'Int'],
['lastModified', 'Date'],
]);
registerValue('Problem', [
['_id', 'ObjectID!'],
['owner', 'Int!'],
['domainId', 'String!'],
['docId', 'Int!'],
['docType', 'Int!'],
['pid', 'String'],
['title', 'String!'],
['content', 'String!'],
['data', '[FileInfo]'],
['additional_file', '[FileInfo]'],
['nSubmit', 'Int'],
['nAccept', 'Int'],
['difficulty', 'Int'],
['tag', '[String]'],
['hidden', 'Boolean'],
]);
registerResolver(
'Query', 'problem(id: Int, pid: String)', 'Problem',
async (arg, ctx) => {
ctx.checkPerm(PERM.PERM_VIEW);
const pdoc = await problem.get(ctx.args.domainId, arg.pid || arg.id);
if (!pdoc) return null;
if (pdoc.hidden) ctx.checkPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN);
ctx.pdoc = pdoc;
return pdoc;
},
);
registerResolver('Query', 'problems(ids: [Int])', '[Problem]', async (arg, ctx) => {
ctx.checkPerm(PERM.PERM_VIEW);
const res = await problem.getList(ctx.args.domainId, arg.ids, ctx.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN) || ctx.user._id,
undefined, undefined, true);
return Object.keys(res).map((id) => res[+id]);
}, 'Get a list of problem by ids');
registerResolver(
'Problem', 'manage', 'ProblemManage',
(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.args.domainId, ctx.pdoc.docId);
if (tdocs.length) throw new ProblemAlreadyUsedByContestError(ctx.pdoc.docId, 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.args.domainId, ctx.pdoc.docId, arg),
);
function buildQuery(udoc: User) {
const q: Filter<ProblemDoc> = {};
if (!udoc.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN)) {
@@ -1078,7 +1017,7 @@ export class ProblemPrefixListHandler extends Handler {
}
}
export async function apply(ctx) {
export async function apply(ctx: Context) {
ctx.Route('problem_main', '/p', ProblemMainHandler, PERM.PERM_VIEW_PROBLEM);
ctx.Route('problem_random', '/problem/random', ProblemRandomHandler, PERM.PERM_VIEW_PROBLEM);
ctx.Route('problem_detail', '/p/:pid', ProblemDetailHandler);
@@ -1095,4 +1034,65 @@ export async function apply(ctx) {
ctx.Route('problem_statistics', '/p/:pid/stat', ProblemStatisticsHandler, PERM.PERM_VIEW_PROBLEM);
ctx.Route('problem_create', '/problem/create', ProblemCreateHandler, PERM.PERM_CREATE_PROBLEM);
ctx.Route('problem_prefix_list', '/problem/list', ProblemPrefixListHandler, PERM.PERM_VIEW_PROBLEM);
ctx.inject(['api'], ({ api }) => {
api.value('FileInfo', [
['_id', 'String!'],
['name', 'String!'],
['size', 'Int'],
['lastModified', 'Date'],
]);
api.value('Problem', [
['_id', 'ObjectID!'],
['owner', 'Int!'],
['domainId', 'String!'],
['docId', 'Int!'],
['docType', 'Int!'],
['pid', 'String'],
['title', 'String!'],
['content', 'String!'],
['data', '[FileInfo]'],
['additional_file', '[FileInfo]'],
['nSubmit', 'Int'],
['nAccept', 'Int'],
['difficulty', 'Int'],
['tag', '[String]'],
['hidden', 'Boolean'],
]);
api.resolver(
'Query', 'problem(id: Int, pid: String)', 'Problem',
async (arg, c) => {
c.checkPerm(PERM.PERM_VIEW);
const pdoc = await problem.get(c.args.domainId, arg.pid || arg.id);
if (!pdoc) return null;
if (pdoc.hidden) c.checkPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN);
c.pdoc = pdoc;
return pdoc;
},
);
api.resolver('Query', 'problems(ids: [Int])', '[Problem]', async (arg, c) => {
c.checkPerm(PERM.PERM_VIEW);
const res = await problem.getList(c.args.domainId, arg.ids, c.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN) || c.user._id,
undefined, undefined, true);
return Object.keys(res).map((id) => res[+id]);
}, 'Get a list of problem by ids');
api.resolver(
'Problem', 'manage', 'ProblemManage',
(arg, c) => {
if (!c.user.own(c.pdoc, PERM.PERM_EDIT_PROBLEM_SELF)) c.checkPerm(PERM.PERM_EDIT_PROBLEM);
return {};
},
);
api.resolver(
'ProblemManage', 'delete', 'Boolean!',
async (arg, c) => {
const tdocs = await contest.getRelated(c.args.domainId, c.pdoc.docId);
if (tdocs.length) throw new ProblemAlreadyUsedByContestError(c.pdoc.docId, tdocs[0]._id);
return problem.del(c.pdoc.domainId, c.pdoc.docId);
},
);
api.resolver(
'ProblemManage', 'edit(title: String, content: String, tag: [String], hidden: Boolean)', 'Problem!',
(arg, c) => problem.edit(c.args.domainId, c.pdoc.docId, arg),
);
});
}