From 56897bf62292a7fe997f8fa39d11c347891d7759 Mon Sep 17 00:00:00 2001 From: panda Date: Fri, 30 May 2025 09:57:23 +0000 Subject: [PATCH] move to document --- packages/hydrooj/src/handler/manage.ts | 26 +++++++++---- packages/hydrooj/src/interface.ts | 28 ++++++++------ packages/hydrooj/src/model/document.ts | 5 ++- packages/hydrooj/src/model/record.ts | 28 +++++++++----- packages/hydrooj/src/script/rejudge.ts | 51 -------------------------- 5 files changed, 57 insertions(+), 81 deletions(-) delete mode 100644 packages/hydrooj/src/script/rejudge.ts diff --git a/packages/hydrooj/src/handler/manage.ts b/packages/hydrooj/src/handler/manage.ts index ecc22cb8a..6f86f88e4 100644 --- a/packages/hydrooj/src/handler/manage.ts +++ b/packages/hydrooj/src/handler/manage.ts @@ -1,7 +1,7 @@ import { exec } from 'child_process'; import { inspect } from 'util'; import * as yaml from 'js-yaml'; -import { omit } from 'lodash'; +import { omit, pick } from 'lodash'; import moment from 'moment'; import { Filter, ObjectId } from 'mongodb'; import Schema from 'schemastery'; @@ -367,7 +367,7 @@ class SystemUserPrivHandler extends SystemHandler { class SystemRejudgeHandler extends SystemHandler { async get() { this.response.body = { - rrdocs: await record.getMultiRejudgeTask({}), + rrdocs: await record.getMultiRejudgeTask(undefined, {}), apply: true, status: NORMAL_STATUS.filter((i: STATUS) => ![STATUS.STATUS_COMPILE_ERROR, STATUS.STATUS_ACCEPTED].includes(i)).join(','), }; @@ -440,7 +440,7 @@ class SystemRejudgeHandler extends SystemHandler { highPriority, apply: _apply, recordLength: rdocs.length, - rrdocs: await record.getMultiRejudgeTask({}), + rrdocs: await record.getMultiRejudgeTask(undefined, {}), }; this.response.template = 'manage_rejudge.html'; return; @@ -448,10 +448,19 @@ class SystemRejudgeHandler extends SystemHandler { const rid = await record.addRejudgeTask(domainId, { owner: this.user._id, apply: _apply, - rids: rdocs.map((i) => i._id), }); - const priority = await record.submissionPriority(this.user._id, -10000 - rdocs.length * 5 - 50); - await record.reset(domainId, rdocs.map((rdoc) => rdoc._id), true); + const priority = await record.submissionPriority(this.user._id, (highPriority ? 0 : -10000) - rdocs.length * 5 - 50); + if (_apply) await record.reset(domainId, rdocs.map((rdoc) => rdoc._id), true); + else { + await record.collHistory.insertMany(rdocs.map((rdoc) => ({ + ...pick(rdoc, [ + 'compilerTexts', 'judgeTexts', 'testCases', 'subtasks', + 'score', 'time', 'memory', 'status', 'judgeAt', 'judger', + ]), + rid: rdoc._id, + _id: new ObjectId(), + }))); + } await Promise.all([ record.judge(domainId, rdocs.filter((i) => i.contest).map((i) => i._id), priority, { detail: false }, { rejudge: _apply ? true : 'controlled' }), @@ -465,9 +474,10 @@ class SystemRejudgeHandler extends SystemHandler { class SystemRejudgeDetailHandler extends SystemHandler { @param('rid', Types.ObjectId) async get(domainId: string, rid: ObjectId) { - const rrdoc = await record.getRejudgeTask(rid); + const rrdoc = await record.getRejudgeTask(domainId, rid); + const rdocs = await record.getMulti(domainId, { _id: { $in: rrdoc.rids } }).toArray(); if (!rrdoc) throw new RecordNotFoundError(domainId, rid); - this.response.body = { rrdoc }; + this.response.body = { rrdoc, rdocs }; this.response.template = 'manage_rejudge_detail.html'; } } diff --git a/packages/hydrooj/src/interface.ts b/packages/hydrooj/src/interface.ts index 4dcc66470..6dea12597 100644 --- a/packages/hydrooj/src/interface.ts +++ b/packages/hydrooj/src/interface.ts @@ -228,18 +228,24 @@ export interface RecordStatDoc { lang: string; } -export interface RecordRejudgeDoc { - _id: ObjectId; - domainId: string; - owner: number; +export interface RecordRejudgeDoc extends Document { + content: string; + docId: ObjectId; + docType: document['TYPE_REJUDGE']; apply: boolean; finishAt?: Date; - rids: ObjectId[]; - changes?: { - rid: ObjectId; - old: number; - new: number; - }[]; +} + +export interface RecordRejudgeResultDoc { + _id: ObjectId; + rrid: ObjectId; + rid: ObjectId; + oldRev: ObjectId; + newRev: ObjectId; + oldStatus: number; + newStatus: number; + oldScore: number; + newScore: number; } export interface ScoreboardNode { @@ -548,7 +554,7 @@ declare module './service/db' { 'record': RecordDoc; 'record.stat': RecordStatDoc; 'record.history': RecordHistoryDoc; - 'record.rejudge': RecordRejudgeDoc; + 'record.rejudge': RecordRejudgeResultDoc; 'document': any; 'document.status': StatusDocBase & { [K in keyof DocStatusType]: { docType: K } & DocStatusType[K]; diff --git a/packages/hydrooj/src/model/document.ts b/packages/hydrooj/src/model/document.ts index d076b0a26..44fcaa55b 100644 --- a/packages/hydrooj/src/model/document.ts +++ b/packages/hydrooj/src/model/document.ts @@ -7,7 +7,7 @@ import { Context } from '../context'; import { Content, ContestClarificationDoc, DiscussionDoc, DiscussionReplyDoc, ProblemDoc, ProblemStatusDoc, - Tdoc, TrainingDoc, + RecordRejudgeDoc, Tdoc, TrainingDoc, } from '../interface'; import bus from '../service/bus'; import db from '../service/db'; @@ -29,6 +29,7 @@ export const TYPE_DISCUSSION_REPLY = 22 as const; export const TYPE_CONTEST = 30 as const; export const TYPE_CONTEST_CLARIFICATION = 31 as const; export const TYPE_TRAINING = 40 as const; +export const TYPE_REJUDGE = 50 as const; export interface DocType { [TYPE_PROBLEM]: ProblemDoc; @@ -40,6 +41,7 @@ export interface DocType { [TYPE_CONTEST]: Tdoc; [TYPE_CONTEST_CLARIFICATION]: ContestClarificationDoc; [TYPE_TRAINING]: TrainingDoc; + [TYPE_REJUDGE]: RecordRejudgeDoc; } export interface DocStatusType { @@ -487,5 +489,6 @@ global.Hydro.model.document = { TYPE_PROBLEM, TYPE_PROBLEM_LIST, TYPE_PROBLEM_SOLUTION, + TYPE_REJUDGE, TYPE_TRAINING, }; diff --git a/packages/hydrooj/src/model/record.ts b/packages/hydrooj/src/model/record.ts index f68ea2b97..4572846de 100644 --- a/packages/hydrooj/src/model/record.ts +++ b/packages/hydrooj/src/model/record.ts @@ -13,6 +13,7 @@ import db from '../service/db'; import { MaybeArray, NumberKeys } from '../typeutils'; import { ArgMethod, buildProjection, Time } from '../utils'; import { STATUS } from './builtin'; +import * as document from './document'; import DomainModel from './domain'; import problem from './problem'; import task from './task'; @@ -282,24 +283,27 @@ export default class RecordModel { return r; } - static async getMultiRejudgeTask(query: Filter) { - return RecordModel.collRejudge.find(query).toArray(); + static async getMultiRejudgeTask(domainId: string | undefined, query: Filter) { + return document.getMulti(domainId, document.TYPE_REJUDGE, query).toArray(); } - static async getRejudgeTask(_id: ObjectId) { - return RecordModel.collRejudge.findOne({ _id }); + static async getRejudgeTask(domainId: string, _id: ObjectId) { + return document.get(domainId, document.TYPE_REJUDGE, _id); } - static async addRejudgeTask(domainId: string, doc: Pick) { - const res = await RecordModel.collRejudge.insertOne({ _id: new ObjectId(), domainId, ...doc }); - return res.insertedId; + static async addRejudgeTask(domainId: string, doc: Partial) { + return await document.add(domainId, '', doc.owner, document.TYPE_REJUDGE, null, null, null, doc); } - static async pushRejudgeResult(rrid: ObjectId, result: { rid: ObjectId, old: number, new: number }) { + static async pushRejudgeResult(rrid: ObjectId, newStatus: number, newScore: number, newRev) { await RecordModel.collRejudge.updateOne({ _id: rrid }, { - $push: { - changes: result, + $set: { + newStatus, + newScore, + newRev, }, + }, { + upsert: true, }); } } @@ -349,6 +353,10 @@ export async function apply(ctx: Context) { RecordModel.collHistory, { key: { rid: 1, _id: -1 }, name: 'basic' }, ), + db.ensureIndexes( + RecordModel.collRejudge, + { key: { domainId: 1, rrid: 1, rid: 1 }, name: 'basic' }, + ), ]); } global.Hydro.model.record = RecordModel; diff --git a/packages/hydrooj/src/script/rejudge.ts b/packages/hydrooj/src/script/rejudge.ts deleted file mode 100644 index 9b2927e1e..000000000 --- a/packages/hydrooj/src/script/rejudge.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Filter, ObjectId } from 'mongodb'; -import Schema from 'schemastery'; -import { Context } from '../context'; -import { RecordDoc } from '../interface'; -import { STATUS, STATUS_SHORT_TEXTS } from '../model/builtin'; -import record from '../model/record'; - -export const apply = (ctx: Context) => ctx.addScript( - 'rejudge', 'rejudge with filter', - Schema.object({ - rrid: Schema.string(), - domainId: Schema.string(), - uid: Schema.number(), - pid: Schema.number(), - contest: Schema.string(), - lang: Schema.string(), - status: Schema.number(), - apply: Schema.boolean(), - }), - async (arg, report) => { - const q: Filter = { 'files.hack': { $exists: false } }; - for (const key of ['domainId', 'uid', 'pid', 'contest', 'lang', 'status']) { - if (arg[key]) q[key] = arg[key]; - } - q.contest ||= { $nin: [record.RECORD_GENERATE, record.RECORD_PRETEST] }; - q.status ||= { $ne: STATUS.STATUS_CANCELED }; - const rdocs = await record.getMulti(arg.domainId, q).project({ _id: 1, contest: 1, status: 1 }).toArray(); - const rdict = new Map(rdocs.map((rdoc) => [rdoc._id, rdoc.status])); - report({ message: `Found ${rdocs.length} records` }); - ctx.on('record/change', async (rdoc: RecordDoc) => { - if (rdict.has(rdoc._id)) { - rdict.delete(rdoc._id); - report({ message: `Rejudged ${rdoc._id}, ${STATUS_SHORT_TEXTS[rdict.get(rdoc._id)]} -> ${STATUS_SHORT_TEXTS[rdoc.status]}` }); - await record.pushRejudgeResult(new ObjectId(arg.rrid), { rid: rdoc._id, old: rdict.get(rdoc._id), new: rdoc.status }); - } - }); - if (rdocs.length) { - const priority = await record.submissionPriority(1, -10000 - rdocs.length * 5 - 50); - if (arg.apply) { - await record.reset(arg.domainId, rdocs.map((rdoc) => rdoc._id), true); - } - await Promise.all([ - record.judge(arg.domainId, rdocs.filter((i) => i.contest).map((i) => i._id), - priority, { detail: false }, { rejudge: arg.apply ? true : 'controlled' }), - record.judge(arg.domainId, rdocs.filter((i) => !i.contest).map((i) => i._id), - priority, {}, { rejudge: arg.apply ? true : 'controlled' }), - ]); - } - return true; - }, -);