Skip to content

Commit c90dbf9

Browse files
authored
Merge pull request Kernel360#459 from GBGreenBravo/feature/#458_My_Gym_Liked_List
Feat : 내가 저장한(좋아요 누른) 암장 목록 반환
2 parents 9aa4b4f + 941bcaa commit c90dbf9

File tree

14 files changed

+204
-9
lines changed

14 files changed

+204
-9
lines changed

orury-client/src/main/java/org/orury/client/gym/application/GymService.java

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ public interface GymService {
1313

1414
List<GymDto> getGymDtosByAreaGridOrderByDistanceAsc(AreaGrid areaGrid, float latitude, float longitude);
1515

16+
List<GymDto> getGymDtosByUserLiked(Long userId, Long cursor);
17+
1618
void createGymLike(GymLikeDto gymLikeDto);
1719

1820
void deleteGymLike(GymLikeDto gymLikeDto);

orury-client/src/main/java/org/orury/client/gym/application/GymServiceImpl.java

+12
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
import org.orury.common.error.code.GymErrorCode;
77
import org.orury.common.error.exception.BusinessException;
88
import org.orury.common.util.BusinessHoursConverter;
9+
import org.orury.domain.global.constants.NumberConstants;
910
import org.orury.domain.gym.domain.GymReader;
1011
import org.orury.domain.gym.domain.GymStore;
1112
import org.orury.domain.gym.domain.dto.GymDto;
1213
import org.orury.domain.gym.domain.dto.GymLikeDto;
1314
import org.orury.domain.gym.domain.entity.Gym;
15+
import org.springframework.data.domain.PageRequest;
1416
import org.springframework.stereotype.Service;
1517
import org.springframework.transaction.annotation.Transactional;
1618

@@ -49,6 +51,16 @@ public List<GymDto> getGymDtosByAreaGridOrderByDistanceAsc(AreaGrid areaGrid, fl
4951
return sortGymsByDistanceAsc(gyms, latitude, longitude);
5052
}
5153

54+
@Override
55+
@Transactional(readOnly = true)
56+
public List<GymDto> getGymDtosByUserLiked(Long userId, Long cursor) {
57+
var pageRequest = PageRequest.of(0, NumberConstants.GYM_PAGINATION_SIZE);
58+
return gymReader.findGymsByUserLiked(userId, cursor, pageRequest)
59+
.stream()
60+
.map(GymDto::from)
61+
.toList();
62+
}
63+
5264
@Override
5365
@Transactional
5466
public void createGymLike(GymLikeDto gymLikeDto) {

orury-client/src/main/java/org/orury/client/user/application/UserFacade.java

+10-5
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,19 @@
66
import org.orury.client.crew.application.CrewService;
77
import org.orury.client.global.IdIdentifiable;
88
import org.orury.client.global.WithCursorResponse;
9+
import org.orury.client.gym.application.GymService;
910
import org.orury.client.meeting.application.MeetingService;
1011
import org.orury.client.post.application.PostService;
1112
import org.orury.client.review.application.ReviewService;
1213
import org.orury.client.user.interfaces.request.MeetingViewedRequest;
1314
import org.orury.client.user.interfaces.request.UserInfoRequest;
14-
import org.orury.client.user.interfaces.response.*;
1515
import org.orury.client.user.interfaces.request.UserReportRequest;
16-
import org.orury.client.user.interfaces.response.MyCommentResponse;
17-
import org.orury.client.user.interfaces.response.MyMeetingResponse;
18-
import org.orury.client.user.interfaces.response.MyPostResponse;
19-
import org.orury.client.user.interfaces.response.MyReviewResponse;
16+
import org.orury.client.user.interfaces.response.*;
2017
import org.orury.domain.comment.domain.dto.CommentDto;
2118
import org.orury.domain.crew.domain.dto.CrewDto;
2219
import org.orury.domain.crew.domain.entity.CrewMemberPK;
2320
import org.orury.domain.global.constants.NumberConstants;
21+
import org.orury.domain.gym.domain.dto.GymDto;
2422
import org.orury.domain.meeting.domain.dto.MeetingDto;
2523
import org.orury.domain.post.domain.dto.PostDto;
2624
import org.orury.domain.review.domain.dto.ReviewDto;
@@ -42,6 +40,7 @@ public class UserFacade {
4240
private final CommentService commentService;
4341
private final MeetingService meetingService;
4442
private final CrewService crewService;
43+
private final GymService gymService;
4544

4645
public UserDto readMypage(Long id) {
4746
return userService.getUserDtoById(id);
@@ -78,6 +77,12 @@ public WithCursorResponse<MyCommentResponse> getCommentsByUserId(Long id, Long c
7877
return convertDtosToWithCursorResponse(commmentDtos, MyCommentResponse::of, cursor);
7978
}
8079

80+
public WithCursorResponse<MyGymResponse> getGymsByUserLiked(Long userId, Long cursor) {
81+
List<GymDto> gymDtos = gymService.getGymDtosByUserLiked(userId, cursor);
82+
83+
return convertDtosToWithCursorResponse(gymDtos, MyGymResponse::of, cursor);
84+
}
85+
8186
public List<MyMeetingResponse> getMeetingsByUserId(Long userId) {
8287
List<MeetingDto> meetingDtos = meetingService.getUpcomingMeetingDtosByUserId(userId);
8388

orury-client/src/main/java/org/orury/client/user/interfaces/UserController.java

+8
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ public ApiResponse getCommentsByUserId(@AuthenticationPrincipal UserPrincipal us
8181
return ApiResponse.of(UserMessage.USER_COMMENTS_READ.getMessage(), cursorResponse);
8282
}
8383

84+
@Operation(summary = "내가 저장한 암장목록 조회", description = "user_id로 내가 저장한 암장목록을 조회한다.")
85+
@GetMapping("/gyms")
86+
public ApiResponse getGymsByUserLiked(@AuthenticationPrincipal UserPrincipal userPrincipal, @RequestParam Long cursor) {
87+
WithCursorResponse<MyGymResponse> cursorResponse = userFacade.getGymsByUserLiked(userPrincipal.id(), cursor);
88+
89+
return ApiResponse.of(UserMessage.USER_GYMS_READ.getMessage(), cursorResponse);
90+
}
91+
8492
@Operation(summary = "다가오는 크루일정 조회", description = "user_id로 다가오는 크루일정 목록을 조회한다.")
8593
@GetMapping("/meetings")
8694
public ApiResponse getMeetingsByUserId(@AuthenticationPrincipal UserPrincipal userPrincipal) {

orury-client/src/main/java/org/orury/client/user/interfaces/message/UserMessage.java

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public enum UserMessage {
1212
USER_POSTS_READ("작성한 게시글을 조회했습니다."),
1313
USER_COMMENTS_READ("작성한 댓글을 조회했습니다."),
1414
USER_REVIEWS_READ("작성한 리뷰를 조회했습니다."),
15+
USER_GYMS_READ("저장한 암장을 조회했습니다."),
1516
USER_CREW_MEMBERS_READ("크루 일정 조회여부를 조회했습니다."),
1617
USER_MEETING_VIEWED_UPDATED("크루 일정 조회여부를 수정했습니다."),
1718
USER_MEETINGS_READ("다가오는 크루 일정을 조회했습니다."),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.orury.client.user.interfaces.response;
2+
3+
import org.orury.client.global.IdIdentifiable;
4+
import org.orury.domain.global.domain.Region;
5+
import org.orury.domain.gym.domain.dto.GymDto;
6+
7+
public record MyGymResponse(
8+
Long id,
9+
String gymName,
10+
String gymType,
11+
String region
12+
) implements IdIdentifiable {
13+
public static MyGymResponse of(GymDto gymDto) {
14+
return new MyGymResponse(
15+
gymDto.id(),
16+
gymDto.name(),
17+
gymDto.gymType().getDescription(),
18+
Region.getDescriptionFromAddress(gymDto.address())
19+
);
20+
}
21+
}

orury-client/src/test/java/org/orury/client/config/FacadeTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ void setUp() {
5959
meetingService = mock(MeetingService.class);
6060
notificationService = mock(NotificationService.class);
6161

62-
userFacade = new UserFacade(userService, postService, reviewService, commentService, meetingService, crewService);
62+
userFacade = new UserFacade(userService, postService, reviewService, commentService, meetingService, crewService, gymService);
6363
gymFacade = new GymFacade(gymService, reviewService);
6464
commentFacade = new CommentFacade(commentService, postService, userService, notificationService);
6565
crewFacade = new CrewFacade(crewService, userService);

orury-client/src/test/java/org/orury/client/gym/application/GymServiceImplTest.java

+30
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.orury.domain.gym.domain.dto.GymLikeDto;
1111
import org.orury.domain.gym.domain.entity.Gym;
1212
import org.orury.domain.gym.domain.entity.GymLikePK;
13+
import org.springframework.data.domain.PageRequest;
1314

1415
import java.time.DayOfWeek;
1516
import java.time.LocalTime;
@@ -125,6 +126,35 @@ void when_NothingSearched_Then_RetrieveEmptyList() {
125126
.findGymsBySearchWord(anyString());
126127
}
127128

129+
@Test
130+
@DisplayName("유저id와 cursor에 대해, 해당 유저가 좋아요한 GymDto 목록을 반환한다.")
131+
void should_RetrieveGymDtoListByUserLiked() {
132+
// given
133+
Long userId = 98L;
134+
Long cursor = 20L;
135+
List<Gym> gyms = List.of(
136+
createGym().id(19L).build().get(),
137+
createGym().id(14L).build().get(),
138+
createGym().id(3L).build().get()
139+
);
140+
List<GymDto> expectedGymDtos = List.of(
141+
GymDto.from(gyms.get(0)),
142+
GymDto.from(gyms.get(1)),
143+
GymDto.from(gyms.get(2))
144+
);
145+
146+
given(gymReader.findGymsByUserLiked(userId, cursor, PageRequest.of(0, 15)))
147+
.willReturn(gyms);
148+
149+
// when
150+
List<GymDto> actualGymDtos = gymService.getGymDtosByUserLiked(userId, cursor);
151+
152+
// then
153+
assertEquals(expectedGymDtos, actualGymDtos);
154+
then(gymReader).should(times(1))
155+
.findGymsByUserLiked(anyLong(), anyLong(), any());
156+
}
157+
128158
@Test
129159
@DisplayName("암장에 대한 유저의 암장 좋아요 기존에 없다면, 정상적으로 암장 좋아요를 생성한다.")
130160
void should_CreateGymLike() {

orury-client/src/test/java/org/orury/client/user/application/UserFacadeTest.java

+29
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
import org.orury.client.global.WithCursorResponse;
77
import org.orury.client.user.interfaces.request.UserInfoRequest;
88
import org.orury.client.user.interfaces.response.MyCommentResponse;
9+
import org.orury.client.user.interfaces.response.MyGymResponse;
910
import org.orury.client.user.interfaces.response.MyPostResponse;
1011
import org.orury.client.user.interfaces.response.MyReviewResponse;
1112
import org.orury.domain.comment.domain.dto.CommentDto;
13+
import org.orury.domain.gym.domain.dto.GymDto;
1214
import org.orury.domain.post.domain.dto.PostDto;
1315
import org.orury.domain.review.domain.dto.ReviewDto;
1416
import org.orury.domain.user.domain.dto.UserDto;
@@ -27,6 +29,7 @@
2729
import static org.orury.client.ClientFixtureFactory.TestReportRequest.createReportRequest;
2830
import static org.orury.client.ClientFixtureFactory.TestUserInfoRequest.createUserInfoRequest;
2931
import static org.orury.domain.CommentDomainFixture.TestCommentDto.createCommentDto;
32+
import static org.orury.domain.GymDomainFixture.TestGymDto.createGymDto;
3033
import static org.orury.domain.PostDomainFixture.TestPostDto.createPostDto;
3134
import static org.orury.domain.ReviewDomainFixture.TestReviewDto.createReviewDto;
3235
import static org.orury.domain.UserDomainFixture.TestUserDto.createUserDto;
@@ -166,6 +169,32 @@ void should_returnWithCommentsCursorResponse() {
166169
then(commentService).should(times(1)).getCommentDtosByUserId(anyLong(), anyLong());
167170
}
168171

172+
@Test
173+
@DisplayName("getGymsByUserLiked(Long id, Long cursor) test: id, cursor 값을 입력받아 내가 저장한 암장목록을 반환한다. [성공] ")
174+
void should_returnWithGymsCursorResponse() {
175+
//given
176+
Long userId = 1L;
177+
Long cursor = 0L;
178+
179+
List<GymDto> gymDtos = new ArrayList<>();
180+
for (int i = 10; i >= 1; i--) {
181+
gymDtos.add(createGymDto((long) i).build().get());
182+
}
183+
184+
WithCursorResponse<MyGymResponse> response = WithCursorResponse.of(gymDtos.stream()
185+
.map(MyGymResponse::of)
186+
.toList(), cursor);
187+
188+
given(gymService.getGymDtosByUserLiked(anyLong(), anyLong())).willReturn(gymDtos);
189+
190+
//when
191+
WithCursorResponse<MyGymResponse> actualResponse = userFacade.getGymsByUserLiked(userId, cursor);
192+
193+
//then
194+
assertThat(actualResponse).isEqualTo(response);
195+
then(gymService).should(times(1)).getGymDtosByUserLiked(anyLong(), anyLong());
196+
}
197+
169198
@Test
170199
@DisplayName("deleteUser(Long id) test: userId를 받아 해당하는 User를 삭제한다. [성공] ")
171200
void should_deleteUser() {

orury-domain/src/main/java/org/orury/domain/global/domain/Region.java

+9
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,13 @@ public static Region getEnumFromValue(String value) {
4444
}
4545
return null;
4646
}
47+
48+
public static String getDescriptionFromAddress(String address) {
49+
for (Region region : Region.values()) {
50+
if (address.contains(region.getDescription())) {
51+
return region.description;
52+
}
53+
}
54+
return null;
55+
}
4756
}

orury-domain/src/main/java/org/orury/domain/gym/domain/GymReader.java

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import org.orury.domain.gym.domain.entity.Gym;
44
import org.orury.domain.gym.domain.entity.GymLikePK;
5+
import org.springframework.data.domain.Pageable;
56

67
import java.util.List;
78
import java.util.Map;
@@ -16,6 +17,8 @@ public interface GymReader {
1617

1718
List<Gym> findGymsInAreaGrid(Map<String, Double> gridMap);
1819

20+
List<Gym> findGymsByUserLiked(Long userId, Long cursor, Pageable pageRequest);
21+
1922
boolean existsGymLikeById(GymLikePK gymLikePK);
2023

2124
boolean existsGymLikeByUserIdAndGymId(Long userId, Long gymId);
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
package org.orury.domain.gym.infrastructure;
22

3-
import org.orury.domain.gym.domain.entity.GymLikePK;
43
import org.orury.domain.gym.domain.entity.GymLike;
4+
import org.orury.domain.gym.domain.entity.GymLikePK;
5+
import org.springframework.data.domain.Pageable;
56
import org.springframework.data.jpa.repository.JpaRepository;
67

78
import java.util.List;
@@ -10,4 +11,8 @@ public interface GymLikeRepository extends JpaRepository<GymLike, GymLikePK> {
1011
boolean existsByGymLikePK_UserIdAndGymLikePK_GymId(Long userId, Long gymId);
1112

1213
List<GymLike> findByGymLikePK_UserId(Long userId);
14+
15+
List<GymLike> findByGymLikePK_UserIdOrderByGymLikePKDesc(Long userId, Pageable pageable);
16+
17+
List<GymLike> findByGymLikePK_UserIdAndGymLikePK_GymIdLessThanOrderByGymLikePKDesc(Long userId, Long cursor, Pageable pageable);
1318
}

orury-domain/src/main/java/org/orury/domain/gym/infrastructure/GymReaderImpl.java

+13
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package org.orury.domain.gym.infrastructure;
22

33
import lombok.RequiredArgsConstructor;
4+
import org.orury.domain.global.constants.NumberConstants;
45
import org.orury.domain.gym.domain.GymReader;
56
import org.orury.domain.gym.domain.entity.Gym;
7+
import org.orury.domain.gym.domain.entity.GymLike;
68
import org.orury.domain.gym.domain.entity.GymLikePK;
9+
import org.springframework.data.domain.Pageable;
710
import org.springframework.stereotype.Repository;
811

912
import java.util.List;
@@ -40,6 +43,16 @@ public List<Gym> findGymsInAreaGrid(Map<String, Double> gridMap) {
4043
);
4144
}
4245

46+
@Override
47+
public List<Gym> findGymsByUserLiked(Long userId, Long cursor, Pageable pageRequest) {
48+
List<GymLike> gymLikes = (cursor.equals(NumberConstants.FIRST_CURSOR))
49+
? gymLikeRepository.findByGymLikePK_UserIdOrderByGymLikePKDesc(userId, pageRequest)
50+
: gymLikeRepository.findByGymLikePK_UserIdAndGymLikePK_GymIdLessThanOrderByGymLikePKDesc(userId, cursor, pageRequest);
51+
return gymLikes.stream()
52+
.map(gymLike -> gymRepository.findById(gymLike.getGymLikePK().getGymId()).orElse(null))
53+
.toList();
54+
}
55+
4356
@Override
4457
public boolean existsGymLikeById(GymLikePK gymLikePK) {
4558
return gymLikeRepository.existsById(gymLikePK);

0 commit comments

Comments
 (0)