Conversation
… and invitation code checks
… logic in StudyService
…sor and take parameters
…tialize in GroupService
| const tags = await this.prisma.problemTag.findMany({ | ||
| where: { | ||
| problemId: { | ||
| in: problemIds |
There was a problem hiding this comment.
problemIds가 optional이라서 undefined면 전체 ProblemTag를 조회하게 될 거 같아요! 그래 전체 태그가 그룹에 연결될지도??
| throw new EntityNotExistException('StudyGroup') | ||
| } | ||
|
|
||
| if (dto.capacity && dto.capacity < studyGroup._count.userGroup) |
There was a problem hiding this comment.
capacity가 0으로 설정되면 검증을 건너뛸거같아요! 그래서 나중에 studyinfo.update에서 capacity: 0으로 들어가면 정원이 0명이 될거같아요.
(나중에 찾아보니까 DTO 검증에서 capacity 0 검사를 하긴 하네요.)
| capacity: studyGroup.studyInfo?.capacity, | ||
| tags: studyGroup.groupTag.map((tag) => tag.tag.name), | ||
| isPublic: !studyGroup.studyInfo?.invitationCode, | ||
| isJoined: userId ? studyGroup._count.userGroup > 0 : false |
There was a problem hiding this comment.
userId가 null이면 _count에서 타입 에러 날거같아요. 아근데 삼항연산자가 뒤에 또 있긴 하네요.
There was a problem hiding this comment.
이건 그냥 해결된걸로 하시죠 ㅋㅋ 문제 없을듯
| } | ||
| }, | ||
| sharedProblems: { | ||
| connect: problemIds?.map((problmeId) => ({ id: problmeId })) |
| async deleteStudyGroup(groupId: number) { | ||
| const studyGroup = await this.prisma.group.findUnique({ | ||
| where: { | ||
| id: groupId |
There was a problem hiding this comment.
여기엔 groupType: GroupType.Study 없어도 되나요?
There was a problem hiding this comment.
사실 groupId가 unique하기 때문에 크게 문제는 없어 보이는데, 가독성을 위해서 추가해두도록 하겠습니다.
There was a problem hiding this comment.
지금은 should be defined만 확인하는데 이것도 나중에 추가되면 좋을거 같아요.
createStudyGroup: 정상 생성, problemIds 없이 생성
joinStudyGroupById: 정원 초과, 이미 가입, 초대 코드 불일치
updateStudyGroup: capacity < 현재 멤버 수
deleteStudyGroup: 존재하지 않는 그룹 삭제 시도
| async joinStudyGroupById( | ||
| @Req() req: AuthenticatedRequest, | ||
| @Param('groupId', GroupIDPipe) groupId: number, | ||
| @Query('invitation') invitation?: string |
There was a problem hiding this comment.
저도 오늘 찾아보다가 갑자기 생각난건데 초대코드는 get보다는 request body로 전달하는게 낫지 않을까요? url로 받으면 브라우저 히스토리랑 서버 로그에 기록된다고 하더라고요. 근데 초대코드가 사실 대학교 수업용으로 수업에서 뿌리는 거라 그정도로 보안에 신경써야할지는 좀 고민해봐야겠네요.
There was a problem hiding this comment.
아마 쿼리 스트링으로 받는 것 때문에 그러시는 것 같은데, 크게 문제 없지 않을까요?
브라우저 히스토리에 남아도 요청자 브라우저에만 남고, 서버 로그도 저희만 볼 수 있어서 크게 문제 없을 것 같아용
|
|
||
| @Controller('study') | ||
| export class StudyController { | ||
| private readonly logger = new Logger(StudyController.name) |
There was a problem hiding this comment.
추후에 Logging 작업 시에 사용하려고 넣어뒀습니다.
지금 당장은 사용하지 않으니깐 빼도록 할까요?
| }), | ||
| ...(problemIds && { | ||
| groupTag: { | ||
| deleteMany: {}, |
There was a problem hiding this comment.
$transaction 감싸는거 어때요? create때문에 race condition 안나려나?
There was a problem hiding this comment.
찾아보니깐 prisma 내부에서 중첩 쓰기 작업이 이루어지면 자동으로 단일 트랜잭션으로 묶어서 처리하는 것 같더라구요.
그래서 해당 부분은 문제가 되지 않을 것 같아요.
다만, updateStudyGroup 함수 상단 부분에서 studyGroup을 조회하는데 DB 조회랑 중첩 쓰기 작업 사이에 다른 요청으로 인해 DB 변경이 이루어질 경우 문제가 생길 수 있을 것 같더라구요.
| @Query('take', new DefaultValuePipe(10), new RequiredIntPipe('take')) | ||
| take: number | ||
| ) { | ||
| return await this.studyService.getStudyGroups({ |
There was a problem hiding this comment.
나중에 페이지네이션 필요할 수도 있을거같은데 GroupService.getGroups() 처럼 total도 받는것도 나쁘지 않을 것 같습니다! 물론 명세서가 커서 기반일지 오프셋 방식일지는 모르겠지만...!
| export class StudyService { | ||
| constructor(private readonly prisma: PrismaService) {} | ||
|
|
||
| async createStudyGroup(userId: number, dto: CreateStudyDto) { |
There was a problem hiding this comment.
getStudyGroups, getStudyGroup이랑 다르게 create랑 update는 raw 모델 그대로 나가는거같은데 의도된건가요?
There was a problem hiding this comment.
codedang/apps/backend/apps/client/src/group/group.service.ts
Lines 1332 to 1375 in dcf54e4
codedang/apps/backend/apps/client/src/user/user.service.ts
Lines 689 to 724 in dcf54e4
codedang/apps/backend/apps/client/src/contest/contest.service.ts
Lines 259 to 308 in dcf54e4
client 내부에 Post, Patch 요청을 찾아보니깐 대부분이 Prisma 객체를 그대로 return 하는 경우가 많이 있어서 위와 같이 구현하였습니다
There was a problem hiding this comment.
근데 형님 친절한 코드 붙여넣기 감동이네요 근데 저희 말 편하게 하면 안되나요 친해지고 싶은데~
Choi-Jung-Hyeon
left a comment
There was a problem hiding this comment.
저에게는 룩굿투미인데 도현이는 언제쯤 룩해줄까요
| capacity: studyGroup.studyInfo?.capacity, | ||
| tags: studyGroup.groupTag.map((tag) => tag.tag.name), | ||
| isPublic: !studyGroup.studyInfo?.invitationCode, | ||
| isJoined: userId ? studyGroup._count.userGroup > 0 : false |
There was a problem hiding this comment.
이건 그냥 해결된걸로 하시죠 ㅋㅋ 문제 없을듯
| export class StudyService { | ||
| constructor(private readonly prisma: PrismaService) {} | ||
|
|
||
| async createStudyGroup(userId: number, dto: CreateStudyDto) { |
| export class StudyService { | ||
| constructor(private readonly prisma: PrismaService) {} | ||
|
|
||
| async createStudyGroup(userId: number, dto: CreateStudyDto) { |
There was a problem hiding this comment.
근데 형님 친절한 코드 붙여넣기 감동이네요 근데 저희 말 편하게 하면 안되나요 친해지고 싶은데~
Description
StudyGroupmain API의 기본적인 뼈대를 구현해보았습니다.우선
StudyGroup에서 활용할 schema를 추가하고 API를 구현했습니다.Additional context
Group모델에groupTag필드를 추가하였습니다.codedang/apps/backend/prisma/schema.prisma
Lines 138 to 162 in 3072118
해당 필드는 특정 스터디 그룹에서 진행하고 있는 문제들의 태그들의 합집합으로 이루어져 있으며,
별도의 필드 없이도 Group -> Problem -> ProblemTag -> Tag.name 를 통해 얻을 수는 있습니다.
다만 위와 같이 Tag의 이름을 찾을 경우 3번의 join 연산이 StudyGroup 조회 시 필요해 DB에 너무 많은 부담이 갈 것으로 예상됩니다.
따라서, 의도적으로
Group모델 내부에groupTag필드를 추가해 Group -> GroupTag -> Tag.name 를 통해 그룹에 속한 Tag 명을 찾을 수 있도록 하였습니다.현재로서는 StudyGroup에 속한 문제 리스트가 바뀔때 마다
GroupTag를 업데이트 하도록 하는 방식을 사용했습니다.StudyGroup을 수정하는
PATCH요청에 대해UseGroupLeaderGuard를 적용했습니다.codedang/apps/backend/apps/client/src/study/study.controller.ts
Lines 60 to 67 in 3072118
현재로서는 Group의 Leader가 아닌 일반 참여자들도 StudyGroup을 수정하는 것이 가능하게 해야 할지 정해진 것이 없어, 우선은 Leader만 이
StudyGroup을 수정 및 문제를 추가 및 제거할 수 있도록 하였습니다.Before submitting the PR, please make sure you do the following
fixes #123).