diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc index a88cbbc1..3e6fa5b9 100644 --- a/src/docs/asciidoc/index.adoc +++ b/src/docs/asciidoc/index.adoc @@ -673,7 +673,7 @@ include::{snippets}/bookmark/checkBookmarked/notExist/http-response.adoc[] == shortReview -=== GET api/v1/short-reviews/animeId/1 +=== GET api/v1/short-reviews/animeId/:animeId ==== 성공시, cursor가 없을 경우 .curl-request include::{snippets}/getShortReviews/success/curl-request.adoc[] @@ -719,7 +719,7 @@ include::{snippets}/getShortReviews/withCursor/success/response-body.adoc[] include::{snippets}/getShortReviews/withCursor/success/response-fields.adoc[] ==== 실패시 -=== POST api/v1/short-reviews/1 +=== POST api/v1/short-reviews/:id .curl-request include::{snippets}/postShortReview/success/curl-request.adoc[] @@ -739,7 +739,7 @@ include::{snippets}/postShortReview/success/http-response.adoc[] ==== 실패시 -=== shortReview/getAttractionPoint api/v1/short-reviews//attraction-points +=== GET api/v1/short-reviews/attraction-points .curl-request include::{snippets}/shortReview/getAttractionPoints/success/curl-request.adoc[] @@ -766,7 +766,7 @@ include::{snippets}/shortReview/getAttractionPoints/success/http-response.adoc[] .response-fields include::{snippets}/shortReview/getAttractionPoints/success/response-fields.adoc[] -=== PATCH api/v1/short-reviews/1 +=== PATCH api/v1/short-reviews/:id .curl-request include::{snippets}/patchShortReview/success/curl-request.adoc[] @@ -787,9 +787,22 @@ include::{snippets}/patchShortReview/success/request-fields.adoc[] .http-response include::{snippets}/patchShortReview/success/http-response.adoc[] -.response-fields -include::{snippets}/patchShortReview/success/response-fields.adoc[] +==== 실패시 + +=== DELETE api/v1/short-reivews/animes/:id +.curl-request +include::{snippets}/deleteShortReview/success/curl-request.adoc[] + +.http-request +include::{snippets}/deleteShortReview/success/http-request.adoc[] +.request-param +include::{snippets}/deleteShortReview/success/path-parameters.adoc[] + +==== 성공시 + +.http-response +include::{snippets}/deleteShortReview/success/http-response.adoc[] ==== 실패시 diff --git a/src/main/java/io/oduck/api/domain/review/controller/ShortReviewController.java b/src/main/java/io/oduck/api/domain/review/controller/ShortReviewController.java index e71e22f3..208d226c 100644 --- a/src/main/java/io/oduck/api/domain/review/controller/ShortReviewController.java +++ b/src/main/java/io/oduck/api/domain/review/controller/ShortReviewController.java @@ -16,14 +16,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PatchMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; @Validated @RequestMapping("/short-reviews") @@ -58,20 +51,28 @@ public ResponseEntity getShortReviews( @GetMapping("/attraction-points") public ResponseEntity patchShortReview( @LoginUser AuthUser user, - @RequestParam(required = false) Long animeId, - @RequestParam(required = false) String name) { + @RequestBody @Valid ShortReviewReqDto.PatchShortReview req) { //TODO : 짧은 리뷰 수정, 입덕포인트 반환 - IsAttractionPoint attractionPointRes = attractionPointService.isAttractionPoint(user.getId(), animeId); + IsAttractionPoint attractionPointRes = attractionPointService.isAttractionPoint(user.getId(), req.getAnimeId()); return ResponseEntity.ok(attractionPointRes); } - @PatchMapping("/{reviewId}") + @PatchMapping("/{shortReviewId}") public ResponseEntity patchShortReview( @LoginUser AuthUser user, - @PathVariable Long reviewId, + @PathVariable Long shortReviewId, @RequestBody @Valid ShortReviewReqDto.ShortReviewReq req) { //TODO : 짧은 리뷰 수정 - shortReviewService.update(user.getId(), reviewId, req); + shortReviewService.update(user.getId(), shortReviewId, req); + return ResponseEntity.noContent().build(); + } + + @DeleteMapping("/{shortReviewId}") + public ResponseEntity deleteShortReview( + @LoginUser AuthUser user, + @PathVariable Long shortReviewId) { + //TODO : 짧은 리뷰 삭제 + shortReviewService.delete(user.getId(), shortReviewId); return ResponseEntity.noContent().build(); } } \ No newline at end of file diff --git a/src/main/java/io/oduck/api/domain/review/dto/ShortReviewReqDto.java b/src/main/java/io/oduck/api/domain/review/dto/ShortReviewReqDto.java index 383d1713..be86dbd9 100644 --- a/src/main/java/io/oduck/api/domain/review/dto/ShortReviewReqDto.java +++ b/src/main/java/io/oduck/api/domain/review/dto/ShortReviewReqDto.java @@ -15,7 +15,6 @@ public class ShortReviewReqDto { @Builder public static class ShortReviewReq{ private Long animeId; -// private String name; private boolean hasSpoiler; @NotBlank @Length(min = 10, max = 100, @@ -23,6 +22,14 @@ public static class ShortReviewReq{ private String content; } + @Getter + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class PatchShortReview{ + private Long animeId; + } + @Getter @AllArgsConstructor public enum Sort{ diff --git a/src/main/java/io/oduck/api/domain/review/entity/ShortReview.java b/src/main/java/io/oduck/api/domain/review/entity/ShortReview.java index 34a877c3..4fc6e5f5 100644 --- a/src/main/java/io/oduck/api/domain/review/entity/ShortReview.java +++ b/src/main/java/io/oduck/api/domain/review/entity/ShortReview.java @@ -15,6 +15,7 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; @@ -46,8 +47,9 @@ public class ShortReview extends BaseEntity { @Column(nullable = false) private boolean hasSpoiler; - @OneToMany(mappedBy = "shortReview", cascade = CascadeType.PERSIST) - private List shortReviewLikes; + @OneToMany(mappedBy = "shortReview", cascade = CascadeType.PERSIST, orphanRemoval = true) + @Builder.Default + private List shortReviewLikes = new ArrayList<>(); @Builder @@ -75,4 +77,9 @@ public void updateSpoiler(boolean hasSpoiler){ this.hasSpoiler = hasSpoiler; } } + + public void delete(){ + this.shortReviewLikes.clear(); + this.deletedAt = LocalDateTime.now(); + } } diff --git a/src/main/java/io/oduck/api/domain/review/repository/ShortReviewRepository.java b/src/main/java/io/oduck/api/domain/review/repository/ShortReviewRepository.java index f26e0814..125f1440 100644 --- a/src/main/java/io/oduck/api/domain/review/repository/ShortReviewRepository.java +++ b/src/main/java/io/oduck/api/domain/review/repository/ShortReviewRepository.java @@ -2,9 +2,14 @@ import io.oduck.api.domain.review.entity.ShortReview; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; +import java.util.Optional; + @Repository public interface ShortReviewRepository extends JpaRepository, ShortReviewRepositoryCustom { - Long countByMemberId(Long memberId); + Optional findByIdAndDeletedAtIsNull(Long memberId); + + Long countByMemberIdAndDeletedAtIsNull(Long memberId); } diff --git a/src/main/java/io/oduck/api/domain/review/repository/ShortReviewRepositoryImpl.java b/src/main/java/io/oduck/api/domain/review/repository/ShortReviewRepositoryImpl.java index 8c0253e2..adbc006a 100644 --- a/src/main/java/io/oduck/api/domain/review/repository/ShortReviewRepositoryImpl.java +++ b/src/main/java/io/oduck/api/domain/review/repository/ShortReviewRepositoryImpl.java @@ -59,7 +59,7 @@ public Slice selectShortReviews(Long animeId, String cursor, .leftJoin(shortReviewLike).on(shortReview.id.eq(shortReviewLike.shortReview.id)) .join(starRating).on(starRating.anime.id.eq(shortReview.anime.id) .and(starRating.member.id.eq(shortReview.member.id))) - .where(anime.id.eq(animeId)) + .where(anime.id.eq(animeId).and(shortReview.deletedAt.isNull())) .groupBy(shortReview.id, member.id) .having(cursorCondition(cursor, pageable)) .limit(pageable.getPageSize()); @@ -91,7 +91,7 @@ public Slice selectShortReviewsByMemberId(Long memberId .leftJoin(starRating).on(starRating.anime.id.eq(shortReview.anime.id) .and(starRating.member.id.eq(shortReview.member.id))) .leftJoin(shortReviewLike).on(shortReview.id.eq(shortReviewLike.shortReview.id)) - .where(shortReview.member.id.eq(memberId)) + .where(shortReview.member.id.eq(memberId).and(shortReview.deletedAt.isNull())) .groupBy(shortReview.id) .having(cursorCondition(cursor, pageable)) .limit(pageable.getPageSize()); diff --git a/src/main/java/io/oduck/api/domain/review/service/ShortReviewService.java b/src/main/java/io/oduck/api/domain/review/service/ShortReviewService.java index 7d422983..4a83f3d7 100644 --- a/src/main/java/io/oduck/api/domain/review/service/ShortReviewService.java +++ b/src/main/java/io/oduck/api/domain/review/service/ShortReviewService.java @@ -25,5 +25,5 @@ public interface ShortReviewService { void update(Long memberId, Long reviewId, ShortReviewReq req); //애니 리뷰 삭제 - + void delete(Long memberId, Long reviewId); } \ No newline at end of file diff --git a/src/main/java/io/oduck/api/domain/review/service/ShortReviewServiceImpl.java b/src/main/java/io/oduck/api/domain/review/service/ShortReviewServiceImpl.java index 67ada982..df8fb12a 100644 --- a/src/main/java/io/oduck/api/domain/review/service/ShortReviewServiceImpl.java +++ b/src/main/java/io/oduck/api/domain/review/service/ShortReviewServiceImpl.java @@ -21,8 +21,10 @@ import io.oduck.api.global.common.SliceResponse; import io.oduck.api.global.exception.BadRequestException; import io.oduck.api.global.exception.NotFoundException; + import java.util.List; import java.util.Optional; + import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Slice; @@ -34,7 +36,7 @@ @Slf4j @Service @RequiredArgsConstructor -public class ShortReviewServiceImpl implements ShortReviewService{ +public class ShortReviewServiceImpl implements ShortReviewService { private final ShortReviewRepository shortReviewRepository; private final MemberRepository memberRepository; @@ -47,15 +49,15 @@ public void save(Long memberId, ShortReviewReq shortReviewReq) { //애니 입력 Anime anime = animeRepository.findByIdForUpdate(shortReviewReq.getAnimeId()) - .orElseThrow( - () -> new NotFoundException("Anime") - ); + .orElseThrow( + () -> new NotFoundException("Anime") + ); //회원 입력 - Member member = memberRepository.findById(memberId) - .orElseThrow( - () -> new NotFoundException("Member") - ); + Member member = memberRepository.findByIdAndDeletedAtIsNull(memberId) + .orElseThrow( + () -> new NotFoundException("Member") + ); ShortReview shortReview = ShortReview .builder() @@ -73,68 +75,68 @@ public void save(Long memberId, ShortReviewReq shortReviewReq) { @Override @Transactional - public SliceResponse getShortReviews(Long animeId, String cursor,ShortReviewReqDto.Sort sort, OrderDirection order, int size) { + public SliceResponse getShortReviews(Long animeId, String cursor, ShortReviewReqDto.Sort sort, OrderDirection order, int size) { Sort sortList = Sort.by( - Direction.fromString(order.getOrder()), - sort.getSort() + Direction.fromString(order.getOrder()), + sort.getSort() ); - if(sort == ShortReviewReqDto.Sort.LIKE_COUNT){ + if (sort == ShortReviewReqDto.Sort.LIKE_COUNT) { sortList = sortList.and(Sort.by(Direction.DESC, "createdAt")); - }else if(sort == ShortReviewReqDto.Sort.SCORE){ + } else if (sort == ShortReviewReqDto.Sort.SCORE) { sortList = sortList.and(Sort.by(Direction.DESC, "createdAt")); } Slice shortReviews = shortReviewRepository.selectShortReviews( - animeId, - cursor, - applyPageableForNonOffset( - size, - sortList - ) + animeId, + cursor, + applyPageableForNonOffset( + size, + sortList + ) ); List res = shortReviews.getContent() - .stream() - .map(ShortReviewRes::of) - .toList(); + .stream() + .map(ShortReviewRes::of) + .toList(); return SliceResponse.of(shortReviews, res, sort.getSort()); } @Override public ShortReviewCountRes getShortReviewCountByMemberId(Long memberId) { - Long count = shortReviewRepository.countByMemberId(memberId); + Long count = shortReviewRepository.countByMemberIdAndDeletedAtIsNull(memberId); return ShortReviewCountRes.builder() - .count(count) - .build(); + .count(count) + .build(); } @Override public SliceResponse getShortReviewsByMemberId(Long memberId, String cursor, - ShortReviewReqDto.SortForProfile sort, OrderDirection order, int size) { + ShortReviewReqDto.SortForProfile sort, OrderDirection order, int size) { Sort sortList = Sort.by( - Direction.fromString(order.getOrder()), - sort.getSort() + Direction.fromString(order.getOrder()), + sort.getSort() ); - if(sort.equals(SortForProfile.SCORE)){ + if (sort.equals(SortForProfile.TITLE) || sort.equals(SortForProfile.SCORE)) { sortList = sortList.and(Sort.by(Direction.DESC, "createdAt")); } Slice shortReviews = shortReviewRepository.selectShortReviewsByMemberId( - memberId, - cursor, - applyPageableForNonOffset( - size, - sortList - ) + memberId, + cursor, + applyPageableForNonOffset( + size, + sortList + ) ); List res = shortReviews.getContent() - .stream() - .map(ShortReviewResWithTitle::of) - .toList(); + .stream() + .map(ShortReviewResWithTitle::of) + .toList(); return SliceResponse.of(shortReviews, res, sort.getSort()); } @@ -153,25 +155,32 @@ public void update(Long memberId, Long reviewId, ShortReviewReq req) { //리뷰 작성자 인지 확인 Optional - .ofNullable(findMemberId) - .ifPresent( - id -> { - if(!findMemberId.equals(memberId)) { - throw new BadRequestException("Not the author of the review."); - } - findShortReview.updateContent(req.getContent()); - findShortReview.updateSpoiler(req.isHasSpoiler()); - } - ); + .ofNullable(findMemberId) + .ifPresent( + id -> { + if (!findMemberId.equals(memberId)) { + throw new BadRequestException("Not the author of the review."); + } + findShortReview.updateContent(req.getContent()); + findShortReview.updateSpoiler(req.isHasSpoiler()); + } + ); findAnime.increaseReviewCount(); shortReviewRepository.save(findShortReview); } + @Override + public void delete(Long memberId, Long reviewId) { + ShortReview find = getShortReview(reviewId); + find.delete(); + shortReviewRepository.save(find); + } - private ShortReview getShortReview(Long reviewId){ - return shortReviewRepository.findById(reviewId) - .orElseThrow( - () -> new NotFoundException("shortReview") - ); + + private ShortReview getShortReview(Long reviewId) { + return shortReviewRepository.findByIdAndDeletedAtIsNull(reviewId) + .orElseThrow( + () -> new NotFoundException("shortReview") + ); } } \ No newline at end of file diff --git a/src/test/java/io/oduck/api/e2e/shortReview/ShortReviewControllerTest.java b/src/test/java/io/oduck/api/e2e/shortReview/ShortReviewControllerTest.java index 5f99acde..9312125e 100644 --- a/src/test/java/io/oduck/api/e2e/shortReview/ShortReviewControllerTest.java +++ b/src/test/java/io/oduck/api/e2e/shortReview/ShortReviewControllerTest.java @@ -22,6 +22,7 @@ import com.google.gson.Gson; import io.oduck.api.domain.member.entity.Role; +import io.oduck.api.domain.review.dto.ShortReviewReqDto; import io.oduck.api.domain.review.dto.ShortReviewReqDto.ShortReviewReq; import io.oduck.api.global.mockMember.WithCustomMockMember; import io.oduck.api.global.utils.ShortReviewTestUtils; @@ -329,13 +330,16 @@ void getShortReviewsWithCursor() throws Exception{ @Nested @DisplayName("입덕포인트 조회") class getAttractionPoint{ - @DisplayName("애니아이디와 회원이름으로 입덕포인트 조회") + @DisplayName("애니아이디로 입덕포인트 조회") @Test @WithCustomMockMember(id = 1L, email = "john", password = "Qwer!234", role = Role.MEMBER) void getAttractionPointsShortReview() throws Exception{ //given - String animeId = "1"; - String name = "회원 이름"; + ShortReviewReqDto.PatchShortReview req = ShortReviewReqDto.PatchShortReview + .builder() + .animeId(1L) + .build(); + String content = gson.toJson(req); //when ResultActions actions = mockMvc.perform( @@ -343,8 +347,7 @@ void getAttractionPointsShortReview() throws Exception{ .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .header(HttpHeaders.COOKIE, "oDuckio.sid={SESSION_VALUE}") - .param("animeId", animeId) - .param("name", name) + .content(content) ); //then @@ -363,16 +366,11 @@ void getAttractionPointsShortReview() throws Exception{ .attributes(field("constraints", "oDuckio.sid={SESSION_VALUE}")) .description("Header Cookie, 세션 쿠키") ), - queryParameters( - parameterWithName("animeId") - .attributes(field("constraints","애니메 ID, NotNull, Min(1)")) - .optional() - .description("애니 고유의 식별자"), - parameterWithName("name") - .attributes(field("constraints","회원 이름")) - .optional() - .description("회원 이름") - ), + requestFields(attributes(key("title").value("Fields for shortReview creation")), + fieldWithPath("animeId") + .type(JsonFieldType.NUMBER) + .attributes(field("constraints","애니메 ID, NotNull, Min(1)")) + .description("리뷰를 수정 할 애니 고유 식별 번호")), responseFields( fieldWithPath("drawing") .type(JsonFieldType.BOOLEAN) @@ -396,20 +394,20 @@ void getAttractionPointsShortReview() throws Exception{ @Nested @DisplayName("짧은 리뷰 수정") class PatchShortReview{ - + @DisplayName("짧은 리뷰 수정 성공시 Http Status 204 반환") @Test @WithCustomMockMember(id = 1L, email = "john", password = "Qwer!234", role = Role.MEMBER) void patchShortReview() throws Exception{ //given - Long reviewId = 1L; + Long reviewId = 2L; ShortReviewReq req = ShortReviewTestUtils.createPatchShortReview(); String content = gson.toJson(req); //when ResultActions actions = mockMvc.perform( - patch(BASE_URL +"/{reviewId}", reviewId) + patch(BASE_URL +"/{shortReviewId}", reviewId) .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .header(HttpHeaders.COOKIE, "oDuckio.sid={SESSION_VALUE}") @@ -428,7 +426,7 @@ void patchShortReview() throws Exception{ .description("Header Cookie, 세션 쿠키") ), pathParameters( - parameterWithName("reviewId") + parameterWithName("shortReviewId") .description("리뷰 식별자")), requestFields(attributes(key("title").value("Fields for shortReview creation")), fieldWithPath("animeId") @@ -489,5 +487,44 @@ void patchShortReview() throws Exception{ // ) // )); // } + + } + @Nested + @DisplayName("짧은 리뷰 삭제") + class DeleteShortReview{ + + @Test + @DisplayName("짧은 리뷰 삭제 성공 시 status 204반환") + @WithCustomMockMember(id = 1L, email = "john", password = "Qwer!234", role = Role.MEMBER) + void deleteShortReview() throws Exception { + //given + Long reviewId = 1L; + + //when + ResultActions actions = mockMvc.perform( + delete(BASE_URL + "/{shortReviewId}", reviewId) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.COOKIE, "oDuckio.sid={SESSION_VALUE}") + ); + + //then + + actions.andExpect(status().isNoContent()) + .andDo(document("deleteShortReview/success", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestHeaders( + headerWithName(HttpHeaders.COOKIE) + .attributes(field("constraints", "oDuckio.sid={SESSION_VALUE}")) + .description("Header Cookie, 세션 쿠키") + ), + pathParameters( + parameterWithName("shortReviewId") + .description("리뷰 식별자")) +// requestFields(attributes(key("title").value("Fields for shortReview creation"))) + + )); + } } } \ No newline at end of file diff --git a/src/test/java/io/oduck/api/unit/shortReview/repository/ShortReviewRepositoryTest.java b/src/test/java/io/oduck/api/unit/shortReview/repository/ShortReviewRepositoryTest.java index af0b6c81..93acba01 100644 --- a/src/test/java/io/oduck/api/unit/shortReview/repository/ShortReviewRepositoryTest.java +++ b/src/test/java/io/oduck/api/unit/shortReview/repository/ShortReviewRepositoryTest.java @@ -1,16 +1,7 @@ package io.oduck.api.unit.shortReview.repository; -import static io.oduck.api.global.utils.AnimeTestUtils.getBroadcastType; -import static io.oduck.api.global.utils.AnimeTestUtils.getEpisodeCount; -import static io.oduck.api.global.utils.AnimeTestUtils.getQuarter; -import static io.oduck.api.global.utils.AnimeTestUtils.getRating; -import static io.oduck.api.global.utils.AnimeTestUtils.getStatus; -import static io.oduck.api.global.utils.AnimeTestUtils.getSummary; -import static io.oduck.api.global.utils.AnimeTestUtils.getThumbnail; -import static io.oduck.api.global.utils.AnimeTestUtils.getTitle; -import static io.oduck.api.global.utils.AnimeTestUtils.getYear; -import static io.oduck.api.global.utils.AnimeTestUtils.isReleased; +import static io.oduck.api.global.utils.AnimeTestUtils.*; import static io.oduck.api.global.utils.PagingUtils.applyPageableForNonOffset; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -32,6 +23,7 @@ import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -56,15 +48,15 @@ public class ShortReviewRepositoryTest { @Nested @DisplayName("리뷰 등록") - class PostShortReview{ + class PostShortReview { @Test @DisplayName("리뷰 등록 성공") - void saveShortReview(){ + void saveShortReview() { //given //회원 생성 Member member = Member.builder() - .build(); + .build(); Member saveMember = memberRepository.save(member); Long memberId = saveMember.getId(); @@ -75,9 +67,9 @@ void saveShortReview(){ List animeOriginalAuthors = new ArrayList<>(); Anime createAnime = Anime.createAnime( - getTitle(), getSummary(), getBroadcastType(), getEpisodeCount(), getThumbnail(), - getYear(), getQuarter(), getRating(), getStatus(), isReleased(), - animeOriginalAuthors, animeStudios, animeVoiceActors, animeGenres, null + getTitle(), getSummary(), getBroadcastType(), getEpisodeCount(), getThumbnail(), + getYear(), getQuarter(), getRating(), getStatus(), isReleased(), + animeOriginalAuthors, animeStudios, animeVoiceActors, animeGenres, null ); Anime anime = animeRepository.saveAndFlush(createAnime); @@ -102,13 +94,14 @@ void saveShortReview(){ assertThat(saveShortReview.isHasSpoiler()).isEqualTo(shortReview.isHasSpoiler()); } } + @Nested @DisplayName("리뷰 조회") - class GetShortReviews{ + class GetShortReviews { @Test @DisplayName("리뷰 조회 성공") - void getShortReviews(){ + void getShortReviews() { //given Long animeId = 1L; Pageable pageable = applyPageableForNonOffset(10, "createdAt", "desc"); @@ -142,18 +135,18 @@ void changeShortReviewContent() { //회원 생성 Member member = Member - .builder() - .id(memberId) - .build(); + .builder() + .id(memberId) + .build(); memberRepository.save(member); //리뷰 생성 ShortReview shortReview = ShortReview - .builder() - .content("애니리뷰내용") - .hasSpoiler(hasSpoiler) - .build(); + .builder() + .content("애니리뷰내용") + .hasSpoiler(hasSpoiler) + .build(); //애니 생성 List animeStudios = new ArrayList<>(); @@ -162,9 +155,9 @@ void changeShortReviewContent() { List animeOriginalAuthors = new ArrayList<>(); Anime createAnime = Anime.createAnime( - getTitle(), getSummary(), getBroadcastType(), getEpisodeCount(), getThumbnail(), - getYear(), getQuarter(), getRating(), getStatus(), isReleased(), - animeOriginalAuthors, animeStudios, animeVoiceActors, animeGenres, null + getTitle(), getSummary(), getBroadcastType(), getEpisodeCount(), getThumbnail(), + getYear(), getQuarter(), getRating(), getStatus(), isReleased(), + animeOriginalAuthors, animeStudios, animeVoiceActors, animeGenres, null ); Anime anime = animeRepository.saveAndFlush(createAnime); @@ -196,6 +189,7 @@ void changeShortReviewContent() { @DisplayName("회원 작성한 리뷰 갯수 조회") @Nested + @Order(2) class selectShortReviewsCount { @DisplayName("회원 ID로 회원이 작성한 리뷰 갯수 조회 성공") @Test @@ -204,11 +198,55 @@ void selectShortReviewsCountSuccess() { Long memberId = 1L; // when - Long shortReviewsCount = shortReviewRepository.countByMemberId(memberId); + Long shortReviewsCount = shortReviewRepository.countByMemberIdAndDeletedAtIsNull(memberId); // then assertNotNull(shortReviewsCount); - assertEquals(3L, shortReviewsCount); + assertEquals(2L, shortReviewsCount); + } + } + + @Nested + @DisplayName("짧은 리뷰 삭제") + @Order(1) + class DeleteShortReview { + + @Test + @DisplayName("리뷰 내용 삭제 성공") + void deleteShortReview() { + //given + Long reviewId = 1L; + Long memberId = 1L; + boolean hasSpoiler = true; + + //회원 생성 + Member member = Member + .builder() + .id(memberId) + .build(); + + memberRepository.save(member); + + //리뷰 생성 + ShortReview shortReview = ShortReview + .builder() + .content("애니리뷰내용") + .hasSpoiler(hasSpoiler) + .build(); + + Anime anime = animeRepository.saveAndFlush(createAnime()); + + shortReview.relateMember(member); + shortReview.relateAnime(anime); + + ShortReview saveShortReview = shortReviewRepository.save(shortReview); + saveShortReview.delete(); + + //when + ShortReview updateShortReview = shortReviewRepository.save(saveShortReview); + + //then + assertNotNull(saveShortReview.getDeletedAt()); } } } \ No newline at end of file diff --git a/src/test/java/io/oduck/api/unit/shortReview/service/ShortReviewServiceTest.java b/src/test/java/io/oduck/api/unit/shortReview/service/ShortReviewServiceTest.java index f3735ad4..3e80f750 100644 --- a/src/test/java/io/oduck/api/unit/shortReview/service/ShortReviewServiceTest.java +++ b/src/test/java/io/oduck/api/unit/shortReview/service/ShortReviewServiceTest.java @@ -75,14 +75,14 @@ void postShortReview(){ given(animeRepository.findByIdForUpdate(animeId)).willReturn(Optional.of(anime)); Member member = new MemberStub().getMember(); - given(memberRepository.findById(memberId)).willReturn(Optional.of(member)); + given(memberRepository.findByIdAndDeletedAtIsNull(memberId)).willReturn(Optional.of(member)); //when shortReviewService.save(memberId,shortReviewReq); //then verify(animeRepository,times(1)).findByIdForUpdate(any()); - verify(memberRepository,times(1)).findById(any()); + verify(memberRepository,times(1)).findByIdAndDeletedAtIsNull(any()); } } @@ -135,14 +135,14 @@ void patchShortReview(){ ShortReviewReq patchShortReviewReq = createPatchShortReview(); Anime anime = createAnime(); - given(shortReviewRepository.findById(reviewId)).willReturn(Optional.ofNullable(shortReview)); + given(shortReviewRepository.findByIdAndDeletedAtIsNull(reviewId)).willReturn(Optional.ofNullable(shortReview)); given(animeRepository.findByIdForUpdate(reviewId)).willReturn(Optional.of(anime)); //when shortReviewService.update(memberId, reviewId, patchShortReviewReq); //then - verify(shortReviewRepository, times(1)).findById(anyLong()); + verify(shortReviewRepository, times(1)).findByIdAndDeletedAtIsNull(anyLong()); } } @@ -157,7 +157,7 @@ void getShortReviewCountByMemberId() { Long memberId = 1L; Long count = 1L; - given(shortReviewRepository.countByMemberId(memberId)).willReturn(count); + given(shortReviewRepository.countByMemberIdAndDeletedAtIsNull(memberId)).willReturn(count); //when ShortReviewCountRes result = shortReviewService.getShortReviewCountByMemberId(memberId); @@ -166,4 +166,27 @@ void getShortReviewCountByMemberId() { assertEquals(count, result.getCount()); } } + @Nested + @DisplayName("짧은 리뷰 삭제") + class DeleteShortReview{ + + ShortReview shortReview = createShortReview(); + + @Test + @DisplayName("짧은 리뷰 삭제 성공") + void deleteShortReview(){ + //given + Long shortReviewId = 1L; + Long memberId = 1L; + + given(shortReviewRepository.findByIdAndDeletedAtIsNull(shortReviewId)).willReturn(Optional.ofNullable(shortReview)); + + //when + shortReviewService.delete(memberId, shortReviewId); + + //then + verify(shortReviewRepository, times(1)).findByIdAndDeletedAtIsNull(anyLong()); + } + } + } \ No newline at end of file