Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,24 +1,53 @@
package com.listywave.user.application.dto.search;

import java.util.List;
import lombok.Builder;
import java.util.Map;

@Builder
public record UserSearchResponse(
List<UserSearchResult> users,
List<UserDto> users,
Long totalCount,
Boolean hasNext
) {

public static UserSearchResponse of(
List<UserSearchResult> users,
Long totalCount,
Boolean hasNext
public static UserSearchResponse createWithoutLogin(List<UserSearchResult> userSearchResults, Long totalCount, Boolean hasNext) {
return new UserSearchResponse(
userSearchResults.stream().map(UserDto::from).toList(),
totalCount,
hasNext
);
}

public static UserSearchResponse createWithLogin(Map<UserSearchResult, Boolean> 팔로우_유무, Long totalCount, Boolean hasNext) {
return new UserSearchResponse(
팔로우_유무.entrySet().stream().map(UserDto::fromEntry).toList(),
totalCount,
hasNext
);
}
Comment on lines +12 to +26
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

비회원이랑 회원 나눈거 좋네요!


public record UserDto(
Long id,
String nickname,
String profileImageUrl,
boolean isFollowing // 검색하는 자가 검색 대상인 유저를 팔로우하고 있는 지에 대한 여부입니다.
) {
return UserSearchResponse.builder()
.users(users)
.totalCount(totalCount)
.hasNext(hasNext)
.build();

public static UserDto from(UserSearchResult userSearchResult) {
return new UserDto(
userSearchResult.id,
userSearchResult.nickname,
userSearchResult.profileImageUrl,
false
);
}

public static UserDto fromEntry(Map.Entry<UserSearchResult, Boolean> entry) {
return new UserDto(
entry.getKey().id,
entry.getKey().nickname,
entry.getKey().profileImageUrl,
entry.getValue()
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
import com.listywave.user.repository.user.UserRepository;
import com.listywave.user.repository.user.elastic.UserElasticRepository;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Pageable;
Expand Down Expand Up @@ -58,17 +62,25 @@ public UserInfoResponse getUserInfo(Long targetUserId, Long loginUserId) {

@Transactional(readOnly = true)
public UserSearchResponse searchUser(Long loginUserId, String search, Pageable pageable) {
Slice<UserSearchResult> searchResult = userRepository.findAllBySearch(search, pageable, loginUserId);
Long count = userRepository.countBySearch(search, loginUserId);

if (loginUserId == null) {
return createUserSearchResponse(null, search, pageable);
return UserSearchResponse.createWithoutLogin(searchResult.getContent(), count, searchResult.hasNext());
}
User user = userRepository.getById(loginUserId);
return createUserSearchResponse(user.getId(), search, pageable);
}

private UserSearchResponse createUserSearchResponse(Long loginUserId, String search, Pageable pageable) {
Long count = userRepository.countBySearch(search, loginUserId);
Slice<UserSearchResult> result = userRepository.findAllBySearch(search, pageable, loginUserId);
return UserSearchResponse.of(result.getContent(), count, result.hasNext());
User 검색하는_유저 = userRepository.getById(loginUserId);
List<Long> 검색_결과_유저_ID_리스트 = searchResult.getContent().stream()
.map(UserSearchResult::getId)
.toList();
Set<Long> 검색하는_유저가_팔로우하고_있는_검색_결과_유저_ID_리스트 = followRepository.검색하는_유저가_검색_결과_유저_중_팔로우하고_있는_유저만을_조회한다(검색하는_유저, 검색_결과_유저_ID_리스트);
Map<UserSearchResult, Boolean> 회원_검색_결과와_팔로우_여부 = searchResult.getContent().stream()
.collect(Collectors.toMap(
Function.identity(),
userSearchResult -> 검색하는_유저가_팔로우하고_있는_검색_결과_유저_ID_리스트.contains(userSearchResult.getId())
));

return UserSearchResponse.createWithLogin(회원_검색_결과와_팔로우_여부, count, searchResult.hasNext());
}

public FollowingsResponse getFollowings(Long followerUserId, String search) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,24 @@
import com.listywave.user.application.domain.User;
import com.listywave.user.repository.follow.custom.CustomFollowRepository;
import java.util.List;
import java.util.Set;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

public interface FollowRepository extends JpaRepository<Follow, Long>, CustomFollowRepository {

List<Follow> getAllByFollowerUser(User followerUser);
List<Follow> getAllByFollowerUser(User 팔로우_하는_유저);

List<Follow> getAllByFollowingUser(User followingUser);
List<Follow> getAllByFollowingUser(User 팔로우_당하는_유저);

void deleteByFollowingUserAndFollowerUser(User following, User follower);
void deleteByFollowingUserAndFollowerUser(User 팔로우_하는_유저, User 팔로우_당하는_유저);

boolean existsByFollowerUserAndFollowingUser(User followerUser, User followingUser);
boolean existsByFollowerUserAndFollowingUser(User 팔로우_하는_유저, User 팔로우_당하는_유저);

@Query("""
select f.followingUser.id
from Follow f
where f.followerUser = :검색하는_유저 and f.followingUser.isDelete = false and f.followingUser.id in :검색_대상_유저_ID_리스트
""")
Set<Long> 검색하는_유저가_검색_결과_유저_중_팔로우하고_있는_유저만을_조회한다(User 검색하는_유저, List<Long> 검색_대상_유저_ID_리스트);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.listywave.user.application.domain.User;
import com.listywave.user.application.dto.search.UserSearchResult;
import jakarta.annotation.Nullable;
import java.util.List;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
Expand All @@ -10,9 +11,9 @@ public interface CustomUserRepository {

List<User> getRecommendUsers(List<User> myFollowingUsers, User user);

Long countBySearch(String search, Long loginUserId);
Long countBySearch(String search, @Nullable Long loginUserId);

Slice<UserSearchResult> findAllBySearch(String search, Pageable pageable, Long loginUserId);
Slice<UserSearchResult> findAllBySearch(String search, Pageable pageable, @Nullable Long loginUserId);

void deleteNDaysAgo(int n);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.annotation.Nullable;
import java.time.LocalDateTime;
import java.util.List;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -53,7 +54,7 @@ private BooleanExpression userIdNotEqual(User me) {
}

@Override
public Long countBySearch(String search, Long loginUserId) {
public Long countBySearch(String search, @Nullable Long loginUserId) {
if (search.isEmpty()) {
return 0L;
}
Expand All @@ -73,7 +74,7 @@ private BooleanExpression userIdNe(Long loginUserId) {
}

@Override
public Slice<UserSearchResult> findAllBySearch(String search, Pageable pageable, Long loginUserId) {
public Slice<UserSearchResult> findAllBySearch(String search, Pageable pageable, @Nullable Long loginUserId) {
if (search.isEmpty()) {
return new SliceImpl<>(List.of(), pageable, false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,56 +8,56 @@

public abstract class FollowAcceptanceTestHelper {

public static ExtractableResponse<Response> 팔로우_요청_API(String accessToken, Long userId) {
public static ExtractableResponse<Response> 팔로우_요청_API(String 팔로우를_하는_유저의_액세스토큰, Long 팔로우_대상_유저_ID) {
return given()
.header(AUTHORIZATION, "Bearer " + accessToken)
.when().post("/follow/{userId}", userId)
.header(AUTHORIZATION, "Bearer " + 팔로우를_하는_유저의_액세스토큰)
.when().post("/follow/{userId}", 팔로우_대상_유저_ID)
.then().log().all()
.extract();
}

public static ExtractableResponse<Response> 팔로우_취소_API(String accessToken, Long userId) {
public static ExtractableResponse<Response> 팔로우_취소_API(String 팔로우_취소를_하는_유저의_액세스토큰, Long 팔로우_취소_대상_유저_ID) {
return given()
.header(AUTHORIZATION, "Bearer " + accessToken)
.when().delete("/follow/{userId}", userId)
.header(AUTHORIZATION, "Bearer " + 팔로우_취소를_하는_유저의_액세스토큰)
.when().delete("/follow/{userId}", 팔로우_취소_대상_유저_ID)
.then().log().all()
.extract();
}

public static ExtractableResponse<Response> 팔로워_목록_조회_API(Long userId) {
public static ExtractableResponse<Response> 팔로워_목록_조회_API(Long 조회하려는_유저_ID) {
return given()
.when().get("/users/{userId}/followers", userId)
.when().get("/users/{userId}/followers", 조회하려는_유저_ID)
.then().log().all()
.extract();
}

public static ExtractableResponse<Response> 팔로워_검색_API(Long userId, String search) {
public static ExtractableResponse<Response> 팔로워_검색_API(Long 검색하려는_유저_ID, String 검색어) {
return given()
.queryParam("search", search)
.when().get("/users/{userId}/followers", userId)
.queryParam("search", 검색어)
.when().get("/users/{userId}/followers", 검색하려는_유저_ID)
.then().log().all()
.extract();
}

public static ExtractableResponse<Response> 팔로잉_목록_조회_API(Long userId) {
public static ExtractableResponse<Response> 팔로잉_목록_조회_API(Long 조회하려는_유저_ID) {
return given()
.when().get("/users/{userId}/followings", userId)
.when().get("/users/{userId}/followings", 조회하려는_유저_ID)
.then().log().all()
.extract();
}

public static ExtractableResponse<Response> 팔로잉_검색_API(Long userId, String search) {
public static ExtractableResponse<Response> 팔로잉_검색_API(Long 검색하려는_유저_ID, String 검색어) {
return given()
.queryParam("search", search)
.when().get("/users/{userId}/followings", userId)
.queryParam("search", 검색어)
.when().get("/users/{userId}/followings", 검색하려는_유저_ID)
.then().log().all()
.extract();
}

public static ExtractableResponse<Response> 팔로워_삭제_API(String accessToken, Long followerId) {
public static ExtractableResponse<Response> 팔로워_삭제_API(String 삭제를_수행하려는_유저의_액세스토큰, Long 삭제의_대상이_되는_유저의_ID) {
return given()
.header(AUTHORIZATION, "Bearer " + accessToken)
.when().delete("/followers/{userId}", followerId)
.header(AUTHORIZATION, "Bearer " + 삭제를_수행하려는_유저의_액세스토큰)
.when().delete("/followers/{userId}", 삭제의_대상이_되는_유저의_ID)
.then().log().all()
.extract();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@

import com.listywave.acceptance.common.AcceptanceTest;
import com.listywave.list.application.dto.response.ListCreateResponse;
import com.listywave.user.application.domain.User;
import com.listywave.user.application.dto.UserInfoResponse;
import com.listywave.user.application.dto.UsersRecommendedResponse;
import com.listywave.user.application.dto.search.UserSearchResponse;
import io.restassured.common.mapper.TypeRef;
import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
Expand Down Expand Up @@ -112,11 +115,35 @@ class 회원_검색 {
회원을_저장한다(유진());

// when
var 결과 = 비회원이_사용자_검색(동호.getNickname()).as(UserSearchResponse.class);
UserSearchResponse 결과 = 비회원이_사용자_검색(동호.getNickname()).as(UserSearchResponse.class);

// then
assertThat(결과.totalCount()).isOne();
assertThat(결과.users().get(0).getNickname()).isEqualTo(동호.getNickname());
assertAll(
() -> assertThat(결과.totalCount()).isOne(),
() -> assertThat(결과.users().get(0).nickname()).isEqualTo(동호.getNickname()),
() -> assertThat(결과.users().get(0).isFollowing()).isFalse()
);
}

@Test
void 검색_대상_회원이_내가_현재_팔로우하고_있는_유저인_경우() {
// given
User 동호 = 회원을_저장한다(동호());
User 정수 = 회원을_저장한다(정수());
String 정수의_액세스_토큰 = 액세스_토큰을_발급한다(정수);

팔로우_요청_API(정수의_액세스_토큰, 동호.getId());

// when
ExtractableResponse<Response> 응답 = 회원이_사용자_검색(정수의_액세스_토큰, "kdkdhoho");
UserSearchResponse 결과 = 응답.as(UserSearchResponse.class);

// then
assertAll(
() -> assertThat(결과.totalCount()).isOne(),
() -> assertThat(결과.users().get(0).id()).isEqualTo(동호.getId()),
() -> assertThat(결과.users().get(0).isFollowing()).isTrue()
);
}

@Test
Expand Down
Loading