Skip to content

Commit

Permalink
Merge branch 'main' into t939-refactor-client-notice-user-module
Browse files Browse the repository at this point in the history
  • Loading branch information
Jaehyeon1020 authored Jan 4, 2025
2 parents 76594b2 + 2cbada0 commit facbf44
Show file tree
Hide file tree
Showing 431 changed files with 12,857 additions and 10,026 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ jobs:
working-directory: ./apps/iris

- name: Lint (Node.js)
run: git diff --name-only --diff-filter=ACMRUXB origin/main | grep -E "(.ts$|.tsx$|.js$|.jsx$)" | xargs -r pnpm eslint
run: git diff --name-only --diff-filter=ACMRUXB origin/main | grep -E "(.ts$|.tsx$|.js$|.jsx$)" | grep -v 'next.config.js$' | xargs -r pnpm eslint

test-backend:
name: Test Backend
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,4 @@ coverage

*.pkg


.idea
4 changes: 2 additions & 2 deletions apps/backend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
ARG target=client
ARG app_env=production

FROM node:20.17.0-alpine AS builder
FROM node:20.18.0-alpine AS builder
ARG target

COPY . /build
Expand All @@ -19,7 +19,7 @@ RUN npx prisma generate
RUN npm run build ${target}

### PRODUCTION ###
FROM node:20.17.0-alpine
FROM node:20.18.0-alpine
ARG target
ARG app_env

Expand Down
234 changes: 61 additions & 173 deletions apps/backend/apps/admin/src/contest/contest.resolver.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,8 @@
import {
InternalServerErrorException,
Logger,
NotFoundException,
ParseBoolPipe
} from '@nestjs/common'
import { ParseBoolPipe } from '@nestjs/common'
import { Args, Context, Int, Mutation, Query, Resolver } from '@nestjs/graphql'
import { Contest, ContestProblem } from '@generated'
import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library'
import { AuthenticatedRequest, UseRolesGuard } from '@libs/auth'
import { OPEN_SPACE_ID } from '@libs/constants'
import {
ConflictFoundException,
EntityNotExistException,
UnprocessableDataException
} from '@libs/exception'
import {
CursorValidationPipe,
GroupIDPipe,
Expand All @@ -25,7 +14,7 @@ import { ContestSubmissionSummaryForUser } from './model/contest-submission-summ
import { ContestWithParticipants } from './model/contest-with-participants.model'
import { CreateContestInput } from './model/contest.input'
import { UpdateContestInput } from './model/contest.input'
import { ContestsGroupedByStatus } from './model/contests-grouped-by-status'
import { ContestsGroupedByStatus } from './model/contests-grouped-by-status.output'
import { DuplicatedContestResponse } from './model/duplicated-contest-response.output'
import { ProblemScoreInput } from './model/problem-score.input'
import { PublicizingRequest } from './model/publicizing-request.model'
Expand All @@ -34,7 +23,6 @@ import { UserContestScoreSummaryWithUserInfo } from './model/score-summary'

@Resolver(() => Contest)
export class ContestResolver {
private readonly logger = new Logger(ContestResolver.name)
constructor(private readonly contestService: ContestService) {}

@Query(() => [ContestWithParticipants])
Expand Down Expand Up @@ -62,16 +50,7 @@ export class ContestResolver {
@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)
}
}
return await this.contestService.getContest(contestId)
}

