diff --git a/src/main/java/com/leets/X/domain/post/controller/PostController.java b/src/main/java/com/leets/X/domain/post/controller/PostController.java index 365481c..e229f6e 100644 --- a/src/main/java/com/leets/X/domain/post/controller/PostController.java +++ b/src/main/java/com/leets/X/domain/post/controller/PostController.java @@ -1,20 +1,19 @@ package com.leets.X.domain.post.controller; -import com.leets.X.domain.post.domain.Post; + import com.leets.X.domain.post.dto.request.PostRequestDTO; +import com.leets.X.domain.post.dto.response.ParentPostResponseDto; import com.leets.X.domain.post.dto.response.PostResponseDto; import com.leets.X.domain.post.service.PostService; import com.leets.X.global.common.response.ResponseDto; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; import java.util.List; -import java.util.Map; -//컨트롤러에서 ResponseDto만들게끔 + @Tag(name = "POST") @RestController @RequestMapping("/api/v1/posts") @@ -23,27 +22,35 @@ public class PostController { private final PostService postService; - + // 게시물 상세 조회(자식 게시물 까지 함께 조회됨) @GetMapping("/{id}") - @Operation(summary = "게시물 ID로 조회") - public ResponseDto getPost(@PathVariable Long id) { - PostResponseDto postResponseDto = postService.getPostResponse(id); + @Operation(summary = "게시물 ID로 상세 조회") + public ResponseDto getPost(@PathVariable Long id, @AuthenticationPrincipal String email) { + PostResponseDto postResponseDto = postService.getPostResponse(id, email); return ResponseDto.response(ResponseMessage.GET_POST_SUCCESS.getCode(), ResponseMessage.GET_POST_SUCCESS.getMessage(), postResponseDto); } + // 모든 부모게시물 조회 + @GetMapping("/all") + @Operation(summary = "전체 부모 글 조회") + public ResponseDto> getAllParentPosts(@AuthenticationPrincipal String email) { + List posts = postService.getAllParentPosts(email); + return ResponseDto.response(ResponseMessage.GET_ALL_PARENT_POSTS_SUCCESS.getCode(), ResponseMessage.GET_ALL_PARENT_POSTS_SUCCESS.getMessage(), posts); + } + @GetMapping("/likes") @Operation(summary = "좋아요 수로 정렬한 게시물 조회") - public ResponseDto> getPostsSortedByLikes() { - List posts = postService.getPostsSortedByLikes(); + public ResponseDto> getPostsSortedByLikes(@AuthenticationPrincipal String email) { + List posts = postService.getPostsSortedByLikes(email); return ResponseDto.response(ResponseMessage.GET_SORTED_BY_LIKES_SUCCESS.getCode(), ResponseMessage.GET_SORTED_BY_LIKES_SUCCESS.getMessage(), posts); } @GetMapping("/latest") @Operation(summary = "최신 게시물 조회") - public ResponseDto> getLatestPosts() { - List posts = postService.getLatestPosts(); + public ResponseDto> getLatestPosts(@AuthenticationPrincipal String email) { + List posts = postService.getLatestParentPosts(email); return ResponseDto.response(ResponseMessage.GET_LATEST_POST_SUCCESS.getCode(), ResponseMessage.GET_LATEST_POST_SUCCESS.getMessage(), posts); } @@ -63,12 +70,20 @@ public ResponseDto addLike(@PathVariable Long postId, @AuthenticationPri return ResponseDto.response(ResponseMessage.ADD_LIKE_SUCCESS.getCode(), responseMessage); } + @PostMapping("/{postId}/reply") + @Operation(summary = "답글 생성") + public ResponseDto createReply(@PathVariable Long postId, @RequestBody PostRequestDTO postRequestDTO, @AuthenticationPrincipal String email) { + // 답글 생성 서비스 호출 (부모 ID를 직접 전달) + PostResponseDto postResponseDto = postService.createReply(postId, postRequestDTO, email); + return ResponseDto.response(ResponseMessage.REPLY_SUCCESS.getCode(), ResponseMessage.REPLY_SUCCESS.getMessage(), postResponseDto); + } + @DeleteMapping("/{postId}") @Operation(summary = "게시물 삭제") public ResponseDto deletePost(@PathVariable Long postId, @AuthenticationPrincipal String email) { - String responseMessage = postService.deletePost(postId, email); - return ResponseDto.response(ResponseMessage.POST_DELETED_SUCCESS.getCode(), responseMessage); + postService.deletePost(postId, email); + return ResponseDto.response(ResponseMessage.POST_DELETED_SUCCESS.getCode(), ResponseMessage.POST_DELETED_SUCCESS.getMessage()); } diff --git a/src/main/java/com/leets/X/domain/post/controller/ResponseMessage.java b/src/main/java/com/leets/X/domain/post/controller/ResponseMessage.java index 74fcfb1..d32c59d 100644 --- a/src/main/java/com/leets/X/domain/post/controller/ResponseMessage.java +++ b/src/main/java/com/leets/X/domain/post/controller/ResponseMessage.java @@ -13,7 +13,9 @@ public enum ResponseMessage { GET_LATEST_POST_SUCCESS(200, "최신 게시물 조회에 성공했습니다."), ADD_LIKE_SUCCESS(201, "좋아요가 추가되었습니다."), POST_DELETED_SUCCESS(200, "게시물이 성공적으로 삭제되었습니다."), - LIKE_CANCEL_SUCCESS(200, "좋아요가 성공적으로 취소되었습니다."); + LIKE_CANCEL_SUCCESS(200, "좋아요가 성공적으로 취소되었습니다."), + REPLY_SUCCESS(201, "답글이 생성되었습니다."), + GET_ALL_PARENT_POSTS_SUCCESS(200, "모든 게시글 조회에 성공하였습니다."); private final int code; private final String message; diff --git a/src/main/java/com/leets/X/domain/post/domain/Post.java b/src/main/java/com/leets/X/domain/post/domain/Post.java index d882a57..3516ac3 100644 --- a/src/main/java/com/leets/X/domain/post/domain/Post.java +++ b/src/main/java/com/leets/X/domain/post/domain/Post.java @@ -1,6 +1,6 @@ package com.leets.X.domain.post.domain; -import com.leets.X.domain.comment.domain.Comment; + import com.leets.X.domain.image.domain.Image; import com.leets.X.domain.like.domain.Like; import com.leets.X.domain.post.domain.enums.IsDeleted; @@ -29,6 +29,14 @@ public class Post extends BaseTimeEntity { @JoinColumn(name = "user_id") private User user; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "parent_id") + private Post parent; + + @OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE, orphanRemoval = true) + private List replies = new ArrayList<>(); //답글 리스트 + + @OneToMany(mappedBy = "post", cascade = CascadeType.REMOVE, orphanRemoval = true) private List likes = new ArrayList<>(); @@ -46,32 +54,19 @@ public class Post extends BaseTimeEntity { private LocalDateTime deletedAt; // 좋아요 수를 관리하기 위한 필드 - @Column(name = "like_count") private Long likeCount = 0L; // 기본값을 0L로 초기화하여 null을 방지 - public void incrementLikeCount() { - if (this.likeCount == null) { - this.likeCount = 1L; // null인 경우 1로 초기화 - } else { - this.likeCount++; - } + public void updateLikeCount(long newLikeCount) { + this.likeCount = newLikeCount; } - public void decrementLikeCount() { - if (this.likeCount == null || this.likeCount == 0) { - this.likeCount = 0L; // null이거나 0일 경우 0으로 유지 - } else { - this.likeCount--; - } - } public long getLikesCount() { return likeCount != null ? likeCount : 0; // null일 경우 0 반환 } - // 서비스에서 글의 상태를 삭제 상태로 바꾸기 위한 메서드 public void delete() { if (this.isDeleted == IsDeleted.ACTIVE) { // 이미 삭제 상태가 아닐 때만 변경 @@ -82,13 +77,26 @@ public void delete() { // 정적 메서드로 글 생성 public static Post create(User user, String content) { return Post.builder() - .user(user) - .content(content) - .views(0) // 기본 조회 수 - .likeCount(0L) // 좋아요 갯수 추가 - .isDeleted(IsDeleted.ACTIVE) // 기본값 ACTIVE로 설정 - .images(new ArrayList<>()) // 빈 리스트로 초기화 - .build(); - } + .user(user) + .content(content) + .views(0) // 기본 조회 수 + .likeCount(0L) // 좋아요 갯수 추가 + .isDeleted(IsDeleted.ACTIVE) // 기본값 ACTIVE로 설정 + .images(new ArrayList<>()) // 빈 리스트로 초기화 + .build(); + } + + // 정적 팩토리 메서드 + public static Post create(User user, String content, Post parent) { + return Post.builder() + .user(user) + .content(content) + .views(0) // 기본값 설정 + .likeCount(0L) // 기본값 설정 + .isDeleted(IsDeleted.ACTIVE) // 기본값 설정 + .parent(parent) // 부모 글 설정 + .build(); + + } } diff --git a/src/main/java/com/leets/X/domain/post/dto/response/CommentResponseDto.java b/src/main/java/com/leets/X/domain/post/dto/response/CommentResponseDto.java index e653121..5a68b32 100644 --- a/src/main/java/com/leets/X/domain/post/dto/response/CommentResponseDto.java +++ b/src/main/java/com/leets/X/domain/post/dto/response/CommentResponseDto.java @@ -1,17 +1,11 @@ package com.leets.X.domain.post.dto.response; import com.leets.X.domain.comment.domain.Comment; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Getter -@NoArgsConstructor -@AllArgsConstructor -public class CommentResponseDto { - private Long commentId; - private String content; +public record CommentResponseDto( + Long commentId, + String content +) { public static CommentResponseDto from(Comment comment) { return new CommentResponseDto(comment.getId(), comment.getContent()); } diff --git a/src/main/java/com/leets/X/domain/post/dto/response/ImageResponseDto.java b/src/main/java/com/leets/X/domain/post/dto/response/ImageResponseDto.java index e4b45b5..46d9266 100644 --- a/src/main/java/com/leets/X/domain/post/dto/response/ImageResponseDto.java +++ b/src/main/java/com/leets/X/domain/post/dto/response/ImageResponseDto.java @@ -1,18 +1,12 @@ package com.leets.X.domain.post.dto.response; import com.leets.X.domain.image.domain.Image; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -@Getter -@NoArgsConstructor -@AllArgsConstructor -public class ImageResponseDto { - - private Long imageId; - private String url; +public record ImageResponseDto( + Long imageId, + String url +) { public static ImageResponseDto from(Image image) { return new ImageResponseDto(image.getId(), image.getUrl()); } diff --git a/src/main/java/com/leets/X/domain/post/dto/response/ParentPostResponseDto.java b/src/main/java/com/leets/X/domain/post/dto/response/ParentPostResponseDto.java new file mode 100644 index 0000000..3ad2428 --- /dev/null +++ b/src/main/java/com/leets/X/domain/post/dto/response/ParentPostResponseDto.java @@ -0,0 +1,46 @@ +package com.leets.X.domain.post.dto.response; + +import com.leets.X.domain.post.domain.Post; +import com.leets.X.domain.post.domain.enums.IsDeleted; +import com.leets.X.domain.user.domain.User; + +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public record ParentPostResponseDto( + Long id, + String content, + Integer views, + IsDeleted isDeleted, + LocalDateTime createdAt, + PostUserResponse user, + List images, + Long likeCount, + Boolean isLikedByUser +) { + public static ParentPostResponseDto from(Post post, boolean isLikedByUser) { + return new ParentPostResponseDto( + post.getId(), + post.getContent(), + post.getViews(), + post.getIsDeleted(), + post.getCreatedAt(), + convertUser(post.getUser()), // User 변환 + convertImagesToDtoList(post), // Images 변환 + post.getLikesCount(), + isLikedByUser // 좋아요 여부 설정 + ); +} + + private static PostUserResponse convertUser(User user) { + return user != null ? PostUserResponse.from(user) : null; + } + + private static List convertImagesToDtoList(Post post) { + return post.getImages() != null ? post.getImages().stream() + .map(ImageResponseDto::from) + .collect(Collectors.toList()) : Collections.emptyList(); + } +} diff --git a/src/main/java/com/leets/X/domain/post/dto/response/PostResponseDto.java b/src/main/java/com/leets/X/domain/post/dto/response/PostResponseDto.java index 4d31e0f..274e408 100644 --- a/src/main/java/com/leets/X/domain/post/dto/response/PostResponseDto.java +++ b/src/main/java/com/leets/X/domain/post/dto/response/PostResponseDto.java @@ -1,34 +1,33 @@ package com.leets.X.domain.post.dto.response; -import com.leets.X.domain.comment.domain.Comment; -import com.leets.X.domain.image.domain.Image; +import com.leets.X.domain.like.repository.LikeRepository; import com.leets.X.domain.post.domain.Post; import com.leets.X.domain.post.domain.enums.IsDeleted; import com.leets.X.domain.user.domain.User; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; + import java.time.LocalDateTime; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; + + +public record PostResponseDto( + Long id, + String content, + Integer views, + IsDeleted isDeleted, + LocalDateTime createdAt, + PostUserResponse user, + List images, + Long likeCount, + List replies, + Boolean isLikedByUser // 좋아요 여부 확인 +) { -@Getter -@NoArgsConstructor -@AllArgsConstructor -public class PostResponseDto { - private Long id; - private String content; - private Integer views; - private IsDeleted isDeleted; - private LocalDateTime createdAt; - private PostUserResponse user; // 작성자 정보 - private List images; // 관련 이미지 리스트 - private Long likeCount; // 좋아요 개수 추가 - - public static PostResponseDto from(Post post) { + public static PostResponseDto from(Post post, boolean isLikedByUser) { return new PostResponseDto( post.getId(), post.getContent(), @@ -37,22 +36,44 @@ public static PostResponseDto from(Post post) { post.getCreatedAt(), convertUser(post.getUser()), convertImagesToDtoList(post), - post.getLikesCount() // 좋아요 개수 추가 + post.getLikesCount(), + convertRepliesToDtoList(post.getReplies()), + isLikedByUser // 서비스에서 전달된 boolean 값 사용 ); } + // 좋아요 여부를 확인하기 위한 메서드 오버로딩 + public static PostResponseDto from(Post post, User user, LikeRepository likeRepository) { + boolean isLikedByUser = user != null && likeRepository.existsByPostAndUser(post, user); // 좋아요 여부 확인 + + return new PostResponseDto( + post.getId(), + post.getContent(), + post.getViews(), + post.getIsDeleted(), + post.getCreatedAt(), + convertUser(post.getUser()), + convertImagesToDtoList(post), + post.getLikesCount(), + convertRepliesToDtoList(post.getReplies()), + isLikedByUser // 좋아요 여부를 동적으로 설정 + ); + } + + + private static List convertRepliesToDtoList(List replies) { + return replies != null ? replies.stream() + .map(reply -> PostResponseDto.from(reply, false)) // 기본적으로 isLikedByUser를 false로 설정 + .collect(Collectors.toList()) : Collections.emptyList(); + } private static PostUserResponse convertUser(User user) { return user != null ? PostUserResponse.from(user) : null; } private static List convertImagesToDtoList(Post post) { - return post.getImages().stream() + return post.getImages() != null ? post.getImages().stream() .map(ImageResponseDto::from) - .toList(); + .collect(Collectors.toList()) : Collections.emptyList(); } - - } - - diff --git a/src/main/java/com/leets/X/domain/post/dto/response/PostUserResponse.java b/src/main/java/com/leets/X/domain/post/dto/response/PostUserResponse.java index 1e92273..9e303fb 100644 --- a/src/main/java/com/leets/X/domain/post/dto/response/PostUserResponse.java +++ b/src/main/java/com/leets/X/domain/post/dto/response/PostUserResponse.java @@ -1,27 +1,18 @@ package com.leets.X.domain.post.dto.response; - - import com.leets.X.domain.user.domain.User; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -@Getter -@NoArgsConstructor -@AllArgsConstructor -public class PostUserResponse { - - private Long userId; - private String name; - private String customId; +public record PostUserResponse( + Long userId, + String name, + String customId +) { public static PostUserResponse from(User user) { return new PostUserResponse( user.getId(), user.getName(), user.getCustomId() ); - } } diff --git a/src/main/java/com/leets/X/domain/post/repository/PostRepository.java b/src/main/java/com/leets/X/domain/post/repository/PostRepository.java index f9fc584..35ecc2c 100644 --- a/src/main/java/com/leets/X/domain/post/repository/PostRepository.java +++ b/src/main/java/com/leets/X/domain/post/repository/PostRepository.java @@ -1,11 +1,27 @@ package com.leets.X.domain.post.repository; import com.leets.X.domain.post.domain.Post; +import com.leets.X.domain.post.domain.enums.IsDeleted; +import io.lettuce.core.dynamic.annotation.Param; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; import java.util.List; +import java.util.Optional; +@Repository public interface PostRepository extends JpaRepository { List findTop10ByOrderByCreatedAtDesc(); // 최신 10개 게시물 조회하기위해 구현 + + +// 부모 글만 조회하고, 자식 글은 포함하지 않음 + List findByParentIsNullAndIsDeletedOrderByCreatedAtDesc(IsDeleted isDeleted); + + // 특정 부모 글과 자식 글을 함께 조회하는 메서드 (페치 조인 자동 생성) + Optional findWithRepliesByIdAndIsDeleted(Long postId, IsDeleted isDeleted); + } + + diff --git a/src/main/java/com/leets/X/domain/post/service/PostService.java b/src/main/java/com/leets/X/domain/post/service/PostService.java index f3b892d..83a1aa3 100644 --- a/src/main/java/com/leets/X/domain/post/service/PostService.java +++ b/src/main/java/com/leets/X/domain/post/service/PostService.java @@ -2,10 +2,10 @@ import com.leets.X.domain.like.domain.Like; import com.leets.X.domain.like.repository.LikeRepository; -import com.leets.X.domain.post.controller.ResponseMessage; import com.leets.X.domain.post.domain.Post; import com.leets.X.domain.post.domain.enums.IsDeleted; import com.leets.X.domain.post.dto.request.PostRequestDTO; +import com.leets.X.domain.post.dto.response.ParentPostResponseDto; import com.leets.X.domain.post.dto.response.PostResponseDto; import com.leets.X.domain.post.dto.response.PostUserResponse; import com.leets.X.domain.post.exception.AlreadyLikedException; @@ -16,12 +16,10 @@ import com.leets.X.domain.user.domain.User; import com.leets.X.domain.user.exception.UserNotFoundException; import com.leets.X.domain.user.service.UserService; -import com.leets.X.global.common.response.ResponseDto; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.time.LocalDateTime; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; @@ -34,127 +32,149 @@ public class PostService { private final UserService userService; private final LikeRepository likeRepository; - // 게시물 ID로 조회 - public PostResponseDto getPostResponse(Long id) { - Post post = findPost(id); - // 삭제되지 않은 게시물만 조회 가능하게끔 수정 - if (post.getIsDeleted() != IsDeleted.ACTIVE) { - throw new PostNotFoundException(); - } - return PostResponseDto.from(post); + // 모든 부모 글만 조회 (자식 글 제외) + public List getAllParentPosts(String email) { + User user = userService.find(email); + + List posts = postRepository.findByParentIsNullAndIsDeletedOrderByCreatedAtDesc(IsDeleted.ACTIVE); + + return posts.stream() + .map(post -> { + boolean isLikedByUser = likeRepository.existsByPostAndUser(post, user); + return ParentPostResponseDto.from(post, isLikedByUser); + }) + .collect(Collectors.toList()); } - // 좋아요 수로 정렬한 게시물 조회 (직접 구현) + // 전체 게시물 조회 (자식 글 포함) + public PostResponseDto getPostResponse(Long id, String email) { + Post post = postRepository.findWithRepliesByIdAndIsDeleted(id, IsDeleted.ACTIVE) + .orElseThrow(PostNotFoundException::new); - public List getPostsSortedByLikes() { - List posts = postRepository.findAll(); // 모든 게시물 조회 + User user = userService.find(email); + boolean isLikedByUser = likeRepository.existsByPostAndUser(post, user); + + return PostResponseDto.from(post, isLikedByUser); + } + + // 좋아요 순으로 게시물 조회 + public List getPostsSortedByLikes(String email) { + User user = userService.find(email); + List posts = postRepository.findAll(); return posts.stream() - .filter(post -> post.getIsDeleted() == IsDeleted.ACTIVE) // ACTIVE 상태만 필터링 - .sorted(Comparator.comparing(Post::getLikesCount).reversed()) // 좋아요 수 기준으로 내림차순 정렬 - .map(PostResponseDto::from) // DTO로 변환 + .filter(post -> post.getIsDeleted() == IsDeleted.ACTIVE) + .sorted(Comparator.comparing(Post::getLikesCount).reversed()) + .map(post -> { + boolean isLikedByUser = likeRepository.existsByPostAndUser(post, user); + return PostResponseDto.from(post, isLikedByUser); + }) .collect(Collectors.toList()); } - // 최신 게시물 조회 - public List getLatestPosts() { - List posts = postRepository.findTop10ByOrderByCreatedAtDesc(); // 최신 10개 게시물 조회 - // 현재 시각 가져오기 - LocalDateTime now = LocalDateTime.now(); + // 최신 부모 글 10개 조회 (자식 글 제외) + public List getLatestParentPosts(String email) { + User user = userService.find(email); + + List posts = postRepository.findByParentIsNullAndIsDeletedOrderByCreatedAtDesc(IsDeleted.ACTIVE) + .stream() + .limit(10) + .collect(Collectors.toList()); - // 게시물을 PostResponseDto로 변환하고 정렬 return posts.stream() - .map(PostResponseDto::from) // Post 객체를 PostResponseDto로 변환 - .sorted(Comparator.comparingLong(postResponseDto -> - Math.abs(postResponseDto.getCreatedAt().until(now, java.time.temporal.ChronoUnit.SECONDS)))) // 현재 시각과의 차이를 기준으로 정렬 + .map(post -> { + boolean isLikedByUser = likeRepository.existsByPostAndUser(post, user); + return ParentPostResponseDto.from(post, isLikedByUser); + }) .collect(Collectors.toList()); } - // 글 생성 (Refactoring) + // 글 생성 @Transactional public PostResponseDto createPost(PostRequestDTO postRequestDTO, String email) { - // 이메일로 사용자 조회 - User user = userService.find(email); // JWT에서 추출한 이메일 사용 + User user = userService.find(email); if (user == null) { throw new UserNotFoundException(); } - Post post = Post.create(user, postRequestDTO.content()); // 글 생성 로직 캡슐화 + Post post = Post.create(user, postRequestDTO.content(), null); Post savedPost = postRepository.save(post); - // 저장된 게시글을 ResponseDto에 담아 반환 - return PostResponseDto.from(savedPost); + return PostResponseDto.from(savedPost, false); } - //좋아요 추가 + // 좋아요 추가 @Transactional public String addLike(Long postId, String email) { Post post = findPost(postId); User user = userService.find(email); - // 좋아요가 이미 있는지 확인 if (likeRepository.existsByPostAndUser(post, user)) { throw new AlreadyLikedException(); } - // 새로운 Like 객체 생성 및 저장 - Like newLike = new Like(post, user); - likeRepository.save(newLike); - - // 좋아요 수 증가 - post.incrementLikeCount(); - postRepository.save(post); + likeRepository.save(new Like(post, user)); + updateLikeCount(post); return "좋아요가 추가되었습니다. 현재 좋아요 수: " + post.getLikesCount(); } + // 답글 생성 + @Transactional + public PostResponseDto createReply(Long parentId, PostRequestDTO postRequestDTO, String email) { + User user = userService.find(email); + Post parentPost = findPost(parentId); + + Post reply = Post.create(user, postRequestDTO.content(), parentPost); + Post savedReply = postRepository.save(reply); + + return PostResponseDto.from(savedReply, false); + } + // 게시물 삭제 @Transactional - public String deletePost(Long postId, String email) { + public void deletePost(Long postId, String email) { Post post = findPost(postId); User user = userService.find(email); - // 게시물의 소유자인지 확인 if (!post.getUser().equals(user)) { throw new UnauthorizedPostDeletionException(); } - // 게시물 상태를 삭제 상태로 변경 - post.delete(); // delete 메서드 호출로 상태를 변경 - postRepository.save(post); // 상태 업데이트 - - return "게시물이 삭제되었습니다."; + post.delete(); } + // 좋아요 취소 @Transactional public String cancelLike(Long postId, String email) { Post post = findPost(postId); User user = userService.find(email); - // 좋아요 여부 확인 후 삭제 if (!likeRepository.existsByPostAndUser(post, user)) { - throw new NotLikedException(); // 예외로 변경 + throw new NotLikedException(); } - // Like 객체 삭제 likeRepository.deleteByPostAndUser(post, user); - - // 좋아요 수 증가 - post.decrementLikeCount(); - postRepository.save(post); // likeCount를 데이터베이스에 업데이트 + updateLikeCount(post); return "좋아요가 삭제되었습니다. 현재 좋아요 수: " + post.getLikesCount(); } - // 자주 중복되는 코드 메서드로 뽑기 + // 좋아요 수 갱신 + @Transactional + public void updateLikeCount(Post post) { + long actualLikeCount = likeRepository.countByPost(post); + post.updateLikeCount(actualLikeCount); + postRepository.save(post); + } + public Post findPost(Long postId) { return postRepository.findById(postId) - .orElseThrow(() -> new PostNotFoundException()); + .orElseThrow(PostNotFoundException::new); } - // 사용자 정보를 가져와 PostUserResponse를 반환하는 메서드 public PostUserResponse findUser(String email) { User user = userService.find(email); - return PostUserResponse.from(user); // PostUserResponse로 변환하여 반환 + return PostUserResponse.from(user); } } diff --git a/src/main/java/com/leets/X/global/auth/jwt/JwtFilter.java b/src/main/java/com/leets/X/global/auth/jwt/JwtFilter.java index fcb0c19..4f24e4f 100644 --- a/src/main/java/com/leets/X/global/auth/jwt/JwtFilter.java +++ b/src/main/java/com/leets/X/global/auth/jwt/JwtFilter.java @@ -23,7 +23,7 @@ public class JwtFilter extends OncePerRequestFilter { private final JwtProvider jwtProvider; @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,FilterChain filterChain) throws ServletException, IOException { String token = getToken(request); try { diff --git a/src/main/java/com/leets/X/global/config/RedisConfig.java b/src/main/java/com/leets/X/global/config/RedisConfig.java index 403d918..18b8af6 100644 --- a/src/main/java/com/leets/X/global/config/RedisConfig.java +++ b/src/main/java/com/leets/X/global/config/RedisConfig.java @@ -4,6 +4,7 @@ import com.leets.X.domain.chat.redis.RedisSubscriber; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index d9b001f..0af36bc 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -13,12 +13,11 @@ spring: ddl-auto: update data: redis: - host: ${REDIS_HOST} port: ${REDIS_PORT} + host: ${REDIS_HOST} mongodb: uri: mongodb://localhost:27017/testdb - x: jwt: key: ${JWT_KEY} @@ -28,5 +27,3 @@ x: refresh: expiration: ${REFRESH_EXP} header: ${REFRESH_HEAD} - -