diff --git a/src/main/java/meltingpot/server/comment/dto/CommentsListResponse.java b/src/main/java/meltingpot/server/comment/dto/CommentsListResponse.java index 589a6f0..dba9385 100644 --- a/src/main/java/meltingpot/server/comment/dto/CommentsListResponse.java +++ b/src/main/java/meltingpot/server/comment/dto/CommentsListResponse.java @@ -8,7 +8,6 @@ import java.time.LocalDateTime; import java.util.List; -import java.util.stream.Collectors; @Getter @AllArgsConstructor diff --git a/src/main/java/meltingpot/server/comment/service/CommentService.java b/src/main/java/meltingpot/server/comment/service/CommentService.java index 9cc4049..20c83fd 100644 --- a/src/main/java/meltingpot/server/comment/service/CommentService.java +++ b/src/main/java/meltingpot/server/comment/service/CommentService.java @@ -76,65 +76,9 @@ public ResponseCode updateComment(CommentCreateRequest updateCommentDTO, Account return ResponseCode.UPDATE_COMMENT_SUCCESS; } - - - /* 댓글 목록 불러오기 */ -// @Transactional(readOnly = true) -// public CommentsListResponse getCommentsList(Account account, Long postId, Long cursor, int pageSize) { -// List commentDetailDTOs = new ArrayList<>(); -// int count = 0; -// Long parentCursor = null; -// -// // Cursor가 자식 댓글에 해당하는 경우 처리 -// if (cursor != null) { -// // Cursor가 부모 댓글이 아닌 자식 댓글을 나타내는 경우 -// Comment childComment = commentRepository.findById(cursor).orElse(null); -// if (childComment != null && childComment.getParent() != null) { -// Comment parentComment = childComment.getParent(); -// List remainingChildren = commentRepository.findChildrenCommentsByParentId(parentComment.getId(), cursor); -// for (Comment child : remainingChildren) { -// if (count >= pageSize) break; -// commentDetailDTOs.add(CommentsListResponse.CommentDetail.from(child)); -// count++; -// } -// parentCursor = parentComment.getId(); -// -// // 만약 자식 댓글을 모두 가져왔고, 페이지가 꽉 차지 않았다면 다음 부모 댓글로 넘어감 -// if (count < pageSize && remainingChildren.size() < pageSize) { -// parentCursor = parentComment.getId(); -// } -// } else { -// parentCursor = cursor; // cursor가 부모 댓글인 경우 -// } -// } -// -// // 부모 댓글과 자식 댓글을 가져오는 처리 -// if (count < pageSize) { -// Pageable pageable = PageRequest.of(0, pageSize - count); -// List parentComments = commentRepository.findParentCommentsByPostId(postId, parentCursor, pageable); -// for (Comment parent : parentComments) { -// if (count >= pageSize) break; -// commentDetailDTOs.add(CommentsListResponse.CommentDetail.from(parent)); -// count++; -// -// List children = commentRepository.findChildrenCommentsByParentId(parent.getId(), null); -// for (Comment child : children) { -// if (count >= pageSize) break; -// commentDetailDTOs.add(CommentsListResponse.CommentDetail.from(child)); -// count++; -// } -// } -// } -// -// Long nextCursor = (count < pageSize) ? null : commentDetailDTOs.get(commentDetailDTOs.size() - 1).getCommentId(); -// boolean isLast = (count < pageSize); -// -// return CommentsListResponse.from(commentDetailDTOs,nextCursor,isLast); -// } /* 댓글 목록 불러오기 */ @Transactional(readOnly = true) public CommentsListResponse getCommentsList(Account account, Long postId, Long cursor, int pageSize) { - Post post = findPostById(postId); List commentDetailDTOs = new ArrayList<>(); int count = 0; Long parentCursor = null; @@ -234,12 +178,6 @@ private Comment findCommentById(Long commentId) { .orElseThrow(() -> new RuntimeException("댓글을 찾을 수 없습니다.")); } - - private Account findAccountById(Long accountId) { - return accountRepository.findById(accountId) - .orElseThrow(() -> new RuntimeException("사용자를 찾을 수 없습니다.")); - } - private Post findPostById(Long postId) { return postRepository.findById(postId) .orElseThrow(() -> new RuntimeException("게시물을 찾을 수 없습니다.")); diff --git a/src/main/java/meltingpot/server/domain/entity/post/Post.java b/src/main/java/meltingpot/server/domain/entity/post/Post.java index f6de4a3..0af91f4 100644 --- a/src/main/java/meltingpot/server/domain/entity/post/Post.java +++ b/src/main/java/meltingpot/server/domain/entity/post/Post.java @@ -35,6 +35,8 @@ public class Post extends BaseEntity { @Enumerated(EnumType.STRING) private PostType postType; + private Boolean isDraft; + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id") private Account account; @@ -61,4 +63,7 @@ public void setPostImages(List postImages) { .collect(Collectors.toList()); } + public void setIsDraft(boolean isDraft) { + this.isDraft = isDraft; } +} diff --git a/src/main/java/meltingpot/server/domain/repository/CommentImageRepository.java b/src/main/java/meltingpot/server/domain/repository/CommentImageRepository.java index c609778..0e0b380 100644 --- a/src/main/java/meltingpot/server/domain/repository/CommentImageRepository.java +++ b/src/main/java/meltingpot/server/domain/repository/CommentImageRepository.java @@ -1,6 +1,5 @@ package meltingpot.server.domain.repository; -import meltingpot.server.domain.entity.comment.Comment; import meltingpot.server.domain.entity.comment.CommentImage; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/src/main/java/meltingpot/server/domain/repository/CommentRepository.java b/src/main/java/meltingpot/server/domain/repository/CommentRepository.java index b0e78e6..d08670d 100644 --- a/src/main/java/meltingpot/server/domain/repository/CommentRepository.java +++ b/src/main/java/meltingpot/server/domain/repository/CommentRepository.java @@ -1,11 +1,7 @@ package meltingpot.server.domain.repository; -import aj.org.objectweb.asm.commons.Remapper; import meltingpot.server.domain.entity.Account; import meltingpot.server.domain.entity.comment.Comment; -import meltingpot.server.domain.entity.post.Post; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; import org.springframework.data.jpa.repository.JpaRepository; @@ -16,12 +12,9 @@ import java.util.Optional; public interface CommentRepository extends JpaRepository { - Page findByPostId(Long postId, Pageable pageable); Optional findById(Long id); - - @Query("SELECT c FROM Comment c WHERE c.post.id = :postId AND c.parent IS NULL AND (:parentCursor IS NULL OR c.id > :parentCursor) ORDER BY c.id ASC") List findParentCommentsByPostId(@Param("postId") Long postId, @Param("parentCursor") Long parentCursor, Pageable pageable); diff --git a/src/main/java/meltingpot/server/domain/repository/PostRepository.java b/src/main/java/meltingpot/server/domain/repository/PostRepository.java index 919f43a..65f36e0 100644 --- a/src/main/java/meltingpot/server/domain/repository/PostRepository.java +++ b/src/main/java/meltingpot/server/domain/repository/PostRepository.java @@ -1,10 +1,8 @@ package meltingpot.server.domain.repository; -import aj.org.objectweb.asm.commons.Remapper; import meltingpot.server.domain.entity.Account; import meltingpot.server.domain.entity.post.Post; import meltingpot.server.domain.entity.enums.PostType; -import org.springframework.data.domain.Page; import org.springframework.data.domain.Slice; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -14,6 +12,7 @@ import org.springframework.data.domain.Pageable; import java.util.List; +import java.util.Optional; public interface PostRepository extends JpaRepository { @@ -23,4 +22,6 @@ public interface PostRepository extends JpaRepository { Slice findAllByAccountAndDeletedAtIsNullOrderByIdDesc(Account account, Pageable page); Slice findByIdAndDeletedAtIsNull(Long id); + + Optional findByAccountAndIsDraftTrue(Account account); } diff --git a/src/main/java/meltingpot/server/post/controller/PostController.java b/src/main/java/meltingpot/server/post/controller/PostController.java index 5d917f0..a48f3b1 100644 --- a/src/main/java/meltingpot/server/post/controller/PostController.java +++ b/src/main/java/meltingpot/server/post/controller/PostController.java @@ -5,9 +5,6 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; -import meltingpot.server.domain.entity.comment.Comment; -import meltingpot.server.domain.entity.post.Post; -import meltingpot.server.domain.repository.CommentRepository; import meltingpot.server.post.dto.PostDetailResponse; import meltingpot.server.post.dto.PostsListResponse; import org.springframework.http.ResponseEntity; @@ -27,11 +24,14 @@ public class PostController { private final PostService postService; - @Operation(summary = "게시물 작성, 이미지가 없을 때는 빈 값으로 주시면 됩니다. ") + @Operation(summary = "게시물 작성", description="requestParam으로 임시저장 여부를 알려주세요." + + "이미지가 없을 때는 빈 값으로 주시면 됩니다.") @PostMapping("") - public ResponseEntity createPost( @CurrentUser Account account,@RequestBody PostCreateRequest createPostDTO) { + public ResponseEntity createPost( @CurrentUser Account account, + @RequestBody PostCreateRequest postCreateRequest, + @RequestParam boolean isDraft) { try{ - return ResponseData.toResponseEntity(postService.createPost(createPostDTO,account)); + return ResponseData.toResponseEntity(postService.createPost(postCreateRequest,account,isDraft)); }catch (NoSuchElementException e) { return ResponseData.toResponseEntity(ResponseCode.POST_CREATE_FAIL); } @@ -83,4 +83,14 @@ public ResponseEntity deletePost(@CurrentUser Account account,@Pat } } + @GetMapping("/temp-saved") + @Operation(summary = "임시저장된 글 불러오기", description = "임시저장된 글 불러오기") + public ResponseEntity> getTempPost(@CurrentUser Account account) { + try { + return ResponseData.toResponseEntity(ResponseCode.POST_DETAIL_FETCH_SUCCEESS,postService.getTempPost(account)); + } catch (NoSuchElementException e) { + return ResponseData.toResponseEntity(ResponseCode.POST_NOT_FOUND,null); + } + } + } diff --git a/src/main/java/meltingpot/server/post/dto/PostDetailResponse.java b/src/main/java/meltingpot/server/post/dto/PostDetailResponse.java index 6ae5bdf..f904d48 100644 --- a/src/main/java/meltingpot/server/post/dto/PostDetailResponse.java +++ b/src/main/java/meltingpot/server/post/dto/PostDetailResponse.java @@ -3,8 +3,6 @@ import lombok.*; import meltingpot.server.comment.dto.CommentsListResponse; import meltingpot.server.domain.entity.post.Post; -import meltingpot.server.domain.entity.post.PostImage; - import java.time.LocalDateTime; import java.util.List; import java.util.stream.Collectors; @@ -52,4 +50,19 @@ public static PostDetailResponse of(Post post, CommentsListResponse commentsList .updatedAt(post.getUpdatedAt()) .build(); } + + public static PostDetailResponse from(Post post) { + List imgData = post.getPostImages().stream() + .map(postImage -> new ImageData(postImage.getId(), postImage.getImageUrl())) + .collect(Collectors.toList()); + + return PostDetailResponse.builder() + .postId(post.getId()) + .name(post.getAccount().getName()) + .title(post.getTitle()) + .content(post.getContent()) + .imgData(imgData) + .updatedAt(post.getUpdatedAt()) + .build(); + } } diff --git a/src/main/java/meltingpot/server/post/service/PostService.java b/src/main/java/meltingpot/server/post/service/PostService.java index 4391b32..0b68194 100644 --- a/src/main/java/meltingpot/server/post/service/PostService.java +++ b/src/main/java/meltingpot/server/post/service/PostService.java @@ -4,8 +4,9 @@ import lombok.*; import java.util.ArrayList; -import java.util.Collections; import java.util.List; +import java.util.NoSuchElementException; +import java.util.Optional; import java.util.stream.Collectors; import meltingpot.server.comment.dto.CommentsListResponse; @@ -14,7 +15,6 @@ import meltingpot.server.domain.entity.post.Post; import meltingpot.server.domain.entity.enums.PostType; import meltingpot.server.domain.entity.post.PostImage; -import meltingpot.server.domain.repository.AccountRepository; import meltingpot.server.domain.repository.CommentRepository; import meltingpot.server.domain.repository.PostImageRepository; import meltingpot.server.domain.repository.PostRepository; @@ -25,17 +25,16 @@ import meltingpot.server.util.r2.FileService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.PageRequest; +import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.data.domain.Pageable; - - +import org.springframework.web.server.ResponseStatusException; @Service @RequiredArgsConstructor @Transactional public class PostService { - private final AccountRepository accountRepository; private final PostRepository postRepository; private final CommentRepository commentRepository; private final PostImageRepository postImageRepository; @@ -44,30 +43,34 @@ public class PostService { /*post 작성하기*/ - public ResponseCode createPost(PostCreateRequest createPostDTO,Account account){ - Post post = createPostDTO.toEntity(account); - List postImgUrls = Collections.emptyList(); - List postImages = createPostImages(createPostDTO.getImageKeys(), post, account); - post.setPostImages(postImages); + public ResponseCode createPost(PostCreateRequest postCreateRequest, Account account, boolean isDraft) { + Optional optionalDraft = getDraftPost(account); + Post post = optionalDraft.orElseGet(() -> postCreateRequest.toEntity(account)); + System.out.println("Post " + post.getId() + post.getTitle() + post.getIsDraft()); + + if (optionalDraft.isPresent()) { + updatePostContent(post, account, postCreateRequest); + } + setPostImages(post, account, postCreateRequest); + // isDraft 값을 설정하기 전에 현재 상태 출력 + System.out.println("Setting isDraft for post with ID " + post.getId() + " to " + isDraft); + post.setIsDraft(isDraft); + + // isDraft 값 설정 후 출력 + System.out.println("Post isDraft status: " + post.getIsDraft()); + postRepository.save(post); - return ResponseCode.CREATE_POST_SUCCESS; + + return isDraft ? ResponseCode.DRAFT_SAVE_SUCCESS : ResponseCode.CREATE_POST_SUCCESS; } + /*post 수정하기*/ public ResponseCode updatePost(PostCreateRequest updateRequest,Long postId, Account account){ Post post = findPostById(postId); - - post.setTitle(updateRequest.getTitle()); - post.setContent(updateRequest.getContent()); - - // 기존의 모든 PostImage 삭제 - if (post.getPostImages() != null) { - postImageRepository.deleteAll(post.getPostImages()); - - } - // 새로운 PostImage 설정 - List postImages = createPostImages(updateRequest.getImageKeys(), post, account); - post.setPostImages(postImages); + isAuthenticated ( post, account); + updatePostContent(post, account, updateRequest); + setPostImages(post,account,updateRequest); postRepository.save(post); @@ -95,7 +98,7 @@ public PostsListResponse getPostsList(Account account, PostType postType, Long /*post 삭제하기*/ public ResponseCode deletePost(Long postId, Account account){ Post post = findPostById(postId); - Account postAccount = findAccountById(post.getAccount().getId()); + isAuthenticated ( post, account); // 게시물에 연관된 이미지 삭제 if (!post.getPostImages().isEmpty()) { @@ -114,17 +117,29 @@ public ResponseCode deletePost(Long postId, Account account){ } - - private Account findAccountById(Long accountId) { - return accountRepository.findById(accountId) - .orElseThrow(() -> new RuntimeException("사용자를 찾을 수 없습니다.")); + /* 임시저장된 글 불러오기 */ + public PostDetailResponse getTempPost (Account account ){ + Optional optionalDraft = getDraftPost(account); + if(optionalDraft.isPresent()){ + Post draftPost = optionalDraft.get(); + return PostDetailResponse.from(draftPost); + }else{ + throw new NoSuchElementException(ResponseCode.POST_NOT_FOUND.getDetail()); + } } + private Post findPostById(Long postId) { return postRepository.findById(postId) .orElseThrow(() -> new RuntimeException("게시글을 찾을 수 없습니다.")); } + private void isAuthenticated (Post post, Account account) { + if (!post.getAccount().getId().equals(account.getId())) { + throw new ResponseStatusException(HttpStatus.FORBIDDEN, "권한이 없습니다."); + } + } + private List getCdnUrls(List imageKeys) { return imageKeys.stream() .map(imageKey -> { @@ -134,6 +149,17 @@ private List getCdnUrls(List imageKeys) { .collect(Collectors.toList()); } + private void updatePostContent(Post post, Account account, PostCreateRequest updateRequest) { + post.setTitle(updateRequest.getTitle()); + post.setContent(updateRequest.getContent()); + + // 기존의 모든 PostImage 삭제 + if (post.getPostImages() != null && !post.getPostImages().isEmpty()) { + postImageRepository.deleteAll(post.getPostImages()); + post.getPostImages().clear(); + } + } + private List createPostImages(List imageKeys, Post post, Account account) { List postImgUrls = getCdnUrls(imageKeys); return postImgUrls.stream() @@ -204,6 +230,13 @@ private CommentsListResponse fetchCommentsList(Long postId, Long cursor, int pag return CommentsListResponse.from(commentDetailDTOs, nextCursor, isLast); } + private Optional getDraftPost(Account account) { + return postRepository.findByAccountAndIsDraftTrue(account); + } + private void setPostImages(Post post, Account account,PostCreateRequest postRequest) { + List postImages = createPostImages(postRequest.getImageKeys(), post, account); + post.setPostImages(postImages); + } } diff --git a/src/main/java/meltingpot/server/util/ResponseCode.java b/src/main/java/meltingpot/server/util/ResponseCode.java index 9aa2556..13b750f 100644 --- a/src/main/java/meltingpot/server/util/ResponseCode.java +++ b/src/main/java/meltingpot/server/util/ResponseCode.java @@ -61,6 +61,7 @@ public enum ResponseCode { SIGNUP_SUCCESS(CREATED, "회원가입 성공"), CREATE_CHAT_ROOM_SUCCESS(CREATED, "채팅방 생성 성공"), CREATE_POST_SUCCESS(CREATED, "게시물 작성 성공"), + DRAFT_SAVE_SUCCESS(CREATED,"게시물 임시 저장 성공"), CREATE_COMMENT_SUCCESS(CREATED, "댓글 작성 성공"), CREATE_CHILD_COMMENT_SUCCESS(CREATED, "대댓글 작성 성공"), REPORT_CREATE_SUCCESS(CREATED, "신고 작성 성공"),