Skip to content

Commit

Permalink
feat: 사용자 추천 API 정책 변경으로 비회원도 사용자 추천 나타나도록 API 수정 (#314)
Browse files Browse the repository at this point in the history
* 사용자 추천 리스트 조회 정책 변경으로 비회원도 사용자 추천 나타나도록 API 수정

* test: 비회원도 사용자 추천 나타나도록 API 수정 하여 인수테스트 케이스 추가

* refactor: 코드리뷰를 통한 네이밍 수정 및 테스트 케이스 추가

* 나의 콜렉션 조회 응답에 폴더 이름도 응답하도록 추가

* refactor: 전체 폴더에 대한 콜렉션 조회 추가 및 코드리뷰에 의한 네이밍 변경
  • Loading branch information
pparkjs authored Oct 27, 2024
1 parent ef84178 commit 982b8fd
Show file tree
Hide file tree
Showing 11 changed files with 192 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,44 @@
import java.util.List;
import lombok.Builder;

public record CollectionResponse(
public record CollectionFindResponse(
Long cursorId,
Boolean hasNext,
List<CollectionListsResponse> collectionLists
List<CollectionDto> collectionLists,
String folderName
) {

public static CollectionResponse of(Long cursorId, Boolean hasNext, List<Collect> collects) {
return new CollectionResponse(cursorId, hasNext, toList(collects));
public static CollectionFindResponse of(
Long cursorId,
Boolean hasNext,
List<Collect> collects,
String folderName
) {
return new CollectionFindResponse(cursorId, hasNext, toList(collects), folderName);
}

public static List<CollectionListsResponse> toList(List<Collect> collects) {
public static List<CollectionDto> toList(List<Collect> collects) {
return collects.stream()
.map(CollectionListsResponse::of)
.map(CollectionDto::of)
.toList();
}

public record CollectionListsResponse(
public record CollectionDto(
Long id,
ListsResponse list
ListsDto list
) {

public static CollectionListsResponse of(Collect collect) {
return new CollectionListsResponse(collect.getId(), toResponse(collect.getList()));
public static CollectionDto of(Collect collect) {
return new CollectionDto(collect.getId(), toResponse(collect.getList()));
}

public static ListsResponse toResponse(ListEntity list) {
return ListsResponse.of(list);
public static ListsDto toResponse(ListEntity list) {
return ListsDto.of(list);
}
}

@Builder
public record ListsResponse(
public record ListsDto(
Long id,
String backgroundColor,
String title,
Expand All @@ -48,11 +54,11 @@ public record ListsResponse(
String representativeImageUrl,
String category,
LocalDateTime updatedDate,
List<ListItemsResponse> listItems
List<ListItemsDto> listItems
) {

public static ListsResponse of(ListEntity list) {
return ListsResponse.builder()
public static ListsDto of(ListEntity list) {
return ListsDto.builder()
.id(list.getId())
.backgroundColor(list.getBackgroundColor().name())
.title(list.getTitle().getValue())
Expand All @@ -66,23 +72,23 @@ public static ListsResponse of(ListEntity list) {
.build();
}

public static List<ListItemsResponse> toList(List<Item> items) {
public static List<ListItemsDto> toList(List<Item> items) {
return items.stream()
.map(ListItemsResponse::of)
.map(ListItemsDto::of)
.toList();
}
}

@Builder
public record ListItemsResponse(
public record ListItemsDto(
Long id,
int rank,
String title,
String imageUrl
) {

public static ListItemsResponse of(Item item) {
return ListItemsResponse.builder()
public static ListItemsDto of(Item item) {
return ListItemsDto.builder()
.id(item.getId())
.rank(item.getRanking())
.title(item.getTitle().getValue())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.listywave.alarm.application.domain.AlarmCreateEvent;
import com.listywave.collection.application.domain.Collect;
import com.listywave.collection.application.domain.Folder;
import com.listywave.collection.application.dto.CollectionResponse;
import com.listywave.collection.application.dto.CollectionFindResponse;
import com.listywave.collection.repository.CollectionRepository;
import com.listywave.collection.repository.FolderRepository;
import com.listywave.list.application.domain.category.CategoryType;
Expand Down Expand Up @@ -32,6 +32,8 @@ public class CollectionService {
private final CollectionRepository collectionRepository;
private final ApplicationEventPublisher applicationEventPublisher;

private final static String FOLDER_ENTIRE_NAME = "전체";

public void collectOrCancel(Long listId, Long folderId, Long userId) {
User user = userRepository.getById(userId);
ListEntity list = listRepository.getById(listId);
Expand Down Expand Up @@ -60,17 +62,21 @@ private void addCollect(ListEntity list, User user, Folder folder) {
applicationEventPublisher.publishEvent(AlarmCreateEvent.collect(user, list));
}

public CollectionResponse getCollection(Long loginUserId, Long cursorId, Pageable pageable, Long folderId) {
User user = userRepository.getById(loginUserId);
folderRepository.getById(folderId);
public CollectionFindResponse getCollection(Long userId, Long cursorId, Pageable pageable, Long folderId) {
User user = userRepository.getById(userId);
String folderName = FOLDER_ENTIRE_NAME;
if (folderId != 0L) {
Folder folder = folderRepository.getById(folderId);
folderName = folder.getFolderName();
}
Slice<Collect> result = collectionRepository.getAllCollectionList(cursorId, pageable, user.getId(), folderId);
List<Collect> collectionList = result.getContent();

cursorId = null;
if (!collectionList.isEmpty()) {
cursorId = collectionList.get(collectionList.size() - 1).getId();
}
return CollectionResponse.of(cursorId, result.hasNext(), collectionList);
return CollectionFindResponse.of(cursorId, result.hasNext(), collectionList, folderName);
}

public List<CategoryTypeResponse> getCategoriesOfCollection(Long loginUserId) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
package com.listywave.collection.presentation.controller;

import com.listywave.collection.application.dto.CollectionResponse;
import com.listywave.collection.application.dto.CollectionFindResponse;
import com.listywave.collection.application.service.CollectionService;
import com.listywave.collection.presentation.dto.FolderSelectionRequest;
import com.listywave.common.auth.Auth;
import com.listywave.list.application.dto.response.CategoryTypeResponse;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import org.springframework.web.bind.annotation.GetMapping;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
Expand All @@ -30,13 +34,13 @@ ResponseEntity<Void> collectOrCancel(
}

@GetMapping("/folder/{folderId}/collections")
ResponseEntity<CollectionResponse> getCollection(
ResponseEntity<CollectionFindResponse> getCollection(
@Auth Long loginUserId,
@PathVariable("folderId") Long folderId,
@RequestParam(name = "cursorId", required = false) Long cursorId,
@PageableDefault(size = 10) Pageable pageable
) {
CollectionResponse collection = collectionService.getCollection(loginUserId, cursorId, pageable, folderId);
CollectionFindResponse collection = collectionService.getCollection(loginUserId, cursorId, pageable, folderId);
return ResponseEntity.ok(collection);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import static com.listywave.collection.application.domain.QCollect.collect;
import static com.listywave.common.util.PaginationUtils.checkEndPage;
import static com.listywave.list.application.domain.category.CategoryType.ENTIRE;
import static com.listywave.list.application.domain.item.QItem.item;
import static com.listywave.list.application.domain.list.QListEntity.listEntity;
import static com.listywave.user.application.domain.QUser.user;
Expand All @@ -13,10 +12,10 @@
import com.listywave.user.application.domain.User;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import java.util.List;

@RequiredArgsConstructor
public class CustomCollectionRepositoryImpl implements CustomCollectionRepository {
Expand All @@ -43,7 +42,7 @@ public Slice<Collect> getAllCollectionList(Long cursorId, Pageable pageable, Lon
}

private BooleanExpression folderIdEq(Long folderId) {
return collect.folder.id.eq(folderId);
return folderId == 0L ? null : collect.folder.id.eq(folderId);
}

private BooleanExpression collectIdLt(Long cursorId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
import lombok.Builder;

@Builder
public record RecommendUsersResponse(
public record UsersRecommendedResponse(
Long id,
String nickname,
String profileImageUrl
) {

public static RecommendUsersResponse of(User user) {
return RecommendUsersResponse.builder()
public static UsersRecommendedResponse of(User user) {
return UsersRecommendedResponse.builder()
.id(user.getId())
.nickname(user.getNickname())
.profileImageUrl(user.getProfileImageUrl())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import com.listywave.user.application.domain.User;
import com.listywave.user.application.dto.FollowersResponse;
import com.listywave.user.application.dto.FollowingsResponse;
import com.listywave.user.application.dto.RecommendUsersResponse;
import com.listywave.user.application.dto.UsersRecommendedResponse;
import com.listywave.user.application.dto.UserInfoResponse;
import com.listywave.user.application.dto.UserProflieUpdateCommand;
import com.listywave.user.application.dto.search.UserElasticSearchResponse;
Expand Down Expand Up @@ -121,18 +121,24 @@ public FollowersResponse getFollowers(Long userId, Pageable pageable, String sea
}

@Transactional(readOnly = true)
public List<RecommendUsersResponse> getRecommendUsers(Long loginUserId) {
public List<UsersRecommendedResponse> getRecommendedUsers(Long loginUserId) {
if(loginUserId == null){
List<User> recommendUsers = userRepository.getRecommendUsers(List.of(), null);
return toUsersRecommendedResponse(recommendUsers);
}
User user = userRepository.getById(loginUserId);
List<Follow> follows = followRepository.getAllByFollowerUser(user);

List<User> myFollowingUsers = follows.stream()
.map(Follow::getFollowingUser)
.filter(followingUser -> !followingUser.isDelete())
.toList();

List<User> recommendUsers = userRepository.getRecommendUsers(myFollowingUsers, user);
return toUsersRecommendedResponse(recommendUsers);
}

private List<UsersRecommendedResponse> toUsersRecommendedResponse(List<User> recommendUsers) {
return recommendUsers.stream()
.map(RecommendUsersResponse::of)
.map(UsersRecommendedResponse::of)
.toList();
}

Expand Down
17 changes: 5 additions & 12 deletions src/main/java/com/listywave/user/presentation/UserController.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import com.listywave.common.auth.OptionalAuth;
import com.listywave.user.application.dto.FollowersResponse;
import com.listywave.user.application.dto.FollowingsResponse;
import com.listywave.user.application.dto.RecommendUsersResponse;
import com.listywave.user.application.dto.UserInfoResponse;
import com.listywave.user.application.dto.UsersRecommendedResponse;
import com.listywave.user.application.dto.search.UserElasticSearchResponse;
import com.listywave.user.application.dto.search.UserSearchResponse;
import com.listywave.user.application.service.UserService;
Expand All @@ -15,14 +15,7 @@
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

@RestController
@RequiredArgsConstructor
Expand Down Expand Up @@ -88,10 +81,10 @@ ResponseEntity<Void> unfollow(
}

@GetMapping("/users/recommend")
ResponseEntity<List<RecommendUsersResponse>> getRecommendUsers(
@Auth Long loginUserId
ResponseEntity<List<UsersRecommendedResponse>> getRecommendedUsers(
@OptionalAuth Long loginUserId
) {
List<RecommendUsersResponse> recommendUsers = userService.getRecommendUsers(loginUserId);
List<UsersRecommendedResponse> recommendUsers = userService.getRecommendedUsers(loginUserId);
return ResponseEntity.ok(recommendUsers);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ public List<User> getRecommendUsers(List<User> myFollowingUsers, User me) {
.from(listEntity)
.rightJoin(listEntity.user, user)
.where(
user.id.ne(me.getId()),
user.id.notIn(myFollowingUserIds),
userIdNotEqual(me),
userIdNotIn(myFollowingUserIds),
user.isDelete.isFalse()
)
.groupBy(user)
Expand All @@ -43,6 +43,14 @@ public List<User> getRecommendUsers(List<User> myFollowingUsers, User me) {
.fetch();
}

private BooleanExpression userIdNotIn(List<Long> myFollowingUserIds) {
return myFollowingUserIds.isEmpty() ? null : user.id.notIn(myFollowingUserIds);
}

private BooleanExpression userIdNotEqual(User me) {
return me == null ? null : user.id.ne(me.getId());
}

@Override
public Long countBySearch(String search, Long loginUserId) {
if (search.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@
import static org.springframework.http.HttpStatus.NO_CONTENT;

import com.listywave.acceptance.common.AcceptanceTest;
import com.listywave.collection.application.dto.CollectionResponse;
import com.listywave.collection.application.dto.CollectionResponse.CollectionListsResponse;
import com.listywave.collection.application.dto.CollectionFindResponse;
import com.listywave.list.application.domain.list.ListEntity;
import com.listywave.list.application.dto.response.ListCreateResponse;
import java.util.List;
Expand Down Expand Up @@ -115,9 +114,40 @@ public class CollectionAcceptanceTest extends AcceptanceTest {

// when
var 결과 = 나의_콜렉션_조회_API_호출(정수_엑세스_토큰, 1L)
.as(CollectionResponse.class)
.as(CollectionFindResponse.class)
.collectionLists().stream()
.map(CollectionListsResponse::list)
.map(CollectionFindResponse.CollectionDto::list)
.collect(Collectors.toList());

// then
assertThat(결과).usingRecursiveComparison()
.comparingOnlyFields("id")
.isEqualTo(생성한_리스트.stream().map(ListEntity::getId).toList());
}

@Test
void 나의_전체_콜렉션을_조회한다() {
// given
var 동호 = 회원을_저장한다(동호());
var 정수 = 회원을_저장한다(정수());
var 정수_엑세스_토큰 = 액세스_토큰을_발급한다(정수);
var 생성한_리스트 = 지정된_개수만큼_리스트를_생성한다(동호, 2);
리스트를_모두_저장한다(생성한_리스트);

var 폴더_생성_요청_데이터1 = 폴더_생성_요청_데이터("맛집");
var 폴더_생성_요청_데이터2 = 폴더_생성_요청_데이터("예카");
var 폴더_선택_데이터1 = 폴더_선택_요청_데이터(1L);
var 폴더_선택_데이터2 = 폴더_선택_요청_데이터(2L);
폴더_생성_API_호출(정수_엑세스_토큰, 폴더_생성_요청_데이터1);
폴더_생성_API_호출(정수_엑세스_토큰, 폴더_생성_요청_데이터2);
콜렉트_또는_콜렉트취소_API_호출(정수_엑세스_토큰, 1L, 폴더_선택_데이터1);
콜렉트_또는_콜렉트취소_API_호출(정수_엑세스_토큰, 2L, 폴더_선택_데이터2);

// when
var 결과 = 나의_콜렉션_조회_API_호출(정수_엑세스_토큰, 0L)
.as(CollectionFindResponse.class)
.collectionLists().stream()
.map(CollectionFindResponse.CollectionDto::list)
.collect(Collectors.toList());

// then
Expand Down
Loading

0 comments on commit 982b8fd

Please sign in to comment.