Skip to content

Commit

Permalink
(add) polygon checker
Browse files Browse the repository at this point in the history
  • Loading branch information
shine00chang committed Oct 11, 2024
1 parent a0ebad9 commit 19d0492
Show file tree
Hide file tree
Showing 27 changed files with 6,725 additions and 180 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ node_modules
.env
.DS_Store
replica.key
deploy/dev
!deploy/dev/docker-compose.yml
set-env.sh
50 changes: 43 additions & 7 deletions packages/api-server/src/admin.html
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,17 @@ <h2>Domains</h2>
</div>

<h2>Problems</h2>
<!--
<input type="text" id="problem-name" placeholder="name"><br>
<input type="text" id="problem-context" placeholder="context"><br>
<input type="text" id="problem-input" placeholder="input"><br>
<input type="text" id="problem-output" placeholder="output"><br>
<button id='problem-add'>add</button> <br>
-->
<button id='problem-polygon'>polygon add</button> (zipped package)
<input type="file" id="problem-polygon-input"> <br>
<button id='problem-get'>get</button> <br>
<button id='problem-get'>get</button>
<button id='problem-delete'>delete</button> <br>

<div id='problem-list'>
</div>
Expand All @@ -106,13 +109,15 @@ <h2>Contests</h2>
<input type="number" id="contest-endTime" placeholder="endTime"><br>
<button id='contest-add'>add</button> <br>
<button id='contest-add-problem'>add problem</button> <br>
<button id='contest-get'>get</button> <br>
<button id='contest-get'>get</button>
<button id='contest-delete'>delete</button> <br>

<div id='contest-list'>
</div>

<h2>Contest Problems</h2>
<button id='contest-problem-get'>get</button> <br>
<button id='contest-problem-get'>get</button>
<button id='contest-problem-delete'>delete</button> <br>

<div id='contest-problem-list'>
</div>
Expand All @@ -121,24 +126,27 @@ <h2>Publish</h2>
<button id='contest-publish'>publish</button>

<h2>Testcases</h2>
<!--
<input type="file" id="testcase-input"> <br>
<input type="file" id="testcase-output"> <br>
<button id='testcase-upload'>upload</button>
<button id='testcase-get'>get</button>
<button id='testcase-delete' disabled>delete</button>
-->

<button id='testcase-get'>get</button>
<div id='testcase-list'>
</div>

<script>
const uploadURL = 'http://localhost:8001';
const uploadURL = 'http://13.93.218.61:8001';

let getUserId = _ => undefined;

const getDomainId = _ => {let e = document.querySelector('input[name="domain-radio"]:checked'); return e ? e.value : undefined;};
const getProblemId = _ => {let e = document.querySelector('input[name="problem-radio"]:checked'); return e ? e.value : undefined;};
const getSeriesId = _ => {let e = document.querySelector('input[name="series-radio"]:checked'); return e ? e.value : undefined;};
const getContestId = _ => {let e = document.querySelector('input[name="contest-radio"]:checked'); return e ? e.value : undefined;};
const getContestProblemId = _ => {let e = document.querySelector('input[name="contest-problem-radio"]:checked'); return e ? e.value : undefined;};
const getTestcaseId = _ => {let e = document.querySelector('input[name="testcase-radio"]:checked'); return e ? e.value : undefined;};

const betterFetch = (url, options) =>
Expand Down Expand Up @@ -268,6 +276,7 @@ <h2>Testcases</h2>
document.getElementById('domain-list').innerHTML = html;
}

/*
document.getElementById('problem-add').onclick = async _ => {
console.log('problem-add');
Expand Down Expand Up @@ -301,6 +310,17 @@ <h2>Testcases</h2>
.then(res => console.log(res))
.catch(console.error);
}
*/
document.getElementById('problem-delete').onclick = async _ => {

console.log('problem-delete');

if (getDomainId() === undefined) return alert('no domain selected');
if (getProblemId() === undefined) return alert('no problem selected');

await betterFetch(`/v1/domains/${getDomainId()}/problems/${getProblemId()}`, { method: 'DELETE' })
.then(_ => alert('problem deleted'))
}

document.getElementById('problem-polygon').onclick = async _ => {

Expand Down Expand Up @@ -349,7 +369,7 @@ <h2>Testcases</h2>
<label for='${id}'><b>${name}</b> (<i>${id}</i>)</label>
</summary>
${problemHTML}
</div>`
</details>`
}
document.getElementById('problem-list').innerHTML = html;
}
Expand Down Expand Up @@ -476,12 +496,27 @@ <h2>Testcases</h2>

let html = '';
for (const { name, id } of problems) {
html += `<div><b>${name}</b>: (<i>${id}</i>)</div>`
html += `
<div>
<input type='radio' name='contest-problem-radio' value='${id}'>
<b>${name}</b>: (<i>${id}</i>)
</div>`
}

document.getElementById('contest-problem-list').innerHTML = html;
}

