From 44cca5bc850cdc09386600f49175d8df5e4974ed Mon Sep 17 00:00:00 2001 From: jaeuk520 Date: Mon, 9 Sep 2024 21:15:57 +0900 Subject: [PATCH] =?UTF-8?q?[#34]=20feat:=20=EC=B0=9C=ED=95=9C=20=EC=BD=94?= =?UTF-8?q?=EC=8A=A4=20=EB=AA=A8=EC=95=84=EB=B3=B4=EA=B8=B0,=20=EB=A7=88?= =?UTF-8?q?=EC=9D=B4=20=EC=BD=94=EC=8A=A4=20=EB=AA=A8=EC=95=84=EB=B3=B4?= =?UTF-8?q?=EA=B8=B0=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/CourseController.java | 21 +++- .../repository/CourseRepository.java | 11 ++ .../ku/covigator/service/CourseService.java | 16 +++ .../ku/covigator/service/ReviewService.java | 3 - .../controller/CourseControllerTest.java | 68 ++++++++++++ .../ku/covigator/service/AuthServiceTest.java | 1 - .../covigator/service/CourseServiceTest.java | 105 +++++++++++++++++- .../covigator/service/PlaceServiceTest.java | 1 - 8 files changed, 215 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/ku/covigator/controller/CourseController.java b/src/main/java/com/ku/covigator/controller/CourseController.java index 643d7c2..0ff7b94 100644 --- a/src/main/java/com/ku/covigator/controller/CourseController.java +++ b/src/main/java/com/ku/covigator/controller/CourseController.java @@ -16,21 +16,20 @@ @Tag(name = "course", description = "커뮤니티 코스") @RestController -@RequestMapping("/community/courses") @RequiredArgsConstructor public class CourseController { private final CourseService courseService; @Operation(summary = "코스 등록") - @PostMapping + @PostMapping("/community/courses") public ResponseEntity addCommunityCourse(@LoggedInMemberId Long memberId, @RequestBody PostCourseRequest request) { courseService.addCommunityCourse(memberId, request); return ResponseEntity.ok().build(); } @Operation(summary = "전체 코스 조회") - @GetMapping + @GetMapping("/community/courses") public ResponseEntity getAllCommunityCourses( @PageableDefault( page = 0, size = 10, sort = "createdAt", direction = Sort.Direction.DESC @@ -39,7 +38,7 @@ public ResponseEntity getAllCommunityCourses( } @Operation(summary = "상세 코스 조회") - @GetMapping("/{course_id}") + @GetMapping("/community/courses/{course_id}") public ResponseEntity getCommunityCourseInfo( @LoggedInMemberId Long memberId, @PathVariable(name = "course_id") Long courseId) { @@ -47,10 +46,22 @@ public ResponseEntity getCommunityCourseInfo( } @Operation(summary = "코스 삭제") - @DeleteMapping("/{course_id}") + @DeleteMapping("/community/courses/{course_id}") public ResponseEntity deleteCommunityCourse( @PathVariable(name = "course_id") Long courseId) { courseService.deleteCourse(courseId); return ResponseEntity.ok().build(); } + + @Operation(summary = "찜한 코스 모아보기") + @GetMapping("/my-page/liked-courses") + public ResponseEntity getLikedCourses(@LoggedInMemberId Long memberId){ + return ResponseEntity.ok(courseService.findLikedCourses(memberId)); + } + + @Operation(summary = "마이 코스 모아보기") + @GetMapping("/my-page/my-courses") + public ResponseEntity getMyCourses(@LoggedInMemberId Long memberId) { + return ResponseEntity.ok(courseService.findMyCourses(memberId)); + } } diff --git a/src/main/java/com/ku/covigator/repository/CourseRepository.java b/src/main/java/com/ku/covigator/repository/CourseRepository.java index 7f48852..6e8b405 100644 --- a/src/main/java/com/ku/covigator/repository/CourseRepository.java +++ b/src/main/java/com/ku/covigator/repository/CourseRepository.java @@ -15,4 +15,15 @@ public interface CourseRepository extends JpaRepository { @EntityGraph(attributePaths = "places") Optional findCourseWithPlacesById(Long courseId); + + @Query(""" + SELECT c + FROM Course c, Like l + WHERE l.member.id = :memberId AND l.course.id = c.id + ORDER BY l.createdAt DESC + """) + Slice findLikedCoursesByMemberId(Long memberId, Pageable pageable); + + @EntityGraph(attributePaths = "member") + Slice findMyCoursesByMemberId(Long memberId, Pageable pageable); } diff --git a/src/main/java/com/ku/covigator/service/CourseService.java b/src/main/java/com/ku/covigator/service/CourseService.java index ae5959f..49bc483 100644 --- a/src/main/java/com/ku/covigator/service/CourseService.java +++ b/src/main/java/com/ku/covigator/service/CourseService.java @@ -12,8 +12,10 @@ import com.ku.covigator.repository.CourseRepository; import com.ku.covigator.repository.MemberRepository; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; +import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -49,6 +51,20 @@ public GetCourseListResponse findAllCourses(Pageable pageable) { } + public GetCourseListResponse findLikedCourses(Long memberId) { + + Pageable pageable = PageRequest.of(0, 10); + Slice courses = courseRepository.findLikedCoursesByMemberId(memberId, pageable); + return GetCourseListResponse.fromCourseSlice(courses); + } + + public GetCourseListResponse findMyCourses(Long memberId) { + + Pageable pageable = PageRequest.of(0, 10, Sort.by("createdAt").descending()); + Slice courses = courseRepository.findMyCoursesByMemberId(memberId, pageable); + return GetCourseListResponse.fromCourseSlice(courses); + } + @Transactional(readOnly = true) public GetCommunityCourseInfoResponse findCourse(Long memberId, Long courseId) { diff --git a/src/main/java/com/ku/covigator/service/ReviewService.java b/src/main/java/com/ku/covigator/service/ReviewService.java index 3fd71c0..c3d422c 100644 --- a/src/main/java/com/ku/covigator/service/ReviewService.java +++ b/src/main/java/com/ku/covigator/service/ReviewService.java @@ -11,14 +11,11 @@ import com.ku.covigator.repository.MemberRepository; import com.ku.covigator.repository.ReviewRepository; import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; - @Service @RequiredArgsConstructor public class ReviewService { diff --git a/src/test/java/com/ku/covigator/controller/CourseControllerTest.java b/src/test/java/com/ku/covigator/controller/CourseControllerTest.java index 77daae8..6779c4c 100644 --- a/src/test/java/com/ku/covigator/controller/CourseControllerTest.java +++ b/src/test/java/com/ku/covigator/controller/CourseControllerTest.java @@ -160,4 +160,72 @@ void deleteCommunityCourse() throws Exception { .andDo(print()) .andExpect(status().isOk()); } + + @DisplayName("찜한 코스 모아보기를 요청한다.") + @Test + void getLikedCourses() throws Exception { + //given + Long memberId = 1L; + + GetCourseListResponse.CourseDto courseDto = GetCourseListResponse.CourseDto.builder() + .name("건대 풀코스") + .description("건대 핫플 요약 코스") + .score(5.0) + .build(); + + GetCourseListResponse response = GetCourseListResponse.builder() + .courses(List.of(courseDto)) + .hasNext(false) + .build(); + + given(jwtAuthArgumentResolver.resolveArgument(any(), any(), any(), any())) + .willReturn(memberId); + given(jwtAuthArgumentResolver.supportsParameter(any())).willReturn(true); + given(courseService.findLikedCourses(memberId)).willReturn(response); + + //when //then + mockMvc.perform(get("/my-page/liked-courses")) + .andDo(print()) + .andExpectAll( + status().isOk(), + jsonPath("$.courses[0].name").value("건대 풀코스"), + jsonPath("$.courses[0].description").value("건대 핫플 요약 코스"), + jsonPath("$.courses[0].score").value(5.0), + jsonPath("$.has_next").value(false) + ); + } + + @DisplayName("마이 코스 모아보기를 요청한다.") + @Test + void getMyCourses() throws Exception { + //given + Long memberId = 1L; + + GetCourseListResponse.CourseDto courseDto = GetCourseListResponse.CourseDto.builder() + .name("건대 풀코스") + .description("건대 핫플 요약 코스") + .score(5.0) + .build(); + + GetCourseListResponse response = GetCourseListResponse.builder() + .courses(List.of(courseDto)) + .hasNext(false) + .build(); + + given(jwtAuthArgumentResolver.resolveArgument(any(), any(), any(), any())) + .willReturn(memberId); + given(jwtAuthArgumentResolver.supportsParameter(any())).willReturn(true); + given(courseService.findMyCourses(memberId)).willReturn(response); + + //when //then + mockMvc.perform(get("/my-page/my-courses")) + .andDo(print()) + .andExpectAll( + status().isOk(), + jsonPath("$.courses[0].name").value("건대 풀코스"), + jsonPath("$.courses[0].description").value("건대 핫플 요약 코스"), + jsonPath("$.courses[0].score").value(5.0), + jsonPath("$.has_next").value(false) + ); + } } \ No newline at end of file diff --git a/src/test/java/com/ku/covigator/service/AuthServiceTest.java b/src/test/java/com/ku/covigator/service/AuthServiceTest.java index 068dd46..d6ec4e1 100644 --- a/src/test/java/com/ku/covigator/service/AuthServiceTest.java +++ b/src/test/java/com/ku/covigator/service/AuthServiceTest.java @@ -11,7 +11,6 @@ import com.ku.covigator.security.jwt.JwtProvider; import com.ku.covigator.security.kakao.KakaoOauthProvider; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; diff --git a/src/test/java/com/ku/covigator/service/CourseServiceTest.java b/src/test/java/com/ku/covigator/service/CourseServiceTest.java index 0ef0f43..6def4df 100644 --- a/src/test/java/com/ku/covigator/service/CourseServiceTest.java +++ b/src/test/java/com/ku/covigator/service/CourseServiceTest.java @@ -9,7 +9,10 @@ import com.ku.covigator.dto.response.GetCommunityCourseInfoResponse; import com.ku.covigator.dto.response.GetCourseListResponse; import com.ku.covigator.exception.notfound.NotFoundMemberException; -import com.ku.covigator.repository.*; +import com.ku.covigator.repository.CoursePlaceRepository; +import com.ku.covigator.repository.CourseRepository; +import com.ku.covigator.repository.LikeRepository; +import com.ku.covigator.repository.MemberRepository; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -402,6 +405,106 @@ void test() { ); } + @DisplayName("찜한 코스 리스트를 찜 시간 최신순으로 조회한다.") + @Test + void findLikedCourses() { + //given + Member member = createMember(); + Member savedMember = memberRepository.save(member); + + Course course = Course.builder() + .name("건대 풀코스") + .isPublic('Y') + .description("건대 핫플 리스트") + .member(member) + .likeCnt(100L) + .build(); + Course savedCourse = courseRepository.save(course); + + Course course2 = Course.builder() + .name("건대 풀코스2") + .isPublic('Y') + .description("건대 핫플 리스트2") + .member(member) + .likeCnt(10L) + .build(); + Course savedCourse2 = courseRepository.save(course2); + + Course course3 = Course.builder() + .name("건대 풀코스3") + .isPublic('Y') + .description("건대 핫플 리스트3") + .member(member) + .likeCnt(10L) + .build(); + courseRepository.save(course3); + + Like like = Like.builder() + .member(savedMember) + .course(savedCourse) + .build(); + Like like2 = Like.builder() + .member(savedMember) + .course(savedCourse2) + .build(); + likeRepository.saveAll(List.of(like, like2)); + + //when + GetCourseListResponse response = courseService.findLikedCourses(savedMember.getId()); + + //then + assertAll( + () -> assertEquals(2, response.courses().size()), + () -> assertThat(response.courses()) + .extracting("name") + .containsExactly("건대 풀코스2", "건대 풀코스"), + () -> assertThat(response.courses()) + .extracting("description") + .containsExactly("건대 핫플 리스트2", "건대 핫플 리스트"), + () -> assertThat(response.hasNext()).isFalse() + ); + } + + @DisplayName("마이 코스 리스트를 생성시간 기준 최신순으로 조회한다.") + @Test + void findMyCourses() { + //given + Member member = createMember(); + Member savedMember = memberRepository.save(member); + + Course course = Course.builder() + .name("건대 풀코스") + .isPublic('Y') + .description("건대 핫플 리스트") + .member(member) + .likeCnt(100L) + .build(); + + Course course2 = Course.builder() + .name("건대 풀코스2") + .isPublic('Y') + .description("건대 핫플 리스트2") + .member(member) + .likeCnt(10L) + .build(); + courseRepository.saveAll(List.of(course, course2)); + + //when + GetCourseListResponse response = courseService.findMyCourses(savedMember.getId()); + + //then + assertAll( + () -> assertEquals(2, response.courses().size()), + () -> assertThat(response.courses()) + .extracting("name") + .containsExactly("건대 풀코스2", "건대 풀코스"), + () -> assertThat(response.courses()) + .extracting("description") + .containsExactly("건대 핫플 리스트2", "건대 핫플 리스트"), + () -> assertThat(response.hasNext()).isFalse() + ); + } + private Member createMember() { return Member.builder() .name("김코비") diff --git a/src/test/java/com/ku/covigator/service/PlaceServiceTest.java b/src/test/java/com/ku/covigator/service/PlaceServiceTest.java index b257e07..cc4045b 100644 --- a/src/test/java/com/ku/covigator/service/PlaceServiceTest.java +++ b/src/test/java/com/ku/covigator/service/PlaceServiceTest.java @@ -4,7 +4,6 @@ import com.ku.covigator.exception.notfound.NotFoundPlaceException; import com.ku.covigator.repository.PlaceRepository; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.locationtech.jts.geom.Coordinate;