Skip to content

Commit

Permalink
fix: show submission list when not logged in (#1521)
Browse files Browse the repository at this point in the history
* fix(be): seperate contest submission controller

GET /submission에 로그인하지 않아도 접근할 수 있도록 합니다.
로그인이 필요한 contest submisison은 컨트롤러를 분리하였습니다.

* fix(be): seperate contest problem controller

사용자 정보가 필요한 contest problem 컨트롤러를 분리합니다.

* docs(be): re-write bruno for get problems & submissions

* chore(fe): rename hook files

* chore(be): allow local frontend server to request

* feat(fe): handle when request is not successful

* feat(fe): redesign locked page when submission cannot be accessed

* chore(be): declare user id in problem spec
  • Loading branch information
aintbe authored Feb 28, 2024
1 parent 49088fa commit abf6e02
Show file tree
Hide file tree
Showing 38 changed files with 747 additions and 153 deletions.
3 changes: 2 additions & 1 deletion backend/apps/client/src/contest/contest.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ export class ContestService {
}
throw error
}
/* HACK: standings 업데이트 로직 수정 후 삭제
// get contest participants ranking using ContestRecord
const sortedContestRecordsWithUserDetail =
await this.prisma.contestRecord.findMany({
Expand Down Expand Up @@ -348,10 +349,10 @@ export class ContestService {
standing: index + 1
})
)
*/
// combine contest and sortedContestRecordsWithUserDetail
return {
...contest,
standings: UsersWithStandingDetail,
canRegister
}
}
Expand Down
7 changes: 7 additions & 0 deletions backend/apps/client/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ const bootstrap = async () => {
app.useGlobalPipes(new ValidationPipe({ whitelist: true }))
app.use(cookieParser())
if (process.env.NODE_ENV !== 'production') {
app.enableCors({
origin: 'http://localhost:5525',
credentials: true,
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
allowedHeaders: ['*'],
exposedHeaders: ['Content-Type', 'Authorization', 'Email-Auth']
})
const config = new DocumentBuilder()
.setTitle('SKKU coding platform')
.setDescription('API description')
Expand Down
26 changes: 24 additions & 2 deletions backend/apps/client/src/problem/problem.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { Test, type TestingModule } from '@nestjs/testing'
import { expect } from 'chai'
import { RolesService } from '@libs/auth'
import { ProblemController } from './problem.controller'
import {
ProblemController,
ContestProblemController
} from './problem.controller'
import {
ContestProblemService,
ProblemService,
Expand All @@ -16,7 +19,6 @@ describe('ProblemController', () => {
controllers: [ProblemController],
providers: [
{ provide: ProblemService, useValue: {} },
{ provide: ContestProblemService, useValue: {} },
{ provide: WorkbookProblemService, useValue: {} },
{ provide: RolesService, useValue: {} }
]
Expand All @@ -29,3 +31,23 @@ describe('ProblemController', () => {
expect(controller).to.be.ok
})
})

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

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

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

it('should be defined', () => {
expect(controller).to.be.ok
})
})
94 changes: 69 additions & 25 deletions backend/apps/client/src/problem/problem.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import {
Logger,
NotFoundException,
Param,
Query
Query,
Req
} from '@nestjs/common'
import { Prisma } from '@prisma/client'
import { AuthNotNeededIfOpenSpace } from '@libs/auth'
import { AuthNotNeededIfOpenSpace, type AuthenticatedRequest } from '@libs/auth'
import {
EntityNotExistException,
ForbiddenAccessException
Expand All @@ -35,14 +36,12 @@ export class ProblemController {

constructor(
private readonly problemService: ProblemService,
private readonly contestProblemService: ContestProblemService,
private readonly workbookProblemService: WorkbookProblemService
) {}

@Get()
async getProblems(
@Query('groupId', GroupIDPipe) groupId: number,
@Query('contestId', IDValidationPipe) contestId: number | null,
@Query('workbookId', IDValidationPipe) workbookId: number | null,
@Query('cursor', CursorValidationPipe) cursor: number | null,
@Query('take', new DefaultValuePipe(10), new RequiredIntPipe('take'))
Expand All @@ -52,21 +51,14 @@ export class ProblemController {
@Query('search') search?: string
) {
try {
if (!contestId && !workbookId) {
if (!workbookId) {
return await this.problemService.getProblems({
cursor,
take,
groupId,
order,
search
})
} else if (contestId) {
return await this.contestProblemService.getContestProblems(
contestId,
cursor,
take,
groupId
)
}
return await this.workbookProblemService.getWorkbookProblems(
workbookId!,
Expand All @@ -76,13 +68,10 @@ export class ProblemController {
)
} catch (error) {
if (
(error instanceof Prisma.PrismaClientKnownRequestError &&
error.name === 'NotFoundError') ||
error instanceof EntityNotExistException
error instanceof Prisma.PrismaClientKnownRequestError &&
error.name === 'NotFoundError'
) {
throw new NotFoundException(error.message)
} else if (error instanceof ForbiddenAccessException) {
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
Expand All @@ -92,25 +81,80 @@ export class ProblemController {
@Get(':problemId')
async getProblem(
@Query('groupId', GroupIDPipe) groupId: number,
@Query('contestId', IDValidationPipe) contestId: number | null,
@Query('workbookId', IDValidationPipe) workbookId: number | null,
@Param('problemId', new RequiredIntPipe('problemId')) problemId: number
) {
try {
if (!contestId && !workbookId) {
if (!workbookId) {
return await this.problemService.getProblem(problemId, groupId)
} else if (contestId) {
return await this.contestProblemService.getContestProblem(
contestId,
problemId,
groupId
)
}
return await this.workbookProblemService.getWorkbookProblem(
workbookId!,
problemId,
groupId
)
} catch (error) {
if (
error instanceof Prisma.PrismaClientKnownRequestError &&
error.name === 'NotFoundError'
) {
throw new NotFoundException(error.message)
}
this.logger.error(error)
throw new InternalServerErrorException()
}
}
}

@Controller('contest/:contestId/problem')
export class ContestProblemController {
private readonly logger = new Logger(ContestProblemController.name)

constructor(private readonly contestProblemService: ContestProblemService) {}

@Get()
async getContestProblems(
@Req() req: AuthenticatedRequest,
@Param('contestId', IDValidationPipe) contestId: number,
@Query('groupId', GroupIDPipe) groupId: number,
@Query('cursor', CursorValidationPipe) cursor: number | null,
@Query('take', new DefaultValuePipe(10), new RequiredIntPipe('take'))
take: number
) {
try {
return await this.contestProblemService.getContestProblems(
contestId,
req.user.id,
cursor,
take,
groupId
)
} catch (error) {
if (
error instanceof EntityNotExistException ||
error instanceof ForbiddenAccessException
) {
throw error.convert2HTTPException()
}
this.logger.error(error)
throw new InternalServerErrorException()
}
}

@Get(':problemId')
async getContestProblem(
@Req() req: AuthenticatedRequest,
@Param('contestId', IDValidationPipe) contestId: number,
@Param('problemId', new RequiredIntPipe('problemId')) problemId: number,
@Query('groupId', GroupIDPipe) groupId: number
) {
try {
return await this.contestProblemService.getContestProblem(
contestId,
problemId,
req.user.id,
groupId
)
} catch (error) {
if (
(error instanceof Prisma.PrismaClientKnownRequestError &&
Expand Down
11 changes: 9 additions & 2 deletions backend/apps/client/src/problem/problem.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import { GroupMemberGuard, RolesModule } from '@libs/auth'
import { ContestModule } from '@client/contest/contest.module'
import { WorkbookModule } from '@client/workbook/workbook.module'
import { CodeDraftController } from './code-draft.controller'
import { ProblemController } from './problem.controller'
import {
ContestProblemController,
ProblemController
} from './problem.controller'
import { ProblemRepository } from './problem.repository'
import {
ContestProblemService,
Expand All @@ -15,7 +18,11 @@ import {

@Module({
imports: [RolesModule, ContestModule, WorkbookModule],
controllers: [ProblemController, CodeDraftController],
controllers: [
ProblemController,
ContestProblemController,
CodeDraftController
],
providers: [
ProblemService,
ContestProblemService,
Expand Down
10 changes: 0 additions & 10 deletions backend/apps/client/src/problem/problem.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,6 @@ export class ProblemRepository {
order: true,
problem: {
select: this.problemsSelectOption
},
contest: {
select: {
startTime: true
}
}
}
})
Expand Down Expand Up @@ -245,11 +240,6 @@ export class ProblemRepository {
order: true,
problem: {
select: this.problemSelectOption
},
contest: {
select: {
startTime: true
}
}
}
})
Expand Down
Loading

0 comments on commit abf6e02

Please sign in to comment.