diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/api/GroupCapsuleApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/api/GroupCapsuleApiController.java index 824421e0b..63f19c19a 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/api/GroupCapsuleApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/api/GroupCapsuleApiController.java @@ -13,10 +13,10 @@ 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.capsule.data.dto.CapsuleBasicInfoDto; import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.GroupCapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.GroupCapsuleOpenStateDto; import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.GroupCapsuleSummaryDto; +import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.MyGroupCapsuleDto; import site.timecapsulearchive.core.domain.capsule.group_capsule.data.reqeust.GroupCapsuleCreateRequest; import site.timecapsulearchive.core.domain.capsule.group_capsule.data.reqeust.GroupCapsuleUpdateRequest; import site.timecapsulearchive.core.domain.capsule.group_capsule.data.response.GroupCapsuleDetailResponse; @@ -121,7 +121,7 @@ public ResponseEntity> getMyGroupCapsules( @RequestParam(defaultValue = "20", value = "size") final int size, @RequestParam(value = "created_at") final ZonedDateTime createdAt ) { - final Slice groupCapsules = groupCapsuleService.findMyGroupCapsuleSlice( + final Slice groupCapsules = groupCapsuleService.findMyGroupCapsuleSlice( memberId, size, createdAt diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/data/dto/CapsuleBasicInfoDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/dto/MyGroupCapsuleDto.java similarity index 68% rename from backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/data/dto/CapsuleBasicInfoDto.java rename to backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/dto/MyGroupCapsuleDto.java index fffbe3fe2..e2adb4825 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/data/dto/CapsuleBasicInfoDto.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/dto/MyGroupCapsuleDto.java @@ -1,11 +1,11 @@ -package site.timecapsulearchive.core.domain.capsule.data.dto; +package site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto; import java.time.ZonedDateTime; import java.util.function.Function; -import site.timecapsulearchive.core.domain.capsule.data.response.CapsuleBasicInfoResponse; import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; +import site.timecapsulearchive.core.domain.capsule.group_capsule.data.response.MyGroupCapsuleResponse; -public record CapsuleBasicInfoDto( +public record MyGroupCapsuleDto( Long capsuleId, String skinUrl, ZonedDateTime dueDate, @@ -15,9 +15,9 @@ public record CapsuleBasicInfoDto( CapsuleType capsuleType ) { - public CapsuleBasicInfoResponse toResponse( + public MyGroupCapsuleResponse toResponse( final Function singlePreSignUrlFunction) { - return CapsuleBasicInfoResponse.builder() + return MyGroupCapsuleResponse.builder() .capsuleId(capsuleId) .skinUrl(singlePreSignUrlFunction.apply(skinUrl)) .dueDate(dueDate) @@ -27,4 +27,4 @@ public CapsuleBasicInfoResponse toResponse( .capsuleType(capsuleType) .build(); } -} \ No newline at end of file +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/data/response/CapsuleBasicInfoResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/response/MyGroupCapsuleResponse.java similarity index 82% rename from backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/data/response/CapsuleBasicInfoResponse.java rename to backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/response/MyGroupCapsuleResponse.java index 883e1c4e9..256d80354 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/data/response/CapsuleBasicInfoResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/response/MyGroupCapsuleResponse.java @@ -1,4 +1,4 @@ -package site.timecapsulearchive.core.domain.capsule.data.response; +package site.timecapsulearchive.core.domain.capsule.group_capsule.data.response; import io.swagger.v3.oas.annotations.media.Schema; import java.time.ZonedDateTime; @@ -7,8 +7,8 @@ import site.timecapsulearchive.core.global.common.response.ResponseMappingConstant; @Builder -@Schema(description = "캡슐 기본 정보") -public record CapsuleBasicInfoResponse( +@Schema(description = "사용자가 만든 그룹 캡슐") +public record MyGroupCapsuleResponse( @Schema(description = "캡슐 아이디") Long capsuleId, @@ -32,7 +32,7 @@ public record CapsuleBasicInfoResponse( CapsuleType capsuleType ) { - public CapsuleBasicInfoResponse { + public MyGroupCapsuleResponse { if (dueDate != null) { dueDate = dueDate.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); } @@ -41,4 +41,4 @@ public record CapsuleBasicInfoResponse( createdAt = createdAt.withZoneSameInstant(ResponseMappingConstant.ZONE_ID); } } -} \ No newline at end of file +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/response/MyGroupCapsuleSliceResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/response/MyGroupCapsuleSliceResponse.java index 41aefd50d..dba16b276 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/response/MyGroupCapsuleSliceResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/response/MyGroupCapsuleSliceResponse.java @@ -2,20 +2,19 @@ import java.util.List; import java.util.function.Function; -import site.timecapsulearchive.core.domain.capsule.data.dto.CapsuleBasicInfoDto; -import site.timecapsulearchive.core.domain.capsule.data.response.CapsuleBasicInfoResponse; +import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.MyGroupCapsuleDto; public record MyGroupCapsuleSliceResponse( - List groupCapsules, + List groupCapsules, Boolean hasNext ) { public static MyGroupCapsuleSliceResponse createOf( - final List groupCapsules, + final List groupCapsules, final boolean hasNext, final Function singlePreSignUrlFunction ) { - List groupCapsuleResponses = groupCapsules.stream() + List groupCapsuleResponses = groupCapsules.stream() .map(capsule -> capsule.toResponse(singlePreSignUrlFunction)) .toList(); diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/repository/GroupCapsuleQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/repository/GroupCapsuleQueryRepository.java index 90c01c9d7..3efe95754 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/repository/GroupCapsuleQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/repository/GroupCapsuleQueryRepository.java @@ -17,17 +17,18 @@ 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.capsule.data.dto.CapsuleBasicInfoDto; import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.GroupCapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.GroupCapsuleSummaryDto; +import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.MyGroupCapsuleDto; import site.timecapsulearchive.core.domain.group.data.dto.GroupMemberSummaryDto; import site.timecapsulearchive.core.domain.member.entity.QMember; -import site.timecapsulearchive.core.global.util.SliceUtil; @Repository @RequiredArgsConstructor @@ -130,15 +131,15 @@ public Optional findGroupCapsuleSummaryDtoByCapsuleId( ).get(capsuleId)); } - public Slice findMyGroupCapsuleSlice( + public Slice findMyGroupCapsuleSlice( final Long memberId, final int size, final ZonedDateTime createdAt ) { - final List groupCapsules = jpaQueryFactory + final List groupCapsules = jpaQueryFactory .select( Projections.constructor( - CapsuleBasicInfoDto.class, + MyGroupCapsuleDto.class, capsule.id, capsuleSkin.imageUrl, capsule.dueDate, @@ -158,7 +159,12 @@ public Slice findMyGroupCapsuleSlice( .limit(size + 1) .fetch(); - return SliceUtil.makeSlice(size, groupCapsules); + final boolean hasNext = groupCapsules.size() > size; + if (hasNext) { + groupCapsules.remove(size); + } + + return new SliceImpl<>(groupCapsules, Pageable.ofSize(size), hasNext); } public boolean findGroupCapsuleExistByGroupId(Long groupId) { diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/service/GroupCapsuleService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/service/GroupCapsuleService.java index 396e808a3..d7123fe1c 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/service/GroupCapsuleService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/service/GroupCapsuleService.java @@ -7,7 +7,6 @@ import org.springframework.data.domain.Slice; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import site.timecapsulearchive.core.domain.capsule.data.dto.CapsuleBasicInfoDto; import site.timecapsulearchive.core.domain.capsule.entity.Capsule; import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; import site.timecapsulearchive.core.domain.capsule.exception.CapsuleNotFondException; @@ -15,6 +14,7 @@ import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.GroupCapsuleCreateRequestDto; import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.GroupCapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.GroupCapsuleSummaryDto; +import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.MyGroupCapsuleDto; import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.GroupCapsuleOpenStateDto; import site.timecapsulearchive.core.domain.capsule.group_capsule.repository.GroupCapsuleQueryRepository; import site.timecapsulearchive.core.domain.capsuleskin.entity.CapsuleSkin; @@ -82,7 +82,7 @@ public GroupCapsuleSummaryDto findGroupCapsuleSummaryByGroupIDAndCapsuleId( * @param createdAt 조회를 시작할 캡슐의 생성 시간, 첫 조회라면 현재 시간, 이후 조회라면 맨 마지막 데이터의 시간 * @return 사용자가 생성한 그룹 캡슐 목록 */ - public Slice findMyGroupCapsuleSlice( + public Slice findMyGroupCapsuleSlice( final Long memberId, final int size, final ZonedDateTime createdAt diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApiController.java index 97cd4d050..7b3e7665e 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApiController.java @@ -14,7 +14,6 @@ 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.capsule.data.dto.CapsuleBasicInfoDto; import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; @@ -22,6 +21,7 @@ import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response.CapsuleDetailResponse; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response.CapsuleSummaryResponse; import site.timecapsulearchive.core.domain.capsule.generic_capsule.facade.CapsuleFacade; +import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.MyPublicCapsuleDto; import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.MyPublicCapsuleSliceResponse; import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.PublicCapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.public_capsule.data.reqeust.PublicCapsuleUpdateRequest; @@ -137,7 +137,7 @@ public ResponseEntity> getMyPublicCapsules @RequestParam(defaultValue = "20", value = "size") final int size, @RequestParam(value = "created_at") final ZonedDateTime createdAt ) { - final Slice publicCapsules = publicCapsuleService.findMyPublicCapsuleSlice( + final Slice publicCapsules = publicCapsuleService.findMyPublicCapsuleSlice( memberId, size, createdAt); return ResponseEntity.ok( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/dto/MyPublicCapsuleDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/dto/MyPublicCapsuleDto.java new file mode 100644 index 000000000..8fe22bbc9 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/dto/MyPublicCapsuleDto.java @@ -0,0 +1,30 @@ +package site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto; + +import java.time.ZonedDateTime; +import java.util.function.Function; +import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; +import site.timecapsulearchive.core.domain.capsule.public_capsule.data.response.MyPublicCapsuleResponse; + +public record MyPublicCapsuleDto( + Long capsuleId, + String skinUrl, + ZonedDateTime dueDate, + ZonedDateTime createdAt, + String title, + Boolean isOpened, + CapsuleType capsuleType +) { + + public MyPublicCapsuleResponse toResponse( + final Function singlePreSignUrlFunction) { + return MyPublicCapsuleResponse.builder() + .capsuleId(capsuleId) + .skinUrl(singlePreSignUrlFunction.apply(skinUrl)) + .dueDate(dueDate) + .createdAt(createdAt) + .title(title) + .isOpened(isOpened) + .capsuleType(capsuleType) + .build(); + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/dto/MyPublicCapsuleSliceResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/dto/MyPublicCapsuleSliceResponse.java index a05510495..a74bd4939 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/dto/MyPublicCapsuleSliceResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/dto/MyPublicCapsuleSliceResponse.java @@ -3,25 +3,24 @@ import io.swagger.v3.oas.annotations.media.Schema; import java.util.List; import java.util.function.Function; -import site.timecapsulearchive.core.domain.capsule.data.dto.CapsuleBasicInfoDto; -import site.timecapsulearchive.core.domain.capsule.data.response.CapsuleBasicInfoResponse; +import site.timecapsulearchive.core.domain.capsule.public_capsule.data.response.MyPublicCapsuleResponse; @Schema(description = "사용자가 만든 공개 캡슐 슬라이싱") public record MyPublicCapsuleSliceResponse( @Schema(description = "사용자가 만든 공개 캡슐 정보") - List publicCapsules, + List publicCapsules, @Schema(description = "다음 페이지 유무") Boolean hasNext ) { public static MyPublicCapsuleSliceResponse createOf( - final List publicCapsules, + final List publicCapsules, final boolean hasNext, final Function singlePreSignUrlFunction ) { - List publicCapsuleResponses = publicCapsules.stream() + List publicCapsuleResponses = publicCapsules.stream() .map(capsule -> capsule.toResponse(singlePreSignUrlFunction)) .toList(); diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/response/MyPublicCapsuleResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/response/MyPublicCapsuleResponse.java new file mode 100644 index 000000000..3dea37611 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/response/MyPublicCapsuleResponse.java @@ -0,0 +1,44 @@ +package site.timecapsulearchive.core.domain.capsule.public_capsule.data.response; + +import io.swagger.v3.oas.annotations.media.Schema; +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 = "사용자가 만든 공개 캡슐") +public record MyPublicCapsuleResponse( + + @Schema(description = "캡슐 아이디") + Long capsuleId, + + @Schema(description = "스킨 url") + String skinUrl, + + @Schema(description = "개봉일") + ZonedDateTime dueDate, + + @Schema(description = "생성일") + ZonedDateTime createdAt, + + @Schema(description = "제목") + String title, + + @Schema(description = "캡슐 개봉 여부") + Boolean isOpened, + + @Schema(description = "캡슐 타입") + CapsuleType capsuleType +) { + + public MyPublicCapsuleResponse { + 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/capsule/public_capsule/repository/PublicCapsuleQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/repository/PublicCapsuleQueryRepository.java index b9aa3f28b..980a5caac 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/repository/PublicCapsuleQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/repository/PublicCapsuleQueryRepository.java @@ -19,12 +19,11 @@ import org.springframework.data.domain.Slice; import org.springframework.data.domain.SliceImpl; import org.springframework.stereotype.Repository; -import site.timecapsulearchive.core.domain.capsule.data.dto.CapsuleBasicInfoDto; import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; +import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.MyPublicCapsuleDto; import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.PublicCapsuleDetailDto; -import site.timecapsulearchive.core.global.util.SliceUtil; @Repository @RequiredArgsConstructor @@ -159,22 +158,28 @@ public Slice findPublicCapsulesDtoMadeByFriend( .limit(size + 1) .fetch(); - return SliceUtil.makeSlice(size, publicCapsuleDetailDtos); + final boolean hasNext = canMoreRead(size, publicCapsuleDetailDtos.size()); + if (hasNext) { + publicCapsuleDetailDtos.remove(size); + } + + return new SliceImpl<>(publicCapsuleDetailDtos, Pageable.ofSize(size), hasNext); + } private boolean canMoreRead(final int size, final int capsuleSize) { return capsuleSize > size; } - public Slice findMyPublicCapsuleSlice( + public Slice findMyPublicCapsuleSlice( final Long memberId, final int size, final ZonedDateTime createdAt ) { - final List publicCapsules = jpaQueryFactory + final List publicCapsules = jpaQueryFactory .select( Projections.constructor( - CapsuleBasicInfoDto.class, + MyPublicCapsuleDto.class, capsule.id, capsuleSkin.imageUrl, capsule.dueDate, @@ -194,6 +199,11 @@ public Slice findMyPublicCapsuleSlice( .limit(size + 1) .fetch(); - return SliceUtil.makeSlice(size, publicCapsules); + final boolean hasNext = publicCapsules.size() > size; + if (hasNext) { + publicCapsules.remove(size); + } + + return new SliceImpl<>(publicCapsules, Pageable.ofSize(size), hasNext); } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/service/PublicCapsuleService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/service/PublicCapsuleService.java index 75293a823..e58b91da6 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/service/PublicCapsuleService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/service/PublicCapsuleService.java @@ -6,10 +6,10 @@ import org.springframework.data.domain.Slice; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import site.timecapsulearchive.core.domain.capsule.data.dto.CapsuleBasicInfoDto; import site.timecapsulearchive.core.domain.capsule.exception.CapsuleNotFondException; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; +import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.MyPublicCapsuleDto; import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.PublicCapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.public_capsule.repository.PublicCapsuleQueryRepository; @@ -70,7 +70,7 @@ public Slice findPublicCapsulesMadeByFriend( * @param createdAt 조회를 시작할 캡슐의 생성 시간, 첫 조회라면 현재 시간, 이후 조회라면 맨 마지막 데이터의 시간 * @return 사용자가 생성한 공개 캡슐 목록 */ - public Slice findMyPublicCapsuleSlice( + public Slice findMyPublicCapsuleSlice( final Long memberId, final int size, final ZonedDateTime createdAt diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java index 5ea1bddb2..15458cde6 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java @@ -15,7 +15,6 @@ 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.capsule.data.dto.CapsuleBasicInfoDto; import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; @@ -23,6 +22,7 @@ import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response.CapsuleDetailResponse; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response.CapsuleSummaryResponse; import site.timecapsulearchive.core.domain.capsule.generic_capsule.facade.CapsuleFacade; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.MySecreteCapsuleDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.SecretCapsuleUpdateRequest; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.service.SecretCapsuleService; @@ -64,7 +64,7 @@ public ResponseEntity> getMySecretCapsules @RequestParam(defaultValue = "20", value = "size") final int size, @RequestParam(defaultValue = "0", value = "created_at") final ZonedDateTime createdAt ) { - final Slice dtos = secretCapsuleService.findSecretCapsuleSliceByMemberId( + final Slice dtos = secretCapsuleService.findSecretCapsuleSliceByMemberId( memberId, size, createdAt); return ResponseEntity.ok( 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 new file mode 100644 index 000000000..19d661802 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/MySecreteCapsuleDto.java @@ -0,0 +1,32 @@ +package site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto; + +import java.time.ZonedDateTime; +import java.util.function.Function; +import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecreteCapsuleResponse; + +public record MySecreteCapsuleDto( + Long capsuleId, + String skinUrl, + ZonedDateTime dueDate, + ZonedDateTime createdAt, + String title, + Boolean isOpened, + CapsuleType type +) { + + public MySecreteCapsuleResponse toResponse( + final Function preSignUrlFunction + ) { + return MySecreteCapsuleResponse.builder() + .capsuleId(capsuleId) + .SkinUrl(preSignUrlFunction.apply(skinUrl)) + .dueDate(dueDate) + .createdAt(createdAt) + .title(title) + .isOpened(isOpened) + .type(type) + .build(); + } + +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/MySecretCapsuleSliceResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/MySecretCapsuleSliceResponse.java index 15e626d9d..f2ecc413d 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/MySecretCapsuleSliceResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/MySecretCapsuleSliceResponse.java @@ -4,24 +4,23 @@ import java.util.List; import java.util.function.Function; import org.springframework.data.domain.Slice; -import site.timecapsulearchive.core.domain.capsule.data.dto.CapsuleBasicInfoDto; -import site.timecapsulearchive.core.domain.capsule.data.response.CapsuleBasicInfoResponse; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.MySecreteCapsuleDto; @Schema(description = "내가 생성한 비밀 캡슐 목록 응답") public record MySecretCapsuleSliceResponse( @Schema(description = "내 비밀 캡슐 리스트") - List capsules, + List capsules, @Schema(description = "다음 페이지 유무") Boolean hasNext ) { public static MySecretCapsuleSliceResponse createOf( - final Slice dtos, + final Slice dtos, final Function preSignUrlFunction ) { - final List capsules = dtos.getContent(). + final List capsules = dtos.getContent(). stream() .map(dto -> dto.toResponse(preSignUrlFunction)) .toList(); 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 new file mode 100644 index 000000000..15314fed7 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/MySecreteCapsuleResponse.java @@ -0,0 +1,43 @@ +package site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response; + +import io.swagger.v3.oas.annotations.media.Schema; +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 = "내 비밀 캡슐 응답") +public record MySecreteCapsuleResponse( + @Schema(description = "비밀 캡슐 아이디") + Long capsuleId, + + @Schema(description = "캡슐 스킨 url") + String SkinUrl, + + @Schema(description = "내 비밀 캡슐 만료일") + ZonedDateTime dueDate, + + @Schema(description = "내 비밀 캡슐 생성일") + ZonedDateTime createdAt, + + @Schema(description = "내 비밀 캡슐 제목") + String title, + + @Schema(description = "내 비밀 캡슐 오픈 여부") + Boolean isOpened, + + @Schema(description = "내 비밀 캡슐 타입") + 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/capsule/secret_capsule/repository/SecretCapsuleQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/repository/SecretCapsuleQueryRepository.java index fff856330..99490a193 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/repository/SecretCapsuleQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/repository/SecretCapsuleQueryRepository.java @@ -14,13 +14,14 @@ 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.capsule.data.dto.CapsuleBasicInfoDto; import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; -import site.timecapsulearchive.core.global.util.SliceUtil; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.MySecreteCapsuleDto; @Repository @RequiredArgsConstructor @@ -103,15 +104,32 @@ private StringExpression groupConcatDistinct(final StringExpression expression) return Expressions.stringTemplate("GROUP_CONCAT(DISTINCT {0})", expression); } - public Slice findSecretCapsuleSliceByMemberIdAndCreatedAt( + public Slice findSecretCapsuleSliceByMemberIdAndCreatedAt( final Long memberId, final int size, final ZonedDateTime createdAt ) { - final List mySecretCapsules = jpaQueryFactory + final List mySecretCapsules = findMySecretCapsuleDtosByMemberIdAndCreatedAt( + memberId, size, createdAt + ); + + final boolean hasNext = canMoreRead(size, mySecretCapsules.size()); + if (hasNext) { + mySecretCapsules.remove(size); + } + + return new SliceImpl<>(mySecretCapsules, Pageable.ofSize(size), hasNext); + } + + private List findMySecretCapsuleDtosByMemberIdAndCreatedAt( + final Long memberId, + final int size, + final ZonedDateTime createdAt + ) { + return jpaQueryFactory .select( Projections.constructor( - CapsuleBasicInfoDto.class, + MySecreteCapsuleDto.class, capsule.id, capsuleSkin.imageUrl, capsule.dueDate, @@ -131,7 +149,9 @@ public Slice findSecretCapsuleSliceByMemberIdAndCreatedAt( .orderBy(capsule.id.desc()) .limit(size + 1) .fetch(); + } - return SliceUtil.makeSlice(size, mySecretCapsules); + private boolean canMoreRead(final int size, final int capsuleSize) { + return capsuleSize > size; } } \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/service/SecretCapsuleService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/service/SecretCapsuleService.java index 62e5acd51..87182171f 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/service/SecretCapsuleService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/service/SecretCapsuleService.java @@ -6,10 +6,10 @@ import org.springframework.data.domain.Slice; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import site.timecapsulearchive.core.domain.capsule.data.dto.CapsuleBasicInfoDto; import site.timecapsulearchive.core.domain.capsule.exception.CapsuleNotFondException; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.MySecreteCapsuleDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.repository.SecretCapsuleQueryRepository; @Service @@ -27,7 +27,7 @@ public class SecretCapsuleService { * @param createdAt 마지막 캡슐 생성 날짜 * @return 내 페이지에서 비밀 캡슐을 조회한다. */ - public Slice findSecretCapsuleSliceByMemberId( + public Slice findSecretCapsuleSliceByMemberId( final Long memberId, final int size, final ZonedDateTime createdAt 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 e74d162de..47f1036fa 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 @@ -22,7 +22,6 @@ 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.capsule.data.dto.CapsuleBasicInfoDto; import site.timecapsulearchive.core.domain.capsule.entity.Capsule; import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; import site.timecapsulearchive.core.domain.capsule.entity.GroupCapsuleOpen; @@ -30,6 +29,7 @@ import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.GroupCapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.GroupCapsuleSummaryDto; +import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.MyGroupCapsuleDto; import site.timecapsulearchive.core.domain.capsuleskin.entity.CapsuleSkin; import site.timecapsulearchive.core.domain.group.data.dto.GroupMemberSummaryDto; import site.timecapsulearchive.core.domain.group.entity.Group; @@ -187,14 +187,15 @@ void setup(@Autowired EntityManager entityManager) { ZonedDateTime now = ZonedDateTime.now().plusDays(1); //when - Slice groupCapsules = groupCapsuleQueryRepository.findMyGroupCapsuleSlice( + Slice groupCapsules = groupCapsuleQueryRepository.findMyGroupCapsuleSlice( groupLeaderId, size, now); //then SoftAssertions.assertSoftly(softly -> { assertThat(groupCapsules.hasContent()).isTrue(); - assertThat(groupCapsules).allMatch(c-> c.capsuleType().equals(CapsuleType.GROUP)); - assertThat(groupCapsules).allMatch(c -> c.createdAt().isBefore(now)); + assertThat(groupCapsules).allMatch( + capsule -> capsule.capsuleType().equals(CapsuleType.GROUP)); + assertThat(groupCapsules).allMatch(capsule -> capsule.createdAt().isBefore(now)); }); } } \ No newline at end of file diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/capsule/public_capsule/repository/PublicCapsuleQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/capsule/public_capsule/repository/PublicCapsuleQueryRepositoryTest.java index bdab3a023..3181f65e8 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/capsule/public_capsule/repository/PublicCapsuleQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/capsule/public_capsule/repository/PublicCapsuleQueryRepositoryTest.java @@ -19,11 +19,11 @@ import site.timecapsulearchive.core.common.fixture.domain.CapsuleSkinFixture; import site.timecapsulearchive.core.common.fixture.domain.MemberFixture; import site.timecapsulearchive.core.common.fixture.domain.MemberFriendFixture; -import site.timecapsulearchive.core.domain.capsule.data.dto.CapsuleBasicInfoDto; import site.timecapsulearchive.core.domain.capsule.entity.Capsule; import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; +import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.MyPublicCapsuleDto; import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.PublicCapsuleDetailDto; import site.timecapsulearchive.core.domain.capsuleskin.entity.CapsuleSkin; import site.timecapsulearchive.core.domain.friend.entity.MemberFriend; @@ -193,7 +193,7 @@ void setup(@Autowired EntityManager entityManager) { ZonedDateTime now = ZonedDateTime.now().plusDays(1); //when - Slice publicCapsules = publicCapsuleQueryRepository.findMyPublicCapsuleSlice( + Slice publicCapsules = publicCapsuleQueryRepository.findMyPublicCapsuleSlice( memberId, size, now); //then