diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/query/FriendQueryApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/query/FriendQueryApi.java index 0cd05496a..14cd4c0d6 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/query/FriendQueryApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/query/FriendQueryApi.java @@ -9,7 +9,6 @@ import java.time.ZonedDateTime; import org.springframework.http.ResponseEntity; import site.timecapsulearchive.core.domain.friend.data.request.SearchFriendsRequest; -import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchTagFriendSummaryResponse; @@ -65,8 +64,34 @@ ResponseEntity> findFriendsBeforeGroupInvite( ); @Operation( - summary = "소셜 친구 요청 목록 조회", - description = "사용자의 소셜 친구 요청 목록을 보여준다. 수락 대기 중인 요청만 해당한다.", + summary = "소셜 친구 요청 받은 목록 조회", + description = """ + 사용자가 소셜 친구 요청을 받은 목록을 보여준다. +
+ 수락 대기 중인 요청만 해당한다. + """, + security = {@SecurityRequirement(name = "user_token")}, + tags = {"friend"} + ) + @ApiResponses(value = { + @ApiResponse( + responseCode = "200", + description = "ok" + ) + }) + ResponseEntity> findFriendReceivingInvites( + Long memberId, + + @Parameter(in = ParameterIn.QUERY, description = "페이지 크기", required = true) + int size, + + @Parameter(in = ParameterIn.QUERY, description = "마지막 데이터의 시간", required = true) + ZonedDateTime createdAt + ); + + @Operation( + summary = "소셜 친구 요청 보낸 목록 조회", + description = "사용자가 소셜 친구 요청을 보낸 목록을 보여준다.", security = {@SecurityRequirement(name = "user_token")}, tags = {"friend"} ) @@ -76,7 +101,7 @@ ResponseEntity> findFriendsBeforeGroupInvite( description = "ok" ) }) - ResponseEntity> findFriendRequests( + ResponseEntity> findFriendSendingInvites( Long memberId, @Parameter(in = ParameterIn.QUERY, description = "페이지 크기", required = true) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/query/FriendQueryApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/query/FriendQueryApiController.java index f9856fb3b..f963efba8 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/query/FriendQueryApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/query/FriendQueryApiController.java @@ -18,7 +18,6 @@ import site.timecapsulearchive.core.domain.friend.data.dto.SearchFriendSummaryDtoByTag; import site.timecapsulearchive.core.domain.friend.data.request.FriendBeforeGroupInviteRequest; import site.timecapsulearchive.core.domain.friend.data.request.SearchFriendsRequest; -import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchTagFriendSummaryResponse; @@ -77,23 +76,45 @@ public ResponseEntity> findFriendsBeforeGroupInvit } @GetMapping( - value = "/requests", + value = "/receiving-invites", produces = {"application/json"} ) @Override - public ResponseEntity> findFriendRequests( + public ResponseEntity> findFriendReceivingInvites( @AuthenticationPrincipal final Long memberId, @RequestParam(defaultValue = "20", value = "size") final int size, @RequestParam(value = "created_at") final ZonedDateTime createdAt ) { - final Slice friendRequestsSlice = friendQueryService.findFriendRequestsSlice( + final Slice friendReceivingInvitesSlice = friendQueryService.findFriendReceivingInvitesSlice( memberId, size, createdAt); return ResponseEntity.ok( ApiSpec.success( SuccessCode.SUCCESS, - FriendRequestsSliceResponse.createOf(friendRequestsSlice.getContent(), - friendRequestsSlice.hasNext()) + FriendsSliceResponse.createOf(friendReceivingInvitesSlice.getContent(), + friendReceivingInvitesSlice.hasNext()) + ) + ); + } + + @GetMapping( + value = "/sending-invites", + produces = {"application/json"} + ) + @Override + public ResponseEntity> findFriendSendingInvites( + @AuthenticationPrincipal final Long memberId, + @RequestParam(defaultValue = "20", value = "size") final int size, + @RequestParam(value = "created_at") final ZonedDateTime createdAt + ) { + final Slice friendSendingInvitesSlice = friendQueryService.findFriendSendingInvitesSlice( + memberId, size, createdAt); + + return ResponseEntity.ok( + ApiSpec.success( + SuccessCode.SUCCESS, + FriendsSliceResponse.createOf(friendSendingInvitesSlice.getContent(), + friendSendingInvitesSlice.hasNext()) ) ); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendRequestsSliceResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendRequestsSliceResponse.java deleted file mode 100644 index 731b823e5..000000000 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendRequestsSliceResponse.java +++ /dev/null @@ -1,26 +0,0 @@ -package site.timecapsulearchive.core.domain.friend.data.response; - -import io.swagger.v3.oas.annotations.media.Schema; -import java.util.List; -import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; - -@Schema(description = "친구 요청 리스트") -public record FriendRequestsSliceResponse( - @Schema(description = "친구 요약 정보 리스트") - List friends, - - @Schema(description = "다음 페이지 유무") - Boolean hasNext -) { - - public static FriendRequestsSliceResponse createOf( - List content, - boolean hasNext - ) { - List friends = content.stream() - .map(FriendSummaryDto::toResponse) - .toList(); - - return new FriendRequestsSliceResponse(friends, hasNext); - } -} \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/friend_invite/FriendInviteQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/friend_invite/FriendInviteQueryRepository.java index d8887fb0d..40ba418cc 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/friend_invite/FriendInviteQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/friend_invite/FriendInviteQueryRepository.java @@ -1,8 +1,24 @@ package site.timecapsulearchive.core.domain.friend.repository.friend_invite; +import java.time.ZonedDateTime; import java.util.List; +import org.springframework.data.domain.Slice; +import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; public interface FriendInviteQueryRepository { void bulkSave(final Long ownerId, final List friendIds); + + + Slice findFriendReceivingInvitesSlice( + final Long memberId, + final int size, + final ZonedDateTime createdAt + ); + + Slice findFriendSendingInvitesSlice( + final Long memberId, + final int size, + final ZonedDateTime createdAt + ); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/friend_invite/FriendInviteQueryRepositoryImpl.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/friend_invite/FriendInviteQueryRepositoryImpl.java index 136441e2d..ae6aeceef 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/friend_invite/FriendInviteQueryRepositoryImpl.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/friend_invite/FriendInviteQueryRepositoryImpl.java @@ -1,5 +1,10 @@ package site.timecapsulearchive.core.domain.friend.repository.friend_invite; +import static site.timecapsulearchive.core.domain.friend.entity.QFriendInvite.friendInvite; +import static site.timecapsulearchive.core.domain.member.entity.QMember.member; + +import com.querydsl.core.types.Projections; +import com.querydsl.jpa.impl.JPAQueryFactory; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Timestamp; @@ -7,15 +12,21 @@ import java.time.ZonedDateTime; import java.util.List; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.data.domain.SliceImpl; import org.springframework.jdbc.core.BatchPreparedStatementSetter; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; +import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; +import site.timecapsulearchive.core.global.util.SliceUtil; @Repository @RequiredArgsConstructor public class FriendInviteQueryRepositoryImpl implements FriendInviteQueryRepository { private final JdbcTemplate jdbcTemplate; + private final JPAQueryFactory jpaQueryFactory; public void bulkSave(final Long ownerId, final List friendIds) { if (friendIds.isEmpty()) { @@ -47,4 +58,53 @@ public int getBatchSize() { } ); } + + public Slice findFriendReceivingInvitesSlice( + final Long memberId, + final int size, + final ZonedDateTime createdAt + ) { + final List friends = jpaQueryFactory + .select( + Projections.constructor( + FriendSummaryDto.class, + friendInvite.owner.id, + friendInvite.owner.profileUrl, + friendInvite.owner.nickname, + friendInvite.createdAt + ) + ) + .from(friendInvite) + .join(friendInvite.owner, member) + .where(friendInvite.friend.id.eq(memberId).and(friendInvite.createdAt.lt(createdAt))) + .limit(size + 1) + .fetch(); + + return SliceUtil.makeSlice(size, friends); + } + + @Override + public Slice findFriendSendingInvitesSlice( + final Long memberId, + final int size, + final ZonedDateTime createdAt + ) { + final List friends = jpaQueryFactory + .select( + Projections.constructor( + FriendSummaryDto.class, + friendInvite.friend.id, + friendInvite.friend.profileUrl, + friendInvite.friend.nickname, + friendInvite.createdAt + ) + ) + .from(friendInvite) + .join(friendInvite.owner, member) + .where(friendInvite.owner.id.eq(memberId).and(friendInvite.createdAt.lt(createdAt))) + .limit(size + 1) + .fetch(); + + return SliceUtil.makeSlice(size, friends); + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/member_friend/MemberFriendQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/member_friend/MemberFriendQueryRepository.java index 8e8c32667..de7021d81 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/member_friend/MemberFriendQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/member_friend/MemberFriendQueryRepository.java @@ -18,12 +18,6 @@ Slice findFriendsSlice( final ZonedDateTime createdAt ); - Slice findFriendRequestsSlice( - final Long memberId, - final int size, - final ZonedDateTime createdAt - ); - List findFriendsByPhone( final Long memberId, final List hashes diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/member_friend/MemberFriendQueryRepositoryImpl.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/member_friend/MemberFriendQueryRepositoryImpl.java index 7bc29fdd2..63cb8d93f 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/member_friend/MemberFriendQueryRepositoryImpl.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/member_friend/MemberFriendQueryRepositoryImpl.java @@ -102,30 +102,6 @@ public Slice findFriendsBeforeGroupInvite( return getFriendSummaryDtos(request.size(), friends); } - public Slice findFriendRequestsSlice( - final Long memberId, - final int size, - final ZonedDateTime createdAt - ) { - final List friends = jpaQueryFactory - .select( - Projections.constructor( - FriendSummaryDto.class, - friendInvite.owner.id, - friendInvite.owner.profileUrl, - friendInvite.owner.nickname, - friendInvite.createdAt - ) - ) - .from(friendInvite) - .join(friendInvite.owner, member) - .where(friendInvite.friend.id.eq(memberId).and(friendInvite.createdAt.lt(createdAt))) - .limit(size + 1) - .fetch(); - - return getFriendSummaryDtos(size, friends); - } - public List findFriendsByPhone( final Long memberId, final List hashes diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/query/FriendQueryService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/query/FriendQueryService.java index d34230f0a..2e0ecc5e8 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/query/FriendQueryService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/query/FriendQueryService.java @@ -11,6 +11,7 @@ import site.timecapsulearchive.core.domain.friend.data.dto.SearchFriendSummaryDtoByTag; import site.timecapsulearchive.core.domain.friend.data.request.FriendBeforeGroupInviteRequest; import site.timecapsulearchive.core.domain.friend.exception.FriendNotFoundException; +import site.timecapsulearchive.core.domain.friend.repository.friend_invite.FriendInviteRepository; import site.timecapsulearchive.core.domain.friend.repository.member_friend.MemberFriendRepository; import site.timecapsulearchive.core.global.common.wrapper.ByteArrayWrapper; @@ -20,6 +21,7 @@ public class FriendQueryService { private final MemberFriendRepository memberFriendRepository; + private final FriendInviteRepository friendInviteRepository; public Slice findFriendsSlice( final Long memberId, @@ -34,12 +36,20 @@ public Slice findFriendsBeforeGroupInviteSlice( return memberFriendRepository.findFriendsBeforeGroupInvite(request); } - public Slice findFriendRequestsSlice( + public Slice findFriendReceivingInvitesSlice( final Long memberId, final int size, final ZonedDateTime createdAt ) { - return memberFriendRepository.findFriendRequestsSlice(memberId, size, createdAt); + return friendInviteRepository.findFriendReceivingInvitesSlice(memberId, size, createdAt); + } + + public Slice findFriendSendingInvitesSlice( + final Long memberId, + final int size, + final ZonedDateTime createdAt + ) { + return friendInviteRepository.findFriendSendingInvitesSlice(memberId, size, createdAt); } public List findFriendsByPhone( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/util/SliceUtil.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/util/SliceUtil.java new file mode 100644 index 000000000..be393648a --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/util/SliceUtil.java @@ -0,0 +1,22 @@ +package site.timecapsulearchive.core.global.util; + +import java.util.List; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.data.domain.SliceImpl; + +public final class SliceUtil { + + private SliceUtil() { + + } + + public static Slice makeSlice(final int size, final List dtos) { + final boolean hasNext = dtos.size() > size; + if (hasNext) { + dtos.remove(size); + } + + return new SliceImpl<>(dtos, Pageable.ofSize(size), hasNext); + } +} diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteQueryRepositoryTest.java index c4c63562f..8233b0761 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteQueryRepositoryTest.java @@ -2,17 +2,25 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; import jakarta.persistence.Query; +import java.time.ZoneId; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.data.domain.Slice; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.TestConstructor; import org.springframework.test.context.TestConstructor.AutowireMode; import site.timecapsulearchive.core.common.RepositoryTest; +import site.timecapsulearchive.core.common.fixture.domain.FriendInviteFixture; import site.timecapsulearchive.core.common.fixture.domain.MemberFixture; +import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; import site.timecapsulearchive.core.domain.friend.entity.FriendInvite; import site.timecapsulearchive.core.domain.friend.repository.friend_invite.FriendInviteQueryRepository; import site.timecapsulearchive.core.domain.friend.repository.friend_invite.FriendInviteQueryRepositoryImpl; @@ -21,39 +29,85 @@ @TestConstructor(autowireMode = AutowireMode.ALL) class FriendInviteQueryRepositoryTest extends RepositoryTest { + private static final int MAX_COUNT = 40; + private static final Long BULK_FRIEND_INVITE_MEMBER_START_ID = 2L; + private static final Long FRIEND_RECEIVING_INVITE_MEMBER_START_ID = + BULK_FRIEND_INVITE_MEMBER_START_ID + MAX_COUNT; + private static final Long FRIEND_SENDING_INVITE_MEMBER_START_ID = + FRIEND_RECEIVING_INVITE_MEMBER_START_ID + MAX_COUNT; + private static final Long NOT_FRIEND_INVITE_START_ID = + FRIEND_SENDING_INVITE_MEMBER_START_ID + MAX_COUNT; + private final FriendInviteQueryRepository friendInviteQueryRepository; private final EntityManager entityManager; private final List friends = new ArrayList<>(); - private Member owner; + private Long bulkOwnerId; + private Long ownerId; + private Long ownerInviteReceivingStartId; + private Long ownerInviteSendingStartId; - FriendInviteQueryRepositoryTest(EntityManager entityManager, JdbcTemplate jdbcTemplate) { + FriendInviteQueryRepositoryTest(EntityManager entityManager, JdbcTemplate jdbcTemplate, + JPAQueryFactory jpaQueryFactory) { this.entityManager = entityManager; - this.friendInviteQueryRepository = new FriendInviteQueryRepositoryImpl(jdbcTemplate); + this.friendInviteQueryRepository = new FriendInviteQueryRepositoryImpl(jdbcTemplate, + jpaQueryFactory); } @BeforeEach void setup() { - owner = MemberFixture.member(0); - entityManager.persist(owner); + // 벌크 저장 시 owner 멤버 데이터 + Member bulkOwner = MemberFixture.member(0); + entityManager.persist(bulkOwner); + bulkOwnerId = bulkOwner.getId(); - friends.addAll(MemberFixture.members(1, 11)); + // 벌크 저장 시 owner 친구 데이터 + friends.addAll(MemberFixture.members(2, BULK_FRIEND_INVITE_MEMBER_START_ID.intValue())); friends.forEach(entityManager::persist); + + // 친구 초대 owner 멤버 데이터 + Member owner = MemberFixture.member(1); + entityManager.persist(owner); + ownerId = owner.getId(); + + // owner에게 친구 요청만 받은 멤버 데이터 + List receivingInviteToOwnerMembers = MemberFixture.members( + FRIEND_RECEIVING_INVITE_MEMBER_START_ID.intValue(), MAX_COUNT); + for (Member member : receivingInviteToOwnerMembers) { + entityManager.persist(member); + + FriendInvite receivingInvite = FriendInviteFixture.friendInvite(owner, member); + entityManager.persist(receivingInvite); + } + ownerInviteReceivingStartId = receivingInviteToOwnerMembers.get(0).getId(); + + // owner에게 친구 요청만 보낸 멤버 데이터 + List sendingInviteToOwnerMembers = MemberFixture.members( + FRIEND_SENDING_INVITE_MEMBER_START_ID.intValue(), MAX_COUNT); + for (Member member : sendingInviteToOwnerMembers) { + entityManager.persist(member); + + FriendInvite sendingInvite = FriendInviteFixture.friendInvite(member, owner); + entityManager.persist(sendingInvite); + } + ownerInviteSendingStartId = sendingInviteToOwnerMembers.get(0).getId(); + + entityManager.flush(); + entityManager.clear(); } @Test void 대량의_친구_초대를_저장하면_조회하면_친구_초대를_볼_수_있다() { //given - Long ownerId = owner.getId(); List friendIds = friends.stream() .map(Member::getId) .toList(); //when - friendInviteQueryRepository.bulkSave(ownerId, friendIds); + friendInviteQueryRepository.bulkSave(bulkOwnerId, friendIds); //then - List friendInvites = getFriendInvites(entityManager, ownerId); + List friendInvites = getFriendInvites(entityManager, bulkOwnerId); assertThat(friendInvites.size()).isEqualTo(friendIds.size()); } @@ -63,4 +117,139 @@ private List getFriendInvites(EntityManager entityManager, Long ow query.setParameter("ownerId", ownerId); return query.getResultList(); } + + + @ValueSource(ints = {2, 7, 10, 5}) + @ParameterizedTest + void 사용자가_보낸_친구_요청_받은_목록을_조회하면_보낸_친구_요청목록이_나온다(int size) { + ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(3); + + Slice slice = friendInviteQueryRepository.findFriendSendingInvitesSlice( + ownerId, + size, + now + ); + + assertThat(slice.getContent()).isNotEmpty(); + assertThat(slice.getContent()).allMatch(dto -> dto.id() >= ownerInviteReceivingStartId + && dto.id() < ownerInviteReceivingStartId + MAX_COUNT); + } + + @Test + void 사용자가_첫_페이지_이후의_친구요청_보낸_목록을_조회하면_다음_페이지의_보낸_친구_요청목록이_나온다() { + //given + int size = 20; + ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(3); + Slice firstSlice = friendInviteQueryRepository.findFriendSendingInvitesSlice( + ownerId, size, now); + + //when + FriendSummaryDto dto = firstSlice.getContent().get(firstSlice.getNumberOfElements() - 1); + Slice nextSlice = friendInviteQueryRepository.findFriendSendingInvitesSlice( + ownerId, size, dto.createdAt().plusSeconds(1L)); + + //then + assertThat(nextSlice.getNumberOfElements()).isPositive(); + } + + @Test + void 사용자가_유효하지_않은_시간으로_사용자의_친구_요청_보낸_목록_조회하면_빈_리스트가_나온다() { + //given + int size = 10; + ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(5); + + //when + Slice slice = friendInviteQueryRepository.findFriendSendingInvitesSlice( + ownerId, + size, + now + ); + + //then + assertThat(slice).isEmpty(); + } + + @Test + void 친구_요청을_보내지_않은_사용자가_친구_요청_보낸_목록_조회하면_빈_리스트가_나온다() { + //given + int size = 10; + ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(5); + + //when + Slice slice = friendInviteQueryRepository.findFriendSendingInvitesSlice( + NOT_FRIEND_INVITE_START_ID, + size, + now + ); + + //then + assertThat(slice).isEmpty(); + } + + @ValueSource(ints = {2, 7, 10, 5}) + @ParameterizedTest + void 사용자가_받은_친구_요청_받은_목록을_조회하면_받은_친구_요청목록이_나온다(int size) { + ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(3); + + Slice slice = friendInviteQueryRepository.findFriendReceivingInvitesSlice( + ownerId, + size, + now + ); + + assertThat(slice.getContent()).isNotEmpty(); + assertThat(slice.getContent()).allMatch(dto -> dto.id() >= ownerInviteSendingStartId + && dto.id() < ownerInviteSendingStartId + MAX_COUNT); + } + + @Test + void 사용자가_첫_페이지_이후의_친구요청_받은_목록을_조회하면_다음_페이지의_받은_친구_요청목록이_나온다() { + //given + int size = 20; + ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(3); + Slice firstSlice = friendInviteQueryRepository.findFriendReceivingInvitesSlice( + ownerId, size, now); + + //when + FriendSummaryDto dto = firstSlice.getContent().get(firstSlice.getNumberOfElements() - 1); + Slice nextSlice = friendInviteQueryRepository.findFriendReceivingInvitesSlice( + ownerId, size, dto.createdAt().plusSeconds(1L)); + + //then + assertThat(nextSlice.getNumberOfElements()).isPositive(); + } + + @Test + void 사용자가_유효하지_않은_시간으로_사용자의_친구_요청_받은_목록_조회하면_빈_리스트가_나온다() { + //given + int size = 10; + ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(5); + + //when + Slice slice = friendInviteQueryRepository.findFriendReceivingInvitesSlice( + ownerId, + size, + now + ); + + //then + assertThat(slice).isEmpty(); + } + + @Test + void 친구_요청을_받지_않은_사용자가_친구_요청_받은_목록_조회하면_빈_리스트가_나온다() { + //given + int size = 10; + ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(5); + + //when + Slice slice = friendInviteQueryRepository.findFriendReceivingInvitesSlice( + NOT_FRIEND_INVITE_START_ID, + size, + now + ); + + //then + assertThat(slice).isEmpty(); + } } \ No newline at end of file diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java index 09ae4cf3d..86842d9c4 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java @@ -43,8 +43,9 @@ class MemberFriendQueryRepositoryTest extends RepositoryTest { private static final String PROPAGATION_REQUIRES_NEW = "PROPAGATION_REQUIRES_NEW"; private static final int MAX_COUNT = 10; private static final Long FRIEND_START_ID = 2L; - private static final Long FRIEND_ID_TO_INVITE_OWNER = 12L; - private static final Long NOT_FRIEND_MEMBER_START_ID = 13L; + private static final Long NOT_FRIEND_MEMBER_START_ID = FRIEND_START_ID + MAX_COUNT; + private static final Long FRIEND_INVITE_START_ID = + NOT_FRIEND_MEMBER_START_ID + NOT_FRIEND_MEMBER_START_ID; private final MemberFriendQueryRepository memberFriendQueryRepository; @@ -91,15 +92,6 @@ void setup(@Autowired EntityManager entityManager, friendId = friends.get(0).getId(); friendTag = friends.get(0).getTag(); - // owner에게 친구 요청만 보낸 멤버 데이터 - Member inviteFriendToOwner = MemberFixture.member(FRIEND_ID_TO_INVITE_OWNER.intValue()); - entityManager.persist(inviteFriendToOwner); - friendInviteTag =inviteFriendToOwner.getTag(); - - FriendInvite friendInvite = FriendInviteFixture.friendInvite(inviteFriendToOwner, - owner); - entityManager.persist(friendInvite); - //owner와 친구가 아닌 멤버 데이터 List notFriendMembers = MemberFixture.members( NOT_FRIEND_MEMBER_START_ID.intValue(), @@ -108,11 +100,18 @@ void setup(@Autowired EntityManager entityManager, entityManager.persist(notFriend); hashedNotFriendPhones.add(notFriend.getPhone_hash()); } - //owner에게 친구 요청을 보내지 않은 데이터 notFriendInviteTag = notFriendMembers.get(0).getTag(); //owner와 친구가 아닌 데이터 notFriendTag = notFriendMembers.get(0).getTag(); + + //owner와 친구 초대 관계 멤버 데이터 + Member friendInviteMember = MemberFixture.member(FRIEND_INVITE_START_ID.intValue()); + entityManager.persist(friendInviteMember); + + FriendInvite friendInvite = FriendInviteFixture.friendInvite(owner, friendInviteMember); + entityManager.persist(friendInvite); + friendInviteTag = friendInviteMember.getTag(); }); } @@ -125,8 +124,8 @@ void clear(@Autowired EntityManager entityManager) { entityManager.createNativeQuery("SET FOREIGN_KEY_CHECKS=1").executeUpdate(); } - @ParameterizedTest @ValueSource(ints = {2, 7, 10, 5}) + @ParameterizedTest void 사용자가_친구_목록_조회하면_친구_관계를_맺은_사용자_리스트가_나온다(int size) { //given ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(5); @@ -150,80 +149,51 @@ void clear(@Autowired EntityManager entityManager) { } @Test - void 친구가_친구_목록_조회하면_친구_관계를_맺은_사용자_리스트가_나온다() { - //given - int size = 10; - ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(5); - - //when - Slice slice = memberFriendQueryRepository.findFriendsSlice( - friendId, - size, - now - ); - - assertThat(slice.getContent().size()).isEqualTo(1); - } - - @Test - void 친구_요청만_보낸_사용자가_친구_목록_조회하면_리스트가_나온다() { + void 사용자가_첫_페이지_이후의_친구_목록_조회하면_다음_페이지의_친구_관계를_맺은_사용자_리스트가_나온다() { //given int size = 20; - ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(5); - - //when - Slice slice = memberFriendQueryRepository.findFriendsSlice( - FRIEND_ID_TO_INVITE_OWNER, + ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(3); + Slice firstSlice = memberFriendQueryRepository.findFriendsSlice( + ownerId, size, now ); - //then - assertThat(slice).isEmpty(); - } - - @Test - void 사용자가_유효하지_않은_시간으로_사용자의_친구_목록_조회하면_빈_리스트가_나온다() { - //given - int size = 20; - ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(5); - //when - Slice slice = memberFriendQueryRepository.findFriendsSlice( + FriendSummaryDto dto = firstSlice.getContent().get(firstSlice.getNumberOfElements() - 1); + Slice nextSlice = memberFriendQueryRepository.findFriendsSlice( ownerId, size, - now + dto.createdAt().plusSeconds(1L) ); - //then - assertThat(slice).isEmpty(); + assertThat(nextSlice.getNumberOfElements()).isPositive(); } @Test - void 친구가_없는_사용자가_친구_목록_조회하면_빈_리스트가_나온다() { + void 친구가_친구_목록_조회하면_친구_관계를_맺은_사용자_리스트가_나온다() { //given - int size = 20; + int size = 10; ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(5); //when Slice slice = memberFriendQueryRepository.findFriendsSlice( - NOT_FRIEND_MEMBER_START_ID, + friendId, size, now ); - //then - assertThat(slice).isEmpty(); + assertThat(slice.getContent().size()).isEqualTo(1); } @Test - void 사용자가_유효하지_않은_시간으로_사용자의_친구_요청_목록_조회하면_빈_리스트가_나온다() { + void 사용자가_유효하지_않은_시간으로_사용자의_친구_목록_조회하면_빈_리스트가_나온다() { //given - int size = 20; + int size = 10; ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(5); //when - Slice slice = memberFriendQueryRepository.findFriendRequestsSlice( + Slice slice = memberFriendQueryRepository.findFriendsSlice( ownerId, size, now @@ -234,13 +204,13 @@ void clear(@Autowired EntityManager entityManager) { } @Test - void 친구가_없는_사용자가_친구_요청_목록_조회하면_빈_리스트가_나온다() { + void 친구가_없는_사용자가_친구_목록_조회하면_빈_리스트가_나온다() { //given - int size = 20; + int size = 10; ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(5); //when - Slice slice = memberFriendQueryRepository.findFriendRequestsSlice( + Slice slice = memberFriendQueryRepository.findFriendsSlice( NOT_FRIEND_MEMBER_START_ID, size, now @@ -371,7 +341,7 @@ void clear(@Autowired EntityManager entityManager) { ownerId, friendInviteTag).orElseThrow(); //then - assertThat(dto.isFriendInviteToMe()).isTrue(); + assertThat(dto.isFriendInviteToMe() || dto.isFriendInviteToFriend()).isTrue(); } @Test diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/service/FriendQueryServiceTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/service/FriendQueryServiceTest.java index 6c940d657..97e83bb9f 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/service/FriendQueryServiceTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/service/FriendQueryServiceTest.java @@ -18,8 +18,8 @@ import site.timecapsulearchive.core.common.fixture.dto.FriendDtoFixture; import site.timecapsulearchive.core.domain.friend.data.dto.SearchFriendSummaryDto; import site.timecapsulearchive.core.domain.friend.data.dto.SearchFriendSummaryDtoByTag; -import site.timecapsulearchive.core.domain.friend.data.response.SearchTagFriendSummaryResponse; import site.timecapsulearchive.core.domain.friend.exception.FriendNotFoundException; +import site.timecapsulearchive.core.domain.friend.repository.friend_invite.FriendInviteRepository; import site.timecapsulearchive.core.domain.friend.repository.member_friend.MemberFriendRepository; import site.timecapsulearchive.core.domain.friend.service.query.FriendQueryService; import site.timecapsulearchive.core.global.common.wrapper.ByteArrayWrapper; @@ -28,9 +28,11 @@ class FriendQueryServiceTest { private final MemberFriendRepository memberFriendRepository = mock( MemberFriendRepository.class); + private final FriendInviteRepository friendInviteRepository = mock( + FriendInviteRepository.class); private final FriendQueryService friendQueryService = new FriendQueryService( - memberFriendRepository); + memberFriendRepository, friendInviteRepository); @Test void 사용자는_주소록_기반_핸드폰_번호로_Ahchive_사용자_리스트를_조회_할_수_있다() {