[web] Recreate repos and start contest
This commit is contained in:
parent
87dd37c6a6
commit
85b1a48dd8
950
web/package-lock.json
generated
950
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -25,6 +25,7 @@
|
|||||||
"eslint-plugin-svelte3": "^4.0.0",
|
"eslint-plugin-svelte3": "^4.0.0",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8",
|
||||||
"prettier-plugin-svelte": "^2.10.0",
|
"prettier-plugin-svelte": "^2.10.0",
|
||||||
|
"prisma-erd-generator": "^1.7.0",
|
||||||
"svelte": "^3.58.0",
|
"svelte": "^3.58.0",
|
||||||
"svelte-check": "^3.2.0",
|
"svelte-check": "^3.2.0",
|
||||||
"tslib": "^2.5.0",
|
"tslib": "^2.5.0",
|
||||||
@ -35,10 +36,12 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/client": "^4.13.0",
|
"@prisma/client": "^4.13.0",
|
||||||
"@sveltejs/adapter-node": "^1.2.4",
|
"@sveltejs/adapter-node": "^1.2.4",
|
||||||
|
"@types/fs-extra": "^11.0.1",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"bootstrap": "^5.2.3",
|
"bootstrap": "^5.2.3",
|
||||||
"diff": "^5.1.0",
|
"diff": "^5.1.0",
|
||||||
"diff2html": "^3.4.35",
|
"diff2html": "^3.4.35",
|
||||||
|
"fs-extra": "^11.1.1",
|
||||||
"highlight.js": "^11.8.0",
|
"highlight.js": "^11.8.0",
|
||||||
"memfs": "^3.5.1",
|
"memfs": "^3.5.1",
|
||||||
"node-git-server": "^1.0.0",
|
"node-git-server": "^1.0.0",
|
||||||
|
1
web/prisma/ERD.svg
Normal file
1
web/prisma/ERD.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 43 KiB |
@ -2,6 +2,10 @@ generator client {
|
|||||||
provider = "prisma-client-js"
|
provider = "prisma-client-js"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
generator erd {
|
||||||
|
provider = "prisma-erd-generator"
|
||||||
|
}
|
||||||
|
|
||||||
datasource db {
|
datasource db {
|
||||||
provider = "postgresql"
|
provider = "postgresql"
|
||||||
url = env("DATABASE_URL")
|
url = env("DATABASE_URL")
|
||||||
|
@ -16,7 +16,7 @@ export function startGitServer() {
|
|||||||
const repoDir = 'repo';
|
const repoDir = 'repo';
|
||||||
|
|
||||||
repos = new Git(join(repoDir), {
|
repos = new Git(join(repoDir), {
|
||||||
autoCreate: true,
|
autoCreate: true
|
||||||
});
|
});
|
||||||
|
|
||||||
repos.on('push', (push) => {
|
repos.on('push', (push) => {
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import { error, redirect, type Actions } from '@sveltejs/kit';
|
import { error, redirect, type Actions } from '@sveltejs/kit';
|
||||||
import type { PageServerLoad } from './$types';
|
import type { PageServerLoad } from './$types';
|
||||||
import { db } from '$lib/server/prisma';
|
import { db } from '$lib/server/prisma';
|
||||||
|
import fs from 'fs-extra';
|
||||||
|
import { join } from 'path';
|
||||||
|
import { createRepos } from '../util';
|
||||||
|
|
||||||
export const load = (async ({ params }) => {
|
export const load = (async ({ params }) => {
|
||||||
const contestId = parseInt(params.contestId);
|
const contestId = parseInt(params.contestId);
|
||||||
@ -9,7 +12,7 @@ export const load = (async ({ params }) => {
|
|||||||
}
|
}
|
||||||
const contest = await db.contest.findUnique({
|
const contest = await db.contest.findUnique({
|
||||||
where: { id: contestId },
|
where: { id: contestId },
|
||||||
include: { problems: true, teams: true }
|
include: { problems: true, teams: true, activeTeams: true }
|
||||||
});
|
});
|
||||||
if (!contest) {
|
if (!contest) {
|
||||||
throw redirect(302, '/admin/contests');
|
throw redirect(302, '/admin/contests');
|
||||||
@ -17,11 +20,12 @@ export const load = (async ({ params }) => {
|
|||||||
return {
|
return {
|
||||||
name: contest.name,
|
name: contest.name,
|
||||||
problems: contest.problems.map((problem) => {
|
problems: contest.problems.map((problem) => {
|
||||||
return { name: problem.friendlyName };
|
return { id: problem.id, name: problem.friendlyName };
|
||||||
}),
|
}),
|
||||||
teams: contest.teams.map((team) => {
|
teams: contest.teams.map((team) => {
|
||||||
return { name: team.name };
|
return { id: team.id, name: team.name };
|
||||||
})
|
}),
|
||||||
|
activeTeams: contest.activeTeams.length
|
||||||
};
|
};
|
||||||
}) satisfies PageServerLoad;
|
}) satisfies PageServerLoad;
|
||||||
|
|
||||||
@ -36,5 +40,68 @@ export const actions = {
|
|||||||
return { success: false };
|
return { success: false };
|
||||||
}
|
}
|
||||||
throw redirect(302, '/admin/contests');
|
throw redirect(302, '/admin/contests');
|
||||||
|
},
|
||||||
|
start: async ({ params }) => {
|
||||||
|
if (!params.contestId) {
|
||||||
|
return { success: false };
|
||||||
|
}
|
||||||
|
const contestId = parseInt(params.contestId);
|
||||||
|
if (isNaN(contestId)) {
|
||||||
|
return { success: false };
|
||||||
|
}
|
||||||
|
const contest = await db.contest.findUnique({
|
||||||
|
where: { id: contestId },
|
||||||
|
include: { activeTeams: true, teams: { include: { activeTeam: true } } }
|
||||||
|
});
|
||||||
|
if (
|
||||||
|
!contest ||
|
||||||
|
contest.teams.length === 0 ||
|
||||||
|
contest.activeTeams.length !== 0 ||
|
||||||
|
contest.teams.find((team) => {
|
||||||
|
return team.activeTeam;
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
return { success: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
contest.teams.forEach(async (team) => {
|
||||||
|
await db.activeTeam.create({ data: { teamId: team.id, contestId: contest.id } });
|
||||||
|
});
|
||||||
|
|
||||||
|
return { success: true };
|
||||||
|
},
|
||||||
|
stop: async ({ params }) => {
|
||||||
|
if (!params.contestId) {
|
||||||
|
return { success: false };
|
||||||
|
}
|
||||||
|
const contestId = parseInt(params.contestId);
|
||||||
|
if (isNaN(contestId)) {
|
||||||
|
return { success: false };
|
||||||
|
}
|
||||||
|
const contest = await db.contest.findUnique({
|
||||||
|
where: { id: contestId },
|
||||||
|
include: { activeTeams: true }
|
||||||
|
});
|
||||||
|
if (!contest || contest.activeTeams.length === 0) {
|
||||||
|
return { success: false };
|
||||||
|
}
|
||||||
|
contest.activeTeams.forEach(async (activeTeam) => {
|
||||||
|
await db.activeTeam.delete({ where: { id: activeTeam.id } });
|
||||||
|
});
|
||||||
|
return { success: true };
|
||||||
|
},
|
||||||
|
repo: async ({ params }) => {
|
||||||
|
if (!params.contestId) {
|
||||||
|
return { success: false };
|
||||||
|
}
|
||||||
|
const contestId = parseInt(params.contestId);
|
||||||
|
if (isNaN(contestId)) {
|
||||||
|
return { success: false };
|
||||||
|
}
|
||||||
|
if (fs.existsSync(join('repo', contestId.toString()))) {
|
||||||
|
fs.removeSync(join('repo', contestId.toString()));
|
||||||
|
}
|
||||||
|
await createRepos(contestId);
|
||||||
|
return { success: true };
|
||||||
}
|
}
|
||||||
} satisfies Actions;
|
} satisfies Actions;
|
||||||
|
@ -12,6 +12,10 @@
|
|||||||
|
|
||||||
<h1 style="text-align:center" class="mb-4">{data.name}</h1>
|
<h1 style="text-align:center" class="mb-4">{data.name}</h1>
|
||||||
|
|
||||||
|
{#if data.activeTeams !== 0}
|
||||||
|
<div class="alert alert-success">In Progress</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if form && !form.success}
|
{#if form && !form.success}
|
||||||
<div class="alert alert-danger">An error occured</div>
|
<div class="alert alert-danger">An error occured</div>
|
||||||
{/if}
|
{/if}
|
||||||
@ -20,11 +24,9 @@
|
|||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<a href="/admin/contests" class="btn btn-outline-primary">All Contests</a>
|
<a href="/admin/contests" class="btn btn-outline-primary">All Contests</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
<div class="col-6 text-end">
|
||||||
<div class="text-end">
|
|
||||||
<form
|
<form
|
||||||
method="POST"
|
method="POST"
|
||||||
action="?/delete"
|
|
||||||
use:enhance={({ cancel }) => {
|
use:enhance={({ cancel }) => {
|
||||||
if (!confirm('Are you sure?')) {
|
if (!confirm('Are you sure?')) {
|
||||||
cancel();
|
cancel();
|
||||||
@ -34,10 +36,15 @@
|
|||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<button type="submit" class="btn btn-danger">Delete</button>
|
{#if data.activeTeams === 0}
|
||||||
|
<button type="submit" formaction="?/delete" class="btn btn-danger">Delete</button>
|
||||||
|
<button type="submit" formaction="?/repo" class="btn btn-warning">Recreate Repos</button>
|
||||||
|
<button type="submit" formaction="?/start" class="btn btn-success">Start</button>
|
||||||
|
{:else}
|
||||||
|
<button type="submit" formaction="?/stop" class="btn btn-outline-danger">Stop</button>
|
||||||
|
{/if}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-3 row">
|
<div class="mt-3 row">
|
||||||
@ -45,7 +52,9 @@
|
|||||||
<h4>Teams</h4>
|
<h4>Teams</h4>
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
{#each data.teams as team}
|
{#each data.teams as team}
|
||||||
<div class="list-group-item">{team.name}</div>
|
<a href={`/admin/teams/${team.id}`} class="list-group-item list-group-item-action"
|
||||||
|
>{team.name}</a
|
||||||
|
>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -53,7 +62,9 @@
|
|||||||
<h4>Problems</h4>
|
<h4>Problems</h4>
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
{#each data.problems as problem}
|
{#each data.problems as problem}
|
||||||
<div class="list-group-item">{problem.name}</div>
|
<a href={`/admin/problems/${problem.id}`} class="list-group-item list-group-item-action"
|
||||||
|
>{problem.name}</a
|
||||||
|
>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,6 +3,7 @@ import path, { join } from 'path';
|
|||||||
import type { Actions, PageServerLoad } from './$types';
|
import type { Actions, PageServerLoad } from './$types';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { simpleGit } from 'simple-git';
|
import { simpleGit } from 'simple-git';
|
||||||
|
import { createRepos } from '../util';
|
||||||
|
|
||||||
export const load = (async () => {
|
export const load = (async () => {
|
||||||
const teams = await db.team.findMany();
|
const teams = await db.team.findMany();
|
||||||
@ -63,35 +64,8 @@ export const actions = {
|
|||||||
include: { teams: true, problems: true }
|
include: { teams: true, problems: true }
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create repos
|
await createRepos(createdContest.id);
|
||||||
|
|
||||||
if (fs.existsSync('temp')) {
|
|
||||||
fs.rmSync('temp', { recursive: true });
|
|
||||||
}
|
|
||||||
fs.mkdirSync('temp');
|
|
||||||
createdContest.teams.forEach(async (team) => {
|
|
||||||
fs.mkdirSync(join('temp', team.id.toString()));
|
|
||||||
const git = simpleGit({ baseDir: join('temp', team.id.toString()) });
|
|
||||||
await git.init();
|
|
||||||
await git.checkoutLocalBranch('master');
|
|
||||||
createdContest.problems.forEach((problem) => {
|
|
||||||
fs.mkdirSync(join('temp', team.id.toString(), problem.pascalName));
|
|
||||||
fs.writeFileSync(
|
|
||||||
join('temp', team.id.toString(), problem.pascalName, problem.pascalName + '.java'),
|
|
||||||
`public class ${problem.pascalName} {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
System.out.println("Hello ${problem.pascalName}!");
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
await git.add('.');
|
|
||||||
await git.commit('Initial', { '--author': 'Admin <>' });
|
|
||||||
await git.push(
|
|
||||||
'http://localhost:7006/' + createdContest.id.toString() + '/' + team.id.toString(),
|
|
||||||
'master'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
return { success: true };
|
return { success: true };
|
||||||
}
|
}
|
||||||
} satisfies Actions;
|
} satisfies Actions;
|
||||||
|
41
web/src/routes/admin/contests/util.ts
Normal file
41
web/src/routes/admin/contests/util.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { db } from '$lib/server/prisma';
|
||||||
|
import fs from 'fs-extra';
|
||||||
|
import { join } from 'path';
|
||||||
|
import simpleGit from 'simple-git';
|
||||||
|
|
||||||
|
export async function createRepos(contestId: number) {
|
||||||
|
if (fs.existsSync('temp')) {
|
||||||
|
fs.rmSync('temp', { recursive: true });
|
||||||
|
}
|
||||||
|
fs.mkdirSync('temp');
|
||||||
|
const contest = await db.contest.findUnique({
|
||||||
|
where: { id: contestId },
|
||||||
|
include: { teams: true, problems: true }
|
||||||
|
});
|
||||||
|
if (!contest) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
contest.teams.forEach(async (team) => {
|
||||||
|
fs.mkdirSync(join('temp', team.id.toString()));
|
||||||
|
const git = simpleGit({ baseDir: join('temp', team.id.toString()) });
|
||||||
|
await git.init();
|
||||||
|
await git.checkoutLocalBranch('master');
|
||||||
|
contest.problems.forEach((problem) => {
|
||||||
|
fs.mkdirSync(join('temp', team.id.toString(), problem.pascalName));
|
||||||
|
fs.writeFileSync(
|
||||||
|
join('temp', team.id.toString(), problem.pascalName, problem.pascalName + '.java'),
|
||||||
|
`public class ${problem.pascalName} {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
System.out.println("Hello ${problem.pascalName}!");
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
await git.add('.');
|
||||||
|
await git.commit('Initial', { '--author': 'Admin <>' });
|
||||||
|
await git.push(
|
||||||
|
'http://localhost:7006/' + contest.id.toString() + '/' + team.id.toString(),
|
||||||
|
'master'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
@ -38,7 +38,7 @@
|
|||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<a href="/admin/problems" class="btn btn-outline-primary">Back</a>
|
<a href="/admin/problems" class="btn btn-outline-primary">All Problems</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 text-end">
|
<div class="col-6 text-end">
|
||||||
<button on:click={deleteProblem} type="button" class="btn btn-danger">Delete</button>
|
<button on:click={deleteProblem} type="button" class="btn btn-danger">Delete</button>
|
||||||
|
Loading…
Reference in New Issue
Block a user