Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/skkuding/codedang into t702…
Browse files Browse the repository at this point in the history
…-replace-icons
  • Loading branch information
youznn committed Aug 21, 2024
2 parents d3894d4 + 278df07 commit cb12976
Show file tree
Hide file tree
Showing 39 changed files with 370 additions and 88 deletions.
3 changes: 3 additions & 0 deletions .env.development
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ MEDIA_SECRET_KEY=skku1234
REDIS_HOST=127.0.0.1
REDIS_PORT=6380

MINIO_ROOT_USER=skku
MINIO_ROOT_PASSWORD=skku1234

DATABASE_URL=postgresql://postgres:1234@127.0.0.1:5433/skkuding?schema=public
TEST_DATABASE_URL=postgresql://postgres:1234@127.0.0.1:5434/skkuding?schema=public

Expand Down
2 changes: 2 additions & 0 deletions apps/backend/apps/admin/src/admin.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { ContestModule } from './contest/contest.module'
import { GroupModule } from './group/group.module'
import { ProblemModule } from './problem/problem.module'
import { StorageModule } from './storage/storage.module'
import { SubmissionModule } from './submission/submission.module'
import { UserModule } from './user/user.module'

@Module({
Expand Down Expand Up @@ -55,6 +56,7 @@ import { UserModule } from './user/user.module'
UserModule,
AnnouncementModule,
NoticeModule,
SubmissionModule,
LoggerModule.forRoot(pinoLoggerModuleOption)
],
controllers: [AdminController],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Field, Int, ObjectType } from '@nestjs/graphql'
import { Language, ResultStatus } from '@admin/@generated'

@ObjectType({ description: 'contestSubmissionOverall' })
export class ContestSubmission {
@Field(() => String, { nullable: false })
title!: string // 문제 title

@Field(() => String, { nullable: false })
studentId!: string // 학번

@Field(() => String, { nullable: true })
realname?: string // 실명

@Field(() => String, { nullable: false })
username!: string

@Field(() => ResultStatus, { nullable: false })
result!: ResultStatus // Accepted, WrongAnswer ...

@Field(() => Language, { nullable: false })
language!: Language

@Field(() => String, { nullable: false })
submissionTime!: Date // 제출 시각

@Field(() => Int, { nullable: true })
codeSize: number | null

@Field(() => String, { nullable: true })
ip: string | null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Field, InputType, Int } from '@nestjs/graphql'

@InputType()
export class GetContestSubmissionsInput {
@Field(() => Int, { nullable: false })
contestId!: number

@Field(() => Int, { nullable: true })
problemId?: number
}
8 changes: 8 additions & 0 deletions apps/backend/apps/admin/src/submission/submission.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Module } from '@nestjs/common'
import { SubmissionResolver } from './submission.resolver'
import { SubmissionService } from './submission.service'

@Module({
providers: [SubmissionResolver, SubmissionService]
})
export class SubmissionModule {}
37 changes: 37 additions & 0 deletions apps/backend/apps/admin/src/submission/submission.resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { InternalServerErrorException, Logger } from '@nestjs/common'
import { Args, Int, Query, Resolver } from '@nestjs/graphql'
import { CursorValidationPipe } from '@libs/pipe'
import { Submission } from '@admin/@generated'
import { ContestSubmission } from './model/contest-submission.model'
import { GetContestSubmissionsInput } from './model/get-contest-submission.input'
import { SubmissionService } from './submission.service'

@Resolver(() => Submission)
export class SubmissionResolver {
private readonly logger = new Logger(SubmissionResolver.name)
constructor(private readonly submissionService: SubmissionService) {}

@Query(() => [ContestSubmission])
async getContestSubmissions(
@Args('input', {
nullable: false,
type: () => GetContestSubmissionsInput
})
input: GetContestSubmissionsInput,
@Args('cursor', { nullable: true, type: () => Int }, CursorValidationPipe)
cursor: number | null,
@Args('take', { nullable: true, defaultValue: 10, type: () => Int })
take: number
): Promise<ContestSubmission[]> {
try {
return await this.submissionService.getContestSubmissions(
input,
take,
cursor
)
} catch (error) {
this.logger.error(error.error)
throw new InternalServerErrorException()
}
}
}
62 changes: 62 additions & 0 deletions apps/backend/apps/admin/src/submission/submission.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { Injectable } from '@nestjs/common'
import { PrismaService } from '@libs/prisma'
import type { Language, ResultStatus } from '@admin/@generated'
import type { GetContestSubmissionsInput } from './model/get-contest-submission.input'

