diff --git a/web/prisma/schema.prisma b/web/prisma/schema.prisma
index 890502d..23c8013 100644
--- a/web/prisma/schema.prisma
+++ b/web/prisma/schema.prisma
@@ -48,10 +48,19 @@ model Problem {
realInput String
realOutput String
Submission Submission[]
+ contests Contest[] @relation("ProblemContestRelation")
}
model Team {
id Int @id @default(autoincrement())
name String @unique
Submission Submission[]
+ contests Contest[] @relation("TeamContestRelation")
+}
+
+model Contest {
+ id Int @id @default(autoincrement())
+ name String
+ teams Team[] @relation("TeamContestRelation")
+ problems Problem[] @relation("ProblemContestRelation")
}
diff --git a/web/src/routes/admin/+layout.svelte b/web/src/routes/admin/+layout.svelte
index a0bcf6f..d652b4b 100644
--- a/web/src/routes/admin/+layout.svelte
+++ b/web/src/routes/admin/+layout.svelte
@@ -6,6 +6,7 @@
Problems
Scoreboard
Teams
+ Contests
Logout
diff --git a/web/src/routes/admin/contests/+page.server.ts b/web/src/routes/admin/contests/+page.server.ts
new file mode 100644
index 0000000..9270b13
--- /dev/null
+++ b/web/src/routes/admin/contests/+page.server.ts
@@ -0,0 +1,11 @@
+import { db } from '$lib/server/prisma';
+import type { PageServerLoad } from './$types';
+
+export const load = (async () => {
+ const contests = await db.contest.findMany();
+ return {
+ contests: contests.map((contest) => {
+ return { id: contest.id, name: contest.name };
+ })
+ };
+}) satisfies PageServerLoad;
diff --git a/web/src/routes/admin/contests/+page.svelte b/web/src/routes/admin/contests/+page.svelte
new file mode 100644
index 0000000..cb51504
--- /dev/null
+++ b/web/src/routes/admin/contests/+page.svelte
@@ -0,0 +1,26 @@
+
+
+
+ Contests
+
+
+Contests
+
+
+
+
diff --git a/web/src/routes/admin/contests/[contestId]/+page.server.ts b/web/src/routes/admin/contests/[contestId]/+page.server.ts
new file mode 100644
index 0000000..3445ba7
--- /dev/null
+++ b/web/src/routes/admin/contests/[contestId]/+page.server.ts
@@ -0,0 +1,26 @@
+import { error, redirect } from '@sveltejs/kit';
+import type { PageServerLoad } from './$types';
+import { db } from '$lib/server/prisma';
+
+export const load = (async ({ params }) => {
+ const contestId = parseInt(params.contestId);
+ if (isNaN(contestId)) {
+ throw error(400, 'Invalid request');
+ }
+ const contest = await db.contest.findUnique({
+ where: { id: contestId },
+ include: { problems: true, teams: true }
+ });
+ if (!contest) {
+ throw redirect(302, '/admin/contests');
+ }
+ return {
+ name: contest.name,
+ problems: contest.problems.map((problem) => {
+ return { name: problem.friendlyName };
+ }),
+ teams: contest.teams.map((team) => {
+ return { name: team.name };
+ })
+ };
+}) satisfies PageServerLoad;
diff --git a/web/src/routes/admin/contests/[contestId]/+page.svelte b/web/src/routes/admin/contests/[contestId]/+page.svelte
new file mode 100644
index 0000000..e7bf3b0
--- /dev/null
+++ b/web/src/routes/admin/contests/[contestId]/+page.svelte
@@ -0,0 +1,36 @@
+
+
+
+ {data.name}
+
+
+{data.name}
+
+
+
+
+
+
Teams
+
+ {#each data.teams as team}
+
{team.name}
+ {/each}
+
+
+
+
Problems
+
+ {#each data.problems as problem}
+
{problem.name}
+ {/each}
+
+
+
diff --git a/web/src/routes/admin/contests/create/+page.server.ts b/web/src/routes/admin/contests/create/+page.server.ts
new file mode 100644
index 0000000..93be169
--- /dev/null
+++ b/web/src/routes/admin/contests/create/+page.server.ts
@@ -0,0 +1,47 @@
+import { db } from '$lib/server/prisma';
+import type { Actions, PageServerLoad } from './$types';
+
+export const load = (async () => {
+ const teams = await db.team.findMany();
+ const problems = await db.problem.findMany();
+ return {
+ teams: teams.map((row) => {
+ return { id: row.id, name: row.name };
+ }),
+ problems: problems.map((row) => {
+ return { id: row.id, name: row.friendlyName };
+ })
+ };
+}) satisfies PageServerLoad;
+
+export const actions = {
+ create: async ({ request }) => {
+ const data = await request.formData();
+ const name = data.get('name');
+ const problems = (await db.problem.findMany()).filter((problem) => {
+ return data.get('problem_' + problem.id) !== null;
+ });
+ const teams = (await db.team.findMany()).filter((team) => {
+ return data.get('team_' + team.id) !== null;
+ });
+ if (!name) {
+ return { success: false };
+ }
+ await db.contest.create({
+ data: {
+ name: name.toString(),
+ teams: {
+ connect: teams.map((team) => {
+ return { id: team.id };
+ })
+ },
+ problems: {
+ connect: problems.map((problem) => {
+ return { id: problem.id };
+ })
+ }
+ }
+ });
+ return { success: true };
+ }
+} satisfies Actions;
diff --git a/web/src/routes/admin/contests/create/+page.svelte b/web/src/routes/admin/contests/create/+page.svelte
new file mode 100644
index 0000000..3fb99a7
--- /dev/null
+++ b/web/src/routes/admin/contests/create/+page.svelte
@@ -0,0 +1,115 @@
+
+
+
+ Create Contest
+
+
+Create Contest
+
+Cancel
+
+{#if form && !form.success}
+ Invalid entry
+{/if}
+
+