diff --git a/web/docker/dev-postgress/docker-compose.yml b/web/docker/dev-postgress/docker-compose.yml
index 9da0ad7..efec47c 100644
--- a/web/docker/dev-postgress/docker-compose.yml
+++ b/web/docker/dev-postgress/docker-compose.yml
@@ -1,18 +1,18 @@
version: '3'
services:
db:
- image: "postgres:latest"
+ image: 'postgres:latest'
container_name: 'bwcontest-postgres'
restart: unless-stopped
environment:
POSTGRES_DB: 'bwcontest'
POSTGRES_USER: 'bwcontest'
- POSTGRES_PASSWORD: 'password'
+ POSTGRES_PASSWORD: 'pass123'
TZ: America/New_York
ports:
- - '5432:5432'
+ - '5433:5432'
volumes:
- bwcontest-postgres-data:/var/lib/postgresql/data
volumes:
- bwcontest-postgres-data:
\ No newline at end of file
+ bwcontest-postgres-data:
diff --git a/web/src/routes/admin/contests/import/+page.server.ts b/web/src/routes/admin/contests/import/+page.server.ts
index 789256f..986ea14 100644
--- a/web/src/routes/admin/contests/import/+page.server.ts
+++ b/web/src/routes/admin/contests/import/+page.server.ts
@@ -123,7 +123,7 @@ export const actions = {
}
}
})
- )
+ )
: []
}
}
diff --git a/web/src/routes/admin/scoreboard/+page.server.ts b/web/src/routes/admin/scoreboard/+page.server.ts
index 006f36d..e87f854 100644
--- a/web/src/routes/admin/scoreboard/+page.server.ts
+++ b/web/src/routes/admin/scoreboard/+page.server.ts
@@ -64,7 +64,7 @@ export const load = (async () => {
return (
submission.problemId === problem.id && submission.state === 'Correct'
);
- })
+ })
? 'correct'
: 'incorrect'
: null,
diff --git a/web/src/routes/public/scoreboard/+layout.server.ts b/web/src/routes/public/scoreboard/+layout.server.ts
new file mode 100644
index 0000000..fe14bcc
--- /dev/null
+++ b/web/src/routes/public/scoreboard/+layout.server.ts
@@ -0,0 +1,7 @@
+import { db } from '$lib/server/prisma';
+import type { LayoutServerLoad } from './$types';
+
+export const load = (async () => {
+ const contests = await db.contest.findMany({ select: { id: true, name: true } });
+ return { contests };
+}) satisfies LayoutServerLoad;
diff --git a/web/src/routes/public/scoreboard/+layout.svelte b/web/src/routes/public/scoreboard/+layout.svelte
new file mode 100644
index 0000000..3d3260a
--- /dev/null
+++ b/web/src/routes/public/scoreboard/+layout.svelte
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/web/src/routes/public/scoreboard/+page.svelte b/web/src/routes/public/scoreboard/+page.svelte
new file mode 100644
index 0000000..2e5aa58
--- /dev/null
+++ b/web/src/routes/public/scoreboard/+page.svelte
@@ -0,0 +1,5 @@
+
diff --git a/web/src/routes/public/scoreboard/[contestId]/+page.server.ts b/web/src/routes/public/scoreboard/[contestId]/+page.server.ts
new file mode 100644
index 0000000..85a4542
--- /dev/null
+++ b/web/src/routes/public/scoreboard/[contestId]/+page.server.ts
@@ -0,0 +1,113 @@
+import { db } from '$lib/server/prisma';
+import { redirect } from '@sveltejs/kit';
+import type { PageServerLoad } from './$types';
+
+export const load = (async ({ params }) => {
+ const contestId = parseInt(params.contestId);
+ if (isNaN(contestId)) {
+ throw redirect(302, '/public/scoreboard');
+ }
+ const timestamp = new Date();
+ const contest = await db.contest.findUnique({
+ where: { id: contestId },
+ include: { problems: true, teams: { include: { submissions: true } } }
+ });
+ if (contest === null) {
+ throw redirect(302, '/public/scoreboard');
+ }
+ const data = {
+ timestamp: timestamp,
+ selected: {
+ name: contest.name,
+ problems: contest.problems.map((problem) => {
+ return { id: problem.id, friendlyName: problem.friendlyName };
+ }),
+ teams: contest.teams
+ .map((team) => {
+ return {
+ name: team.name,
+ solves: team.submissions.filter((submission) => {
+ return submission.contestId === contest.id && submission.state === 'Correct';
+ }).length,
+ time: (() => {
+ const correctSubmissions = team.submissions.filter((submission) => {
+ return submission.contestId === contest.id && submission.state === 'Correct';
+ });
+ const penaltyTime =
+ team.submissions.filter((submission) => {
+ return (
+ submission.contestId === contest.id &&
+ submission.state === 'Incorrect' &&
+ correctSubmissions.find((correct) => {
+ return correct.problemId === submission.problemId;
+ })
+ );
+ }).length * 10;
+ let time = penaltyTime;
+ correctSubmissions.forEach((correctSubmission) => {
+ const gradedAt = correctSubmission.gradedAt!.valueOf();
+ const min = (gradedAt - contest.startTime!.valueOf()) / 60000;
+ time += min;
+ });
+ return time;
+ })(),
+ problems: contest.problems.map((problem) => {
+ return {
+ id: problem.id,
+ attempts: team.submissions.filter((submission) => {
+ return (
+ submission.contestId === contest.id &&
+ submission.problemId === problem.id &&
+ (submission.state === 'Correct' || submission.state === 'Incorrect')
+ );
+ }).length,
+ graphic: team.submissions.find((submission) => {
+ return (
+ submission.contestId === contest.id &&
+ submission.problemId === problem.id &&
+ (submission.state === 'Correct' || submission.state === 'Incorrect')
+ );
+ })
+ ? team.submissions.find((submission) => {
+ return submission.problemId === problem.id && submission.state === 'Correct';
+ })
+ ? 'correct'
+ : 'incorrect'
+ : null,
+ min: (() => {
+ const correctSubmission = team.submissions.find((submission) => {
+ return (
+ submission.contestId === contest.id &&
+ submission.problemId === problem.id &&
+ submission.state === 'Correct'
+ );
+ });
+ if (correctSubmission) {
+ const gradedAt = correctSubmission.gradedAt!.valueOf();
+ return (gradedAt - contest.startTime!.valueOf()) / 60000;
+ }
+ return undefined;
+ })()
+ };
+ })
+ };
+ })
+ .sort((a, b) => {
+ if (a.solves > b.solves) {
+ return -1;
+ } else if (a.solves < b.solves) {
+ return 1;
+ } else {
+ if (a.time < b.time) {
+ return -1;
+ } else if (a.time > b.time) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ })
+ }
+ };
+ return data;
+}) satisfies PageServerLoad;
diff --git a/web/src/routes/public/scoreboard/[contestId]/+page.svelte b/web/src/routes/public/scoreboard/[contestId]/+page.svelte
new file mode 100644
index 0000000..3240f76
--- /dev/null
+++ b/web/src/routes/public/scoreboard/[contestId]/+page.svelte
@@ -0,0 +1,8 @@
+
diff --git a/web/src/routes/public/scoreboard/stores.ts b/web/src/routes/public/scoreboard/stores.ts
new file mode 100644
index 0000000..b5278b8
--- /dev/null
+++ b/web/src/routes/public/scoreboard/stores.ts
@@ -0,0 +1,3 @@
+import { writable } from 'svelte/store';
+
+export const contestId = writable(null);