From 332a6aa697b551a75fbccae568feddc686242851 Mon Sep 17 00:00:00 2001 From: undefined Date: Mon, 4 Nov 2024 23:17:49 +0800 Subject: [PATCH] core: allow coping copied problems --- packages/hydrooj/src/error.ts | 1 + packages/hydrooj/src/handler/problem.ts | 27 ++++++++++++++++--------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/packages/hydrooj/src/error.ts b/packages/hydrooj/src/error.ts index fcea8a00d..9ddbbe7cf 100644 --- a/packages/hydrooj/src/error.ts +++ b/packages/hydrooj/src/error.ts @@ -56,6 +56,7 @@ export const ProblemAlreadyExistError = Err('ProblemAlreadyExistError', Forbidde export const ProblemAlreadyUsedByContestError = Err('ProblemAlreadyUsedByContestError', ForbiddenError, 'Problem {0} is already used by contest {1}.'); export const ProblemNotAllowPretestError = Err('ProblemNotAllowPretestError', ForbiddenError, 'Pretesting is not supported for {0}.'); export const ProblemNotAllowLanguageError = Err('ProblemNotAllowSubmitError', ForbiddenError, 'This language is not allowed to submit.'); +export const ProblemNotAllowCopyError = Err('ProblemNotAllowCopyError', ForbiddenError, 'You are not allowed to copy this problem from {0} to {1}.'); export const PretestRejudgeFailedError = Err('PretestRejudgeFailedError', BadRequestError, 'Cannot rejudge a pretest record.'); export const HackRejudgeFailedError = Err('HackRejudgeFailedError', BadRequestError, 'Cannot rejudge a hack record.'); diff --git a/packages/hydrooj/src/handler/problem.ts b/packages/hydrooj/src/handler/problem.ts index 3bb14bfa1..17e3f8e43 100644 --- a/packages/hydrooj/src/handler/problem.ts +++ b/packages/hydrooj/src/handler/problem.ts @@ -13,8 +13,8 @@ import { BadRequestError, ContestNotAttendedError, ContestNotEndedError, ContestNotFoundError, ContestNotLiveError, FileLimitExceededError, HackFailedError, NoProblemError, NotFoundError, PermissionError, ProblemAlreadyExistError, ProblemAlreadyUsedByContestError, ProblemConfigError, - ProblemIsReferencedError, ProblemNotAllowLanguageError, ProblemNotAllowPretestError, ProblemNotFoundError, - RecordNotFoundError, SolutionNotFoundError, ValidationError, + ProblemIsReferencedError, ProblemNotAllowCopyError, ProblemNotAllowLanguageError, ProblemNotAllowPretestError, + ProblemNotFoundError, RecordNotFoundError, SolutionNotFoundError, ValidationError, } from '../error'; import { ProblemDoc, ProblemSearchOptions, ProblemStatusDoc, RecordDoc, User, @@ -414,15 +414,24 @@ export class ProblemDetailHandler extends ContestDetailBaseHandler { } @param('target', Types.String) - async postCopy(domainId: string, target: string) { - if (this.pdoc.reference) throw new BadRequestError('Cannot copy a referenced problem'); - const t = `,${this.domain.share || ''},`; - if (t !== ',*,' && !t.includes(`,${target},`)) throw new PermissionError(target); - const ddoc = await domain.get(target); + async postCopy({ }, target: string) { + let t = `,${this.domain.share || ''},`; + if (t !== ',*,' && !t.includes(`,${target},`)) throw new ProblemNotAllowCopyError(this.domain._id, target); + let ddoc = await domain.get(target); if (!ddoc) throw new NotFoundError(target); const dudoc = await user.getById(target, this.user._id); + let pdoc = this.pdoc; + if (this.pdoc.reference) { + [pdoc, ddoc] = await Promise.all([ + problem.get(this.pdoc.reference.domainId, this.pdoc.reference.pid), + domain.get(this.pdoc.reference.domainId), + ]); + if (!pdoc) throw new ProblemNotFoundError(this.pdoc.reference.domainId, this.pdoc.reference.pid); + t = `,${ddoc.domain.share || ''},`; + if (t !== ',*,' && !t.includes(`,${target},`)) throw new ProblemNotAllowCopyError(ddoc._id, target); + } if (!dudoc.hasPerm(PERM.PERM_CREATE_PROBLEM)) throw new PermissionError(PERM.PERM_CREATE_PROBLEM); - const docId = await problem.copy(domainId, this.pdoc.docId, target); + const docId = await problem.copy(pdoc.domainId, pdoc.docId, target); this.response.redirect = this.url('problem_detail', { domainId: target, pid: docId }); } @@ -980,7 +989,7 @@ export class ProblemCreateHandler extends Handler { @post('title', Types.Title) @post('content', Types.Content) - @post('pid', Types.ProblemId, true, (i) => /^[a-zA-Z]+[a-zA-Z0-9]*$/i.test(i)) + @post('pid', Types.ProblemId, true, (i) => /^([a-zA-Z0-9]{1,10}-)?[a-zA-Z]+[a-zA-Z0-9]*$/i.test(i)) @post('hidden', Types.Boolean) @post('difficulty', Types.PositiveInt, (i) => +i <= 10, true) @post('tag', Types.Content, true, null, parseCategory)