Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions apps/backend/apps/client/src/contest/contest.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,14 @@ export class ContestController {
problemId
)
}

@Get(':id/statistics/submissions')
async getAllSubmissionsByContest(
@Param('id', IDValidationPipe) contestId: number
) {
return await this.contestService.getAllSubmissionsByContest(contestId)
}

@Get(':id/problem/:problemId/statistics/graph')
@UserNullWhenAuthFailedIfPublic()
async getContestProblemStatistics(
Expand Down
67 changes: 65 additions & 2 deletions apps/backend/apps/client/src/contest/contest.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
import {
ConflictFoundException,
EntityNotExistException,
ForbiddenAccessException
ForbiddenAccessException,
UnprocessableDataException
} from '@libs/exception'
import { PrismaService } from '@libs/prisma'
import {
Expand Down Expand Up @@ -569,6 +570,7 @@ export class ContestService {

return {
username: user!.username,
userId,
totalScore: isFrozen ? score : finalScore,
totalPenalty: isFrozen ? totalPenalty : finalTotalPenalty,
problemRecords,
Expand Down Expand Up @@ -1225,7 +1227,7 @@ export class ContestService {
throw new EntityNotExistException('Contest')
}
const now = new Date()
if (contest.endTime <= now) {
if (contest.endTime > now) {
throw new ForbiddenAccessException(
'You can access to statistics after contest ends.'
)
Expand Down Expand Up @@ -1418,6 +1420,67 @@ export class ContestService {
}

/**
* 실시간 리더보드를 위해 대회의 모든 Submission을 반환합니다.
* @param contestId - 조회할 대회의 ID
* @returns submissionsWithOrder - 실시간 리더보드 구현에 필요한 형태의 Submission 리스트
*/
async getAllSubmissionsByContest(contestId: number) {
await this.checkIsContestExistsAndEnded(contestId)

const [contestProblems, submissions] = await Promise.all([
this.prisma.contestProblem.findMany({
where: {
contestId
},
select: {
problemId: true,
order: true
}
}),
this.prisma.submission.findMany({
where: { contestId },
select: {
problemId: true,
problem: {
select: {
title: true
}
},
userId: true,
user: {
select: {
username: true
}
},
result: true,
language: true,
codeSize: true,
id: true,
createTime: true
}
})
])

const problemOrderMap = new Map(
contestProblems.map((cp) => [cp.problemId, cp.order])
)

return submissions.map((submission) => {
const { user, problem, ...rest } = submission
const order = problemOrderMap.get(submission.problemId)
if (order === undefined) {
throw new UnprocessableDataException(
`Problem ${submission.problemId} is not found in contest ${contestId}`
)
}
return {
...rest,
username: user!.username,
title: problem!.title,
order
}
})
/**
* 대회 statistics 페이지의 문제별 통계 그래프를 조회합니다.
* 대회 종료 후에만 조회할 수 있습니다.
*
Expand Down
271 changes: 271 additions & 0 deletions apps/backend/prisma/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2733,6 +2733,277 @@ int main(void) {
data: { result: ResultStatus.OutputLimitExceeded }
})

submissions.push(
await prisma.submission.create({
data: {
userId: users[0].id,
problemId: problems[4].id,
contestId: contests[5].id,
code: [
{
id: 1,
locked: false,
text: `#include <stdio.h>
int main(void) {
int n;
scanf("%d", &n);
printf("%d\\n", n * 2);
return 0;
}`
}
],
language: Language.C,
result: ResultStatus.Judging
}
})
)
await prisma.submissionResult.create({
data: {
submissionId: submissions[submissions.length - 1].id,
problemTestcaseId: problemTestcases[4].id,
result: ResultStatus.Accepted,
output: '10\n',
cpuTime: 1234,
memoryUsage: 5120
}
})
await prisma.submission.update({
where: {
id: submissions[submissions.length - 1].id
},
data: { result: ResultStatus.Accepted }
})

submissions.push(
await prisma.submission.create({
data: {
userId: users[1].id,
problemId: problems[4].id,
contestId: contests[5].id,
code: [
{
id: 1,
locked: false,
text: `#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
cout << n + 1 << endl;
return 0;
}`
}
],
language: Language.Cpp,
result: ResultStatus.Judging
}
})
)
await prisma.submissionResult.create({
data: {
submissionId: submissions[submissions.length - 1].id,
problemTestcaseId: problemTestcases[4].id,
result: ResultStatus.WrongAnswer,
output: '6\n',
cpuTime: 2345,
memoryUsage: 6144
}
})
await prisma.submission.update({
where: {
id: submissions[submissions.length - 1].id
},
data: { result: ResultStatus.WrongAnswer }
})

submissions.push(
await prisma.submission.create({
data: {
userId: users[2].id,
problemId: problems[5].id,
contestId: contests[5].id,
code: [
{
id: 1,
locked: false,
text: `class Main {
public static void main(String[] args) {
java.util.Scanner sc = new java.util.Scanner(System.in);
int n = sc.nextInt();
System.out.println(n * n);
}
}`
}
],
language: Language.Java,
result: ResultStatus.Judging
}
})
)
await prisma.submissionResult.create({
data: {
submissionId: submissions[submissions.length - 1].id,
problemTestcaseId: problemTestcases[5].id,
result: ResultStatus.Accepted,
output: '25\n',
cpuTime: 3456,
memoryUsage: 8192
}
})
await prisma.submission.update({
where: {
id: submissions[submissions.length - 1].id
},
data: { result: ResultStatus.Accepted }
})

submissions.push(
await prisma.submission.create({
data: {
userId: users[3].id,
problemId: problems[4].id,
contestId: contests[5].id,
code: [
{
id: 1,
locked: false,
text: `while True:
pass`
}
],
language: Language.Python3,
result: ResultStatus.Judging
}
})
)
await prisma.submissionResult.create({
data: {
submissionId: submissions[submissions.length - 1].id,
problemTestcaseId: problemTestcases[4].id,
result: ResultStatus.TimeLimitExceeded,
output: null,
cpuTime: 5000,
memoryUsage: 4096
}
})
await prisma.submission.update({
where: {
id: submissions[submissions.length - 1].id
},
data: { result: ResultStatus.TimeLimitExceeded }
})

submissions.push(
await prisma.submission.create({
data: {
userId: users[4].id,
problemId: problems[5].id,
contestId: contests[5].id,
code: [
{
id: 1,
locked: false,
text: `#include <stdio.h>
int main(void) {
int arr[10];
printf("%d\\n", arr[100]);
return 0;
}`
}
],
language: Language.C,
result: ResultStatus.Judging
}
})
)
await prisma.submissionResult.create({
data: {
submissionId: submissions[submissions.length - 1].id,
problemTestcaseId: problemTestcases[5].id,
result: ResultStatus.RuntimeError,
output: null,
cpuTime: 123,
memoryUsage: 2048
}
})
await prisma.submission.update({
where: {
id: submissions[submissions.length - 1].id
},
data: { result: ResultStatus.RuntimeError }
})

submissions.push(
await prisma.submission.create({
data: {
userId: users[0].id,
problemId: problems[5].id,
contestId: contests[5].id,
code: [
{
id: 1,
locked: false,
text: `print(int(input()) ** 2)`
}
],
language: Language.Python3,
result: ResultStatus.Judging
}
})
)
await prisma.submissionResult.create({
data: {
submissionId: submissions[submissions.length - 1].id,
problemTestcaseId: problemTestcases[5].id,
result: ResultStatus.Accepted,
output: '25\n',
cpuTime: 456,
memoryUsage: 3072
}
})
await prisma.submission.update({
where: {
id: submissions[submissions.length - 1].id
},
data: { result: ResultStatus.Accepted }
})

submissions.push(
await prisma.submission.create({
data: {
userId: users[5].id,
problemId: problems[4].id,
contestId: contests[5].id,
code: [
{
id: 1,
locked: false,
text: `#include <stdio.h>
int main(void) {
printf("Hello World"
return 0;
}`
}
],
language: Language.C,
result: ResultStatus.Judging
}
})
)
await prisma.submissionResult.create({
data: {
submissionId: submissions[submissions.length - 1].id,
problemTestcaseId: problemTestcases[4].id,
result: ResultStatus.CompileError
}
})
await prisma.submission.update({
where: {
id: submissions[submissions.length - 1].id
},
data: { result: ResultStatus.CompileError }
})

const checkSeeds = users.map(async (user) => {
const newSubmission = await prisma.submission.create({
data: {
Expand Down
Loading
Loading