diff --git a/packages/hydrooj/src/handler/problem.ts b/packages/hydrooj/src/handler/problem.ts index da6d501cc..8f9f3dd2f 100644 --- a/packages/hydrooj/src/handler/problem.ts +++ b/packages/hydrooj/src/handler/problem.ts @@ -581,6 +581,15 @@ export class ProblemCreateHandler extends Handler { } } +export class ProblemPrefixListHandler extends Handler { + @param('prefix', Types.Name) + async get(domainId: string, prefix: string) { + this.response.body = { + pdocs: await problem.getPrefixList(domainId, prefix), + }; + } +} + export async function apply() { Route('problem_main', '/p', ProblemMainHandler, PERM.PERM_VIEW_PROBLEM); Route('problem_category', '/p/category/:category', ProblemCategoryHandler, PERM.PERM_VIEW_PROBLEM); @@ -596,6 +605,7 @@ export async function apply() { Route('problem_solution_raw', '/p/:pid/solution/:psid/raw', ProblemSolutionRawHandler, PERM.PERM_VIEW_PROBLEM); Route('problem_solution_reply_raw', '/p/:pid/solution/:psid/:psrid/raw', ProblemSolutionRawHandler, PERM.PERM_VIEW_PROBLEM); Route('problem_create', '/problem/create', ProblemCreateHandler, PERM.PERM_CREATE_PROBLEM); + Route('problem_prefix_list', '/problem/list', ProblemPrefixListHandler, PERM.PERM_VIEW_PROBLEM); Connection('problem_pretest_conn', '/conn/pretest', ProblemPretestConnectionHandler, PERM.PERM_SUBMIT_PROBLEM); } diff --git a/packages/hydrooj/src/model/problem.ts b/packages/hydrooj/src/model/problem.ts index 0645752c2..27e630c07 100644 --- a/packages/hydrooj/src/model/problem.ts +++ b/packages/hydrooj/src/model/problem.ts @@ -1,6 +1,6 @@ import type { Readable } from 'stream'; import { ObjectID, FilterQuery } from 'mongodb'; -import { Dictionary, pick } from 'lodash'; +import { Dictionary, escapeRegExp, pick } from 'lodash'; import { STATUS } from './builtin'; import * as document from './document'; import domain from './domain'; @@ -208,6 +208,13 @@ export class ProblemModel { return Object.assign(r, l); } + static async getPrefixList(domainId: string, prefix: string) { + prefix = prefix.toLowerCase(); + const $regex = new RegExp(`\\A${escapeRegExp(prefix)}`, 'gmi'); + const filter = { $or: [{ pid: { $regex } }, { title: { $regex } }] }; + return await document.getMulti(domainId, document.TYPE_PROBLEM, filter, ['domainId', 'docId', 'pid', 'title']).toArray(); + } + static async getListStatus(domainId: string, uid: number, pids: number[]) { const psdocs = await ProblemModel.getMultiStatus( domainId, { uid, docId: { $in: Array.from(new Set(pids)) } }, diff --git a/packages/hydrooj/src/model/user.ts b/packages/hydrooj/src/model/user.ts index 407a2cc72..75373d6a0 100644 --- a/packages/hydrooj/src/model/user.ts +++ b/packages/hydrooj/src/model/user.ts @@ -1,4 +1,5 @@ import { Collection } from 'mongodb'; +import { escapeRegExp } from 'lodash'; import * as system from './system'; import token from './token'; import * as setting from './setting'; @@ -224,7 +225,7 @@ class UserModel { @ArgMethod static async getPrefixList(domainId: string, prefix: string, limit: number = 50) { prefix = prefix.toLowerCase(); - const $regex = new RegExp(`\\A\\Q${prefix}\\E`, 'gmi'); + const $regex = new RegExp(`\\A${escapeRegExp(prefix)}`, 'gmi'); const uids = await coll.find({ unameLower: { $regex } }) .limit(limit).map((doc) => doc._id).toArray(); const users = []; diff --git a/packages/hydrooj/test/db.ts b/packages/hydrooj/test/db.ts index 9812e8c99..cb58498c7 100644 --- a/packages/hydrooj/test/db.ts +++ b/packages/hydrooj/test/db.ts @@ -11,7 +11,7 @@ export async function connect() { while (dbVer < expected) { const func = scripts[dbVer]; dbVer++; - if (func.toString().includes('_FRESH_INSTALL_IGNORE')) continue; + if (typeof func !== 'function' || func.toString().includes('_FRESH_INSTALL_IGNORE')) continue; // eslint-disable-next-line no-await-in-loop await func(); } diff --git a/packages/ui-default/components/autocomplete/ProblemSelectAutoComplete.js b/packages/ui-default/components/autocomplete/ProblemSelectAutoComplete.js new file mode 100644 index 000000000..1eb3c194a --- /dev/null +++ b/packages/ui-default/components/autocomplete/ProblemSelectAutoComplete.js @@ -0,0 +1,41 @@ +import _ from 'lodash'; +import tpl from 'vj/utils/tpl'; +import request from 'vj/utils/request'; +import DOMAttachedObject from 'vj/components/DOMAttachedObject'; +import AutoComplete from '.'; + +function getText(pdoc) { + return pdoc.docId; +} + +function getItems(val) { + return request.get('/problem/list', { q: val }); +} + +function renderItem(pdoc) { + return tpl` +