[web] Format and add CPP to db
This commit is contained in:
parent
6b955857bf
commit
d2d686133c
@ -37,22 +37,22 @@ enum SubmissionStateReason {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model Submission {
|
model Submission {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
gradedAt DateTime?
|
gradedAt DateTime?
|
||||||
state SubmissionState
|
state SubmissionState
|
||||||
stateReason SubmissionStateReason?
|
stateReason SubmissionStateReason?
|
||||||
stateReasonDetails String?
|
stateReasonDetails String?
|
||||||
actualOutput String?
|
actualOutput String?
|
||||||
commitHash String
|
commitHash String
|
||||||
diff String?
|
diff String?
|
||||||
message String?
|
message String?
|
||||||
team Team @relation(fields: [teamId], references: [id])
|
team Team @relation(fields: [teamId], references: [id])
|
||||||
teamId Int
|
teamId Int
|
||||||
problem Problem @relation(fields: [problemId], references: [id])
|
problem Problem @relation(fields: [problemId], references: [id])
|
||||||
problemId Int
|
problemId Int
|
||||||
contestId Int
|
contestId Int
|
||||||
contest Contest @relation(fields: [contestId], references: [id])
|
contest Contest @relation(fields: [contestId], references: [id])
|
||||||
}
|
}
|
||||||
|
|
||||||
model Problem {
|
model Problem {
|
||||||
@ -80,6 +80,7 @@ model Team {
|
|||||||
enum Language {
|
enum Language {
|
||||||
Java
|
Java
|
||||||
CSharp
|
CSharp
|
||||||
|
CPP
|
||||||
}
|
}
|
||||||
|
|
||||||
model ActiveTeam {
|
model ActiveTeam {
|
||||||
|
@ -36,7 +36,8 @@ export const actions = {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await db.contest.delete({ where: { id: parseInt(params.contestId) } });
|
await db.contest.delete({ where: { id: parseInt(params.contestId) } });
|
||||||
} catch {
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
return { success: false };
|
return { success: false };
|
||||||
}
|
}
|
||||||
redirect(302, '/admin/contests');
|
redirect(302, '/admin/contests');
|
||||||
|
@ -4,37 +4,37 @@ import type { Actions, PageServerLoad } from './$types';
|
|||||||
import { fail, redirect } from '@sveltejs/kit';
|
import { fail, redirect } from '@sveltejs/kit';
|
||||||
import { genPassword } from '../../teams/util';
|
import { genPassword } from '../../teams/util';
|
||||||
|
|
||||||
export const load = (async () => { }) satisfies PageServerLoad;
|
export const load = (async () => {}) satisfies PageServerLoad;
|
||||||
|
|
||||||
export type ContestImportData = {
|
export type ContestImportData = {
|
||||||
Name: string,
|
Name: string;
|
||||||
Problems: ProblemImportData[],
|
Problems: ProblemImportData[];
|
||||||
Teams: TeamImportData[],
|
Teams: TeamImportData[];
|
||||||
Submissions: SubmissionImportData[]
|
Submissions: SubmissionImportData[];
|
||||||
}
|
};
|
||||||
|
|
||||||
export type ProblemImportData = {
|
export type ProblemImportData = {
|
||||||
ProblemName: string,
|
ProblemName: string;
|
||||||
ShortName: string,
|
ShortName: string;
|
||||||
SampleInput: string,
|
SampleInput: string;
|
||||||
SampleOutput: string,
|
SampleOutput: string;
|
||||||
RealInput: string,
|
RealInput: string;
|
||||||
RealOutput: string
|
RealOutput: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type TeamImportData = {
|
export type TeamImportData = {
|
||||||
TeamName: string
|
TeamName: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type SubmissionImportData = {
|
export type SubmissionImportData = {
|
||||||
TeamName: string,
|
TeamName: string;
|
||||||
ProblemShortName: string,
|
ProblemShortName: string;
|
||||||
State: string,
|
State: string;
|
||||||
SubmitTime: number,
|
SubmitTime: number;
|
||||||
TeamOutput: string,
|
TeamOutput: string;
|
||||||
Code: string | null,
|
Code: string | null;
|
||||||
Language: "Java" | "C#" | "C++" | null
|
Language: 'Java' | 'C#' | 'C++' | null;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const actions = {
|
export const actions = {
|
||||||
default: async ({ request }) => {
|
default: async ({ request }) => {
|
||||||
@ -45,14 +45,13 @@ export const actions = {
|
|||||||
const formData = await request.formData();
|
const formData = await request.formData();
|
||||||
const contestJson = formData.get('jsonText')?.toString();
|
const contestJson = formData.get('jsonText')?.toString();
|
||||||
if (!contestJson) {
|
if (!contestJson) {
|
||||||
return fail(400, { message: "Could not get json text" });
|
return fail(400, { message: 'Could not get json text' });
|
||||||
}
|
}
|
||||||
|
|
||||||
parsedContest = JSON.parse(contestJson);
|
parsedContest = JSON.parse(contestJson);
|
||||||
includeSubmissions = formData.get('includeSubmissions')?.toString() == "on";
|
includeSubmissions = formData.get('includeSubmissions')?.toString() == 'on';
|
||||||
}
|
} catch (err) {
|
||||||
catch (err) {
|
return fail(400, { message: 'Could not parse contest data: ' + err?.toString() });
|
||||||
return fail(400, { message: "Could not parse contest data: " + err?.toString() });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -62,7 +61,9 @@ export const actions = {
|
|||||||
if (includeSubmissions && parsedContest.Submissions.length > 0) {
|
if (includeSubmissions && parsedContest.Submissions.length > 0) {
|
||||||
hasSubmissions = true;
|
hasSubmissions = true;
|
||||||
|
|
||||||
const maxSubmitTimeMinutes = Math.max(...parsedContest.Submissions.map(s => s.SubmitTime));
|
const maxSubmitTimeMinutes = Math.max(
|
||||||
|
...parsedContest.Submissions.map((s) => s.SubmitTime)
|
||||||
|
);
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
contestStart = new Date(now.getTime() - maxSubmitTimeMinutes * 60 * 1000);
|
contestStart = new Date(now.getTime() - maxSubmitTimeMinutes * 60 * 1000);
|
||||||
}
|
}
|
||||||
@ -73,24 +74,24 @@ export const actions = {
|
|||||||
name: parsedContest.Name,
|
name: parsedContest.Name,
|
||||||
startTime: contestStart,
|
startTime: contestStart,
|
||||||
teams: {
|
teams: {
|
||||||
connectOrCreate: parsedContest.Teams.map(team => ({
|
connectOrCreate: parsedContest.Teams.map((team) => ({
|
||||||
where: { name: team.TeamName },
|
where: { name: team.TeamName },
|
||||||
create: {
|
create: {
|
||||||
name: team.TeamName,
|
name: team.TeamName,
|
||||||
password: genPassword(),
|
password: genPassword(),
|
||||||
language: inferTeamLanguage(parsedContest, team) ?? Language.Java
|
language: inferTeamLanguage(parsedContest, team) ?? Language.Java
|
||||||
}
|
}
|
||||||
})),
|
}))
|
||||||
},
|
},
|
||||||
problems: {
|
problems: {
|
||||||
connectOrCreate: parsedContest.Problems.map(problem => ({
|
connectOrCreate: parsedContest.Problems.map((problem) => ({
|
||||||
where: {
|
where: {
|
||||||
friendlyName: problem.ProblemName,
|
friendlyName: problem.ProblemName,
|
||||||
pascalName: problem.ShortName,
|
pascalName: problem.ShortName,
|
||||||
sampleInput: problem.SampleInput,
|
sampleInput: problem.SampleInput,
|
||||||
sampleOutput: problem.SampleOutput,
|
sampleOutput: problem.SampleOutput,
|
||||||
realInput: problem.RealInput,
|
realInput: problem.RealInput,
|
||||||
realOutput: problem.RealOutput,
|
realOutput: problem.RealOutput
|
||||||
},
|
},
|
||||||
create: {
|
create: {
|
||||||
friendlyName: problem.ProblemName,
|
friendlyName: problem.ProblemName,
|
||||||
@ -100,68 +101,75 @@ export const actions = {
|
|||||||
realInput: problem.RealInput,
|
realInput: problem.RealInput,
|
||||||
realOutput: problem.RealOutput
|
realOutput: problem.RealOutput
|
||||||
}
|
}
|
||||||
})),
|
}))
|
||||||
},
|
},
|
||||||
submissions: {
|
submissions: {
|
||||||
create: hasSubmissions
|
create: hasSubmissions
|
||||||
? parsedContest.Submissions.toSorted((a, b) => a.SubmitTime - b.SubmitTime).map(submission => ({
|
? parsedContest.Submissions.toSorted((a, b) => a.SubmitTime - b.SubmitTime).map(
|
||||||
createdAt: dateFromContestMinutes(contestStart!, submission.SubmitTime),
|
(submission) => ({
|
||||||
gradedAt: dateFromContestMinutes(contestStart!, submission.SubmitTime + 1),
|
createdAt: dateFromContestMinutes(contestStart!, submission.SubmitTime),
|
||||||
state: convertSubmissionState(submission),
|
gradedAt: dateFromContestMinutes(contestStart!, submission.SubmitTime + 1),
|
||||||
actualOutput: submission.TeamOutput,
|
state: convertSubmissionState(submission),
|
||||||
commitHash: "",
|
actualOutput: submission.TeamOutput,
|
||||||
problem: {
|
commitHash: '',
|
||||||
connect: {
|
problem: {
|
||||||
pascalName: submission.ProblemShortName
|
connect: {
|
||||||
}
|
pascalName: submission.ProblemShortName
|
||||||
},
|
}
|
||||||
team: {
|
},
|
||||||
connect: {
|
team: {
|
||||||
name: submission.TeamName
|
connect: {
|
||||||
}
|
name: submission.TeamName
|
||||||
}
|
}
|
||||||
}))
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
: []
|
: []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return fail(400, { message: "Error updating database: " + err?.toString() });
|
return fail(400, { message: 'Error updating database: ' + err?.toString() });
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect(303, "/admin/contests");
|
return redirect(303, '/admin/contests');
|
||||||
}
|
}
|
||||||
} satisfies Actions;
|
} satisfies Actions;
|
||||||
|
|
||||||
function convertSubmissionState(submission: SubmissionImportData): SubmissionState {
|
function convertSubmissionState(submission: SubmissionImportData): SubmissionState {
|
||||||
switch (submission.State) {
|
switch (submission.State) {
|
||||||
case "Correct":
|
case 'Correct':
|
||||||
return SubmissionState.Correct;
|
return SubmissionState.Correct;
|
||||||
case "Incorrect":
|
case 'Incorrect':
|
||||||
return SubmissionState.Incorrect;
|
return SubmissionState.Incorrect;
|
||||||
default:
|
default:
|
||||||
return SubmissionState.InReview;
|
return SubmissionState.InReview;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function inferTeamLanguage(parsedContest: ContestImportData, team: TeamImportData): Language | null {
|
function inferTeamLanguage(
|
||||||
const submissionWithCode = parsedContest.Submissions.find(s => s.TeamName == team.TeamName && s.Code != null);
|
parsedContest: ContestImportData,
|
||||||
|
team: TeamImportData
|
||||||
|
): Language | null {
|
||||||
|
const submissionWithCode = parsedContest.Submissions.find(
|
||||||
|
(s) => s.TeamName == team.TeamName && s.Code != null
|
||||||
|
);
|
||||||
if (!submissionWithCode) {
|
if (!submissionWithCode) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (submissionWithCode.Language) {
|
switch (submissionWithCode.Language) {
|
||||||
case "Java":
|
case 'Java':
|
||||||
return Language.Java;
|
return Language.Java;
|
||||||
case "C#":
|
case 'C#':
|
||||||
return Language.CSharp;
|
return Language.CSharp;
|
||||||
case "C++":
|
case 'C++':
|
||||||
return Language.CPP;
|
return Language.CPP;
|
||||||
default:
|
default:
|
||||||
throw new Error("Unrecognized language: " + submissionWithCode.Language);
|
throw new Error('Unrecognized language: ' + submissionWithCode.Language);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function dateFromContestMinutes(contestStart: Date, minutesFromStart: number): Date {
|
function dateFromContestMinutes(contestStart: Date, minutesFromStart: number): Date {
|
||||||
return new Date(contestStart.getTime() + minutesFromStart * 60 * 1000);
|
return new Date(contestStart.getTime() + minutesFromStart * 60 * 1000);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { enhance } from '$app/forms';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import FormAlert from '$lib/FormAlert.svelte';
|
import FormAlert from '$lib/FormAlert.svelte';
|
||||||
import type { Actions } from './$types';
|
import type { Actions } from './$types';
|
||||||
@ -48,7 +49,7 @@
|
|||||||
|
|
||||||
<FormAlert />
|
<FormAlert />
|
||||||
|
|
||||||
<form method="POST">
|
<form method="POST" use:enhance>
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<h3>Contest JSON:</h3>
|
<h3>Contest JSON:</h3>
|
||||||
<textarea
|
<textarea
|
||||||
@ -57,7 +58,9 @@
|
|||||||
class="form-control"
|
class="form-control"
|
||||||
rows="10"
|
rows="10"
|
||||||
bind:value={jsonText}
|
bind:value={jsonText}
|
||||||
style="{parsesCorrectly == null ? "" : `border: 2px solid ${parsesCorrectly ? 'green' : 'red'}`}"
|
style={parsesCorrectly == null
|
||||||
|
? ''
|
||||||
|
: `border: 2px solid ${parsesCorrectly ? 'green' : 'red'}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -65,9 +68,9 @@
|
|||||||
<h3>Import Info:</h3>
|
<h3>Import Info:</h3>
|
||||||
<span>{numTeams ?? 'No'} Teams</span><br />
|
<span>{numTeams ?? 'No'} Teams</span><br />
|
||||||
<span>{numProblems ?? 'No'} Problems</span><br />
|
<span>{numProblems ?? 'No'} Problems</span><br />
|
||||||
<span>{numSubmissions ?? 'No'} Submissions</span>
|
<span>{numSubmissions ?? 'No'} Submissions</span>
|
||||||
(<input type="checkbox" checked name="includeSubmissions" id="includeSubmissions" />
|
(<input type="checkbox" checked name="includeSubmissions" id="includeSubmissions" />
|
||||||
<label id="includeSubmissionsLabel" for="includeSubmissions">Include</label>)
|
<label id="includeSubmissionsLabel" for="includeSubmissions">Include</label>)
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="d-flex flex-row justify-content-end gap-2 m-2">
|
<div class="d-flex flex-row justify-content-end gap-2 m-2">
|
||||||
|
@ -73,7 +73,12 @@
|
|||||||
<textarea use:stretchTextarea class="code mb-3 form-control" disabled>{data.output}</textarea>
|
<textarea use:stretchTextarea class="code mb-3 form-control" disabled>{data.output}</textarea>
|
||||||
|
|
||||||
<h3>Diff</h3>
|
<h3>Diff</h3>
|
||||||
<div class="mt-3" id="diff" class:d2h-dark-color-scheme={$theme === 'dark'} class:d2h-light-color-scheme={$theme === 'light'}/>
|
<div
|
||||||
|
class="mt-3"
|
||||||
|
id="diff"
|
||||||
|
class:d2h-dark-color-scheme={$theme === 'dark'}
|
||||||
|
class:d2h-light-color-scheme={$theme === 'light'}
|
||||||
|
/>
|
||||||
|
|
||||||
<form method="POST" action="?/submit" use:enhance>
|
<form method="POST" action="?/submit" use:enhance>
|
||||||
<h5>Message</h5>
|
<h5>Message</h5>
|
||||||
|
Loading…
Reference in New Issue
Block a user