| 918 | } |
| 919 | |
| 920 | export async function apply(ctx: Context) { |
| 921 | ctx.Route('contest_create', '/contest/create', ContestEditHandler); |
| 922 | ctx.Route('contest_main', '/contest', ContestListHandler, PERM.PERM_VIEW_CONTEST); |
| 923 | ctx.Route('contest_detail', '/contest/:tid', ContestDetailHandler, PERM.PERM_VIEW_CONTEST); |
| 924 | ctx.Route('contest_problemlist', '/contest/:tid/problems', ContestProblemListHandler, PERM.PERM_VIEW_CONTEST); |
| 925 | ctx.Route('contest_edit', '/contest/:tid/edit', ContestEditHandler, PERM.PERM_VIEW_CONTEST); |
| 926 | ctx.Route('contest_print', '/contest/:tid/print', ContestPrintHandler, PERM.PERM_VIEW_CONTEST); |
| 927 | // Support for DOMJudge printfile |
| 928 | ctx.Route('contest_print_alt', '/contest/:tid/api/printing/team', ContestPrintHandler, PERM.PERM_VIEW_CONTEST); |
| 929 | ctx.Route('contest_manage', '/contest/:tid/management', ContestManagementHandler); |
| 930 | ctx.Route('contest_clarification', '/contest/:tid/clarification', ContestClarificationHandler); |
| 931 | ctx.Route('contest_code', '/contest/:tid/code', ContestCodeHandler, PERM.PERM_VIEW_CONTEST); |
| 932 | ctx.Route('contest_file_download', '/contest/:tid/file/:type/:filename', ContestFileDownloadHandler, PERM.PERM_VIEW_CONTEST); |
| 933 | ctx.Route('contest_user', '/contest/:tid/user', ContestUserHandler, PERM.PERM_VIEW_CONTEST); |
| 934 | ctx.Route('contest_balloon', '/contest/:tid/balloon', ContestBalloonHandler, PERM.PERM_VIEW_CONTEST); |
| 935 | ctx.worker.addHandler('contest', async (doc) => { |
| 936 | const tdoc = await contest.get(doc.domainId, doc.tid); |
| 937 | if (!tdoc) return; |
| 938 | const tasks = []; |
| 939 | for (const op of doc.operation) { |
| 940 | if (op === 'unhide') { |
| 941 | for (const pid of tdoc.pids) { |
| 942 | tasks.push(problem.edit(doc.domainId, pid, { hidden: false })); |
| 943 | } |
| 944 | } |
| 945 | } |
| 946 | await Promise.all(tasks); |
| 947 | }); |
| 948 | ctx.plugin(ScoreboardService); |
| 949 | await ctx.inject(['scoreboard'], ({ Route, scoreboard }) => { |
| 950 | Route('contest_scoreboard', '/contest/:tid/scoreboard', ContestScoreboardHandler, PERM.PERM_VIEW_CONTEST_SCOREBOARD); |
| 951 | Route('contest_scoreboard_view', '/contest/:tid/scoreboard/:view', ContestScoreboardHandler, PERM.PERM_VIEW_CONTEST_SCOREBOARD); |
| 952 | scoreboard.addView('default', 'Default', { tdoc: 'tdoc', groups: 'groups', realtime: Types.Boolean }, { |
| 953 | async display({ realtime, tdoc, groups }) { |
| 954 | if (realtime && !this.user.own(tdoc)) { |
| 955 | this.checkPerm(PERM.PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD); |
| 956 | } |
| 957 | const config: ScoreboardConfig = { isExport: false, showDisplayName: this.user.hasPerm(PERM.PERM_VIEW_USER_PRIVATE_INFO) }; |
| 958 | if (!realtime && this.tdoc.lockAt && !this.tdoc.unlocked) { |
| 959 | config.lockAt = this.tdoc.lockAt; |
| 960 | } |
| 961 | const [, rows, udict, pdict] = await contest.getScoreboard.call(this, tdoc.domainId, tdoc._id, config); |
| 962 | // eslint-disable-next-line ts/naming-convention |
| 963 | const page_name = tdoc.rule === 'homework' |
| 964 | ? 'homework_scoreboard' |
| 965 | : 'contest_scoreboard'; |
| 966 | const availableViews = scoreboard.getAvailableViews(tdoc.rule); |
| 967 | this.response.body = { |
| 968 | tdoc: this.tdoc, tsdoc: this.tsdocAsPublic(), rows, udict, pdict, page_name, groups, availableViews, |
| 969 | }; |
| 970 | this.response.pjax = 'partials/scoreboard.html'; |
| 971 | this.response.template = 'contest_scoreboard.html'; |
| 972 | }, |
| 973 | supportedRules: ['*'], |
| 974 | }); |
| 975 | scoreboard.addView('ghost', 'Ghost', { tdoc: 'tdoc' }, { |
| 976 | async display({ tdoc }) { |
| 977 | if (contest.isLocked(tdoc) && !this.user.own(tdoc)) { |