Skip to content

Commit

Permalink
Merge branch 'main' into 1047-implement-admin-announcement-module
Browse files Browse the repository at this point in the history
  • Loading branch information
Lee-won-hyeok committed Feb 15, 2024
2 parents 63ad162 + 90dba0d commit eb22bb7
Show file tree
Hide file tree
Showing 87 changed files with 3,101 additions and 2,270 deletions.
10 changes: 7 additions & 3 deletions .github/workflows/cd-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,13 @@ jobs:
- name: Create Terraform variable file
working-directory: ./infra/deploy
run: |
echo "${{ secrets.TFVARS }}" >> terraform.tfvars
echo "${{ secrets.OAUTH_GITHUB }}" >> terraform.tfvars
echo "${{ secrets.OAUTH_KAKAO }}" >> terraform.tfvars
echo $TFVARS >> terraform.tfvars
echo $OAUTH_GITHUB >> terraform.tfvars
echo $OAUTH_KAKAO >> terraform.tfvars
env:
TFVARS: ${{ secrets.TFVARS }}
OAUTH_GITHUB: ${{ secrets.OAUTH_GITHUB }}
OAUTH_KAKAO: ${{ secrets.OAUTH_KAKAO }}

- name: Terraform Init
working-directory: ./infra/deploy
Expand Down
30 changes: 25 additions & 5 deletions backend/apps/admin/src/contest/contest.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import {
InternalServerErrorException,
Logger,
NotFoundException,
ParseBoolPipe
} from '@nestjs/common'
import { Args, Context, Int, Mutation, Query, Resolver } from '@nestjs/graphql'
import { ContestProblem } from '@generated'
import { Contest } from '@generated'
import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library'
import { AuthenticatedRequest, UseRolesGuard } from '@libs/auth'
import { OPEN_SPACE_ID } from '@libs/constants'
import {
Expand All @@ -15,6 +17,7 @@ import {
} from '@libs/exception'
import { CursorValidationPipe, GroupIDPipe, RequiredIntPipe } from '@libs/pipe'
import { ContestService } from './contest.service'
import { ContestWithParticipants } from './model/contest-with-participants.model'
import { CreateContestInput } from './model/contest.input'
import { UpdateContestInput } from './model/contest.input'
import { PublicizingRequest } from './model/publicizing-request.model'
Expand All @@ -25,7 +28,7 @@ export class ContestResolver {
private readonly logger = new Logger(ContestResolver.name)
constructor(private readonly contestService: ContestService) {}

@Query(() => [Contest])
@Query(() => [ContestWithParticipants])
async getContests(
@Args(
'take',
Expand All @@ -45,6 +48,23 @@ export class ContestResolver {
return await this.contestService.getContests(take, groupId, cursor)
}

@Query(() => ContestWithParticipants)
async getContest(
@Args('contestId', { type: () => Int }, new RequiredIntPipe('contestId'))
contestId: number
) {
try {
return await this.contestService.getContest(contestId)
} catch (error) {
if (
error instanceof PrismaClientKnownRequestError &&
error.code == 'P2025'
) {
throw new NotFoundException(error.message)
}
}
}

@Mutation(() => Contest)
async createContest(
@Args('input') input: CreateContestInput,
Expand Down Expand Up @@ -96,7 +116,7 @@ export class ContestResolver {
@Mutation(() => Contest)
async deleteContest(
@Args('groupId', { type: () => Int }, GroupIDPipe) groupId: number,
@Args('contestId', { type: () => Int }, new RequiredIntPipe('contestId'))
@Args('contestId', { type: () => Int })
contestId: number
) {
try {
Expand All @@ -119,7 +139,7 @@ export class ContestResolver {
@Mutation(() => PublicizingRequest)
async createPublicizingRequest(
@Args('groupId', { type: () => Int }, GroupIDPipe) groupId: number,
@Args('contestId', { type: () => Int }, new RequiredIntPipe('contestId'))
@Args('contestId', { type: () => Int })
contestId: number
) {
try {
Expand All @@ -142,7 +162,7 @@ export class ContestResolver {
@Mutation(() => PublicizingResponse)
@UseRolesGuard()
async handlePublicizingRequest(
@Args('contestId', { type: () => Int }, new RequiredIntPipe('contestId'))
@Args('contestId', { type: () => Int })
contestId: number,
@Args('isAccepted', ParseBoolPipe) isAccepted: boolean
) {
Expand All @@ -163,7 +183,7 @@ export class ContestResolver {
@Mutation(() => [ContestProblem])
async importProblemsToContest(
@Args('groupId', { type: () => Int }, GroupIDPipe) groupId: number,
@Args('contestId', { type: () => Int }, new RequiredIntPipe('contestId'))
@Args('contestId', { type: () => Int })
contestId: number,
@Args('problemIds', { type: () => [Int] }) problemIds: number[]
) {
Expand Down
55 changes: 49 additions & 6 deletions backend/apps/admin/src/contest/contest.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { stub } from 'sinon'
import { EntityNotExistException } from '@libs/exception'
import { PrismaService } from '@libs/prisma'
import { ContestService } from './contest.service'
import type { ContestWithParticipants } from './model/contest-with-participants.model'
import type {
CreateContestInput,
UpdateContestInput
Expand All @@ -21,21 +22,62 @@ const contestId = 1
const userId = 1
const groupId = 1
const problemId = 2
const startTime = faker.date.past()
const endTime = faker.date.future()
const createTime = faker.date.past()
const updateTime = faker.date.past()

const contest: Contest = {
id: contestId,
createdById: userId,
groupId,
title: 'title',
description: 'description',
startTime: faker.date.past(),
endTime: faker.date.future(),
startTime,
endTime,
config: {
isVisible: true,
isRankVisible: true
},
createTime: faker.date.past(),
updateTime: faker.date.past()
createTime,
updateTime
}

const contestWithCount = {
id: contestId,
createdById: userId,
groupId,
title: 'title',
description: 'description',
startTime,
endTime,
config: {
isVisible: true,
isRankVisible: true
},
createTime,
updateTime,
// eslint-disable-next-line @typescript-eslint/naming-convention
_count: {
contestRecord: 10
}
}

const contestWithParticipants: ContestWithParticipants = {
id: contestId,
createdById: userId,
groupId,
title: 'title',
description: 'description',
startTime,
endTime,
config: {
isVisible: true,
isRankVisible: true
},
createTime,
updateTime,
participants: 10
}

const group: Group = {
Expand All @@ -61,6 +103,7 @@ const problem: Problem = {
inputDescription: 'inputdescription',
outputDescription: 'outputdescription',
hint: 'hint',
isVisible: true,
template: [],
languages: ['C'],
timeLimit: 10000,
Expand Down Expand Up @@ -175,10 +218,10 @@ describe('ContestService', () => {

describe('getContests', () => {
it('should return an array of contests', async () => {
db.contest.findMany.resolves([contest])
db.contest.findMany.resolves([contestWithCount])

const res = await service.getContests(5, 2, 0)
expect(res).to.deep.equal([contest])
expect(res).to.deep.equal([contestWithParticipants])
})
})

Expand Down
37 changes: 35 additions & 2 deletions backend/apps/admin/src/contest/contest.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,44 @@ export class ContestService {
async getContests(take: number, groupId: number, cursor: number | null) {
const paginator = this.prisma.getPaginator(cursor)

return await this.prisma.contest.findMany({
const contests = await this.prisma.contest.findMany({
...paginator,
where: { groupId },
take
take,
include: {
// eslint-disable-next-line @typescript-eslint/naming-convention
_count: {
select: { contestRecord: true }
}
}
})

return contests.map((contest) => {
const { _count, ...data } = contest
return {
...data,
participants: _count.contestRecord
}
})
}

async getContest(contestId: number) {
const { _count, ...data } = await this.prisma.contest.findFirstOrThrow({
where: {
id: contestId
},
include: {
// eslint-disable-next-line @typescript-eslint/naming-convention
_count: {
select: { contestRecord: true }
}
}
})

return {
...data,
participants: _count.contestRecord
}
}

async createContest(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Field, Int, ObjectType } from '@nestjs/graphql'
import { Contest } from '@admin/@generated'

@ObjectType({ description: 'contestWithParticipants' })
export class ContestWithParticipants extends Contest {
@Field(() => Int)
participants: number
}
12 changes: 8 additions & 4 deletions backend/apps/admin/src/problem/mock/mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ export const problems: Problem[] = [
updateTime: faker.date.past(),
exposeTime: faker.date.anytime(),
inputExamples: [],
outputExamples: []
outputExamples: [],
isVisible: true
},
{
id: 2,
Expand All @@ -66,7 +67,8 @@ export const problems: Problem[] = [
updateTime: faker.date.past(),
exposeTime: faker.date.anytime(),
inputExamples: [],
outputExamples: []
outputExamples: [],
isVisible: true
}
]

Expand Down Expand Up @@ -119,7 +121,8 @@ export const importedProblems: Problem[] = [
updateTime: faker.date.past(),
exposeTime: faker.date.anytime(),
inputExamples: [],
outputExamples: []
outputExamples: [],
isVisible: true
},
{
id: 33,
Expand Down Expand Up @@ -159,6 +162,7 @@ export const importedProblems: Problem[] = [
updateTime: faker.date.past(),
exposeTime: faker.date.anytime(),
inputExamples: [],
outputExamples: []
outputExamples: [],
isVisible: true
}
]
6 changes: 6 additions & 0 deletions backend/apps/admin/src/problem/model/problem.input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ export class CreateProblemInput {
@Field(() => String, { nullable: false })
hint!: string

@Field(() => Boolean, { defaultValue: true })
isVisible!: boolean

@Field(() => [Template], { nullable: false })
template!: Array<Template>

Expand Down Expand Up @@ -115,6 +118,9 @@ export class UpdateProblemInput {
@Field(() => String, { nullable: true })
hint?: string

@Field(() => Boolean, { nullable: true })
isVisible?: boolean

@Field(() => [Template], { nullable: true })
template?: Array<Template>

Expand Down
1 change: 1 addition & 0 deletions backend/apps/admin/src/problem/problem.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ describe('ProblemService', () => {
inputDescription: problems[0].inputDescription,
outputDescription: problems[0].outputDescription,
hint: problems[0].hint,
isVisible: false,
template: problems[0].template,
languages: problems[0].languages,
timeLimit: problems[0].timeLimit,
Expand Down
18 changes: 8 additions & 10 deletions backend/apps/admin/src/problem/problem.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -550,20 +550,18 @@ export class ProblemService {
where: { id: contestId, groupId }
})

const contestProblemsToBeUpdated =
await this.prisma.contestProblem.findMany({
where: { contestId }
})
const contestProblems = await this.prisma.contestProblem.findMany({
where: { contestId }
})

if (orders.length !== contestProblemsToBeUpdated.length) {
if (orders.length !== contestProblems.length) {
throw new UnprocessableDataException(
'the len of orders and the len of contestProblem are not equal.'
'the length of orders and the length of contestProblem are not equal.'
)
}
//problemId 기준으로 오름차순 정렬
contestProblemsToBeUpdated.sort((a, b) => a.problemId - b.problemId)
const queries = contestProblemsToBeUpdated.map((record) => {
const newOrder = orders.indexOf(record.problemId) + 1

const queries = contestProblems.map((record) => {
const newOrder = orders.indexOf(record.problemId)
return this.prisma.contestProblem.update({
where: {
// eslint-disable-next-line @typescript-eslint/naming-convention
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Test, type TestingModule } from '@nestjs/testing'
import { expect } from 'chai'
import { RolesService } from '@libs/auth'
import { AnnouncementController } from './announcement.controller'
import { AnnouncementService } from './announcement.service'

describe('AnnouncementController', () => {
let controller: AnnouncementController

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [AnnouncementController],
providers: [
{ provide: AnnouncementService, useValue: {} },
{ provide: RolesService, useValue: {} }
]
}).compile()

controller = module.get<AnnouncementController>(AnnouncementController)
})

it('should be defined', () => {
expect(controller).to.be.ok
})
})
Loading

0 comments on commit eb22bb7

Please sign in to comment.