diff --git a/packages/hydrooj/src/handler/contest.ts b/packages/hydrooj/src/handler/contest.ts index 8b3fb2e17..a2e448926 100644 --- a/packages/hydrooj/src/handler/contest.ts +++ b/packages/hydrooj/src/handler/contest.ts @@ -7,7 +7,6 @@ import { } from '../error'; import { ProblemDoc, Tdoc, User } from '../interface'; import paginate from '../lib/paginate'; -import { parseConfig } from '../lib/testdataConfig'; import { PERM, PRIV } from '../model/builtin'; import * as contest from '../model/contest'; import * as system from '../model/system'; @@ -270,11 +269,6 @@ class ContestProblemHandler extends Handler { attended: this.attended, page_name: 'contest_detail_problem', }; - try { - this.response.body.pdoc.config = await parseConfig(this.pdoc.config); - } catch (e) { - this.response.body.pdoc.config = `Cannot parse: ${e.message}`; - } } // eslint-disable-next-line diff --git a/packages/hydrooj/src/handler/homework.ts b/packages/hydrooj/src/handler/homework.ts index eec3087a5..01be9b319 100644 --- a/packages/hydrooj/src/handler/homework.ts +++ b/packages/hydrooj/src/handler/homework.ts @@ -24,7 +24,6 @@ import problem from '../model/problem'; import record from '../model/record'; import * as document from '../model/document'; import paginate from '../lib/paginate'; -import { parseConfig } from '../lib/testdataConfig'; const validatePenaltyRules = (input: string) => { const s = yaml.load(input); @@ -144,11 +143,6 @@ class HomeworkDetailProblemHandler extends Handler { udoc: this.udoc, attended: this.attended, }; - try { - this.response.body.pdoc.config = await parseConfig(this.pdoc.config); - } catch (e) { - this.response.body.pdoc.config = `Cannot parse: ${e.message}`; - } } @param('tid', Types.ObjectID) diff --git a/packages/hydrooj/src/handler/problem.ts b/packages/hydrooj/src/handler/problem.ts index dc5956d18..fce9340ba 100644 --- a/packages/hydrooj/src/handler/problem.ts +++ b/packages/hydrooj/src/handler/problem.ts @@ -13,7 +13,6 @@ import { import paginate from '../lib/paginate'; import { isPid, parsePid as convertPid } from '../lib/validator'; import difficultyAlgorithm from '../lib/difficulty'; -import { parseConfig } from '../lib/testdataConfig'; import * as system from '../model/system'; import problem from '../model/problem'; import record from '../model/record'; @@ -203,12 +202,6 @@ export class ProblemDetailHandler extends ProblemHandler { ], }; this.extraTitleContent = this.pdoc.title; - // Get time and memory limit - try { - this.response.body.pdoc.config = await parseConfig(this.pdoc.config); - } catch (e) { - this.response.body.pdoc.config = `Cannot parse: ${e.message}`; - } } // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -597,11 +590,20 @@ export class ProblemCreateHandler extends Handler { export class ProblemPrefixListHandler extends Handler { @param('prefix', Types.Name) async get(domainId: string, prefix: string) { - this.response.body = await problem.getPrefixList(domainId, prefix); + const pdocs = await problem.getPrefixList(domainId, prefix); if (!Number.isNaN(+prefix)) { const pdoc = await problem.get(domainId, +prefix, ['domainId', 'docId', 'pid', 'title']); - if (pdoc) this.response.body.unshift(pdoc); + if (pdoc) pdocs.unshift(pdoc); } + const search = global.Hydro.lib.problemSearch; + if (pdocs.length < 20) { + if (search) { + const result = await search(domainId, prefix, 20 - pdocs.length); + const docs = await problem.getMulti(domainId, { docId: { $in: result } }).toArray(); + pdocs.push(...docs); + } + } + this.response.body = pdocs; } } diff --git a/packages/hydrooj/src/interface.ts b/packages/hydrooj/src/interface.ts index 8a07cfc88..5463a7913 100644 --- a/packages/hydrooj/src/interface.ts +++ b/packages/hydrooj/src/interface.ts @@ -207,7 +207,8 @@ declare module './model/problem' { /** @deprecated */ category?: string[], - config: string, + /** string (errormsg) */ + config: string | ProblemConfig, } } export type { ProblemDoc } from './model/problem'; diff --git a/packages/hydrooj/src/lib/testdataConfig.ts b/packages/hydrooj/src/lib/testdataConfig.ts index c6f02b7a3..7fd4abd1d 100644 --- a/packages/hydrooj/src/lib/testdataConfig.ts +++ b/packages/hydrooj/src/lib/testdataConfig.ts @@ -9,21 +9,23 @@ interface ParseResult { timeMax: number; timeMin: number; langs?: string[]; + type: string; } export async function parseConfig(config: string | ProblemConfig = {}) { + let cfg: ProblemConfig = {}; + if (typeof config === 'string') { + // TODO should validate here? + cfg = await readYamlCases(load(config) as Record); + } else if (typeof config === 'object') cfg = await readYamlCases(config); const result: ParseResult = { count: 0, memoryMin: Number.MAX_SAFE_INTEGER, memoryMax: 0, timeMin: Number.MAX_SAFE_INTEGER, timeMax: 0, + type: cfg.type || 'default', }; - let cfg: ProblemConfig = {}; - if (typeof config === 'string') { - // TODO should validate here? - cfg = await readYamlCases(load(config) as Record); - } else if (typeof config === 'object') cfg = await readYamlCases(config); if (cfg.subtasks.length) { for (const subtask of cfg.subtasks) { result.memoryMax = Math.max(result.memoryMax, subtask.memory); diff --git a/packages/hydrooj/src/model/problem.ts b/packages/hydrooj/src/model/problem.ts index d7fb9f7e2..563bc9fa3 100644 --- a/packages/hydrooj/src/model/problem.ts +++ b/packages/hydrooj/src/model/problem.ts @@ -12,6 +12,7 @@ import { } from '../typeutils'; import { ProblemNotFoundError, ValidationError } from '../error'; import * as bus from '../service/bus'; +import { parseConfig } from '../lib/testdataConfig'; export interface ProblemDoc extends Document { } export type Field = keyof ProblemDoc; @@ -79,9 +80,16 @@ export class ProblemModel { if (typeof pid !== 'number') { if (Number.isSafeInteger(parseInt(pid, 10))) pid = parseInt(pid, 10); } - return typeof pid === 'number' + const res = typeof pid === 'number' ? await document.get(domainId, document.TYPE_PROBLEM, pid, projection) : (await document.getMulti(domainId, document.TYPE_PROBLEM, { pid }).toArray())[0]; + if (!res) return null; + try { + res.config = await parseConfig(res.config); + } catch (e) { + res.config = `Cannot parse: ${e.message}`; + } + return res; } static getMulti(domainId: string, query: FilterQuery, projection = ProblemModel.PROJECTION_LIST) { @@ -173,12 +181,12 @@ export class ProblemModel { await bus.emit('problem/delAdditionalFile', domainId, pid, names); } - static async random(domainId: string, query: FilterQuery): Promise { + static async random(domainId: string, query: FilterQuery): Promise { const cursor = document.getMulti(domainId, document.TYPE_PROBLEM, query); const pcount = await cursor.count(); if (pcount) { const pdoc = await cursor.skip(Math.floor(Math.random() * pcount)).limit(1).toArray(); - return pdoc[0].pid; + return pdoc[0].pid || pdoc[0].docId; } return null; } @@ -194,6 +202,12 @@ export class ProblemModel { const pdocs = await document.getMulti(domainId, document.TYPE_PROBLEM, q) .project(buildProjection(projection)).toArray(); for (const pdoc of pdocs) { + try { + // eslint-disable-next-line no-await-in-loop + pdoc.config = await parseConfig(pdoc.config); + } catch (e) { + pdoc.config = `Cannot parse: ${e.message}`; + } r[pdoc.docId] = pdoc; l[pdoc.pid] = pdoc; } diff --git a/packages/ui-default/components/subjective-question/index.jsx b/packages/ui-default/components/subjective-question/index.jsx index 314f94376..2087a228b 100644 --- a/packages/ui-default/components/subjective-question/index.jsx +++ b/packages/ui-default/components/subjective-question/index.jsx @@ -2,7 +2,7 @@ import React from 'react'; import { sortBy } from 'lodash'; import request from 'vj/utils/request'; -export default class MessagePadContainer extends React.PureComponent { +export default class SubjectiveContainer extends React.PureComponent { constructor(args) { super(args); this.state = {}; diff --git a/packages/ui-default/pages/problem_detail.page.jsx b/packages/ui-default/pages/problem_detail.page.jsx index af2d55320..c400fe0d8 100644 --- a/packages/ui-default/pages/problem_detail.page.jsx +++ b/packages/ui-default/pages/problem_detail.page.jsx @@ -103,22 +103,6 @@ const page = new NamedPage(['problem_detail', 'contest_detail_problem', 'homewor let unmountReact = null; const extender = new ProblemPageExtender(); - const copyProblemDialog = new ActionDialog({ - $body: $('.dialog__body--send-to > div'), - onDispatch(action) { - const $target = copyProblemDialog.$dom.find('[name="target"]'); - if (action === 'ok' && $target.val() === '') { - $target.focus(); - return false; - } - return true; - }, - }); - copyProblemDialog.clear = function () { - this.$dom.find('[name="target"]').val(''); - return this; - }; - async function handleClickDownloadProblem() { await downloadProblemSet([UiContext.problemNumId]); } @@ -192,7 +176,8 @@ const page = new NamedPage(['problem_detail', 'contest_detail_problem', 'homewor async function loadSubjective() { try { - const props = yaml.load(base64.decode(document.getElementsByClassName('section__body typo')[0].innerText)); + if (UiContext.pdoc.config?.type !== 'subjective') return; + const props = yaml.load(document.getElementsByClassName('section__body typo')[0].innerText); if (!(props instanceof Array)) return; $('.outer-loader-container').show(); const { default: Subjective } = await import('vj/components/subjective-question/index');