Skip to content

Commit 06640c9

Browse files
committed
core: contest: scoreboard-view: add advanced checker
1 parent aba8d9c commit 06640c9

2 files changed

Lines changed: 24 additions & 9 deletions

File tree

packages/hydrooj/src/handler/contest.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,7 @@ export interface ScoreboardView<T extends { [key: string]: keyof BuiltinInput |
825825
cacheTime?: number; // in seconds
826826
args: T;
827827
display: (this: ContestScoreboardHandler, args: ParseArgs<T>) => Promise<void>;
828+
checker?: (this: ContestScoreboardHandler) => boolean;
828829
}
829830

830831
export class ContestScoreboardHandler extends ContestDetailBaseHandler {
@@ -884,26 +885,29 @@ class ScoreboardService extends Service {
884885

885886
addView<T extends { [key: string]: keyof BuiltinInput | AnyFunction | Type<any> }>(
886887
id: string, name: string, args: T,
887-
{ display, supportedRules, cacheTime }: {
888+
{ display, supportedRules, cacheTime, checker }: {
888889
display: (this: ContestScoreboardHandler, args: ParseArgs<T>) => Promise<void>;
889890
supportedRules: string[];
890891
cacheTime?: number;
892+
checker?: (this: ContestScoreboardHandler) => boolean;
891893
},
892894
) {
893895
if (this.views[id]) throw new Error(`View ${id} already exists`);
894896
this.ctx.effect(() => {
895897
this.views[id] = {
896-
id, name, args, display, supportedRules, cacheTime,
898+
id, name, args, display, supportedRules, cacheTime, checker,
897899
};
898900
return () => {
899901
delete this.views[id];
900902
};
901903
});
902904
}
903905

904-
getAvailableViews(rule: string) {
905-
return Object.fromEntries(Object.values(this.views).filter((i) => i.supportedRules.includes(rule) || i.supportedRules.includes('*'))
906-
.map((i) => [i.id, i.name]));
906+
getAvailableViews(rule: string, handler: ContestScoreboardHandler) {
907+
return Object.fromEntries(Object.values(this.views).filter((i) => (
908+
(i.supportedRules.includes(rule) || i.supportedRules.includes('*'))
909+
&& (!i.checker || i.checker.call(handler))
910+
)).map((i) => [i.id, i.name]));
907911
}
908912

909913
getView(id: string) {
@@ -963,7 +967,7 @@ export async function apply(ctx: Context) {
963967
const page_name = tdoc.rule === 'homework'
964968
? 'homework_scoreboard'
965969
: 'contest_scoreboard';
966-
const availableViews = scoreboard.getAvailableViews(tdoc.rule);
970+
const availableViews = scoreboard.getAvailableViews(tdoc.rule, this);
967971
this.response.body = {
968972
tdoc: this.tdoc, tsdoc: this.tsdocAsPublic(), rows, udict, pdict, page_name, groups, availableViews,
969973
};

packages/onsite-toolkit/index.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ export function apply(ctx: Context, config: ReturnType<typeof Config>) {
144144
...lockDuration && {
145145
scoreboard_freeze_duration: moment().startOf('day').seconds(lockDuration).format('HH:mm:ss.SSS'),
146146
},
147+
scoreboard_type: tdoc.rule === 'acm' ? 'pass-fail' : 'score',
147148
penalty_time: 20,
148149
}),
149150
...Object.keys(STATUS_SHORT_TEXTS).map((i) => getFeed('judgement-types', {
@@ -265,7 +266,12 @@ export function apply(ctx: Context, config: ReturnType<typeof Config>) {
265266
if (!ContestModel.isDone(tdoc)) throw new ContestNotEndedError();
266267
this.binary(await generateCdpZip(tdoc), `contest-${tdoc._id}-cdp.zip`);
267268
},
268-
supportedRules: ['acm', 'oi'],
269+
checker() {
270+
return ContestModel.isDone(this.tdoc)
271+
&& !!this.tdoc.lockAt
272+
&& (this.user.own(this.tdoc) || this.user.hasPerm(PERM.PERM_EDIT_CONTEST));
273+
},
274+
supportedRules: ['acm', 'oi', 'ioi'],
269275
});
270276

271277
scoreboard.addView('resolver', 'Resolver', { tdoc: 'tdoc' }, {
@@ -279,10 +285,15 @@ export function apply(ctx: Context, config: ReturnType<typeof Config>) {
279285
const source = new URL(`/d/${tdoc.domainId}/contest/${tdoc._id}/resolver-cdp/${tokenId}`, SystemModel.get('server.url')).toString();
280286
const target = new URL('https://resolver.hydrooj.com');
281287
target.searchParams.set('source', source);
282-
target.searchParams.set('mode', tdoc.rule === 'oi' ? 'oi' : 'acm');
288+
target.searchParams.set('mode', tdoc.rule === 'acm' ? 'acm' : 'oi');
283289
this.response.redirect = target.toString();
284290
},
285-
supportedRules: ['acm', 'oi'],
291+
checker() {
292+
return ContestModel.isDone(this.tdoc)
293+
&& !!this.tdoc.lockAt
294+
&& (this.user.own(this.tdoc) || this.user.hasPerm(PERM.PERM_EDIT_CONTEST));
295+
},
296+
supportedRules: ['acm', 'oi', 'ioi'],
286297
});
287298
});
288299

0 commit comments

Comments
 (0)