@Mutation(() => Contest)
Expand All @@ -85,105 +64,68 @@ export class ContestResolver {
groupId: number,
@Context('req') req: AuthenticatedRequest
) {
try {
return await this.contestService.createContest(
groupId,
req.user.id,
input
)
} catch (error) {
if (
error instanceof UnprocessableDataException ||
error instanceof EntityNotExistException
) {
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
}
return await this.contestService.createContest(groupId, req.user.id, input)
}

@Mutation(() => Contest)
async updateContest(
@Args('groupId', { type: () => Int }, GroupIDPipe) groupId: number,
@Args('input') input: UpdateContestInput
) {
try {
return await this.contestService.updateContest(groupId, input)
} catch (error) {
if (
error instanceof EntityNotExistException ||
error instanceof UnprocessableDataException
) {
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
}
return await this.contestService.updateContest(groupId, input)
}

@Mutation(() => Contest)
async deleteContest(
@Args('groupId', { type: () => Int }, GroupIDPipe) groupId: number,
@Args('contestId', { type: () => Int }) contestId: number
) {
try {
return await this.contestService.deleteContest(groupId, contestId)
} catch (error) {
if (error instanceof EntityNotExistException) {
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
}
return await this.contestService.deleteContest(groupId, contestId)
}

/**
* Contest의 소속 Group을 Open Space(groupId === 1)로 이동시키기 위한 요청(Publicizing Requests)들을 불러옵니다.
* @returns Publicizing Request 배열
*/
@Query(() => [PublicizingRequest])
@UseRolesGuard()
async getPublicizingRequests() {
return await this.contestService.getPublicizingRequests()
}

/**
* Contest의 소속 Group을 Open Space(groupId === 1)로 이동시키기 위한 요청(Publicizing Request)를 생성합니다.
* @param groupId Contest가 속한 Group의 ID. 이미 Open Space(groupId === 1)이 아니어야 합니다.
* @param contestId Contest의 ID
* @returns 생성된 Publicizing Request
*/
@Mutation(() => PublicizingRequest)
async createPublicizingRequest(
@Args('groupId', { type: () => Int }, GroupIDPipe) groupId: number,
@Args('contestId', { type: () => Int }) contestId: number
) {
try {
return await this.contestService.createPublicizingRequest(
groupId,
contestId
)
} catch (error) {
if (
error instanceof EntityNotExistException ||
error instanceof ConflictFoundException
) {
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
}
return await this.contestService.createPublicizingRequest(
groupId,
contestId
)
}

/**
* Contest의 소속 Group을 Open Space(groupId === 1)로 이동시키기 위한 요청(Publicizing Request)을 처리합니다.
* @param contestId Publicizing Request를 생성한 contest의 Id
* @param isAccepted 요청 수락 여부
* @returns
*/
@Mutation(() => PublicizingResponse)
@UseRolesGuard()
async handlePublicizingRequest(
@Args('contestId', { type: () => Int }) contestId: number,
@Args('isAccepted', ParseBoolPipe) isAccepted: boolean
) {
try {
return await this.contestService.handlePublicizingRequest(
contestId,
isAccepted
)
} catch (error) {
if (error instanceof EntityNotExistException) {
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
}
return await this.contestService.handlePublicizingRequest(
contestId,
isAccepted
)
}

@Mutation(() => [ContestProblem])
Expand All @@ -193,22 +135,11 @@ export class ContestResolver {
@Args('problemIdsWithScore', { type: () => [ProblemScoreInput] })
problemIdsWithScore: ProblemScoreInput[]
) {
try {
return await this.contestService.importProblemsToContest(
groupId,
contestId,
problemIdsWithScore
)
} catch (error) {
if (
error instanceof EntityNotExistException ||
error instanceof UnprocessableDataException
) {
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
}
return await this.contestService.importProblemsToContest(
groupId,
contestId,
problemIdsWithScore
)
}

@Mutation(() => [ContestProblem])
Expand All @@ -218,29 +149,18 @@ export class ContestResolver {
contestId: number,
@Args('problemIds', { type: () => [Int] }) problemIds: number[]
) {
try {
return await this.contestService.removeProblemsFromContest(
groupId,
contestId,
problemIds
)
} catch (error) {
if (
error instanceof EntityNotExistException ||
error instanceof UnprocessableDataException
) {
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
}
return await this.contestService.removeProblemsFromContest(
groupId,
contestId,
problemIds
)
}

/**
* 특정 User의 Contest 제출 내용 요약 정보를 가져옵니다.
*
* Contest Overall 페이지에서 특정 유저를 선택했을 때 사용
* https://github.com/skkuding/codedang/pull/1894
* @see https://github.com/skkuding/codedang/pull/1894
*/
@Query(() => ContestSubmissionSummaryForUser)
async getContestSubmissionSummaryByUserId(
Expand All @@ -257,18 +177,13 @@ export class ContestResolver {
@Args('cursor', { nullable: true, type: () => Int }, CursorValidationPipe)
cursor: number | null
) {
try {
return await this.contestService.getContestSubmissionSummaryByUserId(
take,
contestId,
userId,
problemId,
cursor
)
} catch (error) {
this.logger.error(error)
throw new InternalServerErrorException()
}
return await this.contestService.getContestSubmissionSummaryByUserId(
take,
contestId,
userId,
problemId,
cursor
)
}

@Mutation(() => DuplicatedContestResponse)
Expand All @@ -278,29 +193,18 @@ export class ContestResolver {
contestId: number,
@Context('req') req: AuthenticatedRequest
) {
try {
return await this.contestService.duplicateContest(
groupId,
contestId,
req.user.id
)
} catch (error) {
if (
error instanceof UnprocessableDataException ||
error instanceof EntityNotExistException
) {
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
}
return await this.contestService.duplicateContest(
groupId,
contestId,
req.user.id
)
}

/**
* Contest에 참여한 User와, 점수 요약을 함께 불러옵니다.
*
* Contest Overall 페이지의 Participants 탭의 정보
* https://github.com/skkuding/codedang/pull/2029
* @see https://github.com/skkuding/codedang/pull/2029
*/
@Query(() => [UserContestScoreSummaryWithUserInfo])
async getContestScoreSummaries(
Expand All @@ -313,34 +217,18 @@ export class ContestResolver {
@Args('searchingName', { type: () => String, nullable: true })
searchingName?: string
) {
try {
return await this.contestService.getContestScoreSummaries(
contestId,
take,
cursor,
searchingName
)
} catch (error) {
if (error instanceof EntityNotExistException) {
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
}
return await this.contestService.getContestScoreSummaries(
contestId,
take,
cursor,
searchingName
)
}

@Query(() => ContestsGroupedByStatus)
async getContestsByProblemId(
@Args('problemId', { type: () => Int }) problemId: number
) {
try {
return await this.contestService.getContestsByProblemId(problemId)
} catch (error) {
if (error instanceof EntityNotExistException) {
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
}
return await this.contestService.getContestsByProblemId(problemId)
}
}
Loading

0 comments on commit facbf44

Please sign in to comment.