-
Notifications
You must be signed in to change notification settings - Fork 0
Feat: 특정 그룹의 카드셋 조회 API 구현 #51
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,7 +5,6 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.List; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.Set; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.checkerframework.checker.units.qual.C; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.data.domain.Page; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.data.domain.PageImpl; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.data.domain.Pageable; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -22,7 +21,6 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import lombok.RequiredArgsConstructor; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import lombok.extern.slf4j.Slf4j; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import project.flipnote.cardset.entity.CardSet; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import project.flipnote.cardset.entity.QCardSet; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import project.flipnote.cardset.entity.QCardSetMetadata; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import project.flipnote.cardset.model.CardSetInfo; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -47,6 +45,36 @@ public Page<CardSetInfo> searchByNameContainingAndCategory( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String name, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Category category, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Pageable pageable | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return searchByGroupIdAndNameContainingAndCategory(null, name, category, pageable); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public List<CardSetInfo> findAllByIdWithImageRefId(Set<Long> cardSets) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return queryFactory.select( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Projections.constructor( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CardSetInfo.class, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cardSet, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cardSet.group, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cardSet.name, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cardSet.category, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cardSet.hashtag, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cardSet.imageUrl, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| imageRef.id | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .from(cardSet) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .where(cardSet.id.in(cardSets)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .leftJoin(imageRef) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .on(imageRef.referenceType.eq(ReferenceType.CARD_SET) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .and(imageRef.referenceId.eq(cardSet.id))) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .fetch(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+52
to
+70
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @OverRide 어노테이션이 누락되었습니다. 이 메서드가 인터페이스를 구현하는 경우 + @Override
public List<CardSetInfo> findAllByIdWithImageRefId(Set<Long> cardSets) {📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public Page<CardSetInfo> searchByGroupIdAndNameContainingAndCategory( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Long groupId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String name, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Category category, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Pageable pageable | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| List<OrderSpecifier<?>> orders = new ArrayList<>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -91,7 +119,7 @@ public Page<CardSetInfo> searchByNameContainingAndCategory( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| imageRef.id | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .from(cardSet) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .where(buildCardSetSearchFilterConditions(name, category)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .where(buildCardSetSearchFilterConditions(groupId, name, category)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .leftJoin(imageRef) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .on(imageRef.referenceType.eq(ReferenceType.CARD_SET) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .and(imageRef.referenceId.eq(cardSet.id))); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -109,32 +137,12 @@ public Page<CardSetInfo> searchByNameContainingAndCategory( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Long total = queryFactory | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .select(cardSet.count()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .from(cardSet) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .where(buildCardSetSearchFilterConditions(name, category)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .where(buildCardSetSearchFilterConditions(groupId, name, category)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .fetchOne(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return new PageImpl<>(content, pageable, total != null ? total : 0L); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public List<CardSetInfo> findAllByIdWithImageRefId(Set<Long> cardSets) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return queryFactory.select( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Projections.constructor( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CardSetInfo.class, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cardSet, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cardSet.group, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cardSet.name, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cardSet.category, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cardSet.hashtag, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cardSet.imageUrl, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| imageRef.id | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .from(cardSet) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .where(cardSet.id.in(cardSets)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .leftJoin(imageRef) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .on(imageRef.referenceType.eq(ReferenceType.CARD_SET) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .and(imageRef.referenceId.eq(cardSet.id))) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .fetch(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private OrderSpecifier<?> toOrderSpecifier( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| NumberPath<?> path, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Sort.Order order | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -150,8 +158,13 @@ private BooleanExpression categoryEquals(Category category) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return category == null ? null : cardSet.category.eq(category); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private BooleanExpression[] buildCardSetSearchFilterConditions(String name, Category category) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return new BooleanExpression[]{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private BooleanExpression groupIdEquals(Long groupId) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return groupId == null ? null : cardSet.group.id.eq(groupId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private BooleanExpression[] buildCardSetSearchFilterConditions(Long groupId, String name, Category category) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return new BooleanExpression[] { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| groupIdEquals(groupId), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| nameContains(name), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| categoryEquals(category), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cardSet.publicVisible.isTrue() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -38,11 +38,9 @@ | |
| import project.flipnote.group.repository.GroupRepository; | ||
| import project.flipnote.group.repository.GroupRolePermissionRepository; | ||
| import project.flipnote.groupjoin.exception.GroupJoinErrorCode; | ||
| import project.flipnote.image.entity.Image; | ||
| import project.flipnote.image.entity.ImageMeta; | ||
| import project.flipnote.image.entity.ImageRef; | ||
| import project.flipnote.image.entity.ReferenceType; | ||
| import project.flipnote.image.exception.ImageErrorCode; | ||
| import project.flipnote.image.service.ImageRefService; | ||
| import project.flipnote.image.service.ImageService; | ||
| import project.flipnote.user.entity.UserProfile; | ||
|
|
@@ -448,6 +446,19 @@ public CursorPagingResponse<GroupInfo> findMyGroup(AuthPrinciple authPrinciple, | |
| return createGroupInfoCursorPagingResponse(req, groups); | ||
| } | ||
|
|
||
| /** | ||
| * 지정된 그룹 ID가 존재하는지 검사합니다. | ||
| * | ||
| * @param groupId 존재 여부를 확인할 그룹의 ID | ||
| * @throws BizException 그룹이 존재하지 않을 경우 발생 | ||
| * @author 윤정환 | ||
| */ | ||
| public void validateGroupExists(Long groupId) { | ||
| if (!groupRepository.existsById(groupId)) { | ||
| throw new BizException(GroupErrorCode.GROUP_NOT_FOUND); | ||
| } | ||
| } | ||
|
Comment on lines
+449
to
+460
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 소프트 삭제된 그룹에 대한 검증이 누락되었습니다. 이 메서드는 다음과 같이 수정하세요: public void validateGroupExists(Long groupId) {
- if (!groupRepository.existsById(groupId)) {
+ if (!groupRepository.existsByIdAndDeletedAtIsNull(groupId)) {
throw new BizException(GroupErrorCode.GROUP_NOT_FOUND);
}
}🤖 Prompt for AI Agents |
||
|
|
||
| //리스트 조회시 response 생성 | ||
| private CursorPagingResponse<GroupInfo> createGroupInfoCursorPagingResponse(GroupListRequest req, | ||
| List<GroupInfo> groups) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
인증 및 그룹 유효성 검증을 추가하세요.
이 엔드포인트에는 다음과 같은 보안 문제가 있습니다:
createCardSet,getCardSet,updateCardSet)과 달리@AuthenticationPrincipal어노테이션이 없어 인증되지 않은 사용자도 접근 가능합니다.groupId에 대한 검증이 없습니다.요구사항에 따라 다음 중 하나를 선택하여 적용하세요:
옵션 1: 인증된 사용자만 접근 가능하고 그룹 멤버는 비공개 카드셋도 조회 가능
@GetMapping public ResponseEntity<PagingResponse<CardSetSummaryResponse>> getCardSets( @PathVariable("groupId") Long groupId, - @Valid @ModelAttribute CardSetSearchRequest req + @Valid @ModelAttribute CardSetSearchRequest req, + @AuthenticationPrincipal AuthPrinciple authPrinciple ) { - PagingResponse<CardSetSummaryResponse> res = cardSetService.getCardSets(groupId, req); + PagingResponse<CardSetSummaryResponse> res = cardSetService.getCardSets(groupId, req, authPrinciple.userId()); return ResponseEntity.ok(res); }옵션 2: 인증 없이 공개 카드셋만 조회 가능 (현재 구현과 유사)
@GetMapping public ResponseEntity<PagingResponse<CardSetSummaryResponse>> getCardSets( @PathVariable("groupId") Long groupId, @Valid @ModelAttribute CardSetSearchRequest req ) { + // 그룹 존재 여부 검증은 서비스 레이어에서 수행되어야 함 PagingResponse<CardSetSummaryResponse> res = cardSetService.getCardSets(groupId, req); return ResponseEntity.ok(res); }서비스 레이어에서 그룹 존재 검증도 추가해야 합니다.
🤖 Prompt for AI Agents