core: contest_scoreboard: disable pagination

This commit is contained in:
undefined committed 2022-09-26 23:59:33 +08:00
1 parent 757b5e6bc1
commit 9461499d7c
6 files changed
+32 -35

No files matched your search

+4 -5
View File
@@ -193,10 +193,9 @@ export class ContestBroadcastHandler extends ContestDetailBaseHandler {
export class ContestScoreboardHandler extends ContestDetailBaseHandler {
@param('tid', Types.ObjectID)
@param('page', Types.PositiveInt, true)
@param('ext', Types.Range(['csv', 'html']), true)
@param('ignoreLock', Types.Boolean, true)
async get(domainId: string, tid: ObjectID, page = 1, ext = '', ignoreLock = false) {
async get(domainId: string, tid: ObjectID, ext = '', ignoreLock = false) {
if (ignoreLock && !this.user.own(this.tdoc)) {
this.checkPerm(this.tdoc.rule === 'homework'
? PERM.PERM_VIEW_HOMEWORK_HIDDEN_SCOREBOARD
@@ -210,14 +209,14 @@ export class ContestScoreboardHandler extends ContestDetailBaseHandler {
// Problem statistics display is allowed as we can view submission info in scoreboard.
...problem.PROJECTION_CONTEST_LIST, 'nSubmit', 'nAccept',
]);
const [, rows, udict, , nPages] = await contest.getScoreboard.call(this, domainId, tid, false, page, ignoreLock);
const [, rows, udict] = await contest.getScoreboard.call(this, domainId, tid, false, ignoreLock);
this.response.template = 'contest_scoreboard.html';
// eslint-disable-next-line @typescript-eslint/naming-convention
const page_name = this.tdoc.rule === 'homework'
? 'homework_scoreboard'
: 'contest_scoreboard';
this.response.body = {
tdoc: this.tdoc, rows, udict, nPages, page, pdict, page_name,
tdoc: this.tdoc, rows, udict, pdict, page_name,
};
}
@@ -227,7 +226,7 @@ export class ContestScoreboardHandler extends ContestDetailBaseHandler {
csv: async (rows) => `\uFEFF${rows.map((c) => (c.map((i) => i.value?.toString().replace(/\n/g, ' ')).join(','))).join('\n')}`,
html: (rows, tdoc) => this.renderHTML('contest_scoreboard_download_html.html', { rows, tdoc }),
};
const [, rows] = await contest.getScoreboard.call(this, domainId, tid, true, 0, ignoreLock);
const [, rows] = await contest.getScoreboard.call(this, domainId, tid, true, ignoreLock);
this.binary(await getContent[ext](rows, this.tdoc), `${this.tdoc.title}.${ext}`);
}
}
+3 -3
View File
@@ -514,9 +514,9 @@ export interface ContestRule<T = any> {
) => Promise<ScoreboardRow>;
scoreboard: (
this: ContestRule<T>, isExport: boolean, _: (s: string) => string,
tdoc: Tdoc<30>, pdict: ProblemDict, cursor: Cursor<ContestStat & T>, page: number,
) => Promise<[board: ScoreboardRow[], udict: Udict, nPages: number]>;
ranked: (tdoc: Tdoc<30>, cursor: Cursor<ContestStat & T>) => Promise<[Array<[number, ContestStat & T]>, number]>;
tdoc: Tdoc<30>, pdict: ProblemDict, cursor: Cursor<ContestStat & T>,
) => Promise<[board: ScoreboardRow[], udict: Udict]>;
ranked: (tdoc: Tdoc<30>, cursor: Cursor<ContestStat & T>) => Promise<[number, ContestStat & T][]>;
}
export type ContestRules = Dictionary<ContestRule>;
+6 -7
View File
@@ -1,21 +1,20 @@
import { Cursor } from 'mongodb';
import paginate from './paginate';
type ranked = <T>(cursor: Cursor<T>, equ: ((a: T, b: T) => boolean), page?: number) => Promise<[[number, T][], number]>;
type ranked = <T>(cursor: Cursor<T>, equ: ((a: T, b: T) => boolean)) => Promise<[number, T][]>;
const ranked: ranked = async (cursor, equ, page) => {
const ranked: ranked = async (cursor, equ) => {
let last = null;
let r = page ? (page - 1) * 100 : 0;
let count = page ? r : 0;
let r = 0;
let count = 0;
const results = [];
const [docs, nPages] = page ? await paginate(cursor, page, 100) : [await cursor.toArray(), 1];
const docs = await cursor.toArray();
for (const doc of docs) {
count++;
if (!last || !equ(last, doc)) r = count;
last = doc;
results.push([r, doc]);
}
return [results, nPages];
return results;
};
global.Hydro.lib.rank = ranked;
+14 -14
View File
@@ -154,8 +154,8 @@ const acm = buildContestRule({
}
return row;
},
async scoreboard(isExport, _, tdoc, pdict, cursor, page) {
const [rankedTsdocs, nPages] = await ranked(cursor, (a, b) => a.score === b.score && a.time === b.time, page);
async scoreboard(isExport, _, tdoc, pdict, cursor) {
const rankedTsdocs = await ranked(cursor, (a, b) => a.score === b.score && a.time === b.time);
const uids = rankedTsdocs.map(([, tsdoc]) => tsdoc.uid);
const udict = await user.getList(tdoc.domainId, uids);
// Find first accept
@@ -186,7 +186,7 @@ const acm = buildContestRule({
),
)),
];
return [rows, udict, nPages];
return [rows, udict];
},
async ranked(tdoc, cursor) {
return await ranked(cursor, (a, b) => a.accept === b.accept && a.time === b.time);
@@ -272,8 +272,8 @@ const oi = buildContestRule({
}
return row;
},
async scoreboard(isExport, _, tdoc, pdict, cursor, page) {
const [rankedTsdocs, nPages] = await ranked(cursor, (a, b) => a.score === b.score, page);
async scoreboard(isExport, _, tdoc, pdict, cursor) {
const rankedTsdocs = await ranked(cursor, (a, b) => a.score === b.score);
const uids = rankedTsdocs.map(([, tsdoc]) => tsdoc.uid);
const udict = await user.getList(tdoc.domainId, uids);
const psdict = {};
@@ -307,7 +307,7 @@ const oi = buildContestRule({
),
)),
];
return [rows, udict, nPages];
return [rows, udict];
},
async ranked(tdoc, cursor) {
return await ranked(cursor, (a, b) => a.score === b.score);
@@ -453,8 +453,8 @@ const homework = buildContestRule({
}
return row;
},
async scoreboard(isExport, _, tdoc, pdict, cursor, page) {
const [rankedTsdocs, nPages] = await ranked(cursor, (a, b) => a.score === b.score, page);
async scoreboard(isExport, _, tdoc, pdict, cursor) {
const rankedTsdocs = await ranked(cursor, (a, b) => a.score === b.score);
const uids = rankedTsdocs.map(([, tsdoc]) => tsdoc.uid);
const udict = await user.getList(tdoc.domainId, uids);
const columns = await this.scoreboardHeader(isExport, _, tdoc, pdict);
@@ -464,7 +464,7 @@ const homework = buildContestRule({
([rank, tsdoc]) => this.scoreboardRow(isExport, _, tdoc, pdict, udict[tsdoc.uid], rank, tsdoc),
)),
];
return [rows, udict, nPages];
return [rows, udict];
},
async ranked(tdoc, cursor) {
return await ranked(cursor, (a, b) => a.score === b.score);
@@ -679,18 +679,18 @@ export function canShowScoreboard(tdoc: Tdoc<30>, allowPermOverride = true) {
export async function getScoreboard(
this: Handler, domainId: string, tid: ObjectID,
isExport = false, page: number, ignoreLock = false,
): Promise<[Tdoc<30 | 60>, ScoreboardRow[], Udict, ProblemDict, number]> {
isExport = false, ignoreLock = false,
): Promise<[Tdoc<30 | 60>, ScoreboardRow[], Udict, ProblemDict]> {
const tdoc = await get(domainId, tid);
if (!canShowScoreboard.call(this, tdoc)) throw new ContestScoreboardHiddenError(tid);
if (ignoreLock) delete tdoc.lockAt;
const tsdocsCursor = getMultiStatus(domainId, { docId: tid }).sort(RULES[tdoc.rule].statusSort);
const pdict = await problem.getList(domainId, tdoc.pids, true);
const [rows, udict, nPages] = await RULES[tdoc.rule].scoreboard(
const [rows, udict] = await RULES[tdoc.rule].scoreboard(
isExport, this.translate.bind(this),
tdoc, pdict, tsdocsCursor, page,
tdoc, pdict, tsdocsCursor,
);
return [tdoc, rows, udict, pdict, nPages];
return [tdoc, rows, udict, pdict];
}
export const statusText = (tdoc: Tdoc, tsdoc?: any) => (
+5 -5
View File
@@ -1,4 +1,4 @@
import { escapeRegExp, pick } from 'lodash';
import { escapeRegExp, pick, uniq } from 'lodash';
import LRU from 'lru-cache';
import { Collection, ObjectID } from 'mongodb';
import { LoginError, UserAlreadyExistError, UserNotFoundError } from '../error';
@@ -21,7 +21,7 @@ export const coll: Collection<Udoc> = db.collection('user');
// Virtual user, only for display in contest.
export const collV: Collection<VUdoc> = db.collection('vuser');
export const collGroup: Collection<GDoc> = db.collection('user.group');
const cache = new LRU<string, User>({ max: 500, ttl: 300 * 1000 });
const cache = new LRU<string, User>({ max: 10000, ttl: 300 * 1000 });
export function deleteUserCache(udoc: User | Udoc | string | undefined | null, receiver = false) {
if (!udoc) return;
@@ -192,10 +192,10 @@ class UserModel {
}
static async getList(domainId: string, uids: number[]): Promise<Udict> {
const _uids = new Set(uids);
const r: Udict = {};
// eslint-disable-next-line no-await-in-loop
for (const uid of _uids) r[uid] = (await UserModel.getById(domainId, uid)) || new User(UserModel.defaultUser, {});
await Promise.all(uniq(uids).map(async (uid) => {
r[uid] = (await UserModel.getById(domainId, uid)) || new User(UserModel.defaultUser, {});
}));
return r;
}
@@ -74,7 +74,6 @@
{% endif %}{%- endfor -%}
</tbody>
</table>
{{ paginator.render(page, nPages) }}
</div>
</div>
</div></div>