Compare commits
No commits in common. "23c6711ad6aae2e61e188a55ba44cc23aeb04fb6" and "437bfe4c1fb794b0262da95a119713c07f9c738d" have entirely different histories.
23c6711ad6
...
437bfe4c1f
@ -1,3 +1,2 @@
|
|||||||
node_modules
|
node_modules
|
||||||
.vscode
|
.vscode
|
||||||
../../shared/**/*
|
|
Binary file not shown.
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 192 KiB |
@ -69,12 +69,10 @@ export const runCpp: IRunner<IRunnerParamsCpp> = async function (
|
|||||||
child.stdout.setEncoding('utf8');
|
child.stdout.setEncoding('utf8');
|
||||||
child.stdout.on('data', (data) => {
|
child.stdout.on('data', (data) => {
|
||||||
outputBuffer += data.toString();
|
outputBuffer += data.toString();
|
||||||
params.outputCallback?.(data.toString());
|
|
||||||
});
|
});
|
||||||
child.stderr.setEncoding('utf8');
|
child.stderr.setEncoding('utf8');
|
||||||
child.stderr.on('data', (data) => {
|
child.stderr.on('data', (data) => {
|
||||||
outputBuffer += data.toString();
|
outputBuffer += data.toString();
|
||||||
params.outputCallback?.(data.toString());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const runStartTime = performance.now();
|
const runStartTime = performance.now();
|
||||||
|
@ -22,7 +22,7 @@ services:
|
|||||||
- ORIGIN=${ORIGIN}
|
- ORIGIN=${ORIGIN}
|
||||||
- WEB_SANDBOX_SECRET=${WEB_SANDBOX_SECRET}
|
- WEB_SANDBOX_SECRET=${WEB_SANDBOX_SECRET}
|
||||||
volumes:
|
volumes:
|
||||||
- ./repo:/app/web/repo
|
- ./repo:/app/repo
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
24
web/package-lock.json
generated
24
web/package-lock.json
generated
@ -28,13 +28,13 @@
|
|||||||
"zod": "^3.22.4"
|
"zod": "^3.22.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/kit": "^2.5.4",
|
"@sveltejs/kit": "^2.5.3",
|
||||||
"@sveltejs/vite-plugin-svelte": "^3.0.2",
|
"@sveltejs/vite-plugin-svelte": "^3.0.2",
|
||||||
"@types/bcrypt": "^5.0.2",
|
"@types/bcrypt": "^5.0.2",
|
||||||
"@types/bootstrap": "^5.2.10",
|
"@types/bootstrap": "^5.2.10",
|
||||||
"@types/diff": "^5.0.9",
|
"@types/diff": "^5.0.9",
|
||||||
"@types/js-cookie": "^3.0.6",
|
"@types/js-cookie": "^3.0.6",
|
||||||
"@types/node": "^20.11.27",
|
"@types/node": "^20.11.26",
|
||||||
"@types/uuid": "^9.0.8",
|
"@types/uuid": "^9.0.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||||
"@typescript-eslint/parser": "^7.2.0",
|
"@typescript-eslint/parser": "^7.2.0",
|
||||||
@ -42,7 +42,7 @@
|
|||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"prettier-plugin-svelte": "^3.2.2",
|
"prettier-plugin-svelte": "^3.2.2",
|
||||||
"sass": "^1.72.0",
|
"sass": "^1.71.1",
|
||||||
"svelte": "^4.2.12",
|
"svelte": "^4.2.12",
|
||||||
"svelte-check": "^3.6.7",
|
"svelte-check": "^3.6.7",
|
||||||
"tslib": "^2.6.2",
|
"tslib": "^2.6.2",
|
||||||
@ -996,9 +996,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sveltejs/kit": {
|
"node_modules/@sveltejs/kit": {
|
||||||
"version": "2.5.4",
|
"version": "2.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.5.3.tgz",
|
||||||
"integrity": "sha512-eDxK2d4EGzk99QsZNoPXe7jlzA5EGqfcCpUwZ912bhnalsZ2ZsG5wGRthkydupVjYyqdmzEanVKFhLxU2vkPSQ==",
|
"integrity": "sha512-s6x7HBn/Fp+UNvyhJohjIA0FcJ+BWHGUDQ4PCg1D0EboUlvbimJQYchINu8G6sspLXYmlcsuNsp8bbcrRk85iw==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/cookie": "^0.6.0",
|
"@types/cookie": "^0.6.0",
|
||||||
@ -1127,9 +1127,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.11.27",
|
"version": "20.11.26",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.27.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.26.tgz",
|
||||||
"integrity": "sha512-qyUZfMnCg1KEz57r7pzFtSGt49f6RPkPBis3Vo4PbS7roQEDn22hiHzl/Lo1q4i4hDEgBJmBF/NTNg2XR0HbFg==",
|
"integrity": "sha512-YwOMmyhNnAWijOBQweOJnQPl068Oqd4K3OFbTc6AHJwzweUwwWG3GIFY74OKks2PJUDkQPeddOQES9mLn1CTEQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~5.26.4"
|
"undici-types": "~5.26.4"
|
||||||
}
|
}
|
||||||
@ -3632,9 +3632,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/sass": {
|
"node_modules/sass": {
|
||||||
"version": "1.72.0",
|
"version": "1.71.1",
|
||||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.72.0.tgz",
|
"resolved": "https://registry.npmjs.org/sass/-/sass-1.71.1.tgz",
|
||||||
"integrity": "sha512-Gpczt3WA56Ly0Mn8Sl21Vj94s1axi9hDIzDFn9Ph9x3C3p4nNyvsqJoQyVXKou6cBlfFWEgRW4rT8Tb4i3XnVA==",
|
"integrity": "sha512-wovtnV2PxzteLlfNzbgm1tFXPLoZILYAMJtvoXXkD7/+1uP41eKkIt1ypWq5/q2uT94qHjXehEYfmjKOvjL9sg==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chokidar": ">=3.0.0 <4.0.0",
|
"chokidar": ">=3.0.0 <4.0.0",
|
||||||
|
@ -12,13 +12,13 @@
|
|||||||
"format": "prettier --plugin prettier-plugin-svelte --write ."
|
"format": "prettier --plugin prettier-plugin-svelte --write ."
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/kit": "^2.5.4",
|
"@sveltejs/kit": "^2.5.3",
|
||||||
"@sveltejs/vite-plugin-svelte": "^3.0.2",
|
"@sveltejs/vite-plugin-svelte": "^3.0.2",
|
||||||
"@types/bcrypt": "^5.0.2",
|
"@types/bcrypt": "^5.0.2",
|
||||||
"@types/bootstrap": "^5.2.10",
|
"@types/bootstrap": "^5.2.10",
|
||||||
"@types/diff": "^5.0.9",
|
"@types/diff": "^5.0.9",
|
||||||
"@types/js-cookie": "^3.0.6",
|
"@types/js-cookie": "^3.0.6",
|
||||||
"@types/node": "^20.11.27",
|
"@types/node": "^20.11.26",
|
||||||
"@types/uuid": "^9.0.8",
|
"@types/uuid": "^9.0.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||||
"@typescript-eslint/parser": "^7.2.0",
|
"@typescript-eslint/parser": "^7.2.0",
|
||||||
@ -26,7 +26,7 @@
|
|||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"prettier-plugin-svelte": "^3.2.2",
|
"prettier-plugin-svelte": "^3.2.2",
|
||||||
"sass": "^1.72.0",
|
"sass": "^1.71.1",
|
||||||
"svelte": "^4.2.12",
|
"svelte": "^4.2.12",
|
||||||
"svelte-check": "^3.6.7",
|
"svelte-check": "^3.6.7",
|
||||||
"tslib": "^2.6.2",
|
"tslib": "^2.6.2",
|
||||||
|
@ -101,5 +101,4 @@ model Contest {
|
|||||||
activeTeams ActiveTeam[]
|
activeTeams ActiveTeam[]
|
||||||
submissions Submission[]
|
submissions Submission[]
|
||||||
startTime DateTime?
|
startTime DateTime?
|
||||||
freezeTime DateTime?
|
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,6 @@ import {
|
|||||||
templateCppCMakeLists,
|
templateCppCMakeLists,
|
||||||
templateCppGitIgnore,
|
templateCppGitIgnore,
|
||||||
templateCppProblem,
|
templateCppProblem,
|
||||||
templateCppVscodeLaunch,
|
|
||||||
templateCppVscodeTasks,
|
|
||||||
templateJavaProblem
|
templateJavaProblem
|
||||||
} from './templates';
|
} from './templates';
|
||||||
|
|
||||||
@ -50,14 +48,10 @@ async function addProblemsCSharp(opts: OptsAddProblems) {
|
|||||||
async function addProblemsCPP(opts: OptsAddProblems) {
|
async function addProblemsCPP(opts: OptsAddProblems) {
|
||||||
let cmakeLists = templateCppCMakeLists;
|
let cmakeLists = templateCppCMakeLists;
|
||||||
opts.contest.problems.forEach((problem) => {
|
opts.contest.problems.forEach((problem) => {
|
||||||
cmakeLists += `add_executable(${problem.pascalName} ${problem.pascalName}/${problem.pascalName}.cpp)\n`;
|
cmakeLists += `add_executable(${problem.pascalName} ${problem.pascalName}/${problem.pascalName}.cpp)`;
|
||||||
});
|
});
|
||||||
opts.fs.writeFileSync(join(opts.dir, 'CMakeLists.txt'), cmakeLists);
|
opts.fs.writeFileSync(join(opts.dir, 'CMakeLists.txt'), cmakeLists);
|
||||||
|
|
||||||
opts.fs.mkdirSync(join(opts.dir, '.vscode'));
|
|
||||||
opts.fs.writeFileSync(join(opts.dir, '.vscode', 'launch.json'), templateCppVscodeLaunch);
|
|
||||||
opts.fs.writeFileSync(join(opts.dir, '.vscode', 'tasks.json'), templateCppVscodeTasks);
|
|
||||||
|
|
||||||
opts.contest.problems.forEach((problem) => {
|
opts.contest.problems.forEach((problem) => {
|
||||||
opts.fs.mkdirSync(join(opts.dir, problem.pascalName));
|
opts.fs.mkdirSync(join(opts.dir, problem.pascalName));
|
||||||
const filledTemplate = templateCppProblem.replaceAll('%%pascalName%%', problem.pascalName);
|
const filledTemplate = templateCppProblem.replaceAll('%%pascalName%%', problem.pascalName);
|
||||||
@ -68,7 +62,7 @@ async function addProblemsCPP(opts: OptsAddProblems) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createRepos(contestId: number, teamIds: number[]) {
|
export async function createRepos(contestId: number) {
|
||||||
const vol = new memfs.Volume();
|
const vol = new memfs.Volume();
|
||||||
const fs = createFsFromVolume(vol);
|
const fs = createFsFromVolume(vol);
|
||||||
|
|
||||||
@ -81,37 +75,35 @@ export async function createRepos(contestId: number, teamIds: number[]) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
contest.teams
|
contest.teams.forEach(async (team) => {
|
||||||
.filter((t) => teamIds.includes(t.id))
|
fs.mkdirSync(team.id.toString(), { recursive: true });
|
||||||
.forEach(async (team) => {
|
await git.init({ fs: fs, bare: false, defaultBranch: 'master', dir: team.id.toString() });
|
||||||
fs.mkdirSync(team.id.toString(), { recursive: true });
|
if (team.language === 'Java') {
|
||||||
await git.init({ fs: fs, bare: false, defaultBranch: 'master', dir: team.id.toString() });
|
addProblemsJava({ fs, dir: team.id.toString(), contest });
|
||||||
if (team.language === 'Java') {
|
} else if (team.language === 'CSharp') {
|
||||||
addProblemsJava({ fs, dir: team.id.toString(), contest });
|
addProblemsCSharp({ fs, dir: team.id.toString(), contest });
|
||||||
} else if (team.language === 'CSharp') {
|
fs.writeFileSync(join(team.id.toString(), '.gitignore'), templateCSharpGitIgnore);
|
||||||
addProblemsCSharp({ fs, dir: team.id.toString(), contest });
|
} else if (team.language === 'CPP') {
|
||||||
fs.writeFileSync(join(team.id.toString(), '.gitignore'), templateCSharpGitIgnore);
|
addProblemsCPP({ fs, dir: team.id.toString(), contest });
|
||||||
} else if (team.language === 'CPP') {
|
fs.writeFileSync(join(team.id.toString(), '.gitignore'), templateCppGitIgnore);
|
||||||
addProblemsCPP({ fs, dir: team.id.toString(), contest });
|
} else {
|
||||||
fs.writeFileSync(join(team.id.toString(), '.gitignore'), templateCppGitIgnore);
|
console.error('Language not supported');
|
||||||
} else {
|
return;
|
||||||
console.error('Language not supported');
|
}
|
||||||
return;
|
await git.add({ fs: fs, dir: team.id.toString(), filepath: '.' });
|
||||||
}
|
await git.commit({
|
||||||
await git.add({ fs: fs, dir: team.id.toString(), filepath: '.' });
|
fs: fs,
|
||||||
await git.commit({
|
dir: team.id.toString(),
|
||||||
fs: fs,
|
message: 'Initial',
|
||||||
dir: team.id.toString(),
|
author: { name: 'Admin' }
|
||||||
message: 'Initial',
|
|
||||||
author: { name: 'Admin' }
|
|
||||||
});
|
|
||||||
await git.push({
|
|
||||||
fs: fs,
|
|
||||||
http,
|
|
||||||
dir: team.id.toString(),
|
|
||||||
url: `http://127.0.0.1:${
|
|
||||||
process.env.GIT_PORT ?? 7006
|
|
||||||
}/${contest.id.toString()}/${team.id.toString()}`
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
await git.push({
|
||||||
|
fs: fs,
|
||||||
|
http,
|
||||||
|
dir: team.id.toString(),
|
||||||
|
url: `http://127.0.0.1:${
|
||||||
|
process.env.GIT_PORT ?? 7006
|
||||||
|
}/${contest.id.toString()}/${team.id.toString()}`
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -41,67 +41,5 @@ int main()
|
|||||||
return 0;
|
return 0;
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
export const templateCppGitIgnore = `/**/build
|
export const templateCppGitIgnore = `/build
|
||||||
`;
|
|
||||||
|
|
||||||
export const templateCppVscodeLaunch = `{
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": "C/C++: g++ build and debug active file",
|
|
||||||
"type": "cppdbg",
|
|
||||||
"request": "launch",
|
|
||||||
"program": "\${fileDirname}/build/\${fileBasenameNoExtension}.out",
|
|
||||||
"args": [],
|
|
||||||
"stopAtEntry": false,
|
|
||||||
"cwd": "\${fileDirname}",
|
|
||||||
"environment": [],
|
|
||||||
"externalConsole": false,
|
|
||||||
"MIMode": "gdb",
|
|
||||||
"setupCommands": [
|
|
||||||
{
|
|
||||||
"description": "Enable pretty-printing for gdb",
|
|
||||||
"text": "-enable-pretty-printing",
|
|
||||||
"ignoreFailures": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Set Disassembly Flavor to Intel",
|
|
||||||
"text": "-gdb-set disassembly-flavor intel",
|
|
||||||
"ignoreFailures": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"preLaunchTask": "C/C++: g++ build active file",
|
|
||||||
"miDebuggerPath": "/usr/bin/gdb"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"version": "2.0.0"
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
export const templateCppVscodeTasks = `{
|
|
||||||
"tasks": [
|
|
||||||
{
|
|
||||||
"type": "cppbuild",
|
|
||||||
"label": "C/C++: g++ build active file",
|
|
||||||
"command": "/usr/bin/g++",
|
|
||||||
"args": [
|
|
||||||
"-fdiagnostics-color=always",
|
|
||||||
"-g",
|
|
||||||
"\${file}",
|
|
||||||
"-o",
|
|
||||||
"\${fileDirname}/build/\${fileBasenameNoExtension}.out"
|
|
||||||
],
|
|
||||||
"options": {
|
|
||||||
"cwd": "\${fileDirname}"
|
|
||||||
},
|
|
||||||
"problemMatcher": [
|
|
||||||
"$gcc"
|
|
||||||
],
|
|
||||||
"group": {
|
|
||||||
"kind": "build",
|
|
||||||
"isDefault": true
|
|
||||||
},
|
|
||||||
"detail": "Task generated by Debugger."
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"version": "2.0.0"
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
@ -3,42 +3,3 @@
|
|||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<h1 style="text-align:center" class="mb-4"><i class="bi bi-speedometer2"></i> Dashboard</h1>
|
<h1 style="text-align:center" class="mb-4"><i class="bi bi-speedometer2"></i> Dashboard</h1>
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<a
|
|
||||||
class="card stats-card bg-body-tertiary stats-card-link stats-card-action"
|
|
||||||
draggable="false"
|
|
||||||
href="/public/scoreboard"
|
|
||||||
>
|
|
||||||
<h4><i class="bi bi-link-45deg"></i> Public Scoreboard</h4>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6 mt-3 mt-md-0"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.stats-card {
|
|
||||||
text-align: left;
|
|
||||||
padding: 20px;
|
|
||||||
border-radius: 10px;
|
|
||||||
transform: scale(1);
|
|
||||||
transition: 0.1s;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
.stats-card-link {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
vertical-align: top;
|
|
||||||
transform: scale(1);
|
|
||||||
transition: 0.1s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stats-card-link:hover {
|
|
||||||
transform: scale(1.02);
|
|
||||||
}
|
|
||||||
|
|
||||||
.stats-card-action:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -96,7 +96,7 @@ export const actions = {
|
|||||||
});
|
});
|
||||||
return { success: true };
|
return { success: true };
|
||||||
},
|
},
|
||||||
repo: async ({ params, request }) => {
|
repo: async ({ params }) => {
|
||||||
if (!params.contestId) {
|
if (!params.contestId) {
|
||||||
return { success: false };
|
return { success: false };
|
||||||
}
|
}
|
||||||
@ -104,46 +104,10 @@ export const actions = {
|
|||||||
if (isNaN(contestId)) {
|
if (isNaN(contestId)) {
|
||||||
return { success: false };
|
return { success: false };
|
||||||
}
|
}
|
||||||
const form = await request.formData();
|
if (fs.existsSync(join('repo', contestId.toString()))) {
|
||||||
const formEntries = Array.from(form.entries());
|
fs.removeSync(join('repo', contestId.toString()));
|
||||||
const resetTeamIds = formEntries
|
|
||||||
.filter((e) => e[0].startsWith('teamId'))
|
|
||||||
.map((e) => {
|
|
||||||
return parseInt(e[1].toString());
|
|
||||||
});
|
|
||||||
resetTeamIds.forEach((teamId) => {
|
|
||||||
const repoPath = join('repo', contestId.toString(), `${teamId.toString()}.git`);
|
|
||||||
if (fs.existsSync(repoPath) === true) {
|
|
||||||
fs.removeSync(repoPath);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
await createRepos(contestId, resetTeamIds);
|
|
||||||
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}` };
|
|
||||||
}
|
}
|
||||||
|
await createRepos(contestId);
|
||||||
return { success: true };
|
return { success: true };
|
||||||
}
|
}
|
||||||
} satisfies Actions;
|
} satisfies Actions;
|
||||||
|
@ -3,20 +3,11 @@
|
|||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import ConfirmModal from '$lib/ConfirmModal.svelte';
|
import ConfirmModal from '$lib/ConfirmModal.svelte';
|
||||||
import FormAlert from '$lib/FormAlert.svelte';
|
import FormAlert from '$lib/FormAlert.svelte';
|
||||||
import Modal from '$lib/Modal.svelte';
|
import type { PageData } from './$types';
|
||||||
import type { Actions, PageData } from './$types';
|
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
export let form: Actions;
|
|
||||||
|
|
||||||
$: if (form) {
|
|
||||||
freezeModal.hide();
|
|
||||||
repoModal.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
let confirmModal: ConfirmModal;
|
let confirmModal: ConfirmModal;
|
||||||
let freezeModal: Modal;
|
|
||||||
let repoModal: Modal;
|
|
||||||
|
|
||||||
function enhanceConfirm(form: HTMLFormElement, text: string) {
|
function enhanceConfirm(form: HTMLFormElement, text: string) {
|
||||||
enhance(form, async ({ cancel }) => {
|
enhance(form, async ({ cancel }) => {
|
||||||
@ -28,24 +19,6 @@
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let freezeTimeInputLocal: string | undefined;
|
|
||||||
let freezeTimeInput: string | null = null;
|
|
||||||
$: if (freezeTimeInputLocal !== undefined) {
|
|
||||||
freezeTimeInput = new Date(freezeTimeInputLocal).toISOString();
|
|
||||||
}
|
|
||||||
|
|
||||||
function repoSelectNone() {
|
|
||||||
document.querySelectorAll<HTMLInputElement>('.repoCheck').forEach((e) => {
|
|
||||||
e.checked = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function repoSelectAll() {
|
|
||||||
document.querySelectorAll<HTMLInputElement>('.repoCheck').forEach((e) => {
|
|
||||||
e.checked = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
@ -54,68 +27,6 @@
|
|||||||
|
|
||||||
<ConfirmModal bind:this={confirmModal} />
|
<ConfirmModal bind:this={confirmModal} />
|
||||||
|
|
||||||
<Modal title="Freeze Time" bind:this={freezeModal}>
|
|
||||||
<form action="?/freeze-time" method="POST" use:enhance>
|
|
||||||
<div class="modal-body">
|
|
||||||
<label class="form-label" for="freezeTimeInput">Freeze At</label>
|
|
||||||
<input
|
|
||||||
bind:value={freezeTimeInputLocal}
|
|
||||||
id="freezeTimeInput"
|
|
||||||
class="form-control"
|
|
||||||
type="datetime-local"
|
|
||||||
/>
|
|
||||||
<input type="hidden" name="freezeTime" value={freezeTimeInput} />
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-outline-secondary"
|
|
||||||
on:click={() => {
|
|
||||||
freezeModal.hide();
|
|
||||||
}}>Cancel</button
|
|
||||||
>
|
|
||||||
<button type="submit" class="btn btn-success">Set</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</Modal>
|
|
||||||
|
|
||||||
<Modal title="Reset Repos" bind:this={repoModal}>
|
|
||||||
<form action="?/repo" method="POST" use:enhance>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="d-flex flex-row gap-2 pb-2">
|
|
||||||
<button on:click={repoSelectNone} type="button" class="btn btn-sm btn-outline-secondary"
|
|
||||||
>Select None</button
|
|
||||||
>
|
|
||||||
<button on:click={repoSelectAll} type="button" class="btn btn-sm btn-outline-secondary"
|
|
||||||
>Select All</button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
{#each data.teams as team}
|
|
||||||
<div class="form-check">
|
|
||||||
<input
|
|
||||||
name={`teamId${team.id}`}
|
|
||||||
class="form-check-input repoCheck"
|
|
||||||
type="checkbox"
|
|
||||||
value={team.id}
|
|
||||||
id={`repoCheck${team.id}`}
|
|
||||||
/>
|
|
||||||
<label class="form-check-label" for={`repoCheck${team.id}`}>{team.name}</label>
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-outline-secondary"
|
|
||||||
on:click={() => {
|
|
||||||
repoModal.hide();
|
|
||||||
}}>Cancel</button
|
|
||||||
>
|
|
||||||
<button type="submit" class="btn btn-warning">Reset Selected</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</Modal>
|
|
||||||
|
|
||||||
<h1 style="text-align:center" class="mb-4"><i class="bi bi-flag"></i> Contest - {data.name}</h1>
|
<h1 style="text-align:center" class="mb-4"><i class="bi bi-flag"></i> Contest - {data.name}</h1>
|
||||||
|
|
||||||
<FormAlert />
|
<FormAlert />
|
||||||
@ -129,20 +40,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 text-end">
|
<div class="col-6 text-end">
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-outline-info"
|
|
||||||
on:click={() => {
|
|
||||||
freezeModal.show();
|
|
||||||
}}>Set Freeze Time</button
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-outline-warning"
|
|
||||||
on:click={() => {
|
|
||||||
repoModal.show();
|
|
||||||
}}>Reset Repos</button
|
|
||||||
>
|
|
||||||
{#if data.activeTeams === 0}
|
{#if data.activeTeams === 0}
|
||||||
<form
|
<form
|
||||||
method="POST"
|
method="POST"
|
||||||
@ -152,11 +49,19 @@
|
|||||||
>
|
>
|
||||||
<button type="submit" class="btn btn-danger">Delete</button>
|
<button type="submit" class="btn btn-danger">Delete</button>
|
||||||
</form>
|
</form>
|
||||||
|
<form
|
||||||
|
method="POST"
|
||||||
|
action="?/repo"
|
||||||
|
class="d-inline"
|
||||||
|
use:enhanceConfirm={'Are you sure you want to recreate repos? This WILL DELETE ALL DATA on the repos currently.'}
|
||||||
|
>
|
||||||
|
<button type="submit" class="btn btn-warning">Recreate Repos</button>
|
||||||
|
</form>
|
||||||
<form
|
<form
|
||||||
method="POST"
|
method="POST"
|
||||||
action="?/start"
|
action="?/start"
|
||||||
class="d-inline"
|
class="d-inline"
|
||||||
use:enhanceConfirm={'Are you sure you want to start the contest? (THIS WILL DELETE ALL DATA IF THE CONTEST HAS ALREADY BEEN RUN)'}
|
use:enhanceConfirm={'Are you sure you want to start the contest?'}
|
||||||
>
|
>
|
||||||
<button type="submit" class="btn btn-success">Start</button>
|
<button type="submit" class="btn btn-success">Start</button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -45,10 +45,7 @@ export const actions = {
|
|||||||
include: { teams: true, problems: true }
|
include: { teams: true, problems: true }
|
||||||
});
|
});
|
||||||
|
|
||||||
await createRepos(
|
await createRepos(createdContest.id);
|
||||||
createdContest.id,
|
|
||||||
teams.map((t) => t.id)
|
|
||||||
);
|
|
||||||
|
|
||||||
return { success: true };
|
return { success: true };
|
||||||
}
|
}
|
||||||
|
@ -153,10 +153,7 @@ export const actions = {
|
|||||||
await db.activeTeam.create({ data: { teamId: team.id, contestId: contest.id } });
|
await db.activeTeam.create({ data: { teamId: team.id, contestId: contest.id } });
|
||||||
});
|
});
|
||||||
|
|
||||||
await createRepos(
|
await createRepos(contest.id);
|
||||||
contest.id,
|
|
||||||
fullContest.teams.map((t) => t.id)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -8,24 +8,9 @@ export const load = (async ({ params }) => {
|
|||||||
throw redirect(302, '/public/scoreboard');
|
throw redirect(302, '/public/scoreboard');
|
||||||
}
|
}
|
||||||
const timestamp = new Date();
|
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({
|
const contest = await db.contest.findUnique({
|
||||||
where: { id: contestId },
|
where: { id: contestId },
|
||||||
include: {
|
include: { problems: true, teams: { include: { submissions: true } } }
|
||||||
problems: true,
|
|
||||||
teams: {
|
|
||||||
include: {
|
|
||||||
submissions:
|
|
||||||
contestQuery.freezeTime === null
|
|
||||||
? true
|
|
||||||
: { where: { createdAt: { lt: contestQuery.freezeTime } } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
if (contest === null) {
|
if (contest === null) {
|
||||||
throw redirect(302, '/public/scoreboard');
|
throw redirect(302, '/public/scoreboard');
|
||||||
|
Loading…
Reference in New Issue
Block a user