move to document

This commit is contained in:
panda committed 2025-05-30 09:57:23 +00:00
1 parent 4c120db8de
commit 56897bf622
5 files changed
+56 -80

No files matched your search

+18 -8
View File
@@ -1,7 +1,7 @@
import { exec } from 'child_process'; import { exec } from 'child_process';
import { inspect } from 'util'; import { inspect } from 'util';
import * as yaml from 'js-yaml'; import * as yaml from 'js-yaml';
import { omit } from 'lodash'; import { omit, pick } from 'lodash';
import moment from 'moment'; import moment from 'moment';
import { Filter, ObjectId } from 'mongodb'; import { Filter, ObjectId } from 'mongodb';
import Schema from 'schemastery'; import Schema from 'schemastery';
@@ -367,7 +367,7 @@ class SystemUserPrivHandler extends SystemHandler {
class SystemRejudgeHandler extends SystemHandler { class SystemRejudgeHandler extends SystemHandler {
async get() { async get() {
this.response.body = { this.response.body = {
rrdocs: await record.getMultiRejudgeTask({}), rrdocs: await record.getMultiRejudgeTask(undefined, {}),
apply: true, apply: true,
status: NORMAL_STATUS.filter((i: STATUS) => ![STATUS.STATUS_COMPILE_ERROR, STATUS.STATUS_ACCEPTED].includes(i)).join(','), 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, highPriority,
apply: _apply, apply: _apply,
recordLength: rdocs.length, recordLength: rdocs.length,
rrdocs: await record.getMultiRejudgeTask({}), rrdocs: await record.getMultiRejudgeTask(undefined, {}),
}; };
this.response.template = 'manage_rejudge.html'; this.response.template = 'manage_rejudge.html';
return; return;
@@ -448,10 +448,19 @@ class SystemRejudgeHandler extends SystemHandler {
const rid = await record.addRejudgeTask(domainId, { const rid = await record.addRejudgeTask(domainId, {
owner: this.user._id, owner: this.user._id,
apply: _apply, apply: _apply,
rids: rdocs.map((i) => i._id),
}); });
const priority = await record.submissionPriority(this.user._id, -10000 - rdocs.length * 5 - 50); const priority = await record.submissionPriority(this.user._id, (highPriority ? 0 : -10000) - rdocs.length * 5 - 50);
await record.reset(domainId, rdocs.map((rdoc) => rdoc._id), true); 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([ await Promise.all([
record.judge(domainId, rdocs.filter((i) => i.contest).map((i) => i._id), priority, { detail: false }, record.judge(domainId, rdocs.filter((i) => i.contest).map((i) => i._id), priority, { detail: false },
{ rejudge: _apply ? true : 'controlled' }), { rejudge: _apply ? true : 'controlled' }),
@@ -465,9 +474,10 @@ class SystemRejudgeHandler extends SystemHandler {
class SystemRejudgeDetailHandler extends SystemHandler { class SystemRejudgeDetailHandler extends SystemHandler {
@param('rid', Types.ObjectId) @param('rid', Types.ObjectId)
async get(domainId: string, rid: 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); if (!rrdoc) throw new RecordNotFoundError(domainId, rid);
this.response.body = { rrdoc }; this.response.body = { rrdoc, rdocs };
this.response.template = 'manage_rejudge_detail.html'; this.response.template = 'manage_rejudge_detail.html';
} }
} }
+16 -10
View File
@@ -228,18 +228,24 @@ export interface RecordStatDoc {
lang: string; lang: string;
} }
export interface RecordRejudgeDoc { export interface RecordRejudgeDoc extends Document {
_id: ObjectId; content: string;
domainId: string; docId: ObjectId;
owner: number; docType: document['TYPE_REJUDGE'];
apply: boolean; apply: boolean;
finishAt?: Date; finishAt?: Date;
rids: ObjectId[]; }
changes?: {
export interface RecordRejudgeResultDoc {
_id: ObjectId;
rrid: ObjectId;
rid: ObjectId; rid: ObjectId;
old: number; oldRev: ObjectId;
new: number; newRev: ObjectId;
}[]; oldStatus: number;
newStatus: number;
oldScore: number;
newScore: number;
} }
export interface ScoreboardNode { export interface ScoreboardNode {
@@ -548,7 +554,7 @@ declare module './service/db' {
'record': RecordDoc; 'record': RecordDoc;
'record.stat': RecordStatDoc; 'record.stat': RecordStatDoc;
'record.history': RecordHistoryDoc; 'record.history': RecordHistoryDoc;
'record.rejudge': RecordRejudgeDoc; 'record.rejudge': RecordRejudgeResultDoc;
'document': any; 'document': any;
'document.status': StatusDocBase & { 'document.status': StatusDocBase & {
[K in keyof DocStatusType]: { docType: K } & DocStatusType[K]; [K in keyof DocStatusType]: { docType: K } & DocStatusType[K];
+4 -1
View File
@@ -7,7 +7,7 @@ import { Context } from '../context';
import { import {
Content, ContestClarificationDoc, DiscussionDoc, Content, ContestClarificationDoc, DiscussionDoc,
DiscussionReplyDoc, ProblemDoc, ProblemStatusDoc, DiscussionReplyDoc, ProblemDoc, ProblemStatusDoc,
Tdoc, TrainingDoc, RecordRejudgeDoc, Tdoc, TrainingDoc,
} from '../interface'; } from '../interface';
import bus from '../service/bus'; import bus from '../service/bus';
import db from '../service/db'; 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 = 30 as const;
export const TYPE_CONTEST_CLARIFICATION = 31 as const; export const TYPE_CONTEST_CLARIFICATION = 31 as const;
export const TYPE_TRAINING = 40 as const; export const TYPE_TRAINING = 40 as const;
export const TYPE_REJUDGE = 50 as const;
export interface DocType { export interface DocType {
[TYPE_PROBLEM]: ProblemDoc; [TYPE_PROBLEM]: ProblemDoc;
@@ -40,6 +41,7 @@ export interface DocType {
[TYPE_CONTEST]: Tdoc; [TYPE_CONTEST]: Tdoc;
[TYPE_CONTEST_CLARIFICATION]: ContestClarificationDoc; [TYPE_CONTEST_CLARIFICATION]: ContestClarificationDoc;
[TYPE_TRAINING]: TrainingDoc; [TYPE_TRAINING]: TrainingDoc;
[TYPE_REJUDGE]: RecordRejudgeDoc;
} }
export interface DocStatusType { export interface DocStatusType {
@@ -487,5 +489,6 @@ global.Hydro.model.document = {
TYPE_PROBLEM, TYPE_PROBLEM,
TYPE_PROBLEM_LIST, TYPE_PROBLEM_LIST,
TYPE_PROBLEM_SOLUTION, TYPE_PROBLEM_SOLUTION,
TYPE_REJUDGE,
TYPE_TRAINING, TYPE_TRAINING,
}; };
+18 -10
View File
@@ -13,6 +13,7 @@ import db from '../service/db';
import { MaybeArray, NumberKeys } from '../typeutils'; import { MaybeArray, NumberKeys } from '../typeutils';
import { ArgMethod, buildProjection, Time } from '../utils'; import { ArgMethod, buildProjection, Time } from '../utils';
import { STATUS } from './builtin'; import { STATUS } from './builtin';
import * as document from './document';
import DomainModel from './domain'; import DomainModel from './domain';
import problem from './problem'; import problem from './problem';
import task from './task'; import task from './task';
@@ -282,24 +283,27 @@ export default class RecordModel {
return r; return r;
} }
static async getMultiRejudgeTask(query: Filter<RecordRejudgeDoc>) { static async getMultiRejudgeTask(domainId: string | undefined, query: Filter<RecordRejudgeDoc>) {
return RecordModel.collRejudge.find(query).toArray(); return document.getMulti(domainId, document.TYPE_REJUDGE, query).toArray();
} }
static async getRejudgeTask(_id: ObjectId) { static async getRejudgeTask(domainId: string, _id: ObjectId) {
return RecordModel.collRejudge.findOne({ _id }); return document.get(domainId, document.TYPE_REJUDGE, _id);
} }
static async addRejudgeTask(domainId: string, doc: Pick<RecordRejudgeDoc, 'owner' | 'apply' | 'rids' | 'changes'>) { static async addRejudgeTask(domainId: string, doc: Partial<RecordRejudgeDoc>) {
const res = await RecordModel.collRejudge.insertOne({ _id: new ObjectId(), domainId, ...doc }); return await document.add(domainId, '', doc.owner, document.TYPE_REJUDGE, null, null, null, doc);
return res.insertedId;
} }
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 }, { await RecordModel.collRejudge.updateOne({ _id: rrid }, {
$push: { $set: {
changes: result, newStatus,
newScore,
newRev,
}, },
}, {
upsert: true,
}); });
} }
} }
@@ -349,6 +353,10 @@ export async function apply(ctx: Context) {
RecordModel.collHistory, RecordModel.collHistory,
{ key: { rid: 1, _id: -1 }, name: 'basic' }, { 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; global.Hydro.model.record = RecordModel;
-51
View File
@@ -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<RecordDoc> = { '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;
},
);