Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(be): implement contest participant standings #1233

Merged
merged 17 commits into from
Jan 25, 2024
Merged
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
40 changes: 37 additions & 3 deletions backend/apps/client/src/contest/contest.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,37 @@ const record: ContestRecord = {
contestId,
userId,
acceptedProblemNum: 0,
score: 0,
totalPenalty: 0,
createTime: new Date(),
updateTime: new Date()
}
const sortedContestRecordsWithUserDetail = [
{
user: {
id: 13,
username: 'user10'
},
score: 36,
totalPenalty: 720
},
{
user: {
id: 12,
username: 'user09'
},
score: 33,
totalPenalty: 660
},
{
user: {
id: 11,
username: 'user08'
},
score: 30,
totalPenalty: 600
}
]

const mockPrismaService = {
contest: {
Expand Down Expand Up @@ -330,10 +357,17 @@ describe('ContestService', () => {

it('should return contest', async () => {
mockPrismaService.contest.findUniqueOrThrow.resolves(contestDetail)

expect(await service.getContest(groupId, contestId)).to.deep.equal(
contestDetail
mockPrismaService.contestRecord.findMany.resolves(
sortedContestRecordsWithUserDetail
)

expect(await service.getContest(groupId, contestId)).to.deep.equal({
...contestDetail,
standings: sortedContestRecordsWithUserDetail.map((record, index) => ({
...record,
standing: index + 1
}))
})
})
})

Expand Down
42 changes: 37 additions & 5 deletions backend/apps/client/src/contest/contest.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,7 @@ export class ContestService {
return upcomingContest
}

async getContest(
id: number,
groupId = OPEN_SPACE_ID
): Promise<Partial<Contest>> {
async getContest(id: number, groupId = OPEN_SPACE_ID) {
const contest = await this.prisma.contest.findUniqueOrThrow({
where: {
id,
Expand All @@ -232,8 +229,43 @@ export class ContestService {
description: true
}
})
// get contest participants ranking using ContestRecord
const sortedContestRecordsWithUserDetail =
await this.prisma.contestRecord.findMany({
where: {
contestId: id
},
select: {
user: {
select: {
id: true,
username: true
}
},
score: true,
totalPenalty: true
},
orderBy: [
{
score: 'desc'
},
{
totalPenalty: 'asc'
}
]
})

return contest
const UsersWithStandingDetail = sortedContestRecordsWithUserDetail.map(
(contestRecord, index) => ({
...contestRecord,
standing: index + 1
})
)
// combine contest and sortedContestRecordsWithUserDetail
return {
...contest,
standings: UsersWithStandingDetail
}
}

async createContestRecord(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "contest_record" ADD COLUMN "score" INTEGER NOT NULL DEFAULT 0;
1 change: 1 addition & 0 deletions backend/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ model ContestRecord {
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
userId Int? @map("user_id")
acceptedProblemNum Int @default(0) @map("accepted_problem_num")
score Int @default(0)
totalPenalty Int @default(0) @map("total_penalty")
createTime DateTime @default(now()) @map("create_time")
updateTime DateTime @updatedAt @map("update_time")
Expand Down
33 changes: 32 additions & 1 deletion backend/prisma/seed.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {

Check warning on line 1 in backend/prisma/seed.ts

View workflow job for this annotation

GitHub Actions / Lint

Import "ContestRecord" is only used as types
PrismaClient,
Role,
Level,
Expand All @@ -13,7 +13,8 @@
type Submission,
type ProblemTestcase,
type Announcement,
type CodeDraft
type CodeDraft,
ContestRecord
} from '@prisma/client'
import { hash } from 'argon2'
import { readFile } from 'fs/promises'
Expand Down Expand Up @@ -1562,6 +1563,35 @@
return codeDrafts
}

const createContestRecords = async () => {
const contestRecords: ContestRecord[] = []
let i = 0
// group 1 users
const group1Users = await prisma.userGroup.findMany({
where: {
groupId: 1
}
})
for (const user of group1Users) {
const contestRecord = await prisma.contestRecord.create({
data: {
userId: user.userId,
contestId: 1,
acceptedProblemNum: user.userId,
// TODO: 아직 점수 계산 로직을 구현하지 않아서,
// 임시로 임의로 좀수와 페널티를 부여하도록 하였습니다.
// 점수 계산 로직을 구현하면 아래의 코드를 수정해주세요.
score: i < 3 ? 3 : i * 3,
totalPenalty: i * 60
}
})
contestRecords.push(contestRecord)
i++
}

return contestRecords
}

const main = async () => {
await createUsers()
await createGroups()
Expand All @@ -1572,6 +1602,7 @@
await createSubmissions()
await createAnnouncements()
await createCodeDrafts()
await createContestRecords()
}

main()
Expand Down
20 changes: 17 additions & 3 deletions collection/client/Contest/Get contest by ID/Succeed.bru
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ meta {
}

get {
url: {{baseUrl}}/contest/13
url: {{baseUrl}}/contest/1?groupId=1
body: none
auth: none
}

query {
~groupId: 2
groupId: 1
}

assert {
Expand All @@ -24,12 +24,26 @@ assert {
res("group.groupName"): isString
res("description"): isString
res("_count.contestRecord"): isNumber
res("standings[0].user.id"): isNumber
res("standings[0].user.username"): isString
res("standings[0].score"): isNumber
res("standings[0].totalPenalty"): isNumber
res("standings[0].standing"): isNumber
}

script:pre-request {
await require("./login").loginUser(req);
}

docs {
# Get Contest by ID

하나의 대회 정보를 가져옵니다.
하나의 대회 정보와 Contest 참여자 정보를 가져옵니다.
## Path

| 이름 | 타입 | 설명 |
|-----|-----|-----|
|id|Integer|Contest(대회) ID|

## Query

Expand Down
Loading