diff --git a/src/main/java/com/moongeul/backend/api/bookshelf/entity/DoneReadBookshelf.java b/src/main/java/com/moongeul/backend/api/bookshelf/entity/DoneReadBookshelf.java index b7f49cd..d52c5c8 100644 --- a/src/main/java/com/moongeul/backend/api/bookshelf/entity/DoneReadBookshelf.java +++ b/src/main/java/com/moongeul/backend/api/bookshelf/entity/DoneReadBookshelf.java @@ -47,5 +47,13 @@ public void updateWithNewPost(Post newPost, Float weight, Float height) { this.height = height; this.postCount = this.postCount + 1; } + + // 게시글 삭제 시 이전 기록으로 갱신 (게시글 개수 감소 및 데이터 재설정) + public void updateWithPreviousPost(Post previousPost, Float weight, Float height) { + this.article = previousPost; + this.weight = weight; + this.height = height; + this.postCount = Math.max(0, this.postCount - 1); // 개수 감소 (음수 방지) + } } diff --git a/src/main/java/com/moongeul/backend/api/post/repository/PostRepository.java b/src/main/java/com/moongeul/backend/api/post/repository/PostRepository.java index 70a5806..bc92445 100644 --- a/src/main/java/com/moongeul/backend/api/post/repository/PostRepository.java +++ b/src/main/java/com/moongeul/backend/api/post/repository/PostRepository.java @@ -159,4 +159,11 @@ Page findByMemberAndBookIsbnOrderByCreatedAtDesc( @Modifying(clearAutomatically = true) @Query("DELETE FROM Post p WHERE p.member.id = :memberId") void deleteAllByMemberId(@Param("memberId") Long memberId); + + // 해당 사용자와 책으로 작성된 게시글 중 삭제될 게시글을 제외하고 생성일자 역순으로 첫번째 데이터 가져오기 + // findFirst: 하나만 가져올 건데(LIMIT 1) + // ByMemberAndBook: 조건은 해당 멤버와 책으로 하고 + // AndIdNot: 지금 삭제할 게시글ID는 제외하고 찾고(AND id <> ?) + // OrderByCreatedAtDesc: 가장 최근에 쓴 순대로 정렬해서 가져와 + Optional findFirstByMemberAndBookAndIdNotOrderByCreatedAtDesc(Member member, Book book, Long postId); } diff --git a/src/main/java/com/moongeul/backend/api/post/service/PostService.java b/src/main/java/com/moongeul/backend/api/post/service/PostService.java index 259242a..cdacb79 100644 --- a/src/main/java/com/moongeul/backend/api/post/service/PostService.java +++ b/src/main/java/com/moongeul/backend/api/post/service/PostService.java @@ -16,7 +16,6 @@ import com.moongeul.backend.api.post.repository.PostRepository; import com.moongeul.backend.api.post.repository.QuoteRepository; import com.moongeul.backend.api.post.util.WritingGuideGenerator; -import com.moongeul.backend.api.story.entity.Story; import com.moongeul.backend.api.story.repository.StoryRepository; import com.moongeul.backend.common.annotation.Timer; import com.moongeul.backend.common.exception.NotFoundException; @@ -341,8 +340,6 @@ public void deletePost(Long postId, String email){ Post post = getPost(postId); Book book = post.getBook(); - Story story = storyRepository.findByPostId(postId) - .orElseThrow(() -> new NotFoundException(ErrorStatus.STORY_NOTFOUND_EXCEPTION.getMessage())); // 예외처리: 수정하는 사람과 게시글 주인이 같은지 확인 (본인의 게시글인지) if (!post.getMember().getEmail().equals(email)) { @@ -352,18 +349,43 @@ public void deletePost(Long postId, String email){ // 인상깊은구절 일괄 삭제 quoteRepository.deleteAllByPostId(postId); - // 연동된 Story 삭제 - storyRepository.delete(story); + // 3. 연동된 Story 삭제 (있을 때만 삭제하도록 수정) + storyRepository.findByPostId(postId).ifPresent(storyRepository::delete); - // 읽은 책장 데이터 삭제 - doneReadBookshelfRepository.deleteByArticle(post); + // 읽은 책장 데이터 갱신 로직 + updateBookshelfAfterDeletion(post.getMember(), book, post); // 게시글 삭제 postRepository.delete(post); updateBookRatingStats(book); } - + + // 게시글 삭제 시 읽은 책장의 참조 게시글(article_id)을 이전 기록으로 갱신하는 메서드 + private void updateBookshelfAfterDeletion(Member member, Book book, Post deletedPost) { + doneReadBookshelfRepository.findByMemberAndBook(member, book).ifPresent(bookshelf -> { + // 만약 삭제하려는 게시글이 현재 책장에서 참조하고 있는 게시글(최신글)이라면 + if (bookshelf.getArticle().equals(deletedPost)) { + // 해당 책과 사용자의 게시글 중, 삭제될 게시글을 제외하고 가장 최근 게시글을 찾음 + Optional previousPostOpt = postRepository.findFirstByMemberAndBookAndIdNotOrderByCreatedAtDesc( + member, book, deletedPost.getId()); + + if (previousPostOpt.isPresent()) { + // 이전 기록이 있다면 그것으로 갱신 + Post previousPost = previousPostOpt.get(); + + Float weight = bookshelfCalculator.calculateWeight(previousPost.getPage()); + Float height = bookshelfCalculator.calculateHeight(previousPost.getRating()); + + bookshelf.updateWithPreviousPost(previousPost, weight, height); + + } else { + // 더 이상 남은 기록이 없다면 책장 데이터 자체를 삭제 (선택 사항) + doneReadBookshelfRepository.delete(bookshelf); + } + } + }); + } // 새로운 인상깊은구절 저장 private void saveQuotes(PostRequestDTO postRequestDTO, Post post){ diff --git a/src/main/java/com/moongeul/backend/common/config/security/SecurityConfig.java b/src/main/java/com/moongeul/backend/common/config/security/SecurityConfig.java index 4f1f45d..16bdeb3 100644 --- a/src/main/java/com/moongeul/backend/common/config/security/SecurityConfig.java +++ b/src/main/java/com/moongeul/backend/common/config/security/SecurityConfig.java @@ -39,7 +39,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .requestMatchers("/api/v2/reading-taste", "/api/v2/reading-taste/total-count").permitAll() .requestMatchers("/api/v2/book/bestseller").permitAll() .requestMatchers(HttpMethod.GET, "/api/v2/book/bestseller/**").permitAll() - .requestMatchers(HttpMethod.GET, "/api/v2/post/**", "/api/v2/story/**", "/api/v2/question/list").permitAll() + .requestMatchers(HttpMethod.GET, "/api/v2/post/**", "/api/v2/story/**", "/api/v2/question/list").permitAll() // 홈: 게시글, 스토리, 질문 페이지 + .requestMatchers(HttpMethod.GET, "/api/v2/book/user/search", "/api/v2/book/{isbn}").permitAll() // 도서 검색 + 책 상세 페이지 .requestMatchers(HttpMethod.GET, "/api/v2/bookshelf/done-read", "/api/v2/bookshelf/done-read/**").permitAll() .requestMatchers(HttpMethod.GET, "/api/v2/member/user-info", "/api/v2/member/post-stats", "/api/v2/member/post-stats/**", "/api/v2/member/liked-posts", "/api/v2/member/question-list").permitAll() .anyRequest().authenticated()