mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 17:36:08 +08:00
core: update tdoc type
This commit is contained in:
7 files changed
+37
-35
No files matched your search
@@ -112,7 +112,7 @@ export class ContestListHandler extends Handler {
|
||||
}
|
||||
|
||||
export class ContestDetailBaseHandler extends Handler {
|
||||
tdoc?: Tdoc<30>;
|
||||
tdoc?: Tdoc;
|
||||
tsdoc?: any;
|
||||
|
||||
@param('tid', Types.ObjectId, true)
|
||||
@@ -172,7 +172,7 @@ export class ContestDetailBaseHandler extends Handler {
|
||||
}
|
||||
|
||||
export class ContestDetailHandler extends Handler {
|
||||
tdoc?: Tdoc<30>;
|
||||
tdoc?: Tdoc;
|
||||
tsdoc?: any;
|
||||
|
||||
@param('tid', Types.ObjectId)
|
||||
|
||||
@@ -25,7 +25,7 @@ import { ContestDetailBaseHandler } from './contest';
|
||||
import { postJudge } from './judge';
|
||||
|
||||
class RecordListHandler extends ContestDetailBaseHandler {
|
||||
tdoc?: Tdoc<30>;
|
||||
tdoc?: Tdoc;
|
||||
|
||||
@param('page', Types.PositiveInt, true)
|
||||
@param('pid', Types.ProblemId, true)
|
||||
@@ -122,7 +122,7 @@ class RecordListHandler extends ContestDetailBaseHandler {
|
||||
|
||||
class RecordDetailHandler extends ContestDetailBaseHandler {
|
||||
rdoc: RecordDoc;
|
||||
tdoc?: Tdoc<30>;
|
||||
tdoc?: Tdoc;
|
||||
|
||||
@param('rid', Types.ObjectId)
|
||||
async prepare(domainId: string, rid: ObjectId) {
|
||||
@@ -242,7 +242,7 @@ class RecordMainConnectionHandler extends ConnectionHandler {
|
||||
pid: number;
|
||||
status: number;
|
||||
pretest = false;
|
||||
tdoc: Tdoc<30>;
|
||||
tdoc: Tdoc;
|
||||
applyProjection = false;
|
||||
|
||||
@param('tid', Types.ObjectId, true)
|
||||
@@ -334,7 +334,7 @@ class RecordMainConnectionHandler extends ConnectionHandler {
|
||||
|
||||
class RecordDetailConnectionHandler extends ConnectionHandler {
|
||||
pdoc: ProblemDoc;
|
||||
tdoc?: Tdoc<30>;
|
||||
tdoc?: Tdoc;
|
||||
rid: string = '';
|
||||
disconnectTimeout: NodeJS.Timeout;
|
||||
throttleSend: any;
|
||||
|
||||
@@ -373,9 +373,9 @@ export interface TrainingNode {
|
||||
pids: number[],
|
||||
}
|
||||
|
||||
export interface Tdoc<docType = document['TYPE_CONTEST'] | document['TYPE_TRAINING']> extends Document {
|
||||
export interface Tdoc extends Document {
|
||||
docId: ObjectId;
|
||||
docType: docType & number;
|
||||
docType: document['TYPE_CONTEST'];
|
||||
beginAt: Date;
|
||||
endAt: Date;
|
||||
attend: number;
|
||||
@@ -410,7 +410,8 @@ export interface Tdoc<docType = document['TYPE_CONTEST'] | document['TYPE_TRAINI
|
||||
dag?: TrainingNode[];
|
||||
}
|
||||
|
||||
export interface TrainingDoc extends Tdoc {
|
||||
export interface TrainingDoc extends Omit<Tdoc, 'docType'> {
|
||||
docType: document['TYPE_TRAINING'],
|
||||
description: string;
|
||||
pin?: number;
|
||||
dag: TrainingNode[];
|
||||
@@ -536,24 +537,25 @@ export interface ContestRule<T = any> {
|
||||
check: (args: any) => any;
|
||||
statusSort: Record<string, 1 | -1>;
|
||||
submitAfterAccept: boolean;
|
||||
showScoreboard: (tdoc: Tdoc<30>, now: Date) => boolean;
|
||||
showSelfRecord: (tdoc: Tdoc<30>, now: Date) => boolean;
|
||||
showRecord: (tdoc: Tdoc<30>, now: Date) => boolean;
|
||||
stat: (this: ContestRule<T>, tdoc: Tdoc<30>, journal: any[]) => ContestStat & T;
|
||||
showScoreboard: (tdoc: Tdoc, now: Date) => boolean;
|
||||
showSelfRecord: (tdoc: Tdoc, now: Date) => boolean;
|
||||
showRecord: (tdoc: Tdoc, now: Date) => boolean;
|
||||
stat: (this: ContestRule<T>, tdoc: Tdoc, journal: any[]) => ContestStat & T;
|
||||
scoreboardHeader: (
|
||||
this: ContestRule<T>, config: ScoreboardConfig, _: (s: string) => string,
|
||||
tdoc: Tdoc<30>, pdict: ProblemDict,
|
||||
tdoc: Tdoc, pdict: ProblemDict,
|
||||
) => Promise<ScoreboardRow>;
|
||||
scoreboardRow: (
|
||||
this: ContestRule<T>, config: ScoreboardConfig, _: (s: string) => string,
|
||||
tdoc: Tdoc<30>, pdict: ProblemDict, udoc: BaseUser, rank: number, tsdoc: ContestStat & T,
|
||||
tdoc: Tdoc, pdict: ProblemDict, udoc: BaseUser, rank: number, tsdoc: ContestStat & T,
|
||||
meta?: any,
|
||||
) => Promise<ScoreboardRow>;
|
||||
scoreboard: (
|
||||
this: ContestRule<T>, config: ScoreboardConfig, _: (s: string) => string,
|
||||
tdoc: Tdoc<30>, pdict: ProblemDict, cursor: FindCursor<ContestStat & T>,
|
||||
tdoc: Tdoc, pdict: ProblemDict, cursor: FindCursor<ContestStat & T>,
|
||||
) => Promise<[board: ScoreboardRow[], udict: BaseUserDict]>;
|
||||
ranked: (tdoc: Tdoc<30>, cursor: FindCursor<ContestStat & T>) => Promise<[number, ContestStat & T][]>;
|
||||
ranked: (tdoc: Tdoc, cursor: FindCursor<ContestStat & T>) => Promise<[number, ContestStat & T][]>;
|
||||
applyProjection: (tdoc: Tdoc, rdoc: RecordDoc, user: User) => RecordDoc;
|
||||
}
|
||||
|
||||
export type ContestRules = Dictionary<ContestRule>;
|
||||
|
||||
@@ -13,6 +13,7 @@ import ranked from '../lib/rank';
|
||||
import * as bus from '../service/bus';
|
||||
import db from '../service/db';
|
||||
import type { Handler } from '../service/server';
|
||||
import { Optional } from '../typeutils';
|
||||
import { PERM, STATUS, STATUS_SHORT_TEXTS } from './builtin';
|
||||
import * as document from './document';
|
||||
import problem from './problem';
|
||||
@@ -69,11 +70,11 @@ export function isExtended(tdoc: Tdoc) {
|
||||
return tdoc.penaltySince.getTime() <= now && now < tdoc.endAt.getTime();
|
||||
}
|
||||
|
||||
function buildContestRule<T>(def: ContestRule<T>): ContestRule<T>;
|
||||
function buildContestRule<T>(def: Optional<ContestRule<T>, 'applyProjection'>): ContestRule<T>;
|
||||
function buildContestRule<T>(def: Partial<ContestRule<T>>, baseRule: ContestRule<T>): ContestRule<T>;
|
||||
function buildContestRule<T>(def: Partial<ContestRule<T>>, baseRule: ContestRule<T> = {} as any) {
|
||||
const base = baseRule._originalRule || {};
|
||||
const funcs = ['scoreboard', 'scoreboardRow', 'scoreboardHeader', 'stat'];
|
||||
const funcs = ['scoreboard', 'scoreboardRow', 'scoreboardHeader', 'stat', 'applyProjection'];
|
||||
const f = {};
|
||||
const rule = { ...baseRule, ...def };
|
||||
for (const key of funcs) {
|
||||
@@ -81,6 +82,7 @@ function buildContestRule<T>(def: Partial<ContestRule<T>>, baseRule: ContestRule
|
||||
rule[key] = f[key].bind(rule);
|
||||
}
|
||||
rule._originalRule = f;
|
||||
rule.applyProjection ||= (_, rdoc) => rdoc;
|
||||
return rule;
|
||||
}
|
||||
|
||||
@@ -715,9 +717,6 @@ const homework = buildContestRule({
|
||||
async ranked(tdoc, cursor) {
|
||||
return await ranked(cursor, (a, b) => a.score === b.score);
|
||||
},
|
||||
applyProjection(_, rdoc) {
|
||||
return rdoc;
|
||||
},
|
||||
});
|
||||
|
||||
export const RULES: ContestRules = {
|
||||
@@ -733,7 +732,7 @@ function _getStatusJournal(tsdoc) {
|
||||
export async function add(
|
||||
domainId: string, title: string, content: string, owner: number,
|
||||
rule: string, beginAt = new Date(), endAt = new Date(), pids: number[] = [],
|
||||
rated = false, data: Partial<Tdoc<30>> = {},
|
||||
rated = false, data: Partial<Tdoc> = {},
|
||||
) {
|
||||
if (!RULES[rule]) throw new ValidationError('rule');
|
||||
if (beginAt >= endAt) throw new ValidationError('beginAt', 'endAt');
|
||||
@@ -765,7 +764,7 @@ export async function del(domainId: string, tid: ObjectId) {
|
||||
]);
|
||||
}
|
||||
|
||||
export async function get(domainId: string, tid: ObjectId): Promise<Tdoc<30>> {
|
||||
export async function get(domainId: string, tid: ObjectId): Promise<Tdoc> {
|
||||
const tdoc = await document.get(domainId, document.TYPE_CONTEST, tid);
|
||||
if (!tdoc) throw new ContestNotFoundError(tid);
|
||||
return tdoc;
|
||||
@@ -807,7 +806,7 @@ export async function getStatus(domainId: string, tid: ObjectId, uid: number) {
|
||||
}
|
||||
|
||||
async function _updateStatus(
|
||||
tdoc: Tdoc<30>, uid: number, rid: ObjectId, pid: number, status: STATUS, score: number,
|
||||
tdoc: Tdoc, uid: number, rid: ObjectId, pid: number, status: STATUS, score: number,
|
||||
subtasks: Record<number, SubtaskResult>,
|
||||
) {
|
||||
const tsdoc = await document.revPushStatus(tdoc.domainId, document.TYPE_CONTEST, tdoc.docId, uid, 'journal', {
|
||||
@@ -902,25 +901,25 @@ export async function unlockScoreboard(domainId: string, tid: ObjectId) {
|
||||
await recalcStatus(domainId, tid);
|
||||
}
|
||||
|
||||
export function canViewHiddenScoreboard(this: { user: User }, tdoc: Tdoc<30>) {
|
||||
export function canViewHiddenScoreboard(this: { user: User }, tdoc: Tdoc) {
|
||||
if (this.user.own(tdoc)) return true;
|
||||
if (tdoc.rule === 'homework') return this.user.hasPerm(PERM.PERM_VIEW_HOMEWORK_HIDDEN_SCOREBOARD);
|
||||
return this.user.hasPerm(PERM.PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD);
|
||||
}
|
||||
|
||||
export function canShowRecord(this: { user: User }, tdoc: Tdoc<30>, allowPermOverride = true) {
|
||||
export function canShowRecord(this: { user: User }, tdoc: Tdoc, allowPermOverride = true) {
|
||||
if (RULES[tdoc.rule].showRecord(tdoc, new Date())) return true;
|
||||
if (allowPermOverride && canViewHiddenScoreboard.call(this, tdoc)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
export function canShowSelfRecord(this: { user: User }, tdoc: Tdoc<30>, allowPermOverride = true) {
|
||||
export function canShowSelfRecord(this: { user: User }, tdoc: Tdoc, allowPermOverride = true) {
|
||||
if (RULES[tdoc.rule].showSelfRecord(tdoc, new Date())) return true;
|
||||
if (allowPermOverride && canViewHiddenScoreboard.call(this, tdoc)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
export function canShowScoreboard(this: { user: User }, tdoc: Tdoc<30>, allowPermOverride = true) {
|
||||
export function canShowScoreboard(this: { user: User }, tdoc: Tdoc, allowPermOverride = true) {
|
||||
if (RULES[tdoc.rule].showScoreboard(tdoc, new Date())) return true;
|
||||
if (allowPermOverride && canViewHiddenScoreboard.call(this, tdoc)) return true;
|
||||
return false;
|
||||
@@ -928,7 +927,7 @@ export function canShowScoreboard(this: { user: User }, tdoc: Tdoc<30>, allowPer
|
||||
|
||||
export async function getScoreboard(
|
||||
this: Handler, domainId: string, tid: ObjectId, config: ScoreboardConfig,
|
||||
): Promise<[Tdoc<30>, ScoreboardRow[], BaseUserDict, ProblemDict]> {
|
||||
): Promise<[Tdoc, ScoreboardRow[], BaseUserDict, ProblemDict]> {
|
||||
const tdoc = await get(domainId, tid);
|
||||
if (!canShowScoreboard.call(this, tdoc)) throw new ContestScoreboardHiddenError(tid);
|
||||
const tsdocsCursor = getMultiStatus(domainId, { docId: tid }).sort(RULES[tdoc.rule].statusSort);
|
||||
@@ -972,7 +971,7 @@ export function getMultiClarification(domainId: string, tid: ObjectId, owner = 0
|
||||
).sort('_id', -1).toArray();
|
||||
}
|
||||
|
||||
export function applyProjection(tdoc: Tdoc<30>, rdoc: RecordDoc, udoc: User) {
|
||||
export function applyProjection(tdoc: Tdoc, rdoc: RecordDoc, udoc: User) {
|
||||
if (!RULES[tdoc.rule]) return rdoc;
|
||||
return RULES[tdoc.rule].applyProjection(tdoc, rdoc, udoc);
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ export const RpTypes: Record<string, RpDef> = {
|
||||
},
|
||||
contest: {
|
||||
async run(domainIds, udict, report) {
|
||||
const contests: Tdoc<30>[] = await contest.getMulti('', { domainId: { $in: domainIds }, rated: true })
|
||||
const contests: Tdoc[] = await contest.getMulti('', { domainId: { $in: domainIds }, rated: true })
|
||||
.limit(10).toArray() as any;
|
||||
if (contests.length) await report({ message: `Found ${contests.length} contests in ${domainIds[0]}` });
|
||||
for (const tdoc of contests.reverse()) {
|
||||
|
||||
@@ -91,9 +91,9 @@ export interface EventMap extends LifecycleEvents, HandlerEvents {
|
||||
'problem/renameAdditionalFile': (domainId: string, docId: number, name: string, newName: string) => VoidReturn
|
||||
'problem/delAdditionalFile': (domainId: string, docId: number, name: string[]) => VoidReturn
|
||||
|
||||
'contest/before-add': (payload: Partial<Tdoc<30>>) => VoidReturn
|
||||
'contest/add': (payload: Partial<Tdoc<30>>, id: ObjectId) => VoidReturn
|
||||
'contest/scoreboard': (tdoc: Tdoc<30>, rows: ScoreboardRow[], udict: BaseUserDict, pdict: ProblemDict) => VoidReturn
|
||||
'contest/before-add': (payload: Partial<Tdoc>) => VoidReturn
|
||||
'contest/add': (payload: Partial<Tdoc>, id: ObjectId) => VoidReturn
|
||||
'contest/scoreboard': (tdoc: Tdoc, rows: ScoreboardRow[], udict: BaseUserDict, pdict: ProblemDict) => VoidReturn
|
||||
'contest/balloon': (domainId: string, tid: ObjectId, bdoc: ContestBalloonDoc) => VoidReturn
|
||||
|
||||
'oplog/log': (type: string, handler: Handler, args: any, data: any) => VoidReturn;
|
||||
|
||||
@@ -14,3 +14,4 @@ export type Projection<O> = readonly (string & keyof O)[];
|
||||
export type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
|
||||
export type MaybeArray<T> = T | T[];
|
||||
export type UnionToIntersection<U> = (U extends any ? (arg: U) => void : never) extends ((arg: infer I) => void) ? I : never;
|
||||
export type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
||||
Reference in new issue
Block a user