thanks @Molmin
This commit is contained in:
undefined committed 2024-08-10 22:24:54 +08:00
1 parent 609466016c
commit a1d392a409
4 files changed
+27 -34

No files matched your search

+5 -2
View File
@@ -40,16 +40,19 @@ global.Hydro.lib.problemSearch = async (domainId, q, opts) => {
});
let hits = res.hits.hits.map((i) => i._id);
if (!opts.skip) {
const pdoc = await ProblemModel.get(domainId, +q || q, ProblemModel.PROJECTION_LIST);
let pdoc = await ProblemModel.get(domainId, +q || q, ProblemModel.PROJECTION_LIST);
if (pdoc) {
hits = hits.filter((i) => i !== `${pdoc.domainId}/${pdoc.docId}`);
hits.unshift(`${pdoc.domainId}/${pdoc.docId}`);
} else if (/^P\d+$/.test(q)) {
pdoc = await ProblemModel.get(domainId, +q.substring(1), ProblemModel.PROJECTION_LIST);
if (pdoc) hits.unshift(`${pdoc.domainId}/${pdoc.docId}`);
}
}
return {
countRelation: typeof res.hits.total === 'number' ? 'eq' : res.hits.total.relation,
total: typeof res.hits.total === 'number' ? res.hits.total : res.hits.total.value,
hits,
hits: Array.from(new Set(hits)),
};
};
+16 -30
View File
@@ -1,7 +1,7 @@
import AdmZip from 'adm-zip';
import { readFile, statSync } from 'fs-extra';
import {
escapeRegExp, flattenDeep, intersection, pick, uniqBy,
escapeRegExp, flattenDeep, intersection, pick,
} from 'lodash';
import { Filter, ObjectId } from 'mongodb';
import { nanoid } from 'nanoid';
@@ -34,7 +34,6 @@ import user from '../model/user';
import {
Handler, param, post, query, route, Types,
} from '../service/server';
import { buildProjection } from '../utils';
import { ContestDetailBaseHandler } from './contest';
export const parseCategory = (value: string) => value.replace(/,/g, ',').split(',').map((e) => e.trim());
@@ -53,16 +52,21 @@ function buildQuery(udoc: User) {
const defaultSearch = async (domainId: string, q: string, options?: ProblemSearchOptions) => {
const escaped = escapeRegExp(q.toLowerCase());
const projection: (keyof ProblemDoc)[] = ['domainId', 'docId', 'pid'];
const $regex = new RegExp(q.length >= 2 ? escaped : `\\A${escaped}`, 'gmi');
const filter = { $or: [{ pid: { $regex } }, { title: { $regex } }, { tag: q }] };
const pdocs = await problem.getMulti(domainId, filter, ['domainId', 'docId', 'pid'])
const pdocs = await problem.getMulti(domainId, filter, projection)
.skip(options.skip || 0).limit(options.limit || system.get('pagination.problem')).toArray();
if (!options.skip) {
const pdoc = await problem.get(domainId, +q || q, ['domainId', 'docId', 'pid', 'title']);
let pdoc = await problem.get(domainId, Number.isSafeInteger(+q) ? +q : q, projection);
if (pdoc) pdocs.unshift(pdoc);
else if (/^P\d+$/.test(q)) {
pdoc = await problem.get(domainId, +q.substring(1), projection);
if (pdoc) pdocs.unshift(pdoc);
}
}
return {
hits: pdocs.map((i) => `${i.domainId}/${i.docId}`),
hits: Array.from(new Set(pdocs.map((i) => `${i.domainId}/${i.docId}`))),
total: Math.max(pdocs.length, await problem.count(domainId, filter)),
countRelation: 'eq',
};
@@ -95,7 +99,8 @@ export class ProblemMainHandler extends Handler {
@param('q', Types.Content, true)
@param('limit', Types.PositiveInt, true)
@param('pjax', Types.Boolean)
async get(domainId: string, page = 1, q = '', limit: number, pjax = false) {
@param('quick', Types.Boolean)
async get(domainId: string, page = 1, q = '', limit: number, pjax = false, quick = false) {
this.response.template = 'problem_main.html';
if (!limit || limit > this.ctx.setting.get('pagination.problem') || page > 1) limit = this.ctx.setting.get('pagination.problem');
this.queryContext.query = buildQuery(this.user);
@@ -137,7 +142,11 @@ export class ProblemMainHandler extends Handler {
// eslint-disable-next-line prefer-const
let [pdocs, ppcount, pcount] = this.queryContext.fail
? [[], 0, 0]
: await problem.list(domainId, query, sort.length ? 1 : page, limit, undefined, this.user._id);
: await problem.list(
domainId, query, sort.length ? 1 : page, limit,
quick ? ['title', 'pid', 'domainId', 'docId'] : undefined,
this.user._id,
);
if (total) {
pcount = total;
ppcount = Math.ceil(total / limit);
@@ -995,28 +1004,6 @@ export class ProblemCreateHandler extends Handler {
}
}
export class ProblemPrefixListHandler extends Handler {
@param('prefix', Types.Name)
async get(domainId: string, prefix: string) {
const projection = ['domainId', 'docId', 'pid', 'title', 'hidden'] as const;
const [pdocs, pdoc, apdoc] = await Promise.all([
problem.getPrefixList(domainId, prefix),
problem.get(domainId, Number.isSafeInteger(+prefix) ? +prefix : prefix, projection),
/^P\d+$/.test(prefix) ? problem.get(domainId, +prefix.substring(1), projection) : Promise.resolve(null),
]);
if (apdoc) pdocs.unshift(apdoc);
if (pdoc) pdocs.unshift(pdoc);
if (pdocs.length < 20) {
const search = global.Hydro.lib.problemSearch || defaultSearch;
const result = await search(domainId, prefix, { limit: 20 - pdocs.length });
const docs = await problem.getMulti(domainId, { docId: { $in: result.hits.map((i) => +i.split('/')[1]) } })
.project<ProblemDoc>(buildProjection(projection)).toArray();
pdocs.push(...docs);
}
this.response.body = uniqBy(pdocs, 'docId');
}
}
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);
@@ -1033,7 +1020,6 @@ export async function apply(ctx: Context) {
ctx.Route('problem_solution_reply_raw', '/p/:pid/solution/:psid/:psrid/raw', ProblemSolutionRawHandler, PERM.PERM_VIEW_PROBLEM);
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!'],
+2 -1
View File
@@ -162,7 +162,8 @@ export class ProblemModel {
if (Number.isSafeInteger(+pid)) pid = +pid;
const res = typeof pid === 'number'
? await document.get(domainId, document.TYPE_PROBLEM, pid, projection)
: (await document.getMulti(domainId, document.TYPE_PROBLEM, { sort: sortable(pid), pid }).toArray())[0];
: (await document.getMulti(domainId, document.TYPE_PROBLEM, { sort: sortable(pid), pid })
.project(buildProjection(projection)).limit(1).toArray())[0];
if (!res) return null;
try {
if (!rawConfig) res.config = await parseConfig(res.config);
@@ -8,7 +8,10 @@ const ProblemSelectAutoComplete = forwardRef<AutoCompleteHandle<ProblemDoc>, Aut
<AutoComplete<ProblemDoc>
ref={ref as any}
cacheKey={`problem-${UiContext.domainId}`}
queryItems={(query) => request.get(`/d/${UiContext.domainId}/problem/list`, { prefix: query })}
queryItems={async (query) => {
const { pdocs } = await request.get(`/d/${UiContext.domainId}/p`, { q: query, quick: true });
return pdocs;
}}
fetchItems={(ids) => api(gql`
problems(ids: ${ids.map((i) => +i)}) {
docId