Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package naughty.tuzamate.domain.comment.code;

import lombok.AllArgsConstructor;
import lombok.Getter;
import naughty.tuzamate.global.error.BaseErrorCode;
import org.springframework.http.HttpStatus;

@AllArgsConstructor
@Getter
public enum CommentErrorCode implements BaseErrorCode {

COMMENT_NOT_FOUND(HttpStatus.NOT_FOUND, "COMMENT404", "댓글이 존재하지 않습니다."),;

private final HttpStatus status;
private final String code;
private final String message;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import lombok.RequiredArgsConstructor;
import naughty.tuzamate.auth.principal.PrincipalDetails;
import naughty.tuzamate.domain.comment.code.CommentErrorCode;
import naughty.tuzamate.domain.comment.converter.CommentConverter;
import naughty.tuzamate.domain.comment.dto.CommentReqDTO;
import naughty.tuzamate.domain.comment.dto.CommentResDTO;
Expand All @@ -10,6 +11,7 @@
import naughty.tuzamate.domain.comment.service.FCMService;
import naughty.tuzamate.domain.notification.entity.Notification;
import naughty.tuzamate.domain.notification.service.NotificationService;
import naughty.tuzamate.domain.post.code.PostErrorCode;
import naughty.tuzamate.domain.post.entity.Post;
import naughty.tuzamate.domain.post.repository.PostRepository;
import naughty.tuzamate.domain.user.entity.User;
Expand All @@ -35,16 +37,16 @@ public CommentResDTO.CreateCommentResponseDTO createComment(
CommentReqDTO.CreateCommentRequestDTO reqDTO, Long postId, PrincipalDetails principalDetails
) {
User commentWriter = userRepository.findById(principalDetails.getId())
.orElseThrow(() -> new CustomException(GeneralErrorCode.NOT_FOUND_404));
.orElseThrow(() -> new CustomException(CommentErrorCode.COMMENT_NOT_FOUND));

Post post = postRepository.findById(postId)
.orElseThrow(() -> new CustomException(GeneralErrorCode.NOT_FOUND_404));
.orElseThrow(() -> new CustomException(PostErrorCode.POST_NOT_FOUND));

Comment parent = null;

if (reqDTO.parentId() != null) {
parent = commentRepository.findById(reqDTO.parentId())
.orElseThrow(() -> new CustomException(GeneralErrorCode.NOT_FOUND_404));
.orElseThrow(() -> new CustomException(CommentErrorCode.COMMENT_NOT_FOUND));
}
Comment on lines 47 to 50
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Validate that parent comment belongs to the same post to prevent cross-post replies.

Without this check, a reply can be attached to a parent from a different post, creating inconsistent data.

Apply this diff:

         if (reqDTO.parentId() != null) {
             parent = commentRepository.findById(reqDTO.parentId())
                     .orElseThrow(() -> new CustomException(CommentErrorCode.COMMENT_NOT_FOUND));
+            // Ensure the parent comment belongs to the same post
+            if (!parent.getPost().getId().equals(postId)) {
+                throw new CustomException(GeneralErrorCode.BAD_REQUEST_400);
+            }
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (reqDTO.parentId() != null) {
parent = commentRepository.findById(reqDTO.parentId())
.orElseThrow(() -> new CustomException(GeneralErrorCode.NOT_FOUND_404));
.orElseThrow(() -> new CustomException(CommentErrorCode.COMMENT_NOT_FOUND));
}
if (reqDTO.parentId() != null) {
parent = commentRepository.findById(reqDTO.parentId())
.orElseThrow(() -> new CustomException(CommentErrorCode.COMMENT_NOT_FOUND));
// Ensure the parent comment belongs to the same post
if (!parent.getPost().getId().equals(postId)) {
throw new CustomException(GeneralErrorCode.BAD_REQUEST_400);
}
}
🤖 Prompt for AI Agents
In
src/main/java/naughty/tuzamate/domain/comment/service/command/CommentCommandServiceImpl.java
around lines 47 to 50, after fetching the parent comment add a validation that
the parent’s postId matches reqDTO.postId(); if it does not, throw a suitable
CustomException (e.g. CommentErrorCode.INVALID_PARENT_COMMENT or another
existing error code for invalid parent) to prevent attaching replies to a parent
from a different post. Ensure the check runs only when parentId is non-null and
use the parent object's postId getter and reqDTO.postId() for comparison.


Comment comment = CommentConverter.toComment(reqDTO, commentWriter, post, parent);
Expand Down Expand Up @@ -99,7 +101,7 @@ public CommentResDTO.UpdateCommentResponseDTO updateComment(
PrincipalDetails principalDetails
) {
Comment comment = commentRepository.findById(commentId)
.orElseThrow(() -> new CustomException(GeneralErrorCode.NOT_FOUND_404));
.orElseThrow(() -> new CustomException(CommentErrorCode.COMMENT_NOT_FOUND));

if (!comment.getUser().getId().equals(principalDetails.getUser().getId())) {
throw new CustomException(GeneralErrorCode.FORBIDDEN_403); // 권한 없음
Expand All @@ -113,7 +115,7 @@ public CommentResDTO.UpdateCommentResponseDTO updateComment(
@Override
public CommentResDTO.DeleteCommentResponseDTO deleteComment(Long commentId, PrincipalDetails principalDetails) {
Comment comment = commentRepository.findById(commentId)
.orElseThrow(() -> new CustomException(GeneralErrorCode.NOT_FOUND_404));
.orElseThrow(() -> new CustomException(CommentErrorCode.COMMENT_NOT_FOUND));

if (!comment.getUser().getId().equals(principalDetails.getUser().getId())) {
throw new CustomException(GeneralErrorCode.FORBIDDEN_403);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package naughty.tuzamate.domain.comment.service.query;

import lombok.RequiredArgsConstructor;
import naughty.tuzamate.domain.comment.code.CommentErrorCode;
import naughty.tuzamate.domain.comment.converter.CommentConverter;
import naughty.tuzamate.domain.comment.dto.CommentResDTO;
import naughty.tuzamate.domain.comment.entity.Comment;
Expand All @@ -27,7 +28,7 @@ public class CommentQueryServiceImpl implements CommentQueryService {
@Override
public CommentResDTO.CommentPreviewDTO getComment(Long commentId) {
Comment comment = commentRepository.findById(commentId)
.orElseThrow(() -> new CustomException(GeneralErrorCode.NOT_FOUND_404));
.orElseThrow(() -> new CustomException(CommentErrorCode.COMMENT_NOT_FOUND));

return CommentConverter.toCommentPreviewDTO(comment, List.of());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package naughty.tuzamate.domain.notification.code;

import lombok.AllArgsConstructor;
import lombok.Getter;
import naughty.tuzamate.global.error.BaseErrorCode;
import org.springframework.http.HttpStatus;

@AllArgsConstructor
@Getter
public enum NotificationErrorCode implements BaseErrorCode {

NOTIFICATION_NOT_FOUND(HttpStatus.NOT_FOUND, "NOTIFICATIONT404", "알림이 존재하지 않습니다."),;

private final HttpStatus status;
private final String code;
private final String message;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package naughty.tuzamate.domain.notification.service;

import lombok.RequiredArgsConstructor;
import naughty.tuzamate.domain.notification.code.NotificationErrorCode;
import naughty.tuzamate.domain.notification.converter.NotificationConverter;
import naughty.tuzamate.domain.notification.dto.NotificationResDTO;
import naughty.tuzamate.domain.notification.entity.Notification;
Expand Down Expand Up @@ -58,7 +59,7 @@ public NotificationResDTO.NotificationCursorResDTO getNotificationList(Long user
// 단일 알림 조회(이미 읽은 알림을 다시 읽는 경우)
public NotificationResDTO.toNotificationResDTO getNotification(Long notificationId, Long userId) {
Notification notification = notificationRepository.findByIdAndReceiverId(notificationId, userId)
.orElseThrow(() -> new CustomException(GeneralErrorCode.NOT_FOUND_404));
.orElseThrow(() -> new CustomException(NotificationErrorCode.NOTIFICATION_NOT_FOUND));

return NotificationConverter.toNotificationDTO(notification);
}
Expand All @@ -67,7 +68,7 @@ public NotificationResDTO.toNotificationResDTO getNotification(Long notification
@Transactional
public NotificationResDTO.toNotificationResDTO updateIsRead(Long notificationId, Long userId) {
Notification notification = notificationRepository.findByIdAndReceiverId(notificationId, userId)
.orElseThrow(() -> new CustomException(GeneralErrorCode.NOT_FOUND_404));
.orElseThrow(() -> new CustomException(NotificationErrorCode.NOTIFICATION_NOT_FOUND));

notification.updateIsRead();

Expand All @@ -77,7 +78,7 @@ public NotificationResDTO.toNotificationResDTO updateIsRead(Long notificationId,
@Transactional
public void deleteNotification(Long notificationId, Long userId) {
Notification notification = notificationRepository.findByIdAndReceiverId(notificationId, userId)
.orElseThrow(() -> new CustomException(GeneralErrorCode.NOT_FOUND_404));
.orElseThrow(() -> new CustomException(NotificationErrorCode.NOTIFICATION_NOT_FOUND));

notificationRepository.delete(notification);
}
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/naughty/tuzamate/domain/post/code/PostErrorCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package naughty.tuzamate.domain.post.code;

import lombok.AllArgsConstructor;
import lombok.Getter;
import naughty.tuzamate.global.error.BaseErrorCode;
import org.springframework.http.HttpStatus;

@AllArgsConstructor
@Getter
public enum PostErrorCode implements BaseErrorCode {

POST_NOT_FOUND(HttpStatus.NOT_FOUND, "POST404", "게시글이 존재하지 않습니다."),;

private final HttpStatus status;
private final String code;
private final String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package naughty.tuzamate.domain.post.code;

import lombok.AllArgsConstructor;
import lombok.Getter;
import naughty.tuzamate.global.success.BaseSuccessCode;
import org.springframework.http.HttpStatus;

@AllArgsConstructor
@Getter
public enum PostSuccessCode implements BaseSuccessCode {

POST_OK(HttpStatus.OK, "200", "게시글 조회에 성공했습니다."),

POST_CREATED(HttpStatus.CREATED, "201", "게시글이 생성되었습니다."),

DELETED(HttpStatus.NO_CONTENT, "204", "성공적으로 삭제되었습니다.");
Comment on lines +12 to +16
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify controller usage and 204 semantics.

Ensure PostController consistently returns PostSuccessCode and that 204 (DELETED) responses don’t include a body.

Run to verify usages and check for any remaining GeneralSuccessCode references in post controllers:


🏁 Script executed:

#!/bin/bash
# Find usages of PostSuccessCode and any remaining GeneralSuccessCode in post controllers
rg -n -C2 -g '!**/build/**' -g '!**/out/**' 'PostSuccessCode|GeneralSuccessCode' --type=java | rg -n -C2 'PostController|post'

Length of output: 9693


Align PostController Success Codes & 204 Semantics

– The deletePost endpoint (PostController#deletePost, line 82) is still using GeneralSuccessCode.OK and returning a body. Replace it with:
CustomResponse.onSuccess(PostSuccessCode.DELETED)
• Ensure the HTTP 204 response has no response body.
– The updatePost endpoint (line 71) uses GeneralSuccessCode.OK. Either switch to PostSuccessCode.POST_OK or add a dedicated POST_UPDATED code to the PostSuccessCode enum for clarity.
– Several other actions (postLike, deleteLike, postScrap, deleteScrap) also use GeneralSuccessCode; consider defining and using domain-specific success codes for likes/scraps or confirm that GeneralSuccessCode is acceptable.

Please update these endpoints to use the appropriate PostSuccessCode values and verify that 204 responses omit the body.

🤖 Prompt for AI Agents
In src/main/java/naughty/tuzamate/domain/post/code/PostSuccessCode.java around
lines 12 to 16, update and align controller usage: replace usages of
GeneralSuccessCode.OK in PostController#deletePost with
CustomResponse.onSuccess(PostSuccessCode.DELETED) and ensure the controller
returns an actual 204 with no body (e.g., ResponseEntity.noContent().build() or
equivalent), change PostController#updatePost to use a post-specific code by
either switching the response to PostSuccessCode.POST_OK or preferably add a new
enum constant POST_UPDATED in PostSuccessCode and use
CustomResponse.onSuccess(PostSuccessCode.POST_UPDATED); finally, review
endpoints postLike/deleteLike/postScrap/deleteScrap and either create and use
dedicated success codes in PostSuccessCode (e.g.,
LIKE_CREATED/LIKE_DELETED/SCRAP_CREATED/SCRAP_DELETED) or confirm
GeneralSuccessCode is acceptable, then replace usages accordingly so
domain-specific responses are consistent and 204 responses return no body.


private final HttpStatus status;
private final String code;
private final String message;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import jakarta.validation.constraints.Max;
import lombok.RequiredArgsConstructor;
import naughty.tuzamate.auth.principal.PrincipalDetails;
import naughty.tuzamate.domain.post.code.PostSuccessCode;
import naughty.tuzamate.domain.post.dto.PostReqDTO;
import naughty.tuzamate.domain.post.dto.PostResDTO;
import naughty.tuzamate.domain.post.entity.Post;
Expand Down Expand Up @@ -33,7 +34,7 @@ public CustomResponse<PostResDTO.CreatePostResponseDTO> createPost(
) {
PostResDTO.CreatePostResponseDTO resDTO = postCommandService.createPost(boardType, reqDTO, principalDetails);

return CustomResponse.onSuccess(GeneralSuccessCode.CREATED, resDTO);
return CustomResponse.onSuccess(PostSuccessCode.POST_CREATED, resDTO);
}

@GetMapping("/boards/{boardType}/posts/{postId}")
Expand All @@ -44,7 +45,7 @@ public CustomResponse<PostResDTO.PostDTO> getPost(
) {
PostResDTO.PostDTO resDTO = postQueryService.getPost(postId, principalDetails);

return CustomResponse.onSuccess(GeneralSuccessCode.OK, resDTO);
return CustomResponse.onSuccess(PostSuccessCode.POST_OK, resDTO);
}

@GetMapping("/boards/{boardType}/posts")
Expand All @@ -55,7 +56,7 @@ public CustomResponse<PostResDTO.PostPreviewListDTO> getPostList(
@RequestParam(defaultValue = "10") @Max(10) int size) {
PostResDTO.PostPreviewListDTO resDTO = postQueryService.getPostList(boardType, cursor, size);

return CustomResponse.onSuccess(GeneralSuccessCode.OK, resDTO);
return CustomResponse.onSuccess(PostSuccessCode.POST_OK, resDTO);
}

@PatchMapping("/boards/{boardType}/posts/{postId}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import lombok.RequiredArgsConstructor;
import naughty.tuzamate.auth.principal.PrincipalDetails;
import naughty.tuzamate.domain.post.code.PostErrorCode;
import naughty.tuzamate.domain.post.converter.PostConverter;
import naughty.tuzamate.domain.post.dto.PostReqDTO;
import naughty.tuzamate.domain.post.dto.PostResDTO;
Expand Down Expand Up @@ -46,7 +47,7 @@ public PostResDTO.UpdatePostResponseDTO updatePost(
) {
// reqDTO -> Post Entity, Post Entity -> resDTO
Post post = postRepository.findById(postId)
.orElseThrow(() -> new CustomException(GeneralErrorCode.NOT_FOUND_404));
.orElseThrow(() -> new CustomException(PostErrorCode.POST_NOT_FOUND));

if (!post.getUser().getId().equals(principalDetails.getUser().getId())) {
throw new CustomException(GeneralErrorCode.FORBIDDEN_403); // 권한 없음
Expand All @@ -65,7 +66,7 @@ public PostResDTO.UpdatePostResponseDTO updatePost(
@Override
public PostResDTO.DeletePostResponseDTO deletePost(Long postId, PrincipalDetails principalDetails) {
Post post = postRepository.findById(postId)
.orElseThrow(() -> new CustomException(GeneralErrorCode.NOT_FOUND_404));
.orElseThrow(() -> new CustomException(PostErrorCode.POST_NOT_FOUND));

if (!post.getUser().getId().equals(principalDetails.getUser().getId())) {
throw new CustomException(GeneralErrorCode.FORBIDDEN_403); // 권한 없음
Expand All @@ -79,7 +80,7 @@ public PostResDTO.DeletePostResponseDTO deletePost(Long postId, PrincipalDetails
@Override
public String postLike(Long postId, PrincipalDetails principalDetails) {
Post post = postRepository.findById(postId)
.orElseThrow(() -> new CustomException(GeneralErrorCode.NOT_FOUND_404));
.orElseThrow(() -> new CustomException(PostErrorCode.POST_NOT_FOUND));
User user = userRepository.findById(principalDetails.getId())
.orElseThrow(() -> new CustomException(GeneralErrorCode.NOT_FOUND_404));

Expand All @@ -102,7 +103,7 @@ public String postLike(Long postId, PrincipalDetails principalDetails) {
@Override
public String deleteLike(Long postId, PrincipalDetails principalDetails) {
Post post = postRepository.findById(postId)
.orElseThrow(() -> new CustomException(GeneralErrorCode.NOT_FOUND_404));
.orElseThrow(() -> new CustomException(PostErrorCode.POST_NOT_FOUND));
User user = userRepository.findById(principalDetails.getId())
.orElseThrow(() -> new CustomException(GeneralErrorCode.NOT_FOUND_404));

Expand All @@ -117,7 +118,7 @@ public String deleteLike(Long postId, PrincipalDetails principalDetails) {
@Override
public String postScrap(Long postId, PrincipalDetails principalDetails) {
Post post = postRepository.findById(postId)
.orElseThrow(() -> new CustomException(GeneralErrorCode.NOT_FOUND_404));
.orElseThrow(() -> new CustomException(PostErrorCode.POST_NOT_FOUND));
User user = userRepository.findById(principalDetails.getId())
.orElseThrow(() -> new CustomException(GeneralErrorCode.NOT_FOUND_404));

Expand All @@ -134,7 +135,7 @@ public String postScrap(Long postId, PrincipalDetails principalDetails) {
@Override
public String deleteScrap(Long postId, PrincipalDetails principalDetails) {
Post post = postRepository.findById(postId)
.orElseThrow(() -> new CustomException(GeneralErrorCode.NOT_FOUND_404));
.orElseThrow(() -> new CustomException(PostErrorCode.POST_NOT_FOUND));
User user = userRepository.findById(principalDetails.getId())
.orElseThrow(() -> new CustomException(GeneralErrorCode.NOT_FOUND_404));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import lombok.RequiredArgsConstructor;
import naughty.tuzamate.auth.principal.PrincipalDetails;
import naughty.tuzamate.domain.post.code.PostErrorCode;
import naughty.tuzamate.domain.post.converter.PostConverter;
import naughty.tuzamate.domain.post.dto.PostResDTO;
import naughty.tuzamate.domain.post.entity.Post;
Expand Down Expand Up @@ -33,7 +34,7 @@ public class PostQueryServiceImpl implements PostQueryService {
@Override
public PostResDTO.PostDTO getPost(Long postId, PrincipalDetails principalDetails) {
Post post = postRepository.findById(postId)
.orElseThrow(() -> new CustomException(GeneralErrorCode.NOT_FOUND_404));
.orElseThrow(() -> new CustomException(PostErrorCode.POST_NOT_FOUND));

if (!post.isRead()) {
post.setIsRead();
Expand Down
Loading