document.getElementById('contest-problem-delete').onclick = async _ => {

console.log('contest-problem-delete');

if (getContestId() === undefined) return alert('no contest selected');
if (getContestProblemId() === undefined) return alert('no contest problem selected');

await betterFetch(`/v1/contests/${getContestId()}/problems/${getContestProblemId()}`, { method: 'DELETE' })
}

/*
document.getElementById('testcase-upload').onclick = async _ => {
console.log('testcase-upload');
Expand Down Expand Up @@ -530,6 +565,7 @@ <h2>Testcases</h2>
})
.alert('testcase added')
}
*/

document.getElementById('testcase-get').onclick = async _ => {

Expand Down
8 changes: 6 additions & 2 deletions packages/api-server/src/client.html
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ <h2>Ranklist</h2>
<label for='${id}'><b>${name}</b> (<i>${id}</i>)</label>
</summary>
${problemHTML}
</div>`
</details>`
}

document.getElementById('problem-list').innerHTML = html;
Expand Down Expand Up @@ -327,8 +327,12 @@ <h2>Ranklist</h2>
.then(res => res.json());

let html = '';
for (const { problemName, problemId, createdAt, status, score, testcases, id } of submissions) {
for (const { problemName, problemId, createdAt, status, score, testcases, id, log } of submissions) {
html += `<div><b>${problemName}</b> @ ${(new Date(createdAt)).toLocaleString()}: <b>${status}</b> <i>(${id})</i><br> <b>${score !== undefined ? score : '...'}</b> => `

if (log) html += `<b style='color: red'>${log}</b><br>`
if (status !== 'Graded') continue;
if (!testcases) continue;
for (const { result } of testcases) {
html += `${result.status}:${result.wallTime}ms <b>||</b> `
}
Expand Down
1 change: 1 addition & 0 deletions packages/api-server/src/routes/v1/contest.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import { userAuthHook } from '../../hooks/authentication.hooks.js'
import { contestInfoHook } from '../../hooks/contest.hooks.js'
import { requestUserProfile } from '../../utils/auth.utils.js'
import {fetchUser} from '../../services/user.services.js'
/*=*/

async function contestProblemRoutes (problemRoutes: FastifyTypeBox): Promise<void> {
problemRoutes.addHook('onRequest', contestInfoHook)
Expand Down
13 changes: 10 additions & 3 deletions packages/api-server/src/routes/v1/domain.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ import {
} from '../../services/domain.services.js'
import { isSuperAdmin } from '../../auth/role.auth.js'
import { hasDomainPrivilege } from '../../auth/scope.auth.js'
import { type FastifyTypeBox } from '../../types.js'
import { createDomainProblem, deleteDomainProblem, fetchDomainProblems, updateDomainProblem } from '../../services/problem.services.js'
import { type FastifyTypeBox } from '../../types.js' /*=*/
import { deleteDomainProblem, fetchDomainProblems } from '../../services/problem.services.js'
import { fetchDomainProblem } from '@argoncs/common'
import { createTestingSubmission } from '../../services/submission.services.js'
import { createPolygonUploadSession, createUploadSession } from '../../services/testcase.services.js'
import { createPolygonUploadSession } from '../../services/testcase.services.js'
import { UnauthorizedError, badRequestSchema, forbiddenSchema, methodNotAllowedSchema, notFoundSchema, unauthorizedSchema } from 'http-errors-enhanced'
import { createContest, createContestSeries, fetchDomainContestSeries, fetchDomainContests } from '../../services/contest.services.js'
import { userAuthHook } from '../../hooks/authentication.hooks.js'
/*=*/

async function domainMemberRoutes (memberRoutes: FastifyTypeBox): Promise<void> {
memberRoutes.post(
Expand Down Expand Up @@ -134,6 +135,7 @@ async function domainMemberRoutes (memberRoutes: FastifyTypeBox): Promise<void>
}

async function domainProblemRoutes (problemRoutes: FastifyTypeBox): Promise<void> {
/*
problemRoutes.post(
'/',
{
Expand All @@ -158,6 +160,7 @@ async function domainProblemRoutes (problemRoutes: FastifyTypeBox): Promise<void
return await reply.status(201).send(created)
}
)
*/

problemRoutes.get(
'/',
Expand All @@ -182,6 +185,7 @@ async function domainProblemRoutes (problemRoutes: FastifyTypeBox): Promise<void
}
)

/*
problemRoutes.put(
'/:problemId',
{
Expand All @@ -207,6 +211,7 @@ async function domainProblemRoutes (problemRoutes: FastifyTypeBox): Promise<void
return await reply.status(200).send({ modified })
}
)
*/

problemRoutes.delete(
'/:problemId',
Expand Down Expand Up @@ -286,6 +291,7 @@ async function domainProblemRoutes (problemRoutes: FastifyTypeBox): Promise<void
}
)

/*
problemRoutes.get(
'/:problemId/upload-session',
{
Expand All @@ -309,6 +315,7 @@ async function domainProblemRoutes (problemRoutes: FastifyTypeBox): Promise<void
await reply.status(200).send({ uploadId })
}
)
*/

problemRoutes.get(
'/polygon-upload-session',
Expand Down
3 changes: 2 additions & 1 deletion packages/api-server/src/routes/v1/user.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ async function userSubmissionRoutes (submissionRoutes: FastifyTypeBox): Promise<
])),
400: badRequestSchema,
401: unauthorizedSchema,
403: forbiddenSchema
403: forbiddenSchema,
404: notFoundSchema
}
},
onRequest: [userAuthHook, submissionRoutes.auth([
Expand Down
8 changes: 6 additions & 2 deletions packages/api-server/src/services/problem.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,22 @@ import { testcaseExists } from './testcase.services.js'

import { nanoid } from 'nanoid'

/*
export async function createDomainProblem ({ newProblem, domainId }: { newProblem: NewProblem, domainId: string }): Promise<{ problemId: string }> {
const problemId = nanoid()
const problem: Problem = { ...newProblem, id: problemId, domainId }
await domainProblemCollection.insertOne(problem)
return { problemId }
}
*/

/*
export async function updateDomainProblem ({ problemId, domainId, problem }: { problemId: string, domainId: string, problem: Partial<NewProblem> }): Promise<{ modified: boolean }> {
if (problem.testcases != null) {
const testcasesVerifyQueue: Array<Promise<void>> = []
problem.testcases.forEach((testcase) => {
testcasesVerifyQueue.push(testcaseExists({ problemId, domainId, filename: testcase.input.name, versionId: testcase.input.versionId }))
testcasesVerifyQueue.push(testcaseExists({ problemId, domainId, filename: testcase.output.name, versionId: testcase.output.versionId }))
testcasesVerifyQueue.push(testcaseExists({ problemId, filename: testcase.input.name, versionId: testcase.input.versionId }))
testcasesVerifyQueue.push(testcaseExists({ problemId, filename: testcase.output.name, versionId: testcase.output.versionId }))
})
await Promise.all(testcasesVerifyQueue)
}
Expand All @@ -32,6 +35,7 @@ export async function updateDomainProblem ({ problemId, domainId, problem }: { p
return { modified: modifiedCount > 0 }
}
*/

export async function deleteDomainProblem ({ problemId, domainId }: { problemId: string, domainId: string }): Promise<void> {
const session = mongoClient.startSession()
Expand Down
2 changes: 1 addition & 1 deletion packages/api-server/src/services/submission.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
SubmissionStatus,
type Submission,
type Problem
} from '@argoncs/types'
} from '@argoncs/types' /*=*/
import { rabbitMQ, judgerExchange, judgerTasksKey, submissionCollection, fetchDomainProblem, fetchContestProblem } from '@argoncs/common'
import { languageConfigs } from '../../configs/language.configs.js'

Expand Down
7 changes: 4 additions & 3 deletions packages/api-server/src/services/testcase.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ import { fetchDomainProblem, minio, uploadSessionCollection } from '@argoncs/com
import path = require('node:path')
import { nanoid } from 'nanoid'

export async function testcaseExists ({ problemId, domainId, filename, versionId }: { problemId: string, domainId: string, filename: string, versionId: string }): Promise<void> {
const objectName = path.join(domainId, problemId, filename)
export async function testcaseExists ({ problemId, filename, versionId }: { problemId: string, filename: string, versionId: string }): Promise<void> {
try {
const stat = await minio.statObject('testcases', objectName, { versionId })
const stat = await minio.statObject('testcases', path.join(problemId, filename), { versionId })

if (stat == null || stat.versionId !== versionId) {
throw new NotFoundError('One of the testcases not found')
Expand All @@ -17,12 +16,14 @@ export async function testcaseExists ({ problemId, domainId, filename, versionId
}
}

/*
export async function createUploadSession ({ problemId, domainId }: { problemId: string, domainId: string }): Promise<{ uploadId: string }> {
const id = nanoid(32)
await fetchDomainProblem({ problemId, domainId }) // Could throw not found
await uploadSessionCollection.insertOne({ id, problemId, domainId, createdAt: (new Date()).getTime() })
return { uploadId: id }
}
*/

export async function createPolygonUploadSession ({ domainId }: { domainId: string }): Promise<{ uploadId: string }> {
const id = nanoid(32)
Expand Down
4 changes: 4 additions & 0 deletions packages/common/src/connections/minio.connections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ export async function connectMinIO (url: string): Promise<void> {
if (!await minio.bucketExists('binaries')) {
await minio.makeBucket('binaries')
}
if (!await minio.bucketExists('checkers')) {
await minio.makeBucket('checkers')
}
await minio.setBucketVersioning('testcases', { Status: 'Enabled' })
await minio.setBucketVersioning('checkers', { Status: 'Enabled' })
}

export { minio }
4 changes: 3 additions & 1 deletion packages/judge-daemon/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
node_modules
dist
dist
box-metas
argon-cache
Loading

0 comments on commit 19d0492

Please sign in to comment.