From aa1be3acb7a2b754a252c147c0252772524128d5 Mon Sep 17 00:00:00 2001 From: orosmatthew Date: Wed, 13 Mar 2024 18:35:30 -0400 Subject: [PATCH] Merge feature/scoreboard-freeze --- web/prisma/schema.prisma | 1 + .../contests/[contestId]/+page.server.ts | 26 ++++++++++ .../admin/contests/[contestId]/+page.svelte | 47 ++++++++++++++++++- .../scoreboard/[contestId]/+page.server.ts | 17 ++++++- 4 files changed, 89 insertions(+), 2 deletions(-) diff --git a/web/prisma/schema.prisma b/web/prisma/schema.prisma index 31ffa84..7462750 100644 --- a/web/prisma/schema.prisma +++ b/web/prisma/schema.prisma @@ -101,4 +101,5 @@ model Contest { activeTeams ActiveTeam[] submissions Submission[] startTime DateTime? + freezeTime DateTime? } diff --git a/web/src/routes/admin/contests/[contestId]/+page.server.ts b/web/src/routes/admin/contests/[contestId]/+page.server.ts index 4bfacde..d0baf2a 100644 --- a/web/src/routes/admin/contests/[contestId]/+page.server.ts +++ b/web/src/routes/admin/contests/[contestId]/+page.server.ts @@ -109,5 +109,31 @@ export const actions = { } await createRepos(contestId); return { success: true }; + }, + 'freeze-time': async ({ params, request }) => { + if (!params.contestId) { + return { success: false, message: 'No contest Id specified' }; + } + const contestId = parseInt(params.contestId); + if (isNaN(contestId)) { + return { success: false, message: 'Invalid contest Id' }; + } + const form = await request.formData(); + const formFreezeTime = form.get('freezeTime'); + if (formFreezeTime === null) { + return { success: false, message: 'Invalid input' }; + } + const freezeTime = new Date(formFreezeTime.toString()); + const contest = await db.contest.findUnique({ where: { id: contestId } }); + if (contest === null) { + return { success: false, message: 'Invalid contest' }; + } + try { + await db.contest.update({ where: { id: contestId }, data: { freezeTime } }); + } catch (e) { + console.error(`Database error: ${e}`); + return { success: false, message: `Database error: ${e}` }; + } + return { success: true }; } } satisfies Actions; diff --git a/web/src/routes/admin/contests/[contestId]/+page.svelte b/web/src/routes/admin/contests/[contestId]/+page.svelte index d94f3ed..9796f5f 100644 --- a/web/src/routes/admin/contests/[contestId]/+page.svelte +++ b/web/src/routes/admin/contests/[contestId]/+page.svelte @@ -3,11 +3,18 @@ import { page } from '$app/stores'; import ConfirmModal from '$lib/ConfirmModal.svelte'; import FormAlert from '$lib/FormAlert.svelte'; - import type { PageData } from './$types'; + import Modal from '$lib/Modal.svelte'; + import type { Actions, PageData } from './$types'; export let data: PageData; + export let form: Actions; + + $: if (form) { + freezeModal.hide(); + } let confirmModal: ConfirmModal; + let freezeModal: Modal; function enhanceConfirm(form: HTMLFormElement, text: string) { enhance(form, async ({ cancel }) => { @@ -19,6 +26,12 @@ }; }); } + + let freezeTimeInputLocal: string | undefined; + let freezeTimeInput: string | null = null; + $: if (freezeTimeInputLocal !== undefined) { + freezeTimeInput = new Date(freezeTimeInputLocal).toISOString(); + } @@ -27,6 +40,31 @@ + +
+ + +
+
+

Contest - {data.name}

@@ -40,6 +78,13 @@ All Contests
+ {#if data.activeTeams === 0}
{ throw redirect(302, '/public/scoreboard'); } const timestamp = new Date(); + const contestQuery = await db.contest.findUnique({ where: { id: contestId } }); + if (contestQuery === null) { + throw redirect(302, '/public/scoreboard'); + } + const contest = await db.contest.findUnique({ where: { id: contestId }, - include: { problems: true, teams: { include: { submissions: true } } } + include: { + problems: true, + teams: { + include: { + submissions: + contestQuery.freezeTime === null + ? true + : { where: { createdAt: { lt: contestQuery.freezeTime } } } + } + } + } }); if (contest === null) { throw redirect(302, '/public/scoreboard');