@Injectable()
export class SubmissionService {
constructor(private readonly prisma: PrismaService) {}

async getContestSubmissions(
input: GetContestSubmissionsInput,
take: number,
cursor: number | null
) {
const paginator = this.prisma.getPaginator(cursor)

const { contestId, problemId } = input
const contestSubmissions = await this.prisma.submission.findMany({
...paginator,
take,
where: {
contestId,
problemId
},
include: {
user: {
select: {
id: true,
username: true,
studentId: true,
userProfile: {
select: {
realName: true
}
}
}
},
problem: {
select: {
title: true
}
}
}
})

const results = contestSubmissions.map((c) => {
return {
title: c.problem.title,
studentId: c.user?.studentId ?? 'Unknown',
realname: c.user?.userProfile?.realName ?? 'Unknown',
username: c.user?.username ?? 'Unknown',
result: c.result as ResultStatus,
language: c.language as Language,
submissionTime: c.createTime,
codeSize: c.codeSize ?? null,
ip: c.userIp ?? 'Unknown'
}
})

return results
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
<td>
{{!-- Logo file is uploaded in https://github.com/skkuding/codedang/issues/1066 --}}
<img
src="https://github.com/skkuding/codedang/assets/19747913/592f3ac4-7ac7-4d59-9f87-87fd6fd4965c"
src="https://github.com/user-attachments/assets/09d0e23b-8ce6-4b42-b7af-7b3e120327a0"
height="72"
alt="Codedang"
id="logo"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class JudgeResult {
}

export class JudgerResponse {
@Max(8)
@Max(9)
@Min(0)
@IsNotEmpty()
resultCode: number
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,11 +176,13 @@ describe('SubmissionSubscriptionService', () => {
).to.be.true
})

it('should call handleJudgeError when CompileError or ServerError detected', async () => {
it('should call handleJudgeError when ServerError detected', async () => {
const handlerSpy = sandbox.stub(service, 'handleJudgeError').resolves()

const updateSpy = sandbox
.stub(service, 'updateTestcaseJudgeResult')
.resolves()
const serverErrMsg = {
resultCode: 8,
resultCode: 9,
submissionId: 1,
error: '',
judgeResult
Expand All @@ -189,6 +191,25 @@ describe('SubmissionSubscriptionService', () => {
await service.handleJudgerMessage(serverErrMsg)
expect(handlerSpy.calledOnceWith(ResultStatus.ServerError, serverErrMsg))
.to.be.true
expect(updateSpy.notCalled).to.be.true
})

it('should call handleJudgeError when CompileError detected', async () => {
const handlerSpy = sandbox.stub(service, 'handleJudgeError').resolves()
const updateSpy = sandbox
.stub(service, 'updateTestcaseJudgeResult')
.resolves()
const serverErrMsg = {
resultCode: 6,
submissionId: 1,
error: '',
judgeResult
}

await service.handleJudgerMessage(serverErrMsg)
expect(handlerSpy.calledOnceWith(ResultStatus.CompileError, serverErrMsg))
.to.be.true
expect(updateSpy.notCalled).to.be.true
})
})

Expand Down
4 changes: 2 additions & 2 deletions apps/backend/libs/constants/src/submission.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ export const Status = (code: number) => {
return ResultStatus.CompileError
case 7: // TESTCASE_ERROR
return ResultStatus.ServerError
case 8: // SERVER_ERROR
return ResultStatus.ServerError
case 8: // Segmentation Fault
return ResultStatus.SegmentationFaultError
default:
return ResultStatus.ServerError
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterEnum
ALTER TYPE "ResultStatus" ADD VALUE 'SegmentationFaultError';
3 changes: 2 additions & 1 deletion apps/backend/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ model Problem {
/// "locked": boolean
/// }[]
/// }
template Json[] @default([])
languages Language[]
timeLimit Int @map("time_limit") // unit: MilliSeconds
Expand Down Expand Up @@ -435,6 +435,7 @@ enum ResultStatus {
MemoryLimitExceeded
OutputLimitExceeded
ServerError
SegmentationFaultError
}

model CodeDraft {
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/app/(main)/_components/ContestCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default function ContestCard({ contest }: Props) {
)}
>
<StatusBadge variant={contest.status} />
<div className="line-clamp-4 h-24 text-ellipsis whitespace-pre-wrap text-lg font-semibold leading-tight text-black min-[400px]:line-clamp-2 min-[400px]:h-12">
<div className="line-clamp-4 text-ellipsis whitespace-pre-wrap text-lg font-semibold leading-tight text-black min-[400px]:line-clamp-2">
{contest.title}
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/app/(main)/_components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import NavLink from './NavLink'
export default async function Header() {
const session = await auth()
return (
<header className="fixed left-0 z-40 grid h-16 w-full place-items-center bg-white/80">
<header className="fixed left-0 z-40 grid h-14 w-full place-items-center bg-white/80">
<div className="flex w-full max-w-7xl items-center justify-between gap-5 px-5">
{/* FIXME: If you uncomment a group tab, you have to remove a pr-20 tailwind class */}
<div className="flex min-w-fit items-center justify-between gap-8 text-[16px]">
Expand Down
Loading

0 comments on commit cb12976

Please sign in to comment.