diff --git a/src/main/java/com/hansung/leafly/domain/book/service/BookServiceImpl.java b/src/main/java/com/hansung/leafly/domain/book/service/BookServiceImpl.java index 629a0e0..adb39d8 100644 --- a/src/main/java/com/hansung/leafly/domain/book/service/BookServiceImpl.java +++ b/src/main/java/com/hansung/leafly/domain/book/service/BookServiceImpl.java @@ -58,10 +58,10 @@ public List search(String keyword, BookFilterReq req, Member member) List filters = req.getGenres(); return response.item().stream() - .filter(item -> matchesGenre(item, filters)) + .filter(item -> item.isbn13() != null && !item.isbn13().isBlank()) // ISBN 없는 책 제외 .map(item -> SearchRes.from( item, - bookmarkedSet.contains(Long.parseLong(item.isbn13())) // 북마크 여부 체크 + bookmarkedSet.contains(Long.parseLong(item.isbn13())) )) .toList(); } diff --git a/src/main/java/com/hansung/leafly/domain/bookreview/entity/BookReview.java b/src/main/java/com/hansung/leafly/domain/bookreview/entity/BookReview.java index b87be40..a05f47f 100644 --- a/src/main/java/com/hansung/leafly/domain/bookreview/entity/BookReview.java +++ b/src/main/java/com/hansung/leafly/domain/bookreview/entity/BookReview.java @@ -1,6 +1,7 @@ package com.hansung.leafly.domain.bookreview.entity; import com.hansung.leafly.domain.bookreview.web.dto.ReviewReq; +import com.hansung.leafly.domain.bookreview.web.dto.ReviewUpdateReq; import com.hansung.leafly.domain.member.entity.Member; import com.hansung.leafly.global.entity.BaseEntity; import jakarta.persistence.*; @@ -61,4 +62,18 @@ public static BookReview toEntity(Member member, ReviewReq req) { .build(); } + public void update(ReviewUpdateReq req) { + if (req.getTitle() != null) this.title = req.getTitle(); + if (req.getAuthor() != null) this.author = req.getAuthor(); + if (req.getThumbnail() != null) this.thumbnail = req.getThumbnail(); + if (req.getRating() != null) this.rating = req.getRating(); + if (req.getReviewTitle() != null) this.reviewTitle = req.getReviewTitle(); + if (req.getContent() != null) this.content = req.getContent(); + } + + public void replaceImages(List newImages) { + this.images.clear(); + this.images.addAll(newImages); + } + } diff --git a/src/main/java/com/hansung/leafly/domain/bookreview/service/BookReviewService.java b/src/main/java/com/hansung/leafly/domain/bookreview/service/BookReviewService.java index b20017e..7818a68 100644 --- a/src/main/java/com/hansung/leafly/domain/bookreview/service/BookReviewService.java +++ b/src/main/java/com/hansung/leafly/domain/bookreview/service/BookReviewService.java @@ -3,6 +3,7 @@ import com.hansung.leafly.domain.bookreview.web.dto.ReviewDetailsRes; import com.hansung.leafly.domain.bookreview.web.dto.ReviewListRes; import com.hansung.leafly.domain.bookreview.web.dto.ReviewReq; +import com.hansung.leafly.domain.bookreview.web.dto.ReviewUpdateReq; import com.hansung.leafly.domain.member.entity.Member; public interface BookReviewService { @@ -13,4 +14,6 @@ public interface BookReviewService { ReviewListRes getList(Member member); ReviewDetailsRes getDetails(Long reviewId,Member member); + + void update(Member member, Long reviewId, ReviewUpdateReq req); } diff --git a/src/main/java/com/hansung/leafly/domain/bookreview/service/BookReviewServiceImpl.java b/src/main/java/com/hansung/leafly/domain/bookreview/service/BookReviewServiceImpl.java index a69eac1..32d0ddc 100644 --- a/src/main/java/com/hansung/leafly/domain/bookreview/service/BookReviewServiceImpl.java +++ b/src/main/java/com/hansung/leafly/domain/bookreview/service/BookReviewServiceImpl.java @@ -8,10 +8,7 @@ import com.hansung.leafly.domain.bookreview.repository.BookReviewRepository; import com.hansung.leafly.domain.bookreview.repository.BookTagRepository; import com.hansung.leafly.domain.bookreview.repository.ReviewImageRepository; -import com.hansung.leafly.domain.bookreview.web.dto.ReviewDetailsRes; -import com.hansung.leafly.domain.bookreview.web.dto.ReviewListRes; -import com.hansung.leafly.domain.bookreview.web.dto.ReviewReq; -import com.hansung.leafly.domain.bookreview.web.dto.ReviewRes; +import com.hansung.leafly.domain.bookreview.web.dto.*; import com.hansung.leafly.domain.member.entity.Member; import com.hansung.leafly.infra.s3.S3Service; import com.hansung.leafly.infra.s3.exception.S3RequestFailedException; @@ -82,6 +79,27 @@ public ReviewDetailsRes getDetails(Long reviewId, Member member) { return ReviewDetailsRes.from(review); } + @Override + @Transactional + public void update(Member member, Long reviewId, ReviewUpdateReq req) { + BookReview review = bookReviewRepository.findById(reviewId) + .orElseThrow(BookReviewNotFoundException::new); + + if (!review.getMember().getId().equals(member.getId())) { + throw new BookReviewAccessDeniedException(); + } + review.update(req); + + // 이미지 수정이 요청된 경우에만 처리 + if (req.getImages() != null && !req.getImages().isEmpty()) { + List newImages = processImages(req.getImages(), review); + //기존 이미지 제거 & 새로 교체 + review.replaceImages(newImages); + } + + bookReviewRepository.save(review); + } + // 카테고리 태그화 private List processTags(String rawTags, BookReview review) { if (rawTags == null || rawTags.isEmpty()) { diff --git a/src/main/java/com/hansung/leafly/domain/bookreview/web/controller/BookReviewController.java b/src/main/java/com/hansung/leafly/domain/bookreview/web/controller/BookReviewController.java index 983ed08..07c6dbf 100644 --- a/src/main/java/com/hansung/leafly/domain/bookreview/web/controller/BookReviewController.java +++ b/src/main/java/com/hansung/leafly/domain/bookreview/web/controller/BookReviewController.java @@ -5,6 +5,7 @@ import com.hansung.leafly.domain.bookreview.web.dto.ReviewDetailsRes; import com.hansung.leafly.domain.bookreview.web.dto.ReviewListRes; import com.hansung.leafly.domain.bookreview.web.dto.ReviewReq; +import com.hansung.leafly.domain.bookreview.web.dto.ReviewUpdateReq; import com.hansung.leafly.global.auth.security.CustomMemberDetails; import com.hansung.leafly.global.response.SuccessResponse; import jakarta.validation.Valid; @@ -58,4 +59,15 @@ public ResponseEntity> getDetails( ReviewDetailsRes res = bookReviewService.getDetails(reviewId,memberDetails.getMember()); return ResponseEntity.status(HttpStatus.OK).body(SuccessResponse.from(res)); } + + //독후감 수정 + @PatchMapping("/{reviewId}") + public ResponseEntity> update( + @AuthenticationPrincipal CustomMemberDetails memberDetails, + @PathVariable Long reviewId, + @ModelAttribute @Valid ReviewUpdateReq req + ){ + bookReviewService.update(memberDetails.getMember(), reviewId, req); + return ResponseEntity.status(HttpStatus.OK).body(SuccessResponse.from(null)); + } } diff --git a/src/main/java/com/hansung/leafly/domain/bookreview/web/dto/ReviewUpdateReq.java b/src/main/java/com/hansung/leafly/domain/bookreview/web/dto/ReviewUpdateReq.java new file mode 100644 index 0000000..173a9c2 --- /dev/null +++ b/src/main/java/com/hansung/leafly/domain/bookreview/web/dto/ReviewUpdateReq.java @@ -0,0 +1,30 @@ +package com.hansung.leafly.domain.bookreview.web.dto; + +import jakarta.validation.constraints.Size; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +@Getter +@Setter +@NoArgsConstructor +public class ReviewUpdateReq { + + private String title; + private String author; + private String thumbnail; + private Integer rating; + private String category; + + @Size(max = 20) + private String reviewTitle; + + @Size(min = 10) + private String content; + + @Size(max = 3) + private List images; +}