From 3fa2a8d6080bee92e27ed18b1a898dfa39a3739d Mon Sep 17 00:00:00 2001 From: hong seokho Date: Fri, 19 Apr 2024 20:10:10 +0900 Subject: [PATCH 01/13] =?UTF-8?q?feat=20:=20=EA=B7=B8=EB=A3=B9=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/group/api/GroupApi.java | 22 ++++----- .../domain/group/api/GroupApiController.java | 32 +++++++++++-- .../group/data/dto/GroupSummaryDto.java | 26 ++++++++++ .../data/response/GroupSummaryResponse.java | 15 +++++- .../data/response/GroupsPageResponse.java | 21 -------- .../data/response/GroupsSliceResponse.java | 29 +++++++++++ .../MemberGroupQueryRepository.java | 48 +++++++++++++++++++ .../domain/group/service/GroupService.java | 28 ++++++----- 8 files changed, 170 insertions(+), 51 deletions(-) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupSummaryDto.java delete mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupsPageResponse.java create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupsSliceResponse.java create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepository.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApi.java index 38e255fa7..6c56b8d92 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApi.java @@ -7,8 +7,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.security.SecurityRequirement; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; +import java.time.ZonedDateTime; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -16,11 +15,10 @@ 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.RequestParam; import site.timecapsulearchive.core.domain.group.data.reqeust.GroupCreateRequest; import site.timecapsulearchive.core.domain.group.data.reqeust.GroupUpdateRequest; import site.timecapsulearchive.core.domain.group.data.response.GroupDetailResponse; -import site.timecapsulearchive.core.domain.group.data.response.GroupsPageResponse; +import site.timecapsulearchive.core.domain.group.data.response.GroupsSliceResponse; import site.timecapsulearchive.core.global.common.response.ApiSpec; public interface GroupApi { @@ -156,16 +154,14 @@ ResponseEntity findGroupById( description = "ok" ) }) - @GetMapping( - value = "/groups", - produces = {"application/json"} - ) - ResponseEntity findGroups( - @Parameter(in = ParameterIn.QUERY, description = "페이지 크기", required = true, schema = @Schema()) - @NotNull @Valid @RequestParam(value = "size") Long size, + ResponseEntity> findGroups( + Long memberId, + + @Parameter(in = ParameterIn.QUERY, description = "페이지 크기", required = true) + int size, - @Parameter(in = ParameterIn.QUERY, description = "마지막 그룹 아이디", required = true, schema = @Schema()) - @NotNull @Valid @RequestParam(value = "group_id") Long groupId + @Parameter(in = ParameterIn.QUERY, description = "마지막 데이터의 시간", required = true) + ZonedDateTime createdAt ); @Operation( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApiController.java index 5dec2042c..588e1b7c1 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApiController.java @@ -1,21 +1,27 @@ package site.timecapsulearchive.core.domain.group.api; import jakarta.validation.Valid; +import java.time.ZonedDateTime; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Slice; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import site.timecapsulearchive.core.domain.group.data.dto.GroupCreateDto; +import site.timecapsulearchive.core.domain.group.data.dto.GroupSummaryDto; import site.timecapsulearchive.core.domain.group.data.reqeust.GroupCreateRequest; import site.timecapsulearchive.core.domain.group.data.reqeust.GroupUpdateRequest; import site.timecapsulearchive.core.domain.group.data.response.GroupDetailResponse; -import site.timecapsulearchive.core.domain.group.data.response.GroupsPageResponse; +import site.timecapsulearchive.core.domain.group.data.response.GroupsSliceResponse; import site.timecapsulearchive.core.domain.group.service.GroupService; import site.timecapsulearchive.core.global.common.response.ApiSpec; import site.timecapsulearchive.core.global.common.response.SuccessCode; +import site.timecapsulearchive.core.infra.s3.manager.S3PreSignedUrlManager; import site.timecapsulearchive.core.infra.s3.manager.S3UrlGenerator; @@ -26,6 +32,7 @@ public class GroupApiController implements GroupApi { private final GroupService groupService; private final S3UrlGenerator s3UrlGenerator; + private final S3PreSignedUrlManager s3PreSignedUrlManager; @Override public ResponseEntity acceptGroupInvitation(Long groupId, Long memberId) { @@ -71,9 +78,28 @@ public ResponseEntity findGroupById(Long groupId) { return null; } + @GetMapping( + produces = {"application/json"} + ) @Override - public ResponseEntity findGroups(Long size, Long groupId) { - return null; + public ResponseEntity> findGroups( + @AuthenticationPrincipal final Long memberId, + @RequestParam(defaultValue = "20", value = "size") final int size, + @RequestParam(value = "created_at") final ZonedDateTime createdAt + ) { + Slice groupsSlice = groupService.findGroupsSlice(memberId, size, + createdAt); + + return ResponseEntity.ok( + ApiSpec.success( + SuccessCode.SUCCESS, + GroupsSliceResponse.createOf( + groupsSlice.getContent(), + groupsSlice.hasNext(), + s3PreSignedUrlManager::getS3PreSignedUrlForGet + ) + ) + ); } @Override diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupSummaryDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupSummaryDto.java new file mode 100644 index 000000000..a900ff27d --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupSummaryDto.java @@ -0,0 +1,26 @@ +package site.timecapsulearchive.core.domain.group.data.dto; + +import java.time.ZonedDateTime; +import java.util.function.Function; +import site.timecapsulearchive.core.domain.group.data.response.GroupSummaryResponse; + +public record GroupSummaryDto( + Long id, + String groupName, + String groupDescription, + String groupProfileUrl, + ZonedDateTime createdAt, + Boolean isOwner +) { + + public GroupSummaryResponse toResponse(Function preSignedUrlFunction) { + return GroupSummaryResponse.builder() + .id(id) + .name(groupName) + .description(groupDescription) + .profileUrl(preSignedUrlFunction.apply(groupProfileUrl)) + .createdAt(createdAt) + .isOwner(isOwner) + .build(); + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupSummaryResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupSummaryResponse.java index 59e67168b..bf6783ddc 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupSummaryResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupSummaryResponse.java @@ -1,7 +1,11 @@ package site.timecapsulearchive.core.domain.group.data.response; import io.swagger.v3.oas.annotations.media.Schema; +import java.time.ZonedDateTime; +import lombok.Builder; +import site.timecapsulearchive.core.global.common.response.ResponseMappingConstant; +@Builder @Schema(description = "그룹 요약 정보") public record GroupSummaryResponse( @@ -15,7 +19,16 @@ public record GroupSummaryResponse( String profileUrl, @Schema(description = "그룹 설명") - String description + String description, + + ZonedDateTime createdAt, + + Boolean isOwner ) { + public GroupSummaryResponse { + if (createdAt != null) { + createdAt = createdAt.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); + } + } } \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupsPageResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupsPageResponse.java deleted file mode 100644 index c9f338b92..000000000 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupsPageResponse.java +++ /dev/null @@ -1,21 +0,0 @@ -package site.timecapsulearchive.core.domain.group.data.response; - -import io.swagger.v3.oas.annotations.media.Schema; -import java.util.List; - -@Schema(description = "그룹 리스트 페이징") -public record GroupsPageResponse( - - @Schema(description = "그룹 리스트") - List groups, - - @Schema(description = "다음 페이지 유무") - - Boolean hasNext, - - @Schema(description = "이전 페이지 유무") - - Boolean hasPrevious -) { - -} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupsSliceResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupsSliceResponse.java new file mode 100644 index 000000000..d0f4ad450 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupsSliceResponse.java @@ -0,0 +1,29 @@ +package site.timecapsulearchive.core.domain.group.data.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; +import java.util.function.Function; +import site.timecapsulearchive.core.domain.group.data.dto.GroupSummaryDto; + +@Schema(description = "사용자의 그룹 목록 응답") +public record GroupsSliceResponse( + + @Schema(description = "그룹 목록") + List groups, + + @Schema(description = "다음 페이지 유무") + Boolean hasNext +) { + + public static GroupsSliceResponse createOf( + List groups, + Boolean hasNext, + Function preSignedUrlFunction + ) { + List responses = groups.stream() + .map(dto -> dto.toResponse(preSignedUrlFunction)) + .toList(); + + return new GroupsSliceResponse(responses, hasNext); + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepository.java new file mode 100644 index 000000000..a1dac9c2f --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepository.java @@ -0,0 +1,48 @@ +package site.timecapsulearchive.core.domain.group.repository; + +import static site.timecapsulearchive.core.domain.group.entity.QGroup.group; +import static site.timecapsulearchive.core.domain.group.entity.QMemberGroup.memberGroup; + +import com.querydsl.core.types.Projections; +import com.querydsl.jpa.impl.JPAQueryFactory; +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.stereotype.Repository; +import site.timecapsulearchive.core.domain.group.data.dto.GroupSummaryDto; + +@Repository +@RequiredArgsConstructor +public class MemberGroupQueryRepository { + + private final JPAQueryFactory jpaQueryFactory; + + public Slice findGroupsSlice( + final Long memberId, + final int size, + final ZonedDateTime createdAt + ) { + List groups = jpaQueryFactory + .select( + Projections.constructor( + GroupSummaryDto.class, + group.id, + group.groupName, + group.groupDescription, + group.groupProfileUrl, + group.createdAt, + memberGroup.isOwner + ) + ) + .from(memberGroup) + .join(memberGroup.group, group) + .where(memberGroup.member.id.eq(memberId).and(memberGroup.createdAt.lt(createdAt))) + .limit(size + 1) + .fetch(); + + return new SliceImpl<>(groups, Pageable.ofSize(size), groups.size() > size); + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java index c819b69e0..9f9a080ee 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java @@ -1,43 +1,37 @@ package site.timecapsulearchive.core.domain.group.service; +import java.time.ZonedDateTime; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Slice; import org.springframework.stereotype.Service; -import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; import site.timecapsulearchive.core.domain.group.data.dto.GroupCreateDto; import site.timecapsulearchive.core.domain.group.data.dto.GroupInviteMessageDto; +import site.timecapsulearchive.core.domain.group.data.dto.GroupSummaryDto; import site.timecapsulearchive.core.domain.group.entity.Group; import site.timecapsulearchive.core.domain.group.entity.MemberGroup; import site.timecapsulearchive.core.domain.group.exception.GroupNotFoundException; import site.timecapsulearchive.core.domain.group.repository.GroupRepository; +import site.timecapsulearchive.core.domain.group.repository.MemberGroupQueryRepository; import site.timecapsulearchive.core.domain.group.repository.MemberGroupRepository; import site.timecapsulearchive.core.domain.member.entity.Member; import site.timecapsulearchive.core.domain.member.exception.MemberNotFoundException; import site.timecapsulearchive.core.domain.member.repository.MemberRepository; @Service +@RequiredArgsConstructor public class GroupService { private final GroupRepository groupRepository; private final MemberRepository memberRepository; private final MemberGroupRepository memberGroupRepository; + private final MemberGroupQueryRepository memberGroupQueryRepository; private final TransactionTemplate transactionTemplate; private final GroupInviteMessageManager groupInviteMessageManager; - public GroupService(GroupRepository groupRepository, - MemberRepository memberRepository, - MemberGroupRepository memberGroupRepository, - PlatformTransactionManager platformTransactionManager, - GroupInviteMessageManager groupInviteMessageManager) { - this.groupRepository = groupRepository; - this.transactionTemplate = new TransactionTemplate(platformTransactionManager); - this.groupInviteMessageManager = groupInviteMessageManager; - this.memberRepository = memberRepository; - this.memberGroupRepository = memberGroupRepository; - } - public void createGroup(final Long memberId, final GroupCreateDto dto) { Member member = memberRepository.findMemberById(memberId) .orElseThrow(MemberNotFoundException::new); @@ -64,4 +58,12 @@ public Group findGroupById(Long groupId) { .orElseThrow(GroupNotFoundException::new); } + @Transactional(readOnly = true) + public Slice findGroupsSlice( + final Long memberId, + final int size, + final ZonedDateTime createdAt + ) { + return memberGroupQueryRepository.findGroupsSlice(memberId, size, createdAt); + } } From 8263adf5b12f371ae58b2c27aee9d9660e35ead9 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Fri, 19 Apr 2024 21:31:09 +0900 Subject: [PATCH 02/13] =?UTF-8?q?fix=20:=20=EA=B7=B8=EB=A3=B9=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=EC=BF=BC=EB=A6=AC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/group/repository/MemberGroupQueryRepository.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepository.java index a1dac9c2f..2cd7ade36 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepository.java @@ -43,6 +43,11 @@ public Slice findGroupsSlice( .limit(size + 1) .fetch(); + boolean hasNext = groups.size() > size; + if (hasNext) { + groups.remove(size); + } + return new SliceImpl<>(groups, Pageable.ofSize(size), groups.size() > size); } } From 3ef4cdb8d28d62648e5928433cb9eae3ad11e76a Mon Sep 17 00:00:00 2001 From: hong seokho Date: Fri, 19 Apr 2024 21:31:39 +0900 Subject: [PATCH 03/13] =?UTF-8?q?test=20:=20=EA=B7=B8=EB=A3=B9=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/common/fixture/GroupFixture.java | 14 ++ .../common/fixture/MemberGroupFixture.java | 33 +++++ .../MemberGroupQueryRepositoryTest.java | 135 ++++++++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/GroupFixture.java create mode 100644 backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/MemberGroupFixture.java create mode 100644 backend/core/src/test/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepositoryTest.java diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/GroupFixture.java b/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/GroupFixture.java new file mode 100644 index 000000000..de2ed259d --- /dev/null +++ b/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/GroupFixture.java @@ -0,0 +1,14 @@ +package site.timecapsulearchive.core.common.fixture; + +import site.timecapsulearchive.core.domain.group.entity.Group; + +public class GroupFixture { + + public static Group group() { + return Group.builder() + .groupName("test_group") + .groupDescription("test_group") + .groupProfileUrl("test_group") + .build(); + } +} diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/MemberGroupFixture.java b/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/MemberGroupFixture.java new file mode 100644 index 000000000..1f150bfa4 --- /dev/null +++ b/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/MemberGroupFixture.java @@ -0,0 +1,33 @@ +package site.timecapsulearchive.core.common.fixture; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import site.timecapsulearchive.core.domain.group.entity.Group; +import site.timecapsulearchive.core.domain.group.entity.MemberGroup; +import site.timecapsulearchive.core.domain.member.entity.Member; + +public class MemberGroupFixture { + + public static MemberGroup memberGroup(Member member, Group group, Boolean isOwner) { + try { + Constructor declaredConstructor = MemberGroup.class.getDeclaredConstructor(); + declaredConstructor.setAccessible(true); + + MemberGroup memberGroup = declaredConstructor.newInstance(); + setFieldValue(memberGroup, "member", member); + setFieldValue(memberGroup, "group", group); + setFieldValue(memberGroup, "isOwner", isOwner); + + return memberGroup; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static void setFieldValue(Object instance, String fieldName, Object value) + throws NoSuchFieldException, IllegalAccessException { + Field field = instance.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(instance, value); + } +} diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepositoryTest.java new file mode 100644 index 000000000..e2ec77f16 --- /dev/null +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepositoryTest.java @@ -0,0 +1,135 @@ +package site.timecapsulearchive.core.domain.group.repository; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.SoftAssertions.assertSoftly; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import jakarta.persistence.EntityManager; +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.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Slice; +import org.springframework.test.context.TestConstructor; +import org.springframework.test.context.TestConstructor.AutowireMode; +import org.springframework.transaction.annotation.Transactional; +import site.timecapsulearchive.core.common.RepositoryTest; +import site.timecapsulearchive.core.common.fixture.GroupFixture; +import site.timecapsulearchive.core.common.fixture.MemberFixture; +import site.timecapsulearchive.core.common.fixture.MemberGroupFixture; +import site.timecapsulearchive.core.domain.group.data.dto.GroupSummaryDto; +import site.timecapsulearchive.core.domain.group.entity.Group; +import site.timecapsulearchive.core.domain.group.entity.MemberGroup; +import site.timecapsulearchive.core.domain.member.entity.Member; + +@TestConstructor(autowireMode = AutowireMode.ALL) +class MemberGroupQueryRepositoryTest extends RepositoryTest { + + private final MemberGroupQueryRepository memberGroupQueryRepository; + + private Long memberId; + private Long memberIdWithNoGroup; + + MemberGroupQueryRepositoryTest(EntityManager entityManager) { + this.memberGroupQueryRepository = new MemberGroupQueryRepository( + new JPAQueryFactory(entityManager)); + } + + @Transactional + @BeforeEach + void setup(@Autowired EntityManager entityManager) { + Member member = MemberFixture.member(0); + entityManager.persist(member); + memberId = member.getId(); + + Member memberWithNoGroup = MemberFixture.member(1); + entityManager.persist(memberWithNoGroup); + memberIdWithNoGroup = memberWithNoGroup.getId(); + + List groups = new ArrayList<>(); + for (int count = 0; count < 20; count++) { + Group group = GroupFixture.group(); + entityManager.persist(group); + groups.add(group); + } + + for (int count = 0; count < 10; count++) { + MemberGroup memberGroup = MemberGroupFixture.memberGroup(member, groups.get(count), + Boolean.FALSE); + entityManager.persist(memberGroup); + } + + for (int count = 0; count < 10; count++) { + MemberGroup memberGroup = MemberGroupFixture.memberGroup(member, groups.get(count), + Boolean.TRUE); + entityManager.persist(memberGroup); + } + } + + @ParameterizedTest + @ValueSource(ints = {1, 5, 15, 20}) + void 사용자와_개수_마지막_데이터_생성_시간으로_그룹_목록을_조회하면_개수만큼_그룹이_반환된다(int size) { + //given + ZonedDateTime now = ZonedDateTime.now().plusDays(3); + + //when + Slice groupsSlice = memberGroupQueryRepository.findGroupsSlice(memberId, + size, now); + + //then + assertThat(groupsSlice.getNumberOfElements()).isEqualTo(size); + } + + @Test + void 사용자와_개수_마지막_데이터_생성_시간으로_그룹_목록을_조회하면_개수만큼_그룹의_내용들이_반환된다() { + //given + int size = 20; + ZonedDateTime now = ZonedDateTime.now().plusDays(3); + + //when + List groupsSlice = memberGroupQueryRepository.findGroupsSlice(memberId, + size, now).getContent(); + + //then + assertSoftly(softly -> { + softly.assertThat(groupsSlice).allMatch(dto -> dto.id() != null); + softly.assertThat(groupsSlice).allMatch(dto -> !dto.groupName().isBlank()); + softly.assertThat(groupsSlice).allMatch(dto -> !dto.groupDescription().isBlank()); + softly.assertThat(groupsSlice).allMatch(dto -> !dto.groupProfileUrl().isBlank()); + softly.assertThat(groupsSlice).allMatch(dto -> dto.isOwner() != null); + }); + } + + @Test + void 그룹이_없는_사용자로_그룹_목록을_조회하면_빈_그룹_목록이_반환된다() { + //given + int size = 20; + ZonedDateTime now = ZonedDateTime.now().plusDays(3); + + //when + List groupsSlice = memberGroupQueryRepository.findGroupsSlice( + memberIdWithNoGroup, + size, now).getContent(); + + //then + assertThat(groupsSlice.isEmpty()).isTrue(); + } + + @Test + void 사용자와_범위에_없는_마지막_데이터_생성_시간으로_그룹_목록을_조회하면_빈_그룹_목록이_반환된다() { + //given + int size = 20; + ZonedDateTime now = ZonedDateTime.now().minusDays(5); + + //when + List groupsSlice = memberGroupQueryRepository.findGroupsSlice(memberId, + size, now).getContent(); + + //then + assertThat(groupsSlice.isEmpty()).isTrue(); + } +} \ No newline at end of file From 9bf5a4aa26278929a1f38ca485f02fe5f3ffec19 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Fri, 19 Apr 2024 23:24:18 +0900 Subject: [PATCH 04/13] =?UTF-8?q?fix=20:=20group=20=ED=85=8C=EC=9D=B4?= =?UTF-8?q?=EB=B8=94=20=EC=98=88=EC=95=BD=EC=96=B4=EB=A1=9C=20=EC=9D=B8?= =?UTF-8?q?=ED=95=9C=20=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/group/api/GroupApi.java | 19 ++++-- .../domain/group/api/GroupApiController.java | 21 +++++- .../domain/group/data/dto/GroupDetailDto.java | 29 +++++++++ .../group/data/dto/GroupMemberSummaryDto.java | 22 +++++++ .../data/response/GroupDetailResponse.java | 22 +++++-- .../response/GroupMemberSummaryResponse.java | 18 +++-- .../repository/GroupQueryRepository.java | 65 +++++++++++++++++++ .../domain/group/service/GroupService.java | 12 ++++ backend/core/src/main/resources/config | 2 +- 9 files changed, 188 insertions(+), 22 deletions(-) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupDetailDto.java create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupMemberSummaryDto.java create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/GroupQueryRepository.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApi.java index 6c56b8d92..d90e76ef5 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApi.java @@ -10,7 +10,6 @@ import java.time.ZonedDateTime; 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.ModelAttribute; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -131,15 +130,21 @@ ResponseEntity denyGroupInvitation( @ApiResponse( responseCode = "200", description = "ok" + ), + @ApiResponse( + responseCode = "400", + description = "잘못된 파라미터를 받았을 때 발생하는 오류" + ), + @ApiResponse( + responseCode = "403", + description = "그룹에 포함된 사용자가 아닌 경우 발생하는 오류" ) }) - @GetMapping( - value = "/groups/{group_id}", - produces = {"application/json"} - ) - ResponseEntity findGroupById( + ResponseEntity> findGroupDetailById( + Long memberId, + @Parameter(in = ParameterIn.PATH, description = "조회할 그룹 아이디", required = true, schema = @Schema()) - @PathVariable("group_id") Long groupId + Long groupId ); @Operation( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApiController.java index 588e1b7c1..0af035994 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApiController.java @@ -7,12 +7,14 @@ import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; 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.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import site.timecapsulearchive.core.domain.group.data.dto.GroupCreateDto; +import site.timecapsulearchive.core.domain.group.data.dto.GroupDetailDto; import site.timecapsulearchive.core.domain.group.data.dto.GroupSummaryDto; import site.timecapsulearchive.core.domain.group.data.reqeust.GroupCreateRequest; import site.timecapsulearchive.core.domain.group.data.reqeust.GroupUpdateRequest; @@ -73,9 +75,24 @@ public ResponseEntity denyGroupInvitation(Long groupId, Long memberId) { return null; } + @GetMapping( + value = "/{group_id}", + produces = {"application/json"} + ) @Override - public ResponseEntity findGroupById(Long groupId) { - return null; + public ResponseEntity> findGroupDetailById( + @AuthenticationPrincipal final Long memberId, + @PathVariable("group_id") final Long groupId + ) { + GroupDetailDto groupDetailDto = groupService.findGroupDetailByMemberIdAndGroupId( + memberId, groupId); + + return ResponseEntity.ok( + ApiSpec.success( + SuccessCode.SUCCESS, + groupDetailDto.toResponse() + ) + ); } @GetMapping( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupDetailDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupDetailDto.java new file mode 100644 index 000000000..757388962 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupDetailDto.java @@ -0,0 +1,29 @@ +package site.timecapsulearchive.core.domain.group.data.dto; + +import java.time.ZonedDateTime; +import java.util.List; +import site.timecapsulearchive.core.domain.group.data.response.GroupDetailResponse; +import site.timecapsulearchive.core.domain.group.data.response.GroupMemberSummaryResponse; + +public record GroupDetailDto( + String groupName, + String groupDescription, + String groupProfileUrl, + ZonedDateTime createdAt, + List members +) { + + public GroupDetailResponse toResponse() { + List members = this.members.stream() + .map(GroupMemberSummaryDto::toResponse) + .toList(); + + return GroupDetailResponse.builder() + .groupName(groupName) + .groupDescription(groupDescription) + .groupProfileUrl(groupProfileUrl) + .createdAt(createdAt) + .members(members) + .build(); + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupMemberSummaryDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupMemberSummaryDto.java new file mode 100644 index 000000000..b5e2e48f8 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupMemberSummaryDto.java @@ -0,0 +1,22 @@ +package site.timecapsulearchive.core.domain.group.data.dto; + +import site.timecapsulearchive.core.domain.group.data.response.GroupMemberSummaryResponse; + +public record GroupMemberSummaryDto( + Long memberId, + String profileUrl, + String nickname, + String tag, + Boolean isOwner +) { + + public GroupMemberSummaryResponse toResponse() { + return GroupMemberSummaryResponse.builder() + .memberId(memberId) + .profileUrl(profileUrl) + .nickname(nickname) + .tag(tag) + .isOwner(isOwner) + .build(); + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupDetailResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupDetailResponse.java index f1105e8dc..8a89bc2de 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupDetailResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupDetailResponse.java @@ -3,24 +3,32 @@ import io.swagger.v3.oas.annotations.media.Schema; import java.time.ZonedDateTime; import java.util.List; +import lombok.Builder; +import site.timecapsulearchive.core.global.common.response.ResponseMappingConstant; +@Builder @Schema(description = "그룹 생성 포맷") public record GroupDetailResponse( @Schema(description = "그룹 이름") - String name, - - @Schema(description = "그룹 생성일") - ZonedDateTime createdDate, + String groupName, @Schema(description = "그룹 프로필 url") - String profileUrl, + String groupProfileUrl, @Schema(description = "그룹 설명") - String description, + String groupDescription, + + @Schema(description = "그룹 생성일") + ZonedDateTime createdAt, @Schema(description = "그룹원 리스트") - List members + List members ) { + public GroupDetailResponse { + if (createdAt != null) { + createdAt.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); + } + } } \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupMemberSummaryResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupMemberSummaryResponse.java index d780de6a5..b1857b2c9 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupMemberSummaryResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupMemberSummaryResponse.java @@ -1,18 +1,26 @@ package site.timecapsulearchive.core.domain.group.data.response; import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +@Builder @Schema(description = "그룹원 요약 정보") public record GroupMemberSummaryResponse( - @Schema(description = "닉네임") - String nickname, + @Schema(description = "그룹원 아이디") + Long memberId, - @Schema(description = "프로필 url") + @Schema(description = "그룹원 프로필 url") String profileUrl, - @Schema(description = "개봉 여부") - Boolean isOpened + @Schema(description = "그룹원 닉네임") + String nickname, + + @Schema(description = "그룹원 태그") + String tag, + + @Schema(description = "그룹장 여부") + Boolean isOwner ) { } \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/GroupQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/GroupQueryRepository.java new file mode 100644 index 000000000..d0319e76a --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/GroupQueryRepository.java @@ -0,0 +1,65 @@ +package site.timecapsulearchive.core.domain.group.repository; + +import static com.querydsl.core.group.GroupBy.groupBy; +import static com.querydsl.core.group.GroupBy.list; +import static site.timecapsulearchive.core.domain.group.entity.QGroup.group; +import static site.timecapsulearchive.core.domain.group.entity.QMemberGroup.memberGroup; +import static site.timecapsulearchive.core.domain.member.entity.QMember.member; + +import com.querydsl.core.types.Projections; +import com.querydsl.jpa.impl.JPAQueryFactory; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; +import site.timecapsulearchive.core.domain.group.data.dto.GroupDetailDto; +import site.timecapsulearchive.core.domain.group.data.dto.GroupMemberSummaryDto; + +@Repository +@RequiredArgsConstructor +public class GroupQueryRepository { + + private final JPAQueryFactory jpaQueryFactory; + + public Optional findGroupDetailByGroupId(final Long groupId) { + return Optional.ofNullable( + jpaQueryFactory + .select( + group.groupName, + group.groupDescription, + group.groupProfileUrl, + group.createdAt, + member.id, + member.profileUrl, + member.nickname, + member.tag, + memberGroup.isOwner + ) + .from(group) + .join(memberGroup).on(memberGroup.group.id.eq(group.id)) + .join(member).on(member.id.eq(memberGroup.member.id)) + .where(group.id.eq(groupId)) + .transform( + groupBy(group.id).as( + Projections.constructor( + GroupDetailDto.class, + group.groupName, + group.groupDescription, + group.groupProfileUrl, + group.createdAt, + list( + Projections.constructor( + GroupMemberSummaryDto.class, + member.id, + member.profileUrl, + member.nickname, + member.tag, + memberGroup.isOwner + ) + ) + ) + ) + ) + .get(groupId) + ); + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java index 9f9a080ee..952b3a646 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java @@ -9,11 +9,13 @@ import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; import site.timecapsulearchive.core.domain.group.data.dto.GroupCreateDto; +import site.timecapsulearchive.core.domain.group.data.dto.GroupDetailDto; import site.timecapsulearchive.core.domain.group.data.dto.GroupInviteMessageDto; import site.timecapsulearchive.core.domain.group.data.dto.GroupSummaryDto; import site.timecapsulearchive.core.domain.group.entity.Group; import site.timecapsulearchive.core.domain.group.entity.MemberGroup; import site.timecapsulearchive.core.domain.group.exception.GroupNotFoundException; +import site.timecapsulearchive.core.domain.group.repository.GroupQueryRepository; import site.timecapsulearchive.core.domain.group.repository.GroupRepository; import site.timecapsulearchive.core.domain.group.repository.MemberGroupQueryRepository; import site.timecapsulearchive.core.domain.group.repository.MemberGroupRepository; @@ -31,6 +33,7 @@ public class GroupService { private final MemberGroupQueryRepository memberGroupQueryRepository; private final TransactionTemplate transactionTemplate; private final GroupInviteMessageManager groupInviteMessageManager; + private final GroupQueryRepository groupQueryRepository; public void createGroup(final Long memberId, final GroupCreateDto dto) { Member member = memberRepository.findMemberById(memberId) @@ -66,4 +69,13 @@ public Slice findGroupsSlice( ) { return memberGroupQueryRepository.findGroupsSlice(memberId, size, createdAt); } + + @Transactional(readOnly = true) + public GroupDetailDto findGroupDetailByMemberIdAndGroupId( + final Long memberId, + final Long groupId + ) { + return groupQueryRepository.findGroupDetailByGroupId(groupId) + .orElseThrow(GroupNotFoundException::new); + } } diff --git a/backend/core/src/main/resources/config b/backend/core/src/main/resources/config index c0e68bd09..64a2a4f74 160000 --- a/backend/core/src/main/resources/config +++ b/backend/core/src/main/resources/config @@ -1 +1 @@ -Subproject commit c0e68bd09f28d875346ad85e3ab19e7a23192a09 +Subproject commit 64a2a4f74b06f7e031f721f6581fd0f153d77cde From 18533a255e181d3f3e586bed99aa5f5b7bbeceb8 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 20 Apr 2024 09:55:02 +0900 Subject: [PATCH 05/13] =?UTF-8?q?fix=20:=20=EC=BF=BC=EB=A6=AC=20=EB=A0=88?= =?UTF-8?q?=ED=8F=AC=EC=A7=80=ED=86=A0=EB=A6=AC=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EB=B0=8F=20=EC=9C=84=EC=B9=98=20=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/GroupQueryRepository.java | 37 +++++++++++++ .../MemberGroupQueryRepository.java | 53 ------------------- .../domain/group/service/GroupService.java | 5 +- 3 files changed, 39 insertions(+), 56 deletions(-) delete mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepository.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/GroupQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/GroupQueryRepository.java index d0319e76a..0d51f471c 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/GroupQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/GroupQueryRepository.java @@ -8,11 +8,17 @@ import com.querydsl.core.types.Projections; import com.querydsl.jpa.impl.JPAQueryFactory; +import java.time.ZonedDateTime; +import java.util.List; import java.util.Optional; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.data.domain.SliceImpl; import org.springframework.stereotype.Repository; import site.timecapsulearchive.core.domain.group.data.dto.GroupDetailDto; import site.timecapsulearchive.core.domain.group.data.dto.GroupMemberSummaryDto; +import site.timecapsulearchive.core.domain.group.data.dto.GroupSummaryDto; @Repository @RequiredArgsConstructor @@ -20,6 +26,37 @@ public class GroupQueryRepository { private final JPAQueryFactory jpaQueryFactory; + public Slice findGroupsSlice( + final Long memberId, + final int size, + final ZonedDateTime createdAt + ) { + List groups = jpaQueryFactory + .select( + Projections.constructor( + GroupSummaryDto.class, + group.id, + group.groupName, + group.groupDescription, + group.groupProfileUrl, + group.createdAt, + memberGroup.isOwner + ) + ) + .from(memberGroup) + .join(memberGroup.group, group) + .where(memberGroup.member.id.eq(memberId).and(memberGroup.createdAt.lt(createdAt))) + .limit(size + 1) + .fetch(); + + boolean hasNext = groups.size() > size; + if (hasNext) { + groups.remove(size); + } + + return new SliceImpl<>(groups, Pageable.ofSize(size), groups.size() > size); + } + public Optional findGroupDetailByGroupId(final Long groupId) { return Optional.ofNullable( jpaQueryFactory diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepository.java deleted file mode 100644 index 2cd7ade36..000000000 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepository.java +++ /dev/null @@ -1,53 +0,0 @@ -package site.timecapsulearchive.core.domain.group.repository; - -import static site.timecapsulearchive.core.domain.group.entity.QGroup.group; -import static site.timecapsulearchive.core.domain.group.entity.QMemberGroup.memberGroup; - -import com.querydsl.core.types.Projections; -import com.querydsl.jpa.impl.JPAQueryFactory; -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.stereotype.Repository; -import site.timecapsulearchive.core.domain.group.data.dto.GroupSummaryDto; - -@Repository -@RequiredArgsConstructor -public class MemberGroupQueryRepository { - - private final JPAQueryFactory jpaQueryFactory; - - public Slice findGroupsSlice( - final Long memberId, - final int size, - final ZonedDateTime createdAt - ) { - List groups = jpaQueryFactory - .select( - Projections.constructor( - GroupSummaryDto.class, - group.id, - group.groupName, - group.groupDescription, - group.groupProfileUrl, - group.createdAt, - memberGroup.isOwner - ) - ) - .from(memberGroup) - .join(memberGroup.group, group) - .where(memberGroup.member.id.eq(memberId).and(memberGroup.createdAt.lt(createdAt))) - .limit(size + 1) - .fetch(); - - boolean hasNext = groups.size() > size; - if (hasNext) { - groups.remove(size); - } - - return new SliceImpl<>(groups, Pageable.ofSize(size), groups.size() > size); - } -} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java index 952b3a646..b193a802d 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java @@ -17,7 +17,6 @@ import site.timecapsulearchive.core.domain.group.exception.GroupNotFoundException; import site.timecapsulearchive.core.domain.group.repository.GroupQueryRepository; import site.timecapsulearchive.core.domain.group.repository.GroupRepository; -import site.timecapsulearchive.core.domain.group.repository.MemberGroupQueryRepository; import site.timecapsulearchive.core.domain.group.repository.MemberGroupRepository; import site.timecapsulearchive.core.domain.member.entity.Member; import site.timecapsulearchive.core.domain.member.exception.MemberNotFoundException; @@ -30,7 +29,6 @@ public class GroupService { private final GroupRepository groupRepository; private final MemberRepository memberRepository; private final MemberGroupRepository memberGroupRepository; - private final MemberGroupQueryRepository memberGroupQueryRepository; private final TransactionTemplate transactionTemplate; private final GroupInviteMessageManager groupInviteMessageManager; private final GroupQueryRepository groupQueryRepository; @@ -67,7 +65,7 @@ public Slice findGroupsSlice( final int size, final ZonedDateTime createdAt ) { - return memberGroupQueryRepository.findGroupsSlice(memberId, size, createdAt); + return groupQueryRepository.findGroupsSlice(memberId, size, createdAt); } @Transactional(readOnly = true) @@ -75,6 +73,7 @@ public GroupDetailDto findGroupDetailByMemberIdAndGroupId( final Long memberId, final Long groupId ) { + //TODO: 그룹 상세에서 그룹원 목록에서 내가 조회 가능해야 하는가? return groupQueryRepository.findGroupDetailByGroupId(groupId) .orElseThrow(GroupNotFoundException::new); } From 7e2c3ba1eeeeea0b5af42197287c2e70918b452a Mon Sep 17 00:00:00 2001 From: hong seokho Date: Mon, 6 May 2024 11:38:34 +0900 Subject: [PATCH 06/13] =?UTF-8?q?fix=20:=20=EC=84=9C=EB=B9=84=EC=8A=A4=20?= =?UTF-8?q?=EC=8A=A4=ED=8E=99=20=EC=88=98=EC=A0=95,=20=EC=BB=A8=ED=8A=B8?= =?UTF-8?q?=EB=A1=A4=EB=9F=AC=20=EC=9D=91=EB=8B=B5=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - memberId가 필요 없어 서비스 스펙 수정 - 미리 서명된 스킨 url 위해 응답 부분 생성 수정 --- .../core/domain/group/api/GroupApiController.java | 5 ++--- .../core/domain/group/data/dto/GroupDetailDto.java | 5 +++-- .../core/domain/group/service/GroupService.java | 6 +----- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApiController.java index 0af035994..fc64a407c 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApiController.java @@ -84,13 +84,12 @@ public ResponseEntity> findGroupDetailById( @AuthenticationPrincipal final Long memberId, @PathVariable("group_id") final Long groupId ) { - GroupDetailDto groupDetailDto = groupService.findGroupDetailByMemberIdAndGroupId( - memberId, groupId); + GroupDetailDto groupDetailDto = groupService.findGroupDetailByGroupId(groupId); return ResponseEntity.ok( ApiSpec.success( SuccessCode.SUCCESS, - groupDetailDto.toResponse() + groupDetailDto.toResponse(s3PreSignedUrlManager::getS3PreSignedUrlForGet) ) ); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupDetailDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupDetailDto.java index 757388962..fb4f0dea1 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupDetailDto.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupDetailDto.java @@ -2,6 +2,7 @@ import java.time.ZonedDateTime; import java.util.List; +import java.util.function.Function; import site.timecapsulearchive.core.domain.group.data.response.GroupDetailResponse; import site.timecapsulearchive.core.domain.group.data.response.GroupMemberSummaryResponse; @@ -13,7 +14,7 @@ public record GroupDetailDto( List members ) { - public GroupDetailResponse toResponse() { + public GroupDetailResponse toResponse(Function singlePreSignUrlFunction) { List members = this.members.stream() .map(GroupMemberSummaryDto::toResponse) .toList(); @@ -21,7 +22,7 @@ public GroupDetailResponse toResponse() { return GroupDetailResponse.builder() .groupName(groupName) .groupDescription(groupDescription) - .groupProfileUrl(groupProfileUrl) + .groupProfileUrl(singlePreSignUrlFunction.apply(groupProfileUrl)) .createdAt(createdAt) .members(members) .build(); diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java index b193a802d..e39730b41 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java @@ -69,11 +69,7 @@ public Slice findGroupsSlice( } @Transactional(readOnly = true) - public GroupDetailDto findGroupDetailByMemberIdAndGroupId( - final Long memberId, - final Long groupId - ) { - //TODO: 그룹 상세에서 그룹원 목록에서 내가 조회 가능해야 하는가? + public GroupDetailDto findGroupDetailByGroupId(final Long groupId) { return groupQueryRepository.findGroupDetailByGroupId(groupId) .orElseThrow(GroupNotFoundException::new); } From b0a933b161e4b363d03decc5f43cab76c1c930d8 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Mon, 6 May 2024 11:39:04 +0900 Subject: [PATCH 07/13] =?UTF-8?q?test=20:=20=EA=B7=B8=EB=A3=B9=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=EC=A1=B0=ED=9A=8C=20=EC=BF=BC=EB=A6=AC=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - fixture 주석 추가 --- .../core/common/RepositoryTest.java | 3 +- .../core/common/fixture/MemberFixture.java | 29 +++++ .../common/fixture/MemberGroupFixture.java | 21 ++++ .../MemberGroupQueryRepositoryTest.java | 109 +++++++++++++++--- 4 files changed, 144 insertions(+), 18 deletions(-) diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/common/RepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/common/RepositoryTest.java index d9bfee830..c0430087e 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/common/RepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/common/RepositoryTest.java @@ -8,8 +8,9 @@ import org.springframework.context.annotation.Import; import org.springframework.test.context.ActiveProfiles; import site.timecapsulearchive.core.global.config.JpaAuditingConfig; +import site.timecapsulearchive.core.global.config.QueryDSLConfig; -@Import(JpaAuditingConfig.class) +@Import(value = {JpaAuditingConfig.class, QueryDSLConfig.class}) @DataJpaTest @FlywayTestExtension @FlywayTest diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/MemberFixture.java b/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/MemberFixture.java index fa6b83562..1b30b756e 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/MemberFixture.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/MemberFixture.java @@ -1,7 +1,9 @@ package site.timecapsulearchive.core.common.fixture; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.List; +import java.util.stream.IntStream; import site.timecapsulearchive.core.common.dependency.UnitTestDependency; import site.timecapsulearchive.core.domain.member.entity.Member; import site.timecapsulearchive.core.domain.member.entity.SocialType; @@ -12,6 +14,12 @@ public class MemberFixture { private static final HashEncryptionManager hashEncryptionManager = UnitTestDependency.hashEncryptionManager(); + /** + * 테스트 픽스처 - 멤버 마다 상이한 값을 위한 dataPrefix를 주면 멤버를 생성한다. + *
주의 - 테스트에서 같은 prefix를 사용하면 오류가 발생하므로 서로 다른 prefix를 쓰도록 해야함. + * @param dataPrefix prefix + * @return {@code Member} 테스트 픽스처 + */ public static Member member(int dataPrefix) { Member member = Member.builder() .socialType(SocialType.GOOGLE) @@ -28,6 +36,12 @@ public static Member member(int dataPrefix) { return member; } + /** + * 테스트 픽스처 - 멤버마다 상이한 번호를 위해 dataPrefix를 주면 해당 dataPrefix에 대한 핸드폰 번호 바이트를 반환한다. + *
주의 - 테스트에서 같은 prefix를 사용하면 오류가 발생하므로 서로 다른 prefix를 쓰도록 해야함. + * @param dataPrefix prefix + * @return 핸드폰 번호 바이트 + */ public static byte[] getPhoneBytes(int dataPrefix) { return ("0" + (1000000000 + dataPrefix)).getBytes(StandardCharsets.UTF_8); } @@ -49,4 +63,19 @@ private static byte[] getPhoneBytes(String phone) { return hashEncryptionManager.encrypt(phone.getBytes(StandardCharsets.UTF_8)); } + /** + * 테스트 픽스처 - 크기와 멤버 마다 상이한 값을 위한 startDataPrefix를 주면 멤버들을 생성한다. + *
주의 - 테스트에서 같은 prefix를 사용하면 오류가 발생하므로 서로 다른 prefix를 쓰도록 해야함. + * @param size 생성할 멤버의 크기 + * @param startDataPrefix 시작 prefix + * @return {@code List} 테스트 픽스처들 + */ + public static List members(int size, int startDataPrefix) { + List result = new ArrayList<>(); + for (int i = 0; i < size; i++) { + result.add(member(startDataPrefix++)); + } + + return result; + } } \ No newline at end of file diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/MemberGroupFixture.java b/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/MemberGroupFixture.java index 1f150bfa4..e3fa3d59e 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/MemberGroupFixture.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/MemberGroupFixture.java @@ -2,12 +2,21 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; import site.timecapsulearchive.core.domain.group.entity.Group; import site.timecapsulearchive.core.domain.group.entity.MemberGroup; import site.timecapsulearchive.core.domain.member.entity.Member; public class MemberGroupFixture { + /** + * 테스트 픽스처 - 사용자, 그룹, 그룹장 여부를 받아 그룹원을 만들어준다. + * @param member 사용자 + * @param group 그룹 + * @param isOwner 그룹장 여부 + * @return MemberGroup 테스트 픽스처 + */ public static MemberGroup memberGroup(Member member, Group group, Boolean isOwner) { try { Constructor declaredConstructor = MemberGroup.class.getDeclaredConstructor(); @@ -30,4 +39,16 @@ private static void setFieldValue(Object instance, String fieldName, Object valu field.setAccessible(true); field.set(instance, value); } + + /** + * 테스트 픽스처 - 그룹원들과 그룹을 주면 그룹원들 목록을 만들어준다(그룹장 X) + * @param members 그룹원들 목록 + * @param group 그룹 + * @return {@code List} 테스트 픽스처들 + */ + public static List membersGroup(List members, Group group) { + return members.stream() + .map(m -> memberGroup(m, group, Boolean.FALSE)) + .toList(); + } } diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepositoryTest.java index e2ec77f16..7d14d66db 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepositoryTest.java @@ -8,6 +8,7 @@ import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.List; +import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -21,6 +22,7 @@ import site.timecapsulearchive.core.common.fixture.GroupFixture; import site.timecapsulearchive.core.common.fixture.MemberFixture; import site.timecapsulearchive.core.common.fixture.MemberGroupFixture; +import site.timecapsulearchive.core.domain.group.data.dto.GroupDetailDto; import site.timecapsulearchive.core.domain.group.data.dto.GroupSummaryDto; import site.timecapsulearchive.core.domain.group.entity.Group; import site.timecapsulearchive.core.domain.group.entity.MemberGroup; @@ -29,45 +31,55 @@ @TestConstructor(autowireMode = AutowireMode.ALL) class MemberGroupQueryRepositoryTest extends RepositoryTest { - private final MemberGroupQueryRepository memberGroupQueryRepository; + private final static int GROUP_COUNT = 20; + + private final GroupQueryRepository groupQueryRepository; private Long memberId; private Long memberIdWithNoGroup; + private Long ownerGroupId; - MemberGroupQueryRepositoryTest(EntityManager entityManager) { - this.memberGroupQueryRepository = new MemberGroupQueryRepository( - new JPAQueryFactory(entityManager)); + MemberGroupQueryRepositoryTest(JPAQueryFactory jpaQueryFactory) { + this.groupQueryRepository = new GroupQueryRepository(jpaQueryFactory); } @Transactional @BeforeEach void setup(@Autowired EntityManager entityManager) { + //사용자 Member member = MemberFixture.member(0); entityManager.persist(member); memberId = member.getId(); + //그룹이 없는 사용자 Member memberWithNoGroup = MemberFixture.member(1); entityManager.persist(memberWithNoGroup); memberIdWithNoGroup = memberWithNoGroup.getId(); + //그룹 List groups = new ArrayList<>(); - for (int count = 0; count < 20; count++) { + for (int count = 0; count < GROUP_COUNT; count++) { Group group = GroupFixture.group(); entityManager.persist(group); groups.add(group); } + //사용자가 그룹장인 그룹 + ownerGroupId = groups.get(0).getId(); - for (int count = 0; count < 10; count++) { - MemberGroup memberGroup = MemberGroupFixture.memberGroup(member, groups.get(count), - Boolean.FALSE); - entityManager.persist(memberGroup); - } + //그룹원들 + List members = MemberFixture.members(4, 2); + members.forEach(entityManager::persist); - for (int count = 0; count < 10; count++) { + //그룹에 사용자를 그룹장으로 설정 + for (int count = 0; count < GROUP_COUNT; count++) { MemberGroup memberGroup = MemberGroupFixture.memberGroup(member, groups.get(count), Boolean.TRUE); entityManager.persist(memberGroup); } + + //그룹원들 설정 + List memberGroups = MemberGroupFixture.membersGroup(members, groups.get(0)); + memberGroups.forEach(entityManager::persist); } @ParameterizedTest @@ -77,7 +89,7 @@ void setup(@Autowired EntityManager entityManager) { ZonedDateTime now = ZonedDateTime.now().plusDays(3); //when - Slice groupsSlice = memberGroupQueryRepository.findGroupsSlice(memberId, + Slice groupsSlice = groupQueryRepository.findGroupsSlice(memberId, size, now); //then @@ -91,7 +103,7 @@ void setup(@Autowired EntityManager entityManager) { ZonedDateTime now = ZonedDateTime.now().plusDays(3); //when - List groupsSlice = memberGroupQueryRepository.findGroupsSlice(memberId, + List groupsSlice = groupQueryRepository.findGroupsSlice(memberId, size, now).getContent(); //then @@ -111,9 +123,11 @@ void setup(@Autowired EntityManager entityManager) { ZonedDateTime now = ZonedDateTime.now().plusDays(3); //when - List groupsSlice = memberGroupQueryRepository.findGroupsSlice( - memberIdWithNoGroup, - size, now).getContent(); + List groupsSlice = groupQueryRepository.findGroupsSlice( + memberIdWithNoGroup, + size, + now) + .getContent(); //then assertThat(groupsSlice.isEmpty()).isTrue(); @@ -126,10 +140,71 @@ void setup(@Autowired EntityManager entityManager) { ZonedDateTime now = ZonedDateTime.now().minusDays(5); //when - List groupsSlice = memberGroupQueryRepository.findGroupsSlice(memberId, + List groupsSlice = groupQueryRepository.findGroupsSlice(memberId, size, now).getContent(); //then assertThat(groupsSlice.isEmpty()).isTrue(); } + + @Test + void 그룹_아이디로_그룹을_조회하면_그룹_상세가_반환된다() { + //given + //when + GroupDetailDto groupDetail = groupQueryRepository.findGroupDetailByGroupId( + ownerGroupId).orElseThrow(); + + //then + assertThat(groupDetail).isNotNull(); + } + + @Test + void 그룹_아이디로_그룹을_조회하면_그룹_정보를_볼_수_있다() { + //given + //when + GroupDetailDto groupDetail = groupQueryRepository.findGroupDetailByGroupId( + ownerGroupId).orElseThrow(); + + //then + SoftAssertions.assertSoftly(softly -> { + assertThat(groupDetail.groupName()).isNotBlank(); + assertThat(groupDetail.groupDescription()).isNotBlank(); + assertThat(groupDetail.groupProfileUrl()).isNotBlank(); + assertThat(groupDetail.createdAt()).isNotNull(); + }); + } + + @Test + void 그룹_아이디로_그룹을_조회하면_그룹원들의_정보를_볼_수_있다() { + //given + //when + GroupDetailDto groupDetail = groupQueryRepository.findGroupDetailByGroupId( + ownerGroupId).orElseThrow(); + + //then + SoftAssertions.assertSoftly(softly -> { + assertThat(groupDetail.members()).isNotEmpty(); + assertThat(groupDetail.members()).allSatisfy(m -> assertThat(m.memberId()).isNotNull()); + assertThat(groupDetail.members()).allSatisfy(m -> assertThat(m.tag()).isNotBlank()); + assertThat(groupDetail.members()).allSatisfy( + m -> assertThat(m.nickname()).isNotBlank()); + assertThat(groupDetail.members()).allSatisfy( + m -> assertThat(m.profileUrl()).isNotBlank()); + assertThat(groupDetail.members()).allSatisfy(m -> assertThat(m.isOwner()).isNotNull()); + }); + } + + @Test + void 그룹_아이디로_그룹을_조회하면_한_명의_그룹장만_존재한다() { + //given + //when + GroupDetailDto groupDetail = groupQueryRepository.findGroupDetailByGroupId( + ownerGroupId).orElseThrow(); + + //then + SoftAssertions.assertSoftly(softly -> { + assertThat(groupDetail.members()).satisfiesOnlyOnce( + m -> assertThat(m.isOwner()).isTrue()); + }); + } } \ No newline at end of file From 7fae7d164ccc834a168f1e97f9014cdfdbfedc3c Mon Sep 17 00:00:00 2001 From: hong seokho Date: Mon, 6 May 2024 12:02:11 +0900 Subject: [PATCH 08/13] =?UTF-8?q?fix=20:=20response=20=ED=95=A0=20?= =?UTF-8?q?=EB=95=8C=20=EC=8B=9C=EA=B0=84=20=EB=B3=80=ED=99=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95,=20=EC=9D=91=EB=8B=B5=20=EB=AC=B8=EC=84=9C=ED=99=94?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존 시간 변환 없었던 응답 수정 - 응답 문서화 추가 --- .../data/dto/NearbyARCapsuleSummaryDto.java | 7 ---- .../data/response/CapsuleDetailResponse.java | 4 +- .../data/response/CapsuleSummaryResponse.java | 4 +- .../NearbyARCapsuleSummaryResponse.java | 7 +++- .../data/dto/PublicCapsuleDetailDto.java | 38 +++++++++---------- .../response/PublicCapsuleDetailResponse.java | 38 ++----------------- .../response/PublicCapsuleSliceResponse.java | 1 - .../data/dto/MySecreteCapsuleDto.java | 8 ---- .../response/MySecreteCapsuleResponse.java | 10 +++++ .../response/CapsuleSkinSummaryResponse.java | 6 +++ .../data/response/FriendSummaryResponse.java | 6 +++ .../data/response/GroupDetailResponse.java | 2 +- .../data/response/GroupSummaryResponse.java | 2 + .../response/MemberNotificationResponse.java | 14 +++++++ 14 files changed, 74 insertions(+), 73 deletions(-) rename backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/{generic_capsule => public_capsule}/data/response/PublicCapsuleDetailResponse.java (54%) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/dto/NearbyARCapsuleSummaryDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/dto/NearbyARCapsuleSummaryDto.java index 7187bcdb7..9e8c378cc 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/dto/NearbyARCapsuleSummaryDto.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/dto/NearbyARCapsuleSummaryDto.java @@ -5,7 +5,6 @@ import org.locationtech.jts.geom.Point; import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response.NearbyARCapsuleSummaryResponse; -import site.timecapsulearchive.core.global.common.response.ResponseMappingConstant; public record NearbyARCapsuleSummaryDto( Long id, @@ -18,12 +17,6 @@ public record NearbyARCapsuleSummaryDto( CapsuleType capsuleType ) { - public NearbyARCapsuleSummaryDto { - if (dueDate != null) { - dueDate = dueDate.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); - } - } - public NearbyARCapsuleSummaryResponse toResponse( final Function geoTransformFunction, final Function preSignUrlFunction diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/CapsuleDetailResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/CapsuleDetailResponse.java index d6e835e3c..ffa57b4fe 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/CapsuleDetailResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/CapsuleDetailResponse.java @@ -58,7 +58,9 @@ public record CapsuleDetailResponse( dueDate = dueDate.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); } - createdDate.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); + if (createdDate != null) { + createdDate = createdDate.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); + } } public static CapsuleDetailResponse createOf( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/CapsuleSummaryResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/CapsuleSummaryResponse.java index 4291abf49..047665fd3 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/CapsuleSummaryResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/CapsuleSummaryResponse.java @@ -44,7 +44,9 @@ public record CapsuleSummaryResponse( dueDate = dueDate.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); } - createdAt = createdAt.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); + if (createdAt != null) { + createdAt = createdAt.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); + } } public static CapsuleSummaryResponse createOf( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/NearbyARCapsuleSummaryResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/NearbyARCapsuleSummaryResponse.java index 7f911bfc3..06019f920 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/NearbyARCapsuleSummaryResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/NearbyARCapsuleSummaryResponse.java @@ -4,6 +4,7 @@ import java.time.ZonedDateTime; import lombok.Builder; import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; +import site.timecapsulearchive.core.global.common.response.ResponseMappingConstant; @Schema(description = "AR 캡슐 요약 정보") @Builder @@ -33,5 +34,9 @@ public record NearbyARCapsuleSummaryResponse( @Schema(description = "캡슐 타입") CapsuleType capsuleType ) { - + public NearbyARCapsuleSummaryResponse { + if (dueDate != null) { + dueDate = dueDate.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); + } + } } \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/dto/PublicCapsuleDetailDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/dto/PublicCapsuleDetailDto.java index bef598cb4..84a3f0f40 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/dto/PublicCapsuleDetailDto.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/dto/PublicCapsuleDetailDto.java @@ -5,7 +5,7 @@ import java.util.function.Function; import org.locationtech.jts.geom.Point; import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; -import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response.PublicCapsuleDetailResponse; +import site.timecapsulearchive.core.domain.capsule.public_capsule.data.response.PublicCapsuleDetailResponse; public record PublicCapsuleDetailDto( Long capsuleId, @@ -34,23 +34,23 @@ public PublicCapsuleDetailResponse toResponse( final List preSignedImageUrls = multiplePreSignUrlFunction.apply(images); final List preSignedVideoUrls = multiplePreSignUrlFunction.apply(videos); - return new PublicCapsuleDetailResponse( - capsuleId, - singlePreSignUrlFunction.apply(capsuleSkinUrl), - dueDate, - nickname, - profileUrl, - createdAt, - changePoint.getX(), - changePoint.getY(), - address, - roadName, - title, - content, - preSignedImageUrls, - preSignedVideoUrls, - isOpened, - capsuleType - ); + return PublicCapsuleDetailResponse.builder() + .capsuleId(capsuleId) + .capsuleSkinUrl(singlePreSignUrlFunction.apply(capsuleSkinUrl)) + .dueDate(dueDate) + .nickname(nickname) + .profileUrl(profileUrl) + .createdDate(createdAt) + .latitude(changePoint.getX()) + .longitude(changePoint.getY()) + .address(address) + .roadName(roadName) + .title(title) + .content(content) + .imageUrls(preSignedImageUrls) + .videoUrls(preSignedVideoUrls) + .isOpened(isOpened) + .capsuleType(capsuleType) + .build(); } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/PublicCapsuleDetailResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/response/PublicCapsuleDetailResponse.java similarity index 54% rename from backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/PublicCapsuleDetailResponse.java rename to backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/response/PublicCapsuleDetailResponse.java index bbcb35dd6..606a03015 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/PublicCapsuleDetailResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/response/PublicCapsuleDetailResponse.java @@ -1,12 +1,10 @@ -package site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response; +package site.timecapsulearchive.core.domain.capsule.public_capsule.data.response; import io.swagger.v3.oas.annotations.media.Schema; import java.time.ZonedDateTime; import java.util.List; -import java.util.function.Function; import lombok.Builder; import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; -import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.PublicCapsuleDetailDto; import site.timecapsulearchive.core.global.common.response.ResponseMappingConstant; @Schema(description = "공개 캡슐 상세 정보") @@ -67,36 +65,8 @@ public record PublicCapsuleDetailResponse( dueDate = dueDate.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); } - createdDate.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); - } - - public static PublicCapsuleDetailResponse createOf( - final PublicCapsuleDetailDto detailDto, - final Function singlePreSignUrlFunction, - final Function> multiplePreSignUrlFunction - ) { - final List preSignedImageUrls = multiplePreSignUrlFunction.apply( - detailDto.images()); - final List preSignedVideoUrls = multiplePreSignUrlFunction.apply( - detailDto.videos()); - - return new PublicCapsuleDetailResponse( - detailDto.capsuleId(), - singlePreSignUrlFunction.apply(detailDto.capsuleSkinUrl()), - detailDto.dueDate(), - detailDto.nickname(), - detailDto.profileUrl(), - detailDto.createdAt(), - detailDto.point().getX(), - detailDto.point().getY(), - detailDto.address(), - detailDto.roadName(), - detailDto.title(), - detailDto.content(), - preSignedImageUrls, - preSignedVideoUrls, - detailDto.isOpened(), - detailDto.capsuleType() - ); + if (createdDate != null) { + createdDate = createdDate.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); + } } } \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/response/PublicCapsuleSliceResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/response/PublicCapsuleSliceResponse.java index e9ff12753..a610b9cfe 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/response/PublicCapsuleSliceResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/response/PublicCapsuleSliceResponse.java @@ -4,7 +4,6 @@ import java.util.List; import java.util.function.Function; import org.locationtech.jts.geom.Point; -import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response.PublicCapsuleDetailResponse; import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.PublicCapsuleDetailDto; @Schema(description = "공개 캡슐 슬라이싱") diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/MySecreteCapsuleDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/MySecreteCapsuleDto.java index 3f22e5503..9b3c37704 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/MySecreteCapsuleDto.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/MySecreteCapsuleDto.java @@ -16,14 +16,6 @@ public record MySecreteCapsuleDto( CapsuleType type ) { - public MySecreteCapsuleDto { - if (dueDate != null) { - dueDate = dueDate.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); - } - - createdAt = createdAt.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); - } - public MySecreteCapsuleResponse toResponse( final Function preSignUrlFunction ) { diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/MySecreteCapsuleResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/MySecreteCapsuleResponse.java index 66a287a09..15314fed7 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/MySecreteCapsuleResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/MySecreteCapsuleResponse.java @@ -4,6 +4,7 @@ import java.time.ZonedDateTime; import lombok.Builder; import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; +import site.timecapsulearchive.core.global.common.response.ResponseMappingConstant; @Builder @Schema(description = "내 비밀 캡슐 응답") @@ -30,4 +31,13 @@ public record MySecreteCapsuleResponse( CapsuleType type ) { + public MySecreteCapsuleResponse { + if (dueDate != null) { + dueDate = dueDate.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); + } + + if (createdAt != null) { + createdAt = createdAt.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); + } + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsuleskin/data/response/CapsuleSkinSummaryResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsuleskin/data/response/CapsuleSkinSummaryResponse.java index 2241b2397..35bef1e4b 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsuleskin/data/response/CapsuleSkinSummaryResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsuleskin/data/response/CapsuleSkinSummaryResponse.java @@ -3,6 +3,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import java.time.ZonedDateTime; import lombok.Builder; +import site.timecapsulearchive.core.global.common.response.ResponseMappingConstant; @Schema(description = "캡슐 스킨 요약 정보") @Builder @@ -20,4 +21,9 @@ public record CapsuleSkinSummaryResponse( ZonedDateTime createdAt ) { + public CapsuleSkinSummaryResponse { + if (createdAt != null) { + createdAt = createdAt.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); + } + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSummaryResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSummaryResponse.java index 04030ac7c..461266414 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSummaryResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSummaryResponse.java @@ -3,6 +3,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import java.time.ZonedDateTime; import lombok.Builder; +import site.timecapsulearchive.core.global.common.response.ResponseMappingConstant; @Builder @Schema(description = "친구 요약 정보") @@ -20,4 +21,9 @@ public record FriendSummaryResponse( ZonedDateTime createdAt ) { + public FriendSummaryResponse { + if (createdAt != null) { + createdAt = createdAt.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); + } + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupDetailResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupDetailResponse.java index 8a89bc2de..9d3c78244 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupDetailResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupDetailResponse.java @@ -28,7 +28,7 @@ public record GroupDetailResponse( public GroupDetailResponse { if (createdAt != null) { - createdAt.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); + createdAt = createdAt.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); } } } \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupSummaryResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupSummaryResponse.java index bf6783ddc..d43993dce 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupSummaryResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupSummaryResponse.java @@ -21,8 +21,10 @@ public record GroupSummaryResponse( @Schema(description = "그룹 설명") String description, + @Schema(description = "그룹 생성일") ZonedDateTime createdAt, + @Schema(description = "그룹장 여부") Boolean isOwner ) { diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/response/MemberNotificationResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/response/MemberNotificationResponse.java index 93287c46e..2197b6b78 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/response/MemberNotificationResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/response/MemberNotificationResponse.java @@ -1,17 +1,31 @@ package site.timecapsulearchive.core.domain.member.data.response; +import io.swagger.v3.oas.annotations.media.Schema; import java.time.ZonedDateTime; import lombok.Builder; import site.timecapsulearchive.core.domain.member.entity.CategoryName; import site.timecapsulearchive.core.domain.member.entity.NotificationStatus; +@Schema(description = "알림 정보") @Builder public record MemberNotificationResponse( + + @Schema(description = "알림 제목") String title, + + @Schema(description = "알림 내용") String text, + + @Schema(description = "알림 생성일") ZonedDateTime createdAt, + + @Schema(description = "알림 이미지 링크") String imageUrl, + + @Schema(description = "알림 카테고리 이름") CategoryName categoryName, + + @Schema(description = "알림 상태") NotificationStatus status ) { From b70183a1e7290954ebda357b2d1490142d61fda8 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Mon, 6 May 2024 12:08:28 +0900 Subject: [PATCH 09/13] =?UTF-8?q?fix=20:=20=EA=B7=B8=EB=A3=B9=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=EC=A1=B0=ED=9A=8C=20=EC=8B=9C=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/group/api/GroupApiController.java | 2 +- .../domain/group/service/GroupService.java | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApiController.java index fc64a407c..04177c228 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApiController.java @@ -84,7 +84,7 @@ public ResponseEntity> findGroupDetailById( @AuthenticationPrincipal final Long memberId, @PathVariable("group_id") final Long groupId ) { - GroupDetailDto groupDetailDto = groupService.findGroupDetailByGroupId(groupId); + GroupDetailDto groupDetailDto = groupService.findGroupDetailByGroupId(memberId, groupId); return ResponseEntity.ok( ApiSpec.success( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java index e39730b41..0b3c78ef2 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java @@ -22,6 +22,7 @@ import site.timecapsulearchive.core.domain.member.exception.MemberNotFoundException; import site.timecapsulearchive.core.domain.member.repository.MemberRepository; +@Transactional(readOnly = true) @Service @RequiredArgsConstructor public class GroupService { @@ -33,6 +34,7 @@ public class GroupService { private final GroupInviteMessageManager groupInviteMessageManager; private final GroupQueryRepository groupQueryRepository; + @Transactional public void createGroup(final Long memberId, final GroupCreateDto dto) { Member member = memberRepository.findMemberById(memberId) .orElseThrow(MemberNotFoundException::new); @@ -53,13 +55,11 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { groupInviteMessageManager.sendGroupInviteMessage(groupInviteMessageDto); } - @Transactional(readOnly = true) public Group findGroupById(Long groupId) { return groupRepository.findGroupById(groupId) .orElseThrow(GroupNotFoundException::new); } - @Transactional(readOnly = true) public Slice findGroupsSlice( final Long memberId, final int size, @@ -68,9 +68,18 @@ public Slice findGroupsSlice( return groupQueryRepository.findGroupsSlice(memberId, size, createdAt); } - @Transactional(readOnly = true) - public GroupDetailDto findGroupDetailByGroupId(final Long groupId) { - return groupQueryRepository.findGroupDetailByGroupId(groupId) + public GroupDetailDto findGroupDetailByGroupId(final Long memberId, final Long groupId) { + final GroupDetailDto groupDetailDto = groupQueryRepository.findGroupDetailByGroupId(groupId) .orElseThrow(GroupNotFoundException::new); + + final boolean isGroupMember = groupDetailDto.members() + .stream() + .anyMatch(m -> m.memberId().equals(memberId)); + + if (!isGroupMember) { + throw new GroupNotFoundException(); + } + + return groupDetailDto; } } From edf4be28d906ded4d7a2810809d294eecf9cfeb5 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Mon, 6 May 2024 12:30:22 +0900 Subject: [PATCH 10/13] =?UTF-8?q?fix=20:=20fixture=20=EC=B6=A9=EB=8F=8C=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/common/fixture/MemberFixture.java | 81 ------------------- .../common/fixture/MemberGroupFixture.java | 23 ------ .../fixture/{ => domain}/GroupFixture.java | 2 +- .../common/fixture/domain/MemberFixture.java | 38 +++++---- .../fixture/domain/MemberGroupFixture.java | 64 +++++++++++++++ .../GroupCapsuleQueryRepositoryTest.java | 4 +- .../MemberGroupQueryRepositoryTest.java | 6 +- 7 files changed, 88 insertions(+), 130 deletions(-) delete mode 100644 backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/MemberFixture.java delete mode 100644 backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/MemberGroupFixture.java rename backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/{ => domain}/GroupFixture.java (87%) create mode 100644 backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/domain/MemberGroupFixture.java diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/MemberFixture.java b/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/MemberFixture.java deleted file mode 100644 index 1b30b756e..000000000 --- a/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/MemberFixture.java +++ /dev/null @@ -1,81 +0,0 @@ -package site.timecapsulearchive.core.common.fixture; - -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.IntStream; -import site.timecapsulearchive.core.common.dependency.UnitTestDependency; -import site.timecapsulearchive.core.domain.member.entity.Member; -import site.timecapsulearchive.core.domain.member.entity.SocialType; -import site.timecapsulearchive.core.global.common.wrapper.ByteArrayWrapper; -import site.timecapsulearchive.core.global.security.encryption.HashEncryptionManager; - -public class MemberFixture { - - private static final HashEncryptionManager hashEncryptionManager = UnitTestDependency.hashEncryptionManager(); - - /** - * 테스트 픽스처 - 멤버 마다 상이한 값을 위한 dataPrefix를 주면 멤버를 생성한다. - *
주의 - 테스트에서 같은 prefix를 사용하면 오류가 발생하므로 서로 다른 prefix를 쓰도록 해야함. - * @param dataPrefix prefix - * @return {@code Member} 테스트 픽스처 - */ - public static Member member(int dataPrefix) { - Member member = Member.builder() - .socialType(SocialType.GOOGLE) - .nickname(dataPrefix + "testNickname") - .email(dataPrefix + "test@google.com") - .authId(dataPrefix + "test") - .profileUrl(dataPrefix + "test.com") - .tag(dataPrefix + "testTag") - .build(); - - byte[] number = getPhoneBytes(dataPrefix); - member.updatePhoneHash(hashEncryptionManager.encrypt(number)); - - return member; - } - - /** - * 테스트 픽스처 - 멤버마다 상이한 번호를 위해 dataPrefix를 주면 해당 dataPrefix에 대한 핸드폰 번호 바이트를 반환한다. - *
주의 - 테스트에서 같은 prefix를 사용하면 오류가 발생하므로 서로 다른 prefix를 쓰도록 해야함. - * @param dataPrefix prefix - * @return 핸드폰 번호 바이트 - */ - public static byte[] getPhoneBytes(int dataPrefix) { - return ("0" + (1000000000 + dataPrefix)).getBytes(StandardCharsets.UTF_8); - } - - public static List getPhones() { - return List.of( - new ByteArrayWrapper(MemberFixture.getPhoneBytes("01012341234")), - new ByteArrayWrapper(MemberFixture.getPhoneBytes("01012341235")), - new ByteArrayWrapper(MemberFixture.getPhoneBytes("01012341236")), - new ByteArrayWrapper(MemberFixture.getPhoneBytes("01012341237")), - new ByteArrayWrapper(MemberFixture.getPhoneBytes("01012341238")), - new ByteArrayWrapper(MemberFixture.getPhoneBytes("01012341239")), - new ByteArrayWrapper(MemberFixture.getPhoneBytes("01012341240")), - new ByteArrayWrapper(MemberFixture.getPhoneBytes("01012341241")) - ); - } - - private static byte[] getPhoneBytes(String phone) { - return hashEncryptionManager.encrypt(phone.getBytes(StandardCharsets.UTF_8)); - } - - /** - * 테스트 픽스처 - 크기와 멤버 마다 상이한 값을 위한 startDataPrefix를 주면 멤버들을 생성한다. - *
주의 - 테스트에서 같은 prefix를 사용하면 오류가 발생하므로 서로 다른 prefix를 쓰도록 해야함. - * @param size 생성할 멤버의 크기 - * @param startDataPrefix 시작 prefix - * @return {@code List} 테스트 픽스처들 - */ - public static List members(int size, int startDataPrefix) { - List result = new ArrayList<>(); - for (int i = 0; i < size; i++) { - result.add(member(startDataPrefix++)); - } - - return result; - } -} \ No newline at end of file diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/MemberGroupFixture.java b/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/MemberGroupFixture.java deleted file mode 100644 index bcdc1a507..000000000 --- a/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/MemberGroupFixture.java +++ /dev/null @@ -1,23 +0,0 @@ -package site.timecapsulearchive.core.common.fixture; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; -import site.timecapsulearchive.core.domain.group.entity.Group; -import site.timecapsulearchive.core.domain.group.entity.MemberGroup; -import site.timecapsulearchive.core.domain.member.entity.Member; - -public class MemberGroupFixture { - - /** - * 테스트 픽스처로 그룹장으로 그룹 멤버를 생성한다 - * - * @param member 그룹장이 될 멤버 - * @param group 대상 그룹 - * @return 그룹 멤버 테스트 픽스처 - */ - public static MemberGroup memberGroup(Member member, Group group) { - return MemberGroup.createGroupOwner(member, group); - } -} diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/GroupFixture.java b/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/domain/GroupFixture.java similarity index 87% rename from backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/GroupFixture.java rename to backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/domain/GroupFixture.java index e5ab923e5..615613e58 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/GroupFixture.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/domain/GroupFixture.java @@ -1,4 +1,4 @@ -package site.timecapsulearchive.core.common.fixture; +package site.timecapsulearchive.core.common.fixture.domain; import site.timecapsulearchive.core.domain.group.entity.Group; diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/domain/MemberFixture.java b/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/domain/MemberFixture.java index fff8d12ab..9126a5f9a 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/domain/MemberFixture.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/domain/MemberFixture.java @@ -15,12 +15,10 @@ public class MemberFixture { private static final HashEncryptionManager hashEncryptionManager = UnitTestDependency.hashEncryptionManager(); /** - * MemberdataPrefix 를 붙여서 만들어진 Member를 반환한다 - *

- * 주의 - 하나의 테스트에서 여러 개의 멤버를 생성한다면 서로 다른 dataPrefix 필요 - * - * @param dataPrefix 생성될 Member 에 붙일 prefix - * @return dataPrefix가 붙어서 생성된 Member + * 테스트 픽스처 - 멤버 마다 상이한 값을 위한 dataPrefix를 주면 멤버를 생성한다. + *
주의 - 테스트에서 같은 prefix를 사용하면 오류가 발생하므로 서로 다른 prefix를 쓰도록 해야함. + * @param dataPrefix prefix + * @return {@code Member} 테스트 픽스처 */ public static Member member(int dataPrefix) { byte[] number = getPhoneBytes(dataPrefix); @@ -38,6 +36,13 @@ public static Member member(int dataPrefix) { return member; } + /** + * 테스트 픽스처 - 멤버마다 상이한 번호를 위해 dataPrefix를 주면 해당 dataPrefix에 대한 핸드폰 번호 바이트를 반환한다. + *
주의 - 테스트에서 같은 prefix를 사용하면 오류가 발생하므로 서로 다른 prefix를 쓰도록 해야함. + * + * @param dataPrefix prefix + * @return 핸드폰 번호 바이트 + */ public static byte[] getPhoneBytes(int dataPrefix) { return ("0" + (1000000000 + dataPrefix)).getBytes(StandardCharsets.UTF_8); } @@ -48,23 +53,16 @@ public static List getPhones(int count) { .toList(); } - private static byte[] getPhoneBytes(String phone) { - return hashEncryptionManager.encrypt(phone.getBytes(StandardCharsets.UTF_8)); - } - /** - * Memberstartcount까지 - * 하나씩 증가된 것을 붙여서 만들어진 Member를 반환한다 - *

- * 주의 - 하나의 테스트에서 여러 개의 멤버를 생성한다면 서로 다른 dataPrefix 필요 - * - * @param start 시작할 prefix - * @param count 반환받을 Member 개수 - * @return start가 하나씩 증가되어 붙여서 만들어진 Member들 + * 테스트 픽스처 - 크기와 멤버 마다 상이한 값을 위한 startDataPrefix를 주면 멤버들을 생성한다. + *
주의 - 테스트에서 같은 prefix를 사용하면 오류가 발생하므로 서로 다른 prefix를 쓰도록 해야함. + * @param startDataPrefix 시작 prefix + * @param count 크기 + * @return {@code List} 테스트 픽스처들 */ - public static List members(int start, int count) { + public static List members(int startDataPrefix, int count) { List result = new ArrayList<>(); - for (int index = start; index < start + count; index++) { + for (int index = startDataPrefix; index < startDataPrefix + count; index++) { result.add(member(index)); } diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/domain/MemberGroupFixture.java b/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/domain/MemberGroupFixture.java new file mode 100644 index 000000000..90f02b793 --- /dev/null +++ b/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/domain/MemberGroupFixture.java @@ -0,0 +1,64 @@ +package site.timecapsulearchive.core.common.fixture.domain; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.List; +import site.timecapsulearchive.core.domain.group.entity.Group; +import site.timecapsulearchive.core.domain.group.entity.MemberGroup; +import site.timecapsulearchive.core.domain.member.entity.Member; + +public class MemberGroupFixture { + + /** + * 테스트 픽스처로 그룹장으로 그룹 멤버를 생성한다 + * + * @param member 그룹장이 될 멤버 + * @param group 대상 그룹 + * @return 그룹 멤버 테스트 픽스처 + */ + public static MemberGroup memberGroup(Member member, Group group) { + return MemberGroup.createGroupOwner(member, group); + } + + /** + * 테스트 픽스처 - 사용자, 그룹, 그룹장 여부를 받아 그룹원을 만들어준다. + * @param member 사용자 + * @param group 그룹 + * @param isOwner 그룹장 여부 + * @return MemberGroup 테스트 픽스처 + */ + public static MemberGroup memberGroup(Member member, Group group, Boolean isOwner) { + try { + Constructor declaredConstructor = MemberGroup.class.getDeclaredConstructor(); + declaredConstructor.setAccessible(true); + + MemberGroup memberGroup = declaredConstructor.newInstance(); + setFieldValue(memberGroup, "member", member); + setFieldValue(memberGroup, "group", group); + setFieldValue(memberGroup, "isOwner", isOwner); + + return memberGroup; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static void setFieldValue(Object instance, String fieldName, Object value) + throws NoSuchFieldException, IllegalAccessException { + Field field = instance.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(instance, value); + } + + /** + * 테스트 픽스처 - 그룹원들과 그룹을 주면 그룹원들 목록을 만들어준다(그룹장 X) + * @param members 그룹원들 목록 + * @param group 그룹 + * @return {@code List} 테스트 픽스처들 + */ + public static List membersGroup(List members, Group group) { + return members.stream() + .map(m -> memberGroup(m, group, Boolean.FALSE)) + .toList(); + } +} diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/capsule/group_capsule/repository/GroupCapsuleQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/capsule/group_capsule/repository/GroupCapsuleQueryRepositoryTest.java index de850c081..46beb15b1 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/capsule/group_capsule/repository/GroupCapsuleQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/capsule/group_capsule/repository/GroupCapsuleQueryRepositoryTest.java @@ -14,8 +14,8 @@ import org.springframework.test.context.TestConstructor.AutowireMode; import org.springframework.transaction.annotation.Transactional; import site.timecapsulearchive.core.common.RepositoryTest; -import site.timecapsulearchive.core.common.fixture.GroupFixture; -import site.timecapsulearchive.core.common.fixture.MemberGroupFixture; +import site.timecapsulearchive.core.common.fixture.domain.GroupFixture; +import site.timecapsulearchive.core.common.fixture.domain.MemberGroupFixture; import site.timecapsulearchive.core.common.fixture.domain.CapsuleFixture; import site.timecapsulearchive.core.common.fixture.domain.CapsuleSkinFixture; import site.timecapsulearchive.core.common.fixture.domain.MemberFixture; diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepositoryTest.java index 7d14d66db..6ad5192cc 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepositoryTest.java @@ -19,9 +19,9 @@ import org.springframework.test.context.TestConstructor.AutowireMode; import org.springframework.transaction.annotation.Transactional; import site.timecapsulearchive.core.common.RepositoryTest; -import site.timecapsulearchive.core.common.fixture.GroupFixture; -import site.timecapsulearchive.core.common.fixture.MemberFixture; -import site.timecapsulearchive.core.common.fixture.MemberGroupFixture; +import site.timecapsulearchive.core.common.fixture.domain.GroupFixture; +import site.timecapsulearchive.core.common.fixture.domain.MemberFixture; +import site.timecapsulearchive.core.common.fixture.domain.MemberGroupFixture; import site.timecapsulearchive.core.domain.group.data.dto.GroupDetailDto; import site.timecapsulearchive.core.domain.group.data.dto.GroupSummaryDto; import site.timecapsulearchive.core.domain.group.entity.Group; From 9d4a8ac66491a7b5adeb7d95410e3bb186cec73c Mon Sep 17 00:00:00 2001 From: hong seokho Date: Mon, 6 May 2024 12:31:08 +0900 Subject: [PATCH 11/13] =?UTF-8?q?fix=20:=20dto,=20response=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/group/data/dto/GroupDetailDto.java | 7 ++--- .../domain/group/data/dto/GroupMemberDto.java | 22 ++++++++++++++++ .../group/data/dto/GroupMemberSummaryDto.java | 17 ++++-------- .../data/response/GroupDetailResponse.java | 2 +- .../data/response/GroupMemberResponse.java | 26 +++++++++++++++++++ .../response/GroupMemberSummaryResponse.java | 18 ++++--------- .../repository/GroupQueryRepository.java | 4 +-- .../domain/group/service/GroupService.java | 8 +++--- 8 files changed, 68 insertions(+), 36 deletions(-) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupMemberDto.java create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupMemberResponse.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupDetailDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupDetailDto.java index fb4f0dea1..c45a8a46e 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupDetailDto.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupDetailDto.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.function.Function; import site.timecapsulearchive.core.domain.group.data.response.GroupDetailResponse; +import site.timecapsulearchive.core.domain.group.data.response.GroupMemberResponse; import site.timecapsulearchive.core.domain.group.data.response.GroupMemberSummaryResponse; public record GroupDetailDto( @@ -11,12 +12,12 @@ public record GroupDetailDto( String groupDescription, String groupProfileUrl, ZonedDateTime createdAt, - List members + List members ) { public GroupDetailResponse toResponse(Function singlePreSignUrlFunction) { - List members = this.members.stream() - .map(GroupMemberSummaryDto::toResponse) + List members = this.members.stream() + .map(GroupMemberDto::toResponse) .toList(); return GroupDetailResponse.builder() diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupMemberDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupMemberDto.java new file mode 100644 index 000000000..09a03c5e1 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupMemberDto.java @@ -0,0 +1,22 @@ +package site.timecapsulearchive.core.domain.group.data.dto; + +import site.timecapsulearchive.core.domain.group.data.response.GroupMemberResponse; + +public record GroupMemberDto( + Long memberId, + String profileUrl, + String nickname, + String tag, + Boolean isOwner +) { + + public GroupMemberResponse toResponse() { + return GroupMemberResponse.builder() + .memberId(memberId) + .profileUrl(profileUrl) + .nickname(nickname) + .tag(tag) + .isOwner(isOwner) + .build(); + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupMemberSummaryDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupMemberSummaryDto.java index b5e2e48f8..d4eb241fe 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupMemberSummaryDto.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/dto/GroupMemberSummaryDto.java @@ -3,20 +3,13 @@ import site.timecapsulearchive.core.domain.group.data.response.GroupMemberSummaryResponse; public record GroupMemberSummaryDto( - Long memberId, - String profileUrl, String nickname, - String tag, - Boolean isOwner + String profileUrl, + Boolean isOpened ) { public GroupMemberSummaryResponse toResponse() { - return GroupMemberSummaryResponse.builder() - .memberId(memberId) - .profileUrl(profileUrl) - .nickname(nickname) - .tag(tag) - .isOwner(isOwner) - .build(); + return new GroupMemberSummaryResponse(nickname, profileUrl, isOpened); } -} + +} \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupDetailResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupDetailResponse.java index 9d3c78244..98b21892d 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupDetailResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupDetailResponse.java @@ -23,7 +23,7 @@ public record GroupDetailResponse( ZonedDateTime createdAt, @Schema(description = "그룹원 리스트") - List members + List members ) { public GroupDetailResponse { diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupMemberResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupMemberResponse.java new file mode 100644 index 000000000..db025b957 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupMemberResponse.java @@ -0,0 +1,26 @@ +package site.timecapsulearchive.core.domain.group.data.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; + +@Builder +@Schema(description = "그룹원 정보") +public record GroupMemberResponse( + + @Schema(description = "그룹원 아이디") + Long memberId, + + @Schema(description = "그룹원 프로필 url") + String profileUrl, + + @Schema(description = "그룹원 닉네임") + String nickname, + + @Schema(description = "그룹원 태그") + String tag, + + @Schema(description = "그룹장 여부") + Boolean isOwner +) { + +} \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupMemberSummaryResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupMemberSummaryResponse.java index b1857b2c9..d780de6a5 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupMemberSummaryResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/data/response/GroupMemberSummaryResponse.java @@ -1,26 +1,18 @@ package site.timecapsulearchive.core.domain.group.data.response; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; -@Builder @Schema(description = "그룹원 요약 정보") public record GroupMemberSummaryResponse( - @Schema(description = "그룹원 아이디") - Long memberId, - - @Schema(description = "그룹원 프로필 url") - String profileUrl, - - @Schema(description = "그룹원 닉네임") + @Schema(description = "닉네임") String nickname, - @Schema(description = "그룹원 태그") - String tag, + @Schema(description = "프로필 url") + String profileUrl, - @Schema(description = "그룹장 여부") - Boolean isOwner + @Schema(description = "개봉 여부") + Boolean isOpened ) { } \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/GroupQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/GroupQueryRepository.java index 0d51f471c..360f907ba 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/GroupQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/GroupQueryRepository.java @@ -17,7 +17,7 @@ import org.springframework.data.domain.SliceImpl; import org.springframework.stereotype.Repository; import site.timecapsulearchive.core.domain.group.data.dto.GroupDetailDto; -import site.timecapsulearchive.core.domain.group.data.dto.GroupMemberSummaryDto; +import site.timecapsulearchive.core.domain.group.data.dto.GroupMemberDto; import site.timecapsulearchive.core.domain.group.data.dto.GroupSummaryDto; @Repository @@ -85,7 +85,7 @@ public Optional findGroupDetailByGroupId(final Long groupId) { group.createdAt, list( Projections.constructor( - GroupMemberSummaryDto.class, + GroupMemberDto.class, member.id, member.profileUrl, member.nickname, diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java index 12f76cdca..98b3b1603 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/service/GroupService.java @@ -11,7 +11,6 @@ import org.springframework.transaction.support.TransactionTemplate; import site.timecapsulearchive.core.domain.group.data.dto.GroupCreateDto; import site.timecapsulearchive.core.domain.group.data.dto.GroupDetailDto; -import site.timecapsulearchive.core.domain.group.data.dto.GroupInviteMessageDto; import site.timecapsulearchive.core.domain.group.data.dto.GroupSummaryDto; import site.timecapsulearchive.core.domain.group.entity.Group; import site.timecapsulearchive.core.domain.group.entity.MemberGroup; @@ -24,7 +23,6 @@ import site.timecapsulearchive.core.domain.member.repository.MemberRepository; import site.timecapsulearchive.core.infra.queue.manager.SocialNotificationManager; -@Transactional(readOnly = true) @Service @RequiredArgsConstructor public class GroupService { @@ -34,11 +32,8 @@ public class GroupService { private final MemberGroupRepository memberGroupRepository; private final TransactionTemplate transactionTemplate; private final SocialNotificationManager socialNotificationManager; - - private final GroupInviteMessageManager groupInviteMessageManager; private final GroupQueryRepository groupQueryRepository; - @Transactional public void createGroup(final Long memberId, final GroupCreateDto dto) { final Member member = memberRepository.findMemberById(memberId) .orElseThrow(MemberNotFoundException::new); @@ -59,11 +54,13 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { dto.groupProfileUrl(), dto.targetIds()); } + @Transactional(readOnly = true) public Group findGroupById(Long groupId) { return groupRepository.findGroupById(groupId) .orElseThrow(GroupNotFoundException::new); } + @Transactional(readOnly = true) public Slice findGroupsSlice( final Long memberId, final int size, @@ -72,6 +69,7 @@ public Slice findGroupsSlice( return groupQueryRepository.findGroupsSlice(memberId, size, createdAt); } + @Transactional(readOnly = true) public GroupDetailDto findGroupDetailByGroupId(final Long memberId, final Long groupId) { final GroupDetailDto groupDetailDto = groupQueryRepository.findGroupDetailByGroupId(groupId) .orElseThrow(GroupNotFoundException::new); From b0c84998f4feb18a967721d883d680a268b75256 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Mon, 6 May 2024 12:38:41 +0900 Subject: [PATCH 12/13] =?UTF-8?q?fix=20:=20final=20=EB=88=84=EB=9D=BD=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/group/api/GroupApiController.java | 4 ++-- .../core/domain/group/repository/GroupQueryRepository.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApiController.java index 04177c228..e8a067e35 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/api/GroupApiController.java @@ -84,7 +84,7 @@ public ResponseEntity> findGroupDetailById( @AuthenticationPrincipal final Long memberId, @PathVariable("group_id") final Long groupId ) { - GroupDetailDto groupDetailDto = groupService.findGroupDetailByGroupId(memberId, groupId); + final GroupDetailDto groupDetailDto = groupService.findGroupDetailByGroupId(memberId, groupId); return ResponseEntity.ok( ApiSpec.success( @@ -103,7 +103,7 @@ public ResponseEntity> findGroups( @RequestParam(defaultValue = "20", value = "size") final int size, @RequestParam(value = "created_at") final ZonedDateTime createdAt ) { - Slice groupsSlice = groupService.findGroupsSlice(memberId, size, + final Slice groupsSlice = groupService.findGroupsSlice(memberId, size, createdAt); return ResponseEntity.ok( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/GroupQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/GroupQueryRepository.java index 360f907ba..488c3212f 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/GroupQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/group/repository/GroupQueryRepository.java @@ -31,7 +31,7 @@ public Slice findGroupsSlice( final int size, final ZonedDateTime createdAt ) { - List groups = jpaQueryFactory + final List groups = jpaQueryFactory .select( Projections.constructor( GroupSummaryDto.class, @@ -49,7 +49,7 @@ public Slice findGroupsSlice( .limit(size + 1) .fetch(); - boolean hasNext = groups.size() > size; + final boolean hasNext = groups.size() > size; if (hasNext) { groups.remove(size); } From 8450687d8b660d8eeaa871b43d662d776e768644 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Mon, 6 May 2024 18:06:20 +0900 Subject: [PATCH 13/13] =?UTF-8?q?fix=20:=20=EB=B3=80=EC=88=98=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../group/repository/MemberGroupQueryRepositoryTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepositoryTest.java index 6ad5192cc..66ff5a86f 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/group/repository/MemberGroupQueryRepositoryTest.java @@ -52,9 +52,9 @@ void setup(@Autowired EntityManager entityManager) { memberId = member.getId(); //그룹이 없는 사용자 - Member memberWithNoGroup = MemberFixture.member(1); - entityManager.persist(memberWithNoGroup); - memberIdWithNoGroup = memberWithNoGroup.getId(); + Member memberNotInGroup = MemberFixture.member(1); + entityManager.persist(memberNotInGroup); + memberIdWithNoGroup = memberNotInGroup.getId(); //그룹 List groups = new ArrayList<>();