-
Notifications
You must be signed in to change notification settings - Fork 8
feat: 차단 관련 api 구현 #513
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
feat: 차단 관련 api 구현 #513
Conversation
- 커뮤니티 로직 수정 필요
- 커뮤니티 목록은 로그인하지 않더라도 보이게 수정
- 차단한 댓글이면 대댓글은 차단하지 않았더라도 보이지 않도록 함
Walkthrough
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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.
Actionable comments posted: 2
🧹 Nitpick comments (13)
src/test/java/com/example/solidconnection/community/comment/service/CommentServiceTest.java (2)
195-220: 테스트 안정성: 순서 의존성 제거 제안.
DB/정렬 조건 변화에 덜 민감하게 하려면 containsExactly 대신 containsExactlyInAnyOrder를 고려해 주세요.적용 예시:
- () -> assertThat(responses) - .extracting(PostFindCommentResponse::id) - .containsExactly(parentComment1.getId(), childComment1.getId()), + () -> assertThat(responses) + .extracting(PostFindCommentResponse::id) + .containsExactlyInAnyOrder(parentComment1.getId(), childComment1.getId()),
199-205: 오탈자(nit): 변수명 정정 권장.
parentCommen2 → parentComment2로 바꾸면 가독성이 좋아집니다.- Comment parentCommen2 = commentFixture.부모_댓글("부모 댓글2", post, user2); - Comment childComment3 = commentFixture.자식_댓글("자식 댓글1", post, user1, parentCommen2); - Comment childComment4 = commentFixture.자식_댓글("자식 댓글1", post, user1, parentCommen2); + Comment parentComment2 = commentFixture.부모_댓글("부모 댓글2", post, user2); + Comment childComment3 = commentFixture.자식_댓글("자식 댓글1", post, user1, parentComment2); + Comment childComment4 = commentFixture.자식_댓글("자식 댓글1", post, user1, parentComment2);src/main/java/com/example/solidconnection/community/post/repository/PostRepository.java (1)
19-27: NOT IN 서브쿼리 → NOT EXISTS로의 전환을 고려해 주세요.
NOT EXISTS가 널/성능 측면에서 일반적으로 더 안전합니다. (blockedId가 non-null이라면 현 구현도 문제는 없지만, EXISTS가 쿼리 플랜 상 유리한 경우가 많습니다.)- @Query(""" - SELECT p FROM Post p - WHERE p.boardCode = :boardCode - AND p.siteUserId NOT IN ( - SELECT ub.blockedId FROM UserBlock ub WHERE ub.blockerId = :siteUserId - ) - """) + @Query(""" + SELECT p FROM Post p + WHERE p.boardCode = :boardCode + AND NOT EXISTS ( + SELECT 1 FROM UserBlock ub + WHERE ub.blockerId = :siteUserId + AND ub.blockedId = p.siteUserId + ) + """) List<Post> findByBoardCodeExcludingBlockedUsers(@Param("boardCode") String boardCode, @Param("siteUserId") Long siteUserId);서비스 계층에서 siteUserId가 null일 때는 본 메서드를 호출하지 않고 findByBoardCode(...) 경로만 타는지 한 번만 확인 부탁드립니다.
src/test/java/com/example/solidconnection/siteuser/service/SiteUserServiceTest.java (1)
87-88: 1) 차단 목록 조회 테스트 정렬의 결정성 보강.
동일 초 단위 createdAt 저장 시 역순 정렬이 비결정적일 수 있어 id를 2차 정렬 키로 추가하는 것을 권합니다.아래처럼 보조 정렬 키를 추가해 주세요.
- pageable = PageRequest.of(0, 20, Sort.by(Sort.Direction.DESC, "createdAt")); + pageable = PageRequest.of( + 0, 20, + Sort.by(Sort.Order.desc("createdAt"), Sort.Order.desc("id")) + );src/main/java/com/example/solidconnection/community/board/controller/BoardController.java (1)
34-42: 2) 응답 타입을 구체화해 API 명세를 선명하게.
와일드카드 대신 제네릭 타입을 명시하면 컨트롤러 계약이 더 명확해집니다.아래처럼 변경을 제안드립니다.
- public ResponseEntity<?> findPostsByCodeAndCategory( + public ResponseEntity<List<PostListResponse>> findPostsByCodeAndCategory( ... - List<PostListResponse> postsByCodeAndPostCategory = postQueryService + List<PostListResponse> postsByCodeAndPostCategory = postQueryService .findPostsByCodeAndPostCategory(code, category, siteUserId); - return ResponseEntity.ok().body(postsByCodeAndPostCategory); + return ResponseEntity.ok(postsByCodeAndPostCategory);src/main/java/com/example/solidconnection/community/post/service/PostQueryService.java (1)
55-61: 2) 게시글 목록의 최신순 정렬 일관성 확보 필요.
todo가 남아 있듯 현재 최신순 보장이 없습니다. 리포지토리 레벨에서 createdAt DESC, id DESC 정렬을 명시해 주세요.정렬을 JPQL/Query 메서드에 명시하거나 Pageable 기본 정렬을 강제하는 방식으로 개선을 권장드립니다.
src/main/java/com/example/solidconnection/community/comment/repository/CommentRepository.java (2)
15-39: 1) NOT IN 서브쿼리 대신 NOT EXISTS로 변경해 성능·NULL 안정성 향상.
NOT IN은 NULL 포함 시 예기치 않은 결과를 낳을 수 있습니다. NOT EXISTS와 명시적 NULL 허용 조건으로 대체를 권장합니다.아래처럼 변경하면 명확하고 빠릅니다.
- @Query(value = """ - WITH RECURSIVE CommentTree AS ( - SELECT - id, parent_id, post_id, site_user_id, content, - created_at, updated_at, is_deleted, - 0 AS level, CAST(id AS CHAR(255)) AS path - FROM comment - WHERE post_id = :postId AND parent_id IS NULL - AND site_user_id NOT IN ( - SELECT blocked_id FROM user_block WHERE blocker_id = :siteUserId - ) - UNION ALL - SELECT - c.id, c.parent_id, c.post_id, c.site_user_id, c.content, - c.created_at, c.updated_at, c.is_deleted, - ct.level + 1, CONCAT(ct.path, '->', c.id) - FROM comment c - INNER JOIN CommentTree ct ON c.parent_id = ct.id - WHERE c.site_user_id NOT IN ( - SELECT blocked_id FROM user_block WHERE blocker_id = :siteUserId - ) - ) - SELECT * FROM CommentTree - ORDER BY path - """, nativeQuery = true) + @Query(value = """ + WITH RECURSIVE CommentTree AS ( + SELECT + id, parent_id, post_id, site_user_id, content, + created_at, updated_at, is_deleted, + 0 AS level, CAST(id AS CHAR(255)) AS path + FROM comment + WHERE post_id = :postId + AND parent_id IS NULL + AND ( + :siteUserId IS NULL OR NOT EXISTS ( + SELECT 1 + FROM user_block ub + WHERE ub.blocker_id = :siteUserId + AND ub.blocked_id = comment.site_user_id + ) + ) + UNION ALL + SELECT + c.id, c.parent_id, c.post_id, c.site_user_id, c.content, + c.created_at, c.updated_at, c.is_deleted, + ct.level + 1, CONCAT(ct.path, '->', c.id) + FROM comment c + INNER JOIN CommentTree ct ON c.parent_id = ct.id + WHERE ( + :siteUserId IS NULL OR NOT EXISTS ( + SELECT 1 + FROM user_block ub + WHERE ub.blocker_id = :siteUserId + AND ub.blocked_id = c.site_user_id + ) + ) + ) + SELECT * FROM CommentTree + ORDER BY path + """, nativeQuery = true)
15-39: 3) 인덱스 권장: user_block(blocker_id, blocked_id).
차단 필터가 빈번하므로 해당 복합 인덱스를 권장합니다. 성능에 큰 영향을 줍니다.src/test/java/com/example/solidconnection/siteuser/fixture/UserBlockFixtureBuilder.java (1)
17-19: 1) 빌더 재사용 패턴 명확화.
userBlock()이 새로운 빌더 인스턴스를 반환하므로 체이닝은 반드시 반환 객체에 이어서 호출해야 합니다. 의도된 사용이라면 주석으로 명시하면 가독성이 좋아집니다.src/main/java/com/example/solidconnection/siteuser/service/SiteUserService.java (2)
50-53: 1) 원시 타입 비교는 == 로 간결하게.
auto-boxing을 피하려면 Objects.equals 대신 'blockerId == blockedId'가 더 적합합니다.- if (Objects.equals(blockerId, blockedId)) { + if (blockerId == blockedId) { throw new CustomException(CANNOT_BLOCK_YOURSELF); }
63-70: 2) 차단 해제 시 사용자 존재 여부 노출 최소화.
존재하지 않는 사용자에 대해 USER_NOT_FOUND를 반환하면 사용자 열거 위험이 있습니다. 블록 관계 유무만으로 BLOCK_USER_NOT_FOUND를 반환하는 쪽이 안전합니다.정책 합의가 된다면 아래처럼 단순화하세요.
- public void cancelUserBlock(long blockerId, long blockedId) { - if (!siteUserRepository.existsById(blockedId)) { - throw new CustomException(USER_NOT_FOUND); - } - UserBlock userBlock = userBlockRepository.findByBlockerIdAndBlockedId(blockerId, blockedId) - .orElseThrow(() -> new CustomException(BLOCK_USER_NOT_FOUND)); - userBlockRepository.delete(userBlock); - } + public void cancelUserBlock(long blockerId, long blockedId) { + UserBlock userBlock = userBlockRepository.findByBlockerIdAndBlockedId(blockerId, blockedId) + .orElseThrow(() -> new CustomException(BLOCK_USER_NOT_FOUND)); + userBlockRepository.delete(userBlock); + }src/main/java/com/example/solidconnection/siteuser/controller/SiteUserController.java (1)
45-61: 2) REST 경로 일관성 소폭 개선 제안.
POST/DELETE 모두 /users/blocks/{blocked-id}로 통일하면 리소스 모델이 더 선명합니다. 응답 코드는 201(Created)/204(No Content)도 고려할 수 있습니다.src/main/java/com/example/solidconnection/siteuser/repository/UserBlockRepository.java (1)
18-26: 1) 정렬을 쿼리에 명시해 일관성 확보.
Pageable 정렬 위임도 가능하지만, createdAt DESC, id DESC를 쿼리에 고정하면 테스트/운영에서 결과가 안정적입니다.@Query(""" SELECT new com.example.solidconnection.siteuser.dto.UserBlockResponse( ub.id, ub.blockedId, su.nickname, ub.createdAt ) FROM UserBlock ub JOIN SiteUser su ON ub.blockedId = su.id WHERE ub.blockerId = :blockerId + ORDER BY ub.createdAt DESC, ub.id DESC """)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
src/main/java/com/example/solidconnection/common/exception/ErrorCode.java(2 hunks)src/main/java/com/example/solidconnection/community/board/controller/BoardController.java(1 hunks)src/main/java/com/example/solidconnection/community/comment/repository/CommentRepository.java(1 hunks)src/main/java/com/example/solidconnection/community/comment/service/CommentService.java(1 hunks)src/main/java/com/example/solidconnection/community/post/repository/PostRepository.java(1 hunks)src/main/java/com/example/solidconnection/community/post/service/PostQueryService.java(4 hunks)src/main/java/com/example/solidconnection/siteuser/controller/SiteUserController.java(2 hunks)src/main/java/com/example/solidconnection/siteuser/domain/UserBlock.java(1 hunks)src/main/java/com/example/solidconnection/siteuser/dto/UserBlockResponse.java(1 hunks)src/main/java/com/example/solidconnection/siteuser/repository/UserBlockRepository.java(1 hunks)src/main/java/com/example/solidconnection/siteuser/service/SiteUserService.java(1 hunks)src/test/java/com/example/solidconnection/community/comment/service/CommentServiceTest.java(3 hunks)src/test/java/com/example/solidconnection/community/post/service/PostQueryServiceTest.java(9 hunks)src/test/java/com/example/solidconnection/siteuser/fixture/UserBlockFixture.java(1 hunks)src/test/java/com/example/solidconnection/siteuser/fixture/UserBlockFixtureBuilder.java(1 hunks)src/test/java/com/example/solidconnection/siteuser/service/SiteUserServiceTest.java(3 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
src/test/java/com/example/solidconnection/siteuser/fixture/UserBlockFixture.java (1)
src/test/java/com/example/solidconnection/siteuser/fixture/UserBlockFixtureBuilder.java (1)
TestComponent(8-35)
src/test/java/com/example/solidconnection/siteuser/fixture/UserBlockFixtureBuilder.java (1)
src/test/java/com/example/solidconnection/siteuser/fixture/UserBlockFixture.java (1)
TestComponent(7-20)
src/main/java/com/example/solidconnection/siteuser/controller/SiteUserController.java (1)
src/main/java/com/example/solidconnection/siteuser/service/SiteUserService.java (1)
RequiredArgsConstructor(23-71)
src/main/java/com/example/solidconnection/siteuser/service/SiteUserService.java (1)
src/main/java/com/example/solidconnection/siteuser/controller/SiteUserController.java (1)
RequiredArgsConstructor(21-62)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (22)
src/main/java/com/example/solidconnection/siteuser/domain/UserBlock.java (1)
38-41: 생성자 추가 LGTM.
테스트/픽스처 용도로 깔끔하고 의도가 분명합니다.src/main/java/com/example/solidconnection/common/exception/ErrorCode.java (2)
50-50: BLOCK_USER_NOT_FOUND 추가 적절.
404 매핑과 메시지 모두 흐름에 부합합니다.
130-133: 차단 관련 에러코드 2종 추가 LGTM.
자기차단 방지/중복차단 방지에 맞는 400 매핑입니다.src/main/java/com/example/solidconnection/community/comment/service/CommentService.java (1)
39-45: siteUserId 기반 차단 필터 적용 경로 OK.
Repository 호출부에 siteUserId 전달로 차단 필터가 선반영됩니다.익명 사용자의 댓글 조회는 비범위로 보였는데, 의도적으로 로그인 사용자만 허용하는지 확인 부탁드립니다.
src/test/java/com/example/solidconnection/community/comment/service/CommentServiceTest.java (1)
60-62: 차단 픽스처 주입 LGTM.
테스트 가독성과 재사용성에 도움이 됩니다.src/test/java/com/example/solidconnection/community/post/service/PostQueryServiceTest.java (5)
60-62: 차단 픽스처 주입 LGTM.
차단 시나리오 셋업이 간결해졌습니다.
107-112: siteUserId null 인자 추가 LGTM.
비로그인 목록 조회 요구사항과 일치합니다.
131-135: 전체 카테고리 + null 사용자 시그니처 적용 확인.
기존 시나리오 보존이 잘 되었습니다.
237-259: 차단 사용자의 게시글 제외 테스트 LGTM.
단방향 차단 정책을 정확히 검증하고 있습니다.
205-208: null 사용자 케이스 유지 검증 LGTM.
기존 동작 파괴 없이 요구사항 확장이 잘 되었습니다.Also applies to: 223-226
src/test/java/com/example/solidconnection/siteuser/fixture/UserBlockFixture.java (1)
13-18: 테스트 픽스처 빌더 체인 사용 LGTM.
차단 관계 생성이 간결합니다.src/main/java/com/example/solidconnection/siteuser/dto/UserBlockResponse.java (1)
5-12: DTO 정의 LGTM.
레코드로 불변성과 직관성을 확보했습니다.src/test/java/com/example/solidconnection/siteuser/service/SiteUserServiceTest.java (1)
132-171: 2) 차단/차단해제 서비스 동작 검증 케이스 충실.
중복 차단, 자기 자신 차단, 차단 해제까지 핵심 흐름이 깔끔하게 커버됩니다. 좋은 테스트입니다.src/main/java/com/example/solidconnection/community/board/controller/BoardController.java (1)
36-41: 1) 비로그인 허용 처리(L:36)와 서비스 파라미터 전달(L:40) 적절.
@Authorizeduser(required = false)와 Long 사용으로 익명 접근을 자연스럽게 지원합니다.src/main/java/com/example/solidconnection/community/post/service/PostQueryService.java (2)
70-74: 3) 차단한 작성자의 게시글 접근 제한 로직 적합.
요구사항(차단한 사용자의 글 접근 시 예외)에 부합합니다.
49-62: 1. 메소드 호출부 점검 결과
-findPostsByCodeAndPostCategory호출부 전부에siteUserId파라미터가 정상 반영되었습니다.src/test/java/com/example/solidconnection/siteuser/fixture/UserBlockFixtureBuilder.java (1)
31-34: 2) 테스트 픽스처 구현 간결하고 적절.
엔티티 생성자와 저장까지 일관되게 캡슐화되어 재사용성이 높습니다.src/main/java/com/example/solidconnection/siteuser/service/SiteUserService.java (2)
43-48: 3) 블록 생성 흐름 적절하며 트랜잭션 경계도 타당.
유효성 검증 → 생성 → 저장 순서가 명료합니다.
27-60: 중복 차단 제약 적용 확인
- 이미 선언된 제약
UserBlock 엔티티에uk_user_block_blocker_id_blocked_id유니크 제약이 선언되어 있습니다.- 추가 제약 불필요
별도 DDL 유니크 제약 추가는 필요 없습니다.src/main/java/com/example/solidconnection/siteuser/controller/SiteUserController.java (1)
36-43: 1) 차단 목록 조회 API 시그니처와 페이징 기본값 적절.
Slice 기반 응답과 createdAt DESC 기본 정렬이 의도에 부합합니다.src/main/java/com/example/solidconnection/community/comment/repository/CommentRepository.java (1)
39-40: 시그니처 변경에 따른 호출부 점검 완료
- 호출부 일관성
- CommentService에서findCommentTreeByPostId(postId, siteUserId)호출이 올바르게 적용됨을 확인했습니다.- 누락된 호출부 없음
- 추가 검색 결과, 모든 호출부가 두 개의 파라미터를 사용하고 있습니다.src/main/java/com/example/solidconnection/siteuser/repository/UserBlockRepository.java (1)
18-26: ✅ DTO 생성자 시그니처 일치 확인
- 시그니처 점검
UserBlockResponse(long id, long blockedId, String nickname, ZonedDateTime createdAt)가 쿼리 인자(ub.id, ub.blockedId, su.nickname, ub.createdAt) 순서와 타입 모두 완벽히 일치합니다.
src/test/java/com/example/solidconnection/community/comment/service/CommentServiceTest.java
Show resolved
Hide resolved
src/test/java/com/example/solidconnection/community/post/service/PostQueryServiceTest.java
Show resolved
Hide resolved
- 인자 순서 변경
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.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/test/java/com/example/solidconnection/community/post/service/PostQueryServiceTest.java (2)
180-193: 4) 차단된 사용자의 게시글 접근 시 예외 검증 OK, 메시지 대신 코드 검증을 추천합니다.
메시지는 변경에 취약하니 가능하면 ErrorCode 기반으로 단언하면 테스트 안정성이 올라갑니다. assertThatCode 스타일은 팀 선호에 맞춰 유지하되, 아래처럼 보완해 보세요.- assertThatCode(() -> postQueryService.findPostById(user.getId(), post.getId())) - .isInstanceOf(CustomException.class) - .hasMessage(ACCESS_DENIED.getMessage()); + assertThatCode(() -> postQueryService.findPostById(user.getId(), post.getId())) + .isInstanceOf(CustomException.class) + .satisfies(throwable -> { + CustomException ex = (CustomException) throwable; + // CustomException에 errorCode 접근자가 있을 경우 권장 + assertThat(ex.getErrorCode()).isEqualTo(ACCESS_DENIED); + });가능 여부: CustomException에 getErrorCode()가 없다면 현 구현 유지 또는 hasFieldOrPropertyWithValue("errorCode", ACCESS_DENIED)로 대체를 고려해 주세요.
236-258: 5) 목록에서 차단 사용자 게시글 제외 테스트가 정확합니다.
양성/음성 케이스가 균형 있게 검증되어 회귀 방지에 유용합니다.추가 아이디어:
- 동일 쿼리에 siteUserId=null을 넘겼을 때 차단 필터가 미적용됨을 보이는 보완 테스트를 하나 더 두면 스펙이 더 선명해집니다.
고정된 식별자 파라미터(사용자(1), 사용자(2))가 다른 테스트와 충돌하지 않도록 픽스처가 고유 제약을 안전하게 처리하는지 한 번만 확인해 주세요.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/test/java/com/example/solidconnection/community/comment/service/CommentServiceTest.java(3 hunks)src/test/java/com/example/solidconnection/community/post/service/PostQueryServiceTest.java(9 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/test/java/com/example/solidconnection/community/comment/service/CommentServiceTest.java
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-25T15:53:53.382Z
Learnt from: Gyuhyeok99
PR: solid-connection/solid-connect-server#513
File: src/test/java/com/example/solidconnection/community/post/service/PostQueryServiceTest.java:180-193
Timestamp: 2025-09-25T15:53:53.382Z
Learning: Gyuhyeok99 prefers using assertThatCode() for exception testing in AssertJ tests, even when testing that exceptions are thrown. This works functionally and the user has confirmed it works well in their codebase.
Applied to files:
src/test/java/com/example/solidconnection/community/post/service/PostQueryServiceTest.java
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (3)
src/test/java/com/example/solidconnection/community/post/service/PostQueryServiceTest.java (3)
3-5: 1) 차단 시나리오용 import 추가 적절합니다.
의도와 사용처가 명확해 테스트 가독성이 좋아졌습니다.Also applies to: 8-9, 22-22
60-62: 2) UserBlockFixture 주입 OK, 픽스처 격리만 한 번 확인 부탁.
테스트 간 상태 간섭이 없도록 트랜잭션 롤백/컨테이너 리셋이 보장되는지 점검하면 좋습니다.
110-112: 3) siteUserId 인자(null) 전달 케이스 검증이 명확합니다.
비로그인/필터 미적용 시나리오를 잘 커버하고 있습니다.익명 사용자의 게시글 목록 조회 허용 변화가 API 스펙과 일치하는지(관련 컨트롤러/문서) 한 번만 교차 확인해 주세요.
Also applies to: 133-135, 205-207, 223-225
|
단방향 vs 양방향 차단 관련해서 제 생각에는 대댓글과 마찬가지로 단방향 차단이 좋다고 생각합니다 ㅎㅎ
|
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.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/main/java/com/example/solidconnection/community/comment/repository/CommentRepository.java (1)
15-39: 차단 사용자 목록 서브쿼리 재사용 제안차단 목록을 두 번 계산하면서 살짝 중복이 보입니다. 공통 CTE를 두면 읽기도 쉬워지고 차단 로직을 바꿀 때 한 군데만 수정하면 돼서 유지보수성이 올라갑니다. 작은 손질로 쾌적함을 챙겨봅시다.
- WITH RECURSIVE CommentTree AS ( + WITH RECURSIVE BlockedUsers AS ( + SELECT blocked_id FROM user_block WHERE blocker_id = :siteUserId + ), + CommentTree AS ( SELECT id, parent_id, post_id, site_user_id, content, created_at, updated_at, is_deleted, 0 AS level, CAST(id AS CHAR(255)) AS path FROM comment - WHERE post_id = :postId AND parent_id IS NULL - AND site_user_id NOT IN ( - SELECT blocked_id FROM user_block WHERE blocker_id = :siteUserId - ) + WHERE post_id = :postId AND parent_id IS NULL + AND NOT EXISTS ( + SELECT 1 FROM BlockedUsers bu WHERE bu.blocked_id = site_user_id + ) UNION ALL SELECT c.id, c.parent_id, c.post_id, c.site_user_id, c.content, c.created_at, c.updated_at, c.is_deleted, ct.level + 1, CONCAT(ct.path, '->', c.id) FROM comment c INNER JOIN CommentTree ct ON c.parent_id = ct.id - WHERE c.site_user_id NOT IN ( - SELECT blocked_id FROM user_block WHERE blocker_id = :siteUserId - ) + WHERE NOT EXISTS ( + SELECT 1 FROM BlockedUsers bu WHERE bu.blocked_id = c.site_user_id + ) )
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/main/java/com/example/solidconnection/community/comment/repository/CommentRepository.java(1 hunks)src/main/java/com/example/solidconnection/community/comment/service/CommentService.java(1 hunks)src/test/java/com/example/solidconnection/siteuser/fixture/UserBlockFixture.java(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/test/java/com/example/solidconnection/siteuser/fixture/UserBlockFixture.java (1)
src/test/java/com/example/solidconnection/siteuser/fixture/UserBlockFixtureBuilder.java (1)
TestComponent(8-35)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (2)
src/test/java/com/example/solidconnection/siteuser/fixture/UserBlockFixture.java (1)
13-18: 체이닝 빌더로 깔끔한 픽스처 구성
- 체이닝으로 깔끔한 호출 흐름이 만들어져 읽는 재미가 생겼습니다.
- 빌더 상태를 캡슐화해 다른 테스트와의 간섭 우려도 줄었다는 점이 든든합니다.
src/main/java/com/example/solidconnection/community/comment/service/CommentService.java (1)
39-57: 차단 필터 호출 변경 잘 반영되었습니다서비스 층에서 바로 차단 필터링 메서드를 호출해 흐름이 훨씬 또렷해졌습니다. 테스트만 통과하면 그대로 가도 되겠습니다.
whqtker
left a comment
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.
로직은 문제 없는 거 같아 approve하겠습니다 !!
todo 관련 코멘트도 남겼습니다
|
|
||
| public interface PostRepository extends JpaRepository<Post, Long> { | ||
|
|
||
| List<Post> findByBoardCode(String boardCode); |
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.
todo 관련해서 OrderByCreatedAtDesc 적용하면 될 거 같습니다 !
오래된 순으로 응답이 만들어지는 게 당연한 로직이었네요 ...
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.
앗 이건 일부로 적용 안했습니다! 차단기능 바로 상용 나갈건데 이러면 프론트 강제배포가 필요해서요!
서버만 먼저 나가면 오래된순으로 보이는 문제가 발생할 거 같습니다..
왜 아무도 몰랐을까요 🥲
인성님이 작업해주실테니 그때 수정해서 프론트랑 같이 배포나가면 좋을 거 같습니다! @Hexeong
| SELECT ub.blockedId FROM UserBlock ub WHERE ub.blockerId = :siteUserId | ||
| ) | ||
| """) | ||
| List<Post> findByBoardCodeExcludingBlockedUsers(@Param("boardCode") String boardCode, @Param("siteUserId") Long siteUserId); |
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.
여기도 todo 관련해서 order by p.createAt desc 뒤에 붙이면 정렬될 거 같습니다
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.
위에 말씀드린 것과 같은 이야기입니다!
| boolean isBlockedByMe = userBlockRepository.existsByBlockerIdAndBlockedId(siteUserId, post.getSiteUserId()); | ||
| if (isBlockedByMe) { | ||
| throw new CustomException(ACCESS_DENIED); | ||
| } |
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.
개인적으론 별도의 validate 메서드로 분리하는 것이 더 좋을 거 같습니다 ! 해당 메서드의 핵심은 id 로 게시글 조회라서요.
또한 findPostById 메서드에서 isBlockedByMe 가 재사용되지 않으므로 existsByBlockerIdAndBlockedId 메서드 리턴 값을 변수로 빼는 것 대신 바로 if 문 안에 넣어도 좋을 거 같습니다 !
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.
좋습니다~ 변수 제거하고 validate 메서드로 수정했습니다! d6331ba
| () -> assertThat(responses) | ||
| .extracting(PostFindCommentResponse::id) | ||
| .doesNotContain(childComment2.getId(), parentCommen2.getId(), childComment3.getId(), childComment4.getId())) | ||
| ; |
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.
엇 세미콜론 올려주세요 !!!
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.
- 불필요한 지역변수 제거
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.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/main/java/com/example/solidconnection/community/post/service/PostQueryService.java (1)
126-130: 2. 메서드 네이밍 조정 제안현재 이름은 과거형으로 읽혀서 검증 메서드임을 바로 파악하기 어렵습니다. 예를 들어
validateNotBlockedByMe정도로 바꾸면 의도가 더 분명해질 듯합니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/main/java/com/example/solidconnection/community/post/service/PostQueryService.java(5 hunks)src/test/java/com/example/solidconnection/community/comment/service/CommentServiceTest.java(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/test/java/com/example/solidconnection/community/comment/service/CommentServiceTest.java
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (1)
src/main/java/com/example/solidconnection/community/post/service/PostQueryService.java (1)
55-60: 1. 게시글 목록 차단 필터링이 잘 연결됐습니다로그인 사용자에 대해서만 차단 대상 사용자를 배제하도록 분기 처리한 부분이 명확합니다. 기존 흐름도 그대로 유지되어 안정적으로 보입니다.

관련 이슈
작업 내용
차단 관련 API를 구현하였습니다.
급하게 구현을 하다보니 커밋을 완전 많이 쪼개진 못했는데 그래도 노력은 했습니다 ㅎㅎ..
그래도 커밋 따라가면 이해하기 편하실겁니다!
커뮤니티 부분은 현재 인성님이 수정해주고 계신 거 같아서 최대한 기존코드 유지하면서 로직 추가했습니다!
(커뮤니티 쪽 코드가 엄청 지저분하네요 🥲 앞으로 개선될 것이라고 생각합니다!)
관련 명세서 : https://github.com/solid-connection/api-docs/pull/51
특이 사항
만욱님의 요청으로 여기서 변경할 사항은 아니지만.. 로그인하지 않은 유저도 게시글 목록 볼 수 있게 수정했습니다!
너무 간단한 pr이 될 거 같아 그냥 같이 작업했습니다!
리뷰 요구사항 (선택)
1. 차단 api의 위치
우선 siteUser쪽에 구현했는데 괜찮은가요? 커뮤니티쪽에 구현할까도 생각했는데 추후 채팅 등 다른곳에서도 차단이 생길 수 있다고 생각해 가장 범용적으로 사용될 수 있는 siteUser쪽으로 구현했습니다.
2. 단방향 차단 vs 양방향 차단
우선은 단방향으로 본인이 차단한 유저의 게시글 및 댓글만 보이지 않게 했는데 이래도 문제 없을까요?
3. 댓글 관련 차단
여기가 가장 고민이 되었던 지점인데.. 차단한 유저의 댓글에 차단하지 않은 유저의 대댓글이 있다면 어떻게 해야할까요?
사실 2번이 간단해보여서 2번으로 구현했습니다 ㅎㅎ.. 그런데 구현하고 나니 2번도 나쁘지 않아보인다는 생각이 드네요