diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/entity/Capsule.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/entity/Capsule.java index 7c11fdcd7..bb55358ec 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/entity/Capsule.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/entity/Capsule.java @@ -119,12 +119,8 @@ public void open() { this.isOpened = Boolean.TRUE; } - public boolean isTimeCapsule() { - return dueDate != null; - } - - public boolean canOpen() { - return dueDate == null || dueDate.isBefore(ZonedDateTimeSupplier.utc().get()); + public boolean isNotTimeCapsule() { + return dueDate == null; } public boolean isAllGroupMemberOpened(Long memberId, Long capsuleId) { @@ -132,13 +128,15 @@ public boolean isAllGroupMemberOpened(Long memberId, Long capsuleId) { throw new GroupCapsuleOpenNotFoundException(); } - return groupCapsuleOpens.stream() - .allMatch(groupCapsuleOpen -> { - if (groupCapsuleOpen.matched(capsuleId, memberId)) { - groupCapsuleOpen.open(); - } + boolean isCapsuleOpened = true; + for (GroupCapsuleOpen groupCapsuleOpen : groupCapsuleOpens) { + if (groupCapsuleOpen.matched(capsuleId, memberId)) { + groupCapsuleOpen.open(); + } + + isCapsuleOpened = isCapsuleOpened && groupCapsuleOpen.getIsOpened(); + } - return groupCapsuleOpen.getIsOpened(); - }); + return isCapsuleOpened; } } \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/entity/GroupCapsuleOpen.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/entity/GroupCapsuleOpen.java index 809d9dc64..1364a6fc8 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/entity/GroupCapsuleOpen.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/entity/GroupCapsuleOpen.java @@ -9,11 +9,10 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; -import java.util.Objects; import lombok.AccessLevel; -import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import site.timecapsulearchive.core.domain.group.entity.Group; import site.timecapsulearchive.core.domain.member.entity.Member; import site.timecapsulearchive.core.global.entity.BaseEntity; @@ -39,16 +38,9 @@ public class GroupCapsuleOpen extends BaseEntity { @JoinColumn(name = "member_id", nullable = false) private Member member; - @Builder - private GroupCapsuleOpen(Boolean isOpened, Capsule capsule, Member member) { - this.isOpened = Objects.requireNonNull(isOpened); - this.capsule = Objects.requireNonNull(capsule); - this.member = Objects.requireNonNull(member); - } - - public static GroupCapsuleOpen createOf(Member member, Capsule capsule, Boolean isOpened) { - return new GroupCapsuleOpen(isOpened, capsule, member); - } + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "group_id", nullable = false) + private Group group; public void open() { this.isOpened = Boolean.TRUE; diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/api/GroupCapsuleApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/api/GroupCapsuleApi.java index 06fb9b364..376efced6 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/api/GroupCapsuleApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/api/GroupCapsuleApi.java @@ -19,6 +19,7 @@ import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; +import site.timecapsulearchive.core.domain.capsule.group_capsule.data.response.GroupMemberCapsuleOpenStatusListResponse; 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; @@ -154,6 +155,35 @@ ResponseEntity> getMyGroupCapsules( ZonedDateTime createAt ); + @Operation( + summary = "그룹원의 그룹 캡슐 개봉 상태 확인", + description = """ + 그룹원의 그룹 캡슐 개봉 상태를 확인한다. + """, + security = {@SecurityRequirement(name = "user_token")}, + tags = {"group capsule"} + ) + @ApiResponses(value = { + @ApiResponse( + responseCode = "200", + description = "처리 완료" + ), + @ApiResponse( + responseCode = "404", + description = "그룹 캡슐의 개봉 상태를 찾을 수 없는 경우 예외가 발생한다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)) + ) + }) + ResponseEntity> getGroupCapsuleOpenStatus( + Long memberId, + + @Parameter(in = ParameterIn.PATH, description = "개봉 상태를 확인할 캡슐 아이디", required = true) + Long capsuleId, + + @Parameter(in = ParameterIn.QUERY, description = "생성할 그룹 아이디", required = true) + Long groupId + ); + @Operation( summary = "그룹 캡슐 개봉", description = """ @@ -177,7 +207,7 @@ ResponseEntity> openCapsule( Long memberId, @Parameter(in = ParameterIn.PATH, description = "개봉할 그룹 캡슐 아이디", required = true) - @PathVariable("capsule_id") Long capsuleId + Long capsuleId ); @Operation( 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..f63841be1 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 @@ -2,6 +2,7 @@ import jakarta.validation.Valid; import java.time.ZonedDateTime; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Slice; import org.springframework.http.ResponseEntity; @@ -17,12 +18,15 @@ 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.GroupMemberCapsuleOpenStatusDto; +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; import site.timecapsulearchive.core.domain.capsule.group_capsule.data.response.GroupCapsuleOpenStateResponse; import site.timecapsulearchive.core.domain.capsule.group_capsule.data.response.GroupCapsulePageResponse; import site.timecapsulearchive.core.domain.capsule.group_capsule.data.response.GroupCapsuleSummaryResponse; +import site.timecapsulearchive.core.domain.capsule.group_capsule.data.response.GroupMemberCapsuleOpenStatusListResponse; import site.timecapsulearchive.core.domain.capsule.group_capsule.data.response.MyGroupCapsuleSliceResponse; import site.timecapsulearchive.core.domain.capsule.group_capsule.facade.GroupCapsuleFacade; import site.timecapsulearchive.core.domain.capsule.group_capsule.service.GroupCapsuleService; @@ -139,6 +143,24 @@ public ResponseEntity> getMyGroupCapsules( ); } + @GetMapping(value = "/{capsule_id}/open-status", produces = {"application/json"}) + @Override + public ResponseEntity> getGroupCapsuleOpenStatus( + @AuthenticationPrincipal final Long memberId, + @PathVariable("capsule_id") final Long capsuleId, + @RequestParam("group_id") final Long groupId + ) { + List groupMemberCapsuleOpenStatus = groupCapsuleService.findGroupMemberCapsuleOpenStatus( + memberId, capsuleId, groupId); + + return ResponseEntity.ok( + ApiSpec.success( + SuccessCode.SUCCESS, + GroupMemberCapsuleOpenStatusListResponse.create(groupMemberCapsuleOpenStatus) + ) + ); + } + @PostMapping("/{capsule_id}/open") @Override public ResponseEntity> openCapsule( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/dto/GroupCapsuleOpenStateDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/dto/GroupCapsuleOpenStateDto.java index 56fd18e2a..38d57c2d0 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/dto/GroupCapsuleOpenStateDto.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/dto/GroupCapsuleOpenStateDto.java @@ -3,21 +3,23 @@ import site.timecapsulearchive.core.domain.capsule.group_capsule.data.response.GroupCapsuleOpenStateResponse; public record GroupCapsuleOpenStateDto( - CapsuleOpenStatus capsuleOpenStatus + CapsuleOpenStatus capsuleOpenStatus, + boolean isIndividuallyOpened ) { public static GroupCapsuleOpenStateDto opened() { - return new GroupCapsuleOpenStateDto(CapsuleOpenStatus.OPEN); + return new GroupCapsuleOpenStateDto(CapsuleOpenStatus.OPEN, true); } - public static GroupCapsuleOpenStateDto notOpened() { - return new GroupCapsuleOpenStateDto(CapsuleOpenStatus.NOT_OPEN); + public static GroupCapsuleOpenStateDto notOpened(boolean isIndividuallyOpened) { + return new GroupCapsuleOpenStateDto(CapsuleOpenStatus.NOT_OPEN, isIndividuallyOpened); } public GroupCapsuleOpenStateResponse toResponse() { return new GroupCapsuleOpenStateResponse( capsuleOpenStatus, - capsuleOpenStatus.getStatusMessage() + capsuleOpenStatus.getStatusMessage(), + isIndividuallyOpened ); } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/dto/GroupMemberCapsuleOpenStatusDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/dto/GroupMemberCapsuleOpenStatusDto.java new file mode 100644 index 000000000..ee9481f1b --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/dto/GroupMemberCapsuleOpenStatusDto.java @@ -0,0 +1,20 @@ +package site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto; + +import site.timecapsulearchive.core.domain.capsule.group_capsule.data.response.GroupMemberCapsuleOpenStatusResponse; + +public record GroupMemberCapsuleOpenStatusDto( + Long memberId, + String nickname, + String profileUrl, + boolean isOpened +) { + + public GroupMemberCapsuleOpenStatusResponse toResponse() { + return GroupMemberCapsuleOpenStatusResponse.builder() + .memberId(memberId) + .nickname(nickname) + .profileUrl(profileUrl) + .isOpened(isOpened) + .build(); + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/response/GroupCapsuleOpenStateResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/response/GroupCapsuleOpenStateResponse.java index e77ec5c3a..cd67440eb 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/response/GroupCapsuleOpenStateResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/response/GroupCapsuleOpenStateResponse.java @@ -1,10 +1,19 @@ package site.timecapsulearchive.core.domain.capsule.group_capsule.data.response; +import io.swagger.v3.oas.annotations.media.Schema; import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.CapsuleOpenStatus; +@Schema(description = "그룹 캡슐 개봉 상태 응답") public record GroupCapsuleOpenStateResponse( + + @Schema(description = "캡슐 개봉 상태") CapsuleOpenStatus capsuleOpenStatus, - String statusMessage + + @Schema(description = "캡슐 개봉 상태 메시지") + String statusMessage, + + @Schema(description = "현재 요청한 사용자의 개별적인 캡슐 개봉 상태") + boolean isIndividuallyOpened ) { } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/response/GroupMemberCapsuleOpenStatusListResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/response/GroupMemberCapsuleOpenStatusListResponse.java new file mode 100644 index 000000000..6aabc3fd7 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/response/GroupMemberCapsuleOpenStatusListResponse.java @@ -0,0 +1,20 @@ +package site.timecapsulearchive.core.domain.capsule.group_capsule.data.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; +import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.GroupMemberCapsuleOpenStatusDto; + +@Schema(description = "그룹원들 캡슐 개봉 상태") +public record GroupMemberCapsuleOpenStatusListResponse( + List groupMemberCapsuleOpenStatus +) { + + public static GroupMemberCapsuleOpenStatusListResponse create( + List groupMemberCapsuleOpenStatus) { + List groupMemberCapsuleOpenStatusResponses = groupMemberCapsuleOpenStatus.stream() + .map(GroupMemberCapsuleOpenStatusDto::toResponse) + .toList(); + + return new GroupMemberCapsuleOpenStatusListResponse(groupMemberCapsuleOpenStatusResponses); + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/response/GroupMemberCapsuleOpenStatusResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/response/GroupMemberCapsuleOpenStatusResponse.java new file mode 100644 index 000000000..fc4a98fae --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/data/response/GroupMemberCapsuleOpenStatusResponse.java @@ -0,0 +1,23 @@ +package site.timecapsulearchive.core.domain.capsule.group_capsule.data.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; + +@Schema(description = "그룹원별 캡슐 개봉 상태") +@Builder +public record GroupMemberCapsuleOpenStatusResponse( + + @Schema(description = "회원 아이디") + Long memberId, + + @Schema(description = "회원 닉네임") + String nickname, + + @Schema(description = "회원 프로필") + String profileUrl, + + @Schema(description = "개봉 상태") + boolean isOpened +) { + +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/facade/GroupCapsuleFacade.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/facade/GroupCapsuleFacade.java index c4e160daa..16c37f7c7 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/facade/GroupCapsuleFacade.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/facade/GroupCapsuleFacade.java @@ -56,6 +56,6 @@ public void saveGroupCapsule( final List groupMemberIds = memberGroupQueryService.findGroupMemberIds(groupId); - groupCapsuleOpenService.bulkSave(groupMemberIds, capsule); + groupCapsuleOpenService.bulkSave(groupId, groupMemberIds, capsule); } } \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/repository/GroupCapsuleOpenQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/repository/GroupCapsuleOpenQueryRepository.java index 218d84b9b..31f6e152f 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/repository/GroupCapsuleOpenQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/repository/GroupCapsuleOpenQueryRepository.java @@ -1,5 +1,10 @@ package site.timecapsulearchive.core.domain.capsule.group_capsule.repository; +import static site.timecapsulearchive.core.domain.capsule.entity.QGroupCapsuleOpen.groupCapsuleOpen; +import static site.timecapsulearchive.core.domain.member.entity.QMember.member; + +import com.querydsl.core.types.Projections; +import com.querydsl.jpa.impl.JPAQueryFactory; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Timestamp; @@ -11,19 +16,26 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import site.timecapsulearchive.core.domain.capsule.entity.Capsule; +import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.GroupMemberCapsuleOpenStatusDto; +import site.timecapsulearchive.core.domain.member.entity.QMember; @Repository @RequiredArgsConstructor public class GroupCapsuleOpenQueryRepository { private final JdbcTemplate jdbcTemplate; + private final JPAQueryFactory jpaQueryFactory; - public void bulkSave(final List groupMemberIds, final Capsule capsule) { + public void bulkSave( + final Long groupId, + final List groupMemberIds, + final Capsule capsule + ) { jdbcTemplate.batchUpdate( """ INSERT INTO group_capsule_open ( - group_capsule_open_id, is_opened, member_id, capsule_id, created_at, updated_at - ) values (?, ? ,? ,? ,?, ?) + group_capsule_open_id, is_opened, member_id, capsule_id, group_id, created_at, updated_at + ) values (?, ? ,? ,? ,?, ?, ?) """, new BatchPreparedStatementSetter() { @Override @@ -34,8 +46,9 @@ public void setValues(PreparedStatement ps, int i) throws SQLException { ps.setBoolean(2, isOpened); ps.setLong(3, groupMemberIds.get(i)); ps.setLong(4, capsule.getId()); - ps.setTimestamp(5, Timestamp.valueOf(ZonedDateTime.now().toLocalDateTime())); + ps.setLong(5, groupId); ps.setTimestamp(6, Timestamp.valueOf(ZonedDateTime.now().toLocalDateTime())); + ps.setTimestamp(7, Timestamp.valueOf(ZonedDateTime.now().toLocalDateTime())); } @Override @@ -45,4 +58,26 @@ public int getBatchSize() { } ); } + + public List findGroupMemberCapsuleOpenStatus( + final Long capsuleId, + final Long groupId + ) { + return jpaQueryFactory + .select( + Projections.constructor( + GroupMemberCapsuleOpenStatusDto.class, + groupCapsuleOpen.member.id, + groupCapsuleOpen.member.nickname, + groupCapsuleOpen.member.profileUrl, + groupCapsuleOpen.isOpened + ) + ) + .from(groupCapsuleOpen) + .join(groupCapsuleOpen.member, member) + .where(groupCapsuleOpen.group.id.eq(groupId) + .and(groupCapsuleOpen.capsule.id.eq(capsuleId)) + ) + .fetch(); + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/service/GroupCapsuleOpenService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/service/GroupCapsuleOpenService.java index 32496954d..c695e2d7e 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/service/GroupCapsuleOpenService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/service/GroupCapsuleOpenService.java @@ -12,7 +12,11 @@ public class GroupCapsuleOpenService { private final GroupCapsuleOpenQueryRepository repository; - public void bulkSave(final List groupMemberIds, final Capsule capsule) { - repository.bulkSave(groupMemberIds, capsule); + public void bulkSave( + final Long groupId, + final List groupMemberIds, + final Capsule capsule + ) { + repository.bulkSave(groupId, groupMemberIds, capsule); } } 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 cbcfb1146..c384290d1 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 @@ -2,6 +2,7 @@ import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.util.List; import lombok.RequiredArgsConstructor; import org.locationtech.jts.geom.Point; import org.springframework.data.domain.Slice; @@ -16,10 +17,14 @@ 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.GroupMemberCapsuleOpenStatusDto; +import site.timecapsulearchive.core.domain.capsule.group_capsule.repository.GroupCapsuleOpenQueryRepository; import site.timecapsulearchive.core.domain.capsule.group_capsule.repository.GroupCapsuleQueryRepository; import site.timecapsulearchive.core.domain.capsuleskin.entity.CapsuleSkin; import site.timecapsulearchive.core.domain.group.entity.Group; import site.timecapsulearchive.core.domain.member.entity.Member; +import site.timecapsulearchive.core.domain.member_group.exception.NoGroupAuthorityException; +import site.timecapsulearchive.core.domain.member_group.repository.member_group_repository.MemberGroupRepository; @Service @Transactional(readOnly = true) @@ -28,6 +33,8 @@ public class GroupCapsuleService { private final CapsuleRepository capsuleRepository; private final GroupCapsuleQueryRepository groupCapsuleQueryRepository; + private final GroupCapsuleOpenQueryRepository groupCapsuleOpenQueryRepository; + private final MemberGroupRepository memberGroupRepository; @Transactional public Capsule saveGroupCapsule( @@ -103,22 +110,35 @@ public GroupCapsuleOpenStateDto openGroupCapsule(final Long memberId, final Long capsuleId) .orElseThrow(CapsuleNotFondException::new); - if (!groupCapsule.canOpen()) { - return GroupCapsuleOpenStateDto.notOpened(); + if (groupCapsule.isNotCapsuleOpened()) { + return GroupCapsuleOpenStateDto.notOpened(false); } - if (!groupCapsule.isTimeCapsule()) { + if (groupCapsule.isNotTimeCapsule()) { groupCapsule.open(); return GroupCapsuleOpenStateDto.opened(); } boolean allGroupMemberOpened = groupCapsule.isAllGroupMemberOpened(memberId, capsuleId); if (!allGroupMemberOpened) { - return GroupCapsuleOpenStateDto.notOpened(); + return GroupCapsuleOpenStateDto.notOpened(true); } groupCapsule.open(); return GroupCapsuleOpenStateDto.opened(); } + + public List findGroupMemberCapsuleOpenStatus( + final Long memberId, + final Long capsuleId, + final Long groupId + ) { + boolean isGroupMember = memberGroupRepository.existMemberGroupByMemberIdAndGroupId(memberId, groupId); + if (!isGroupMember) { + throw new NoGroupAuthorityException(); + } + + return groupCapsuleOpenQueryRepository.findGroupMemberCapsuleOpenStatus(capsuleId, groupId); + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member_group/repository/member_group_repository/MemberGroupQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member_group/repository/member_group_repository/MemberGroupQueryRepository.java index b11a3eade..c8aebdf57 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member_group/repository/member_group_repository/MemberGroupQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member_group/repository/member_group_repository/MemberGroupQueryRepository.java @@ -20,4 +20,6 @@ public interface MemberGroupQueryRepository { Optional findGroupMembersCount(Long groupId); List findGroupMemberIdsByGroupId(final Long groupId); + + boolean existMemberGroupByMemberIdAndGroupId(Long memberId, Long groupId); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member_group/repository/member_group_repository/MemberGroupQueryRepositoryImpl.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member_group/repository/member_group_repository/MemberGroupQueryRepositoryImpl.java index 84eb64bfe..51fec1240 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member_group/repository/member_group_repository/MemberGroupQueryRepositoryImpl.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member_group/repository/member_group_repository/MemberGroupQueryRepositoryImpl.java @@ -103,6 +103,7 @@ public Optional findGroupMembersCount(final Long groupId) { ); } + @Override public List findGroupMemberIdsByGroupId(final Long groupId) { return jpaQueryFactory .select(memberGroup.member.id) @@ -110,4 +111,14 @@ public List findGroupMemberIdsByGroupId(final Long groupId) { .where(memberGroup.group.id.eq(groupId)) .fetch(); } + + @Override + public boolean existMemberGroupByMemberIdAndGroupId(Long memberId, Long groupId) { + final Integer count = jpaQueryFactory.selectOne() + .from(memberGroup) + .where(memberGroup.member.id.eq(memberId).and(memberGroup.group.id.eq(groupId))) + .fetchFirst(); + + return count != null; + } } diff --git a/backend/core/src/main/resources/db/migration/V29__group_capsule_open_add_group.sql b/backend/core/src/main/resources/db/migration/V29__group_capsule_open_add_group.sql new file mode 100644 index 000000000..c276318fe --- /dev/null +++ b/backend/core/src/main/resources/db/migration/V29__group_capsule_open_add_group.sql @@ -0,0 +1,3 @@ +alter table group_capsule_open add column group_id BIGINT; +ALTER TABLE group_capsule_open + ADD CONSTRAINT fk_group_capsule_open_group_id FOREIGN KEY (group_id) REFERENCES `group` (group_id); \ No newline at end of file diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/domain/CapsuleFixture.java b/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/domain/CapsuleFixture.java index c9fdb0112..79ee69326 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/domain/CapsuleFixture.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/domain/CapsuleFixture.java @@ -1,7 +1,6 @@ package site.timecapsulearchive.core.common.fixture.domain; import java.lang.reflect.Field; -import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.List; import java.util.Optional; @@ -136,8 +135,10 @@ public static Optional groupCapsuleNotAllMemberOpen( Capsule capsule = capsuleBuilder.dueDate(ZonedDateTimeSupplier.utc().get()) .build(); - List groupCapsuleOpens = GroupCapsuleOpenFixture.groupCapsuleOpens(false, - capsule, groupMembers); + Group group = GroupFixture.group(); + + List groupCapsuleOpens = GroupCapsuleOpenFixture.groupCapsuleOpens(group, + false, capsule, groupMembers); setFieldValue(capsule, "id", capsuleId); setFieldValue(capsule, "groupCapsuleOpens", groupCapsuleOpens); @@ -153,7 +154,10 @@ public static Optional groupCapsuleHalfMemberOpen( Capsule capsule = capsuleBuilder.dueDate(ZonedDateTimeSupplier.utc().get()) .build(); + Group group = GroupFixture.group(); + List groupCapsuleOpens = GroupCapsuleOpenFixture.groupCapsuleOpensNotAllOpened( + group, capsule, groupMembers); setFieldValue(capsule, "id", capsuleId); setFieldValue(capsule, "groupCapsuleOpens", groupCapsuleOpens); @@ -182,8 +186,10 @@ public static Optional groupCapsuleAllMemberOpen( Capsule capsule = capsuleBuilder.dueDate(ZonedDateTimeSupplier.utc().get()) .build(); - List groupCapsuleOpens = GroupCapsuleOpenFixture.groupCapsuleOpens(true, - capsule, groupMembers); + Group group = GroupFixture.group(); + + List groupCapsuleOpens = GroupCapsuleOpenFixture.groupCapsuleOpens(group, + true, capsule, groupMembers); setFieldValue(capsule, "id", capsuleId); setFieldValue(capsule, "groupCapsuleOpens", groupCapsuleOpens); @@ -199,22 +205,13 @@ public static Optional groupCapsuleExcludeSpecificMember( Capsule capsule = capsuleBuilder.dueDate(ZonedDateTimeSupplier.utc().get()) .build(); + Group group = GroupFixture.group(); + List groupCapsuleOpens = GroupCapsuleOpenFixture.groupCapsuleOpensNotOpenSpecificMemberId( - capsule, groupMembers, memberId); + group, capsule, groupMembers, memberId); setFieldValue(capsule, "id", capsuleId); setFieldValue(capsule, "groupCapsuleOpens", groupCapsuleOpens); return Optional.ofNullable(capsule); } - - public static Optional groupCapsuleAlreadyOpen(Long memberId, Long capsuleId) { - CapsuleBuilder capsuleBuilder = getCapsuleBuilder(memberId); - Capsule capsule = capsuleBuilder.dueDate(ZonedDateTimeSupplier.utc().get()) - .build(); - - setFieldValue(capsule, "id", capsuleId); - setFieldValue(capsule, "isOpened", true); - - return Optional.ofNullable(capsule); - } } diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/domain/GroupCapsuleOpenFixture.java b/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/domain/GroupCapsuleOpenFixture.java index e718b048e..7a4c17ff8 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/domain/GroupCapsuleOpenFixture.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/domain/GroupCapsuleOpenFixture.java @@ -1,50 +1,69 @@ package site.timecapsulearchive.core.common.fixture.domain; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Optional; import java.util.stream.Stream; import site.timecapsulearchive.core.domain.capsule.entity.Capsule; -import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; import site.timecapsulearchive.core.domain.capsule.entity.GroupCapsuleOpen; -import site.timecapsulearchive.core.domain.capsuleskin.entity.CapsuleSkin; +import site.timecapsulearchive.core.domain.group.entity.Group; import site.timecapsulearchive.core.domain.member.entity.Member; public class GroupCapsuleOpenFixture { - public static List groupCapsuleOpens(Boolean isOpened, Capsule capsule, - List groupMembers) { + public static List groupCapsuleOpens( + Group group, + Boolean isOpened, + Capsule capsule, + List groupMembers + ) { return groupMembers.stream() - .map(member -> GroupCapsuleOpen.builder() - .isOpened(isOpened) - .capsule(capsule) - .member(member) - .build() - ).toList(); + .map(member -> getGroupCapsuleOpen(group, isOpened, capsule, member)) + .toList(); } - public static Optional groupCapsuleOpen(int dataPrefix) { - Member member = MemberFixture.member(dataPrefix); - CapsuleSkin capsuleSkin = CapsuleSkinFixture.capsuleSkin(member); + private static GroupCapsuleOpen getGroupCapsuleOpen( + Group group, + Boolean isOpened, + Capsule capsule, + Member member + ) { + try { + Constructor declaredConstructor = GroupCapsuleOpen.class.getDeclaredConstructor(); + declaredConstructor.setAccessible(true); + + GroupCapsuleOpen groupCapsuleOpen = declaredConstructor.newInstance(); + setFieldValue(groupCapsuleOpen, "group", group); + setFieldValue(groupCapsuleOpen, "capsule", capsule); + setFieldValue(groupCapsuleOpen, "isOpened", isOpened); + setFieldValue(groupCapsuleOpen, "member", member); + return groupCapsuleOpen; + } catch (Exception e) { + throw new RuntimeException(e); + } + } - return Optional.of( - GroupCapsuleOpen.createOf( - MemberFixture.member(dataPrefix), - CapsuleFixture.capsule(member, capsuleSkin, CapsuleType.GROUP), - Boolean.FALSE - ) - ); + private static void setFieldValue(Object instance, String fieldName, Object value) { + try { + Field field = instance.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(instance, value); + } catch (Exception e) { + throw new RuntimeException(e); + } } public static List groupCapsuleOpensNotAllOpened( + Group group, Capsule capsule, List groupMembers ) { int mid = groupMembers.size() / 2; - List opened = groupCapsuleOpens(true, capsule, + List opened = groupCapsuleOpens(group, true, capsule, groupMembers.subList(0, mid)); - List notOpened = groupCapsuleOpens(false, capsule, + List notOpened = groupCapsuleOpens(group, false, capsule, groupMembers.subList(mid, groupMembers.size() - 1)); return Stream.of(opened, notOpened) @@ -53,6 +72,7 @@ public static List groupCapsuleOpensNotAllOpened( } public static List groupCapsuleOpensNotOpenSpecificMemberId( + Group group, Capsule capsule, List groupMembers, Long memberId @@ -72,8 +92,8 @@ public static List groupCapsuleOpensNotOpenSpecificMemberId( } List result = new ArrayList<>(); - result.add(GroupCapsuleOpen.createOf(specificMember, capsule, false)); - result.addAll(groupCapsuleOpens(true, capsule, filteredMember)); + result.add(getGroupCapsuleOpen(group, false, capsule, specificMember)); + result.addAll(groupCapsuleOpens(group, true, capsule, filteredMember)); return result; } diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/dto/GroupMemberCapsuleOpenStatusDtoFixture.java b/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/dto/GroupMemberCapsuleOpenStatusDtoFixture.java new file mode 100644 index 000000000..695ef1c7b --- /dev/null +++ b/backend/core/src/test/java/site/timecapsulearchive/core/common/fixture/dto/GroupMemberCapsuleOpenStatusDtoFixture.java @@ -0,0 +1,21 @@ +package site.timecapsulearchive.core.common.fixture.dto; + +import java.util.ArrayList; +import java.util.List; +import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.GroupMemberCapsuleOpenStatusDto; + +public class GroupMemberCapsuleOpenStatusDtoFixture { + + public static List groupMemberCapsuleOpenStatusDto( + Long memberId, + int size + ) { + List result = new ArrayList<>(); + for (long count = memberId; count < size; count++) { + result.add(new GroupMemberCapsuleOpenStatusDto(count, count + "test-nickname", + count + "test-profile", true)); + } + + return result; + } +} diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/capsule/group_capsule/repository/GroupCapsuleOpenQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/capsule/group_capsule/repository/GroupCapsuleOpenQueryRepositoryTest.java index 4a9c6c10d..5637192d6 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/capsule/group_capsule/repository/GroupCapsuleOpenQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/capsule/group_capsule/repository/GroupCapsuleOpenQueryRepositoryTest.java @@ -19,12 +19,12 @@ import site.timecapsulearchive.core.common.fixture.domain.CapsuleFixture; import site.timecapsulearchive.core.common.fixture.domain.CapsuleSkinFixture; import site.timecapsulearchive.core.common.fixture.domain.GroupCapsuleOpenFixture; +import site.timecapsulearchive.core.common.fixture.domain.GroupFixture; import site.timecapsulearchive.core.common.fixture.domain.MemberFixture; import site.timecapsulearchive.core.domain.capsule.entity.Capsule; -import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; import site.timecapsulearchive.core.domain.capsule.entity.GroupCapsuleOpen; -import site.timecapsulearchive.core.domain.capsule.group_capsule.repository.GroupCapsuleOpenQueryRepository; import site.timecapsulearchive.core.domain.capsuleskin.entity.CapsuleSkin; +import site.timecapsulearchive.core.domain.group.entity.Group; import site.timecapsulearchive.core.domain.member.entity.Member; @TestConstructor(autowireMode = AutowireMode.ALL) @@ -32,21 +32,29 @@ class GroupCapsuleOpenQueryRepositoryTest extends RepositoryTest { private final NamedParameterJdbcTemplate namedParameterJdbcTemplate; private final GroupCapsuleOpenQueryRepository groupCapsuleOpenRepository; + + private Long groupId; private Capsule capsule; private List groupMembers; private List groupCapsuleOpens; public GroupCapsuleOpenQueryRepositoryTest( JdbcTemplate jdbcTemplate, - DataSource dataSource + DataSource dataSource, + JPAQueryFactory jpaQueryFactory ) { this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); - this.groupCapsuleOpenRepository = new GroupCapsuleOpenQueryRepository(jdbcTemplate); + this.groupCapsuleOpenRepository = new GroupCapsuleOpenQueryRepository(jdbcTemplate, + jpaQueryFactory); } @Transactional @BeforeEach void setUp(@Autowired EntityManager entityManager) { + Group group = GroupFixture.group(); + entityManager.persist(group); + groupId = group.getId(); + groupMembers = MemberFixture.members(1, 5); groupMembers.forEach(entityManager::persist); @@ -55,10 +63,11 @@ void setUp(@Autowired EntityManager entityManager) { CapsuleSkin capsuleSkin = CapsuleSkinFixture.capsuleSkin(groupLeader); entityManager.persist(capsuleSkin); - capsule = CapsuleFixture.capsule(groupLeader, capsuleSkin, CapsuleType.GROUP); + capsule = CapsuleFixture.groupCapsule(groupLeader, capsuleSkin, group); entityManager.persist(capsule); - groupCapsuleOpens = GroupCapsuleOpenFixture.groupCapsuleOpens(false, capsule, groupMembers); + groupCapsuleOpens = GroupCapsuleOpenFixture.groupCapsuleOpens(group, false, capsule, + groupMembers); } @Test @@ -68,7 +77,7 @@ void setUp(@Autowired EntityManager entityManager) { Long capsuleId = capsule.getId(); // when - groupCapsuleOpenRepository.bulkSave(groupMemberIds, capsule); + groupCapsuleOpenRepository.bulkSave(groupId, groupMemberIds, capsule); //then String sql = "SELECT count(*) from group_capsule_open WHERE capsule_id = (:capsuleId) and member_id in (:groupMemberIds)"; 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..0e1aab206 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 @@ -76,7 +76,7 @@ void setup(@Autowired EntityManager entityManager) { capsuleId = capsule.getId(); //그룹 캡슐 오픈 여부 - List groupCapsuleOpens = GroupCapsuleOpenFixture.groupCapsuleOpens(false, + List groupCapsuleOpens = GroupCapsuleOpenFixture.groupCapsuleOpens(group, false, capsule, groupMember); groupCapsuleOpens.forEach(entityManager::persist); } diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/capsule/group_capsule/service/GroupCapsuleServiceTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/capsule/group_capsule/service/GroupCapsuleServiceTest.java index 38750bd68..aba0a1447 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/capsule/group_capsule/service/GroupCapsuleServiceTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/capsule/group_capsule/service/GroupCapsuleServiceTest.java @@ -1,5 +1,6 @@ package site.timecapsulearchive.core.domain.capsule.group_capsule.service; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.SoftAssertions.assertSoftly; import static org.mockito.ArgumentMatchers.anyLong; @@ -14,6 +15,7 @@ import site.timecapsulearchive.core.common.fixture.domain.CapsuleFixture; import site.timecapsulearchive.core.common.fixture.domain.MemberFixture; import site.timecapsulearchive.core.common.fixture.dto.CapsuleDtoFixture; +import site.timecapsulearchive.core.common.fixture.dto.GroupMemberCapsuleOpenStatusDtoFixture; import site.timecapsulearchive.core.domain.capsule.entity.Capsule; import site.timecapsulearchive.core.domain.capsule.exception.CapsuleNotFondException; import site.timecapsulearchive.core.domain.capsule.exception.GroupCapsuleOpenNotFoundException; @@ -22,9 +24,13 @@ import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.CapsuleOpenStatus; 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.GroupMemberCapsuleOpenStatusDto; +import site.timecapsulearchive.core.domain.capsule.group_capsule.repository.GroupCapsuleOpenQueryRepository; import site.timecapsulearchive.core.domain.capsule.group_capsule.repository.GroupCapsuleQueryRepository; import site.timecapsulearchive.core.domain.group.data.dto.GroupMemberSummaryDto; import site.timecapsulearchive.core.domain.member.entity.Member; +import site.timecapsulearchive.core.domain.member_group.exception.NoGroupAuthorityException; +import site.timecapsulearchive.core.domain.member_group.repository.member_group_repository.MemberGroupRepository; import site.timecapsulearchive.core.global.error.ErrorCode; class GroupCapsuleServiceTest { @@ -36,9 +42,13 @@ class GroupCapsuleServiceTest { private final CapsuleRepository capsuleRepository = mock(CapsuleRepository.class); private final GroupCapsuleQueryRepository groupCapsuleQueryRepository = mock( GroupCapsuleQueryRepository.class); + private final GroupCapsuleOpenQueryRepository groupCapsuleOpenQueryRepository = mock( + GroupCapsuleOpenQueryRepository.class); + private final MemberGroupRepository memberGroupRepository = mock(MemberGroupRepository.class); private final GroupCapsuleService groupCapsuleService = new GroupCapsuleService( - capsuleRepository, groupCapsuleQueryRepository); + capsuleRepository, groupCapsuleQueryRepository, groupCapsuleOpenQueryRepository, + memberGroupRepository); @Test void 개봉된_그룹_캡슐의_상세_내용을_볼_수_있다() { @@ -196,7 +206,8 @@ class GroupCapsuleServiceTest { @Test void 그룹_캡슐이_없는_경우_그룹_캡슐_개봉_시_예외가_발생한다() { //given - given(capsuleRepository.findNotOpenedGroupCapsuleByMemberIdAndCapsuleId(anyLong(), anyLong())) + given( + capsuleRepository.findNotOpenedGroupCapsuleByMemberIdAndCapsuleId(anyLong(), anyLong())) .willReturn(Optional.empty()); //when @@ -212,7 +223,8 @@ class GroupCapsuleServiceTest { ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")); Optional groupCapsule = CapsuleFixture.groupCapsuleSpecificTime(memberId, capsuleId, now.plusYears(5)); - given(capsuleRepository.findNotOpenedGroupCapsuleByMemberIdAndCapsuleId(anyLong(), anyLong())) + given( + capsuleRepository.findNotOpenedGroupCapsuleByMemberIdAndCapsuleId(anyLong(), anyLong())) .willReturn(groupCapsule); //when @@ -224,6 +236,7 @@ class GroupCapsuleServiceTest { softly.assertThat(groupCapsule.get().getIsOpened()).isFalse(); softly.assertThat(groupCapsuleOpenStateDto.capsuleOpenStatus()) .isEqualTo(CapsuleOpenStatus.NOT_OPEN); + softly.assertThat(groupCapsuleOpenStateDto.isIndividuallyOpened()).isFalse(); }); } @@ -232,7 +245,8 @@ class GroupCapsuleServiceTest { //given Optional groupCapsule = CapsuleFixture.groupCapsuleSpecificTime(memberId, capsuleId, null); - given(capsuleRepository.findNotOpenedGroupCapsuleByMemberIdAndCapsuleId(anyLong(), anyLong())) + given( + capsuleRepository.findNotOpenedGroupCapsuleByMemberIdAndCapsuleId(anyLong(), anyLong())) .willReturn(groupCapsule); //when @@ -244,6 +258,7 @@ class GroupCapsuleServiceTest { softly.assertThat(groupCapsule.get().getIsOpened()).isTrue(); softly.assertThat(groupCapsuleOpenStateDto.capsuleOpenStatus()) .isEqualTo(CapsuleOpenStatus.OPEN); + softly.assertThat(groupCapsuleOpenStateDto.isIndividuallyOpened()).isTrue(); }); } @@ -254,7 +269,8 @@ class GroupCapsuleServiceTest { Optional groupCapsule = CapsuleFixture.groupCapsuleNotAllMemberOpen(memberId, capsuleId, groupMembers); - given(capsuleRepository.findNotOpenedGroupCapsuleByMemberIdAndCapsuleId(anyLong(), anyLong())) + given( + capsuleRepository.findNotOpenedGroupCapsuleByMemberIdAndCapsuleId(anyLong(), anyLong())) .willReturn(groupCapsule); //when @@ -266,6 +282,7 @@ class GroupCapsuleServiceTest { softly.assertThat(groupCapsule.get().getIsOpened()).isFalse(); softly.assertThat(groupCapsuleOpenStateDto.capsuleOpenStatus()).isEqualTo( CapsuleOpenStatus.NOT_OPEN); + softly.assertThat(groupCapsuleOpenStateDto.isIndividuallyOpened()).isTrue(); }); } @@ -276,7 +293,8 @@ class GroupCapsuleServiceTest { Optional groupCapsule = CapsuleFixture.groupCapsuleHalfMemberOpen(memberId, capsuleId, groupMembers); - given(capsuleRepository.findNotOpenedGroupCapsuleByMemberIdAndCapsuleId(anyLong(), anyLong())) + given( + capsuleRepository.findNotOpenedGroupCapsuleByMemberIdAndCapsuleId(anyLong(), anyLong())) .willReturn(groupCapsule); //when @@ -288,6 +306,7 @@ class GroupCapsuleServiceTest { softly.assertThat(groupCapsule.get().getIsOpened()).isFalse(); softly.assertThat(groupCapsuleOpenStateDto.capsuleOpenStatus()).isEqualTo( CapsuleOpenStatus.NOT_OPEN); + softly.assertThat(groupCapsuleOpenStateDto.isIndividuallyOpened()).isTrue(); }); } @@ -295,7 +314,8 @@ class GroupCapsuleServiceTest { void 그룹_캡슐_개봉이_없는_경우_예외가_발생한다() { //given Optional groupCapsule = CapsuleFixture.groupCapsuleEmptyOpen(memberId, capsuleId); - given(capsuleRepository.findNotOpenedGroupCapsuleByMemberIdAndCapsuleId(anyLong(), anyLong())) + given( + capsuleRepository.findNotOpenedGroupCapsuleByMemberIdAndCapsuleId(anyLong(), anyLong())) .willReturn(groupCapsule); //when @@ -312,7 +332,8 @@ class GroupCapsuleServiceTest { Optional groupCapsule = CapsuleFixture.groupCapsuleAllMemberOpen(memberId, capsuleId, groupMembers); - given(capsuleRepository.findNotOpenedGroupCapsuleByMemberIdAndCapsuleId(anyLong(), anyLong())) + given( + capsuleRepository.findNotOpenedGroupCapsuleByMemberIdAndCapsuleId(anyLong(), anyLong())) .willReturn(groupCapsule); //when @@ -324,6 +345,7 @@ class GroupCapsuleServiceTest { softly.assertThat(groupCapsule.get().getIsOpened()).isTrue(); softly.assertThat(groupCapsuleOpenStateDto.capsuleOpenStatus()).isEqualTo( CapsuleOpenStatus.OPEN); + softly.assertThat(groupCapsuleOpenStateDto.isIndividuallyOpened()).isTrue(); }); } @@ -334,7 +356,8 @@ class GroupCapsuleServiceTest { Optional groupCapsule = CapsuleFixture.groupCapsuleExcludeSpecificMember(memberId, capsuleId, groupMembers); - given(capsuleRepository.findNotOpenedGroupCapsuleByMemberIdAndCapsuleId(anyLong(), anyLong())) + given( + capsuleRepository.findNotOpenedGroupCapsuleByMemberIdAndCapsuleId(anyLong(), anyLong())) .willReturn(groupCapsule); //when @@ -346,6 +369,41 @@ class GroupCapsuleServiceTest { softly.assertThat(groupCapsule.get().getIsOpened()).isTrue(); softly.assertThat(groupCapsuleOpenStateDto.capsuleOpenStatus()).isEqualTo( CapsuleOpenStatus.OPEN); + softly.assertThat(groupCapsuleOpenStateDto.isIndividuallyOpened()).isTrue(); }); } + + @Test + void 그룹원이_아닌_사용자가_그룹_캡슐_개봉_상태를_조회하면_오류가_발생한다() throws Exception { + //given + Long groupId = 1L; + + //when + //then + assertThatThrownBy( + () -> groupCapsuleService.findGroupMemberCapsuleOpenStatus(memberId, capsuleId, + groupId)) + .isInstanceOf(NoGroupAuthorityException.class) + .hasMessageContaining(ErrorCode.NO_GROUP_AUTHORITY_ERROR.getMessage()); + } + + @Test + void 그룹원이_그룹_캡슐_개봉_상태를_조회하면_그룹_캡슐_개봉_상태를_조회할_수_있다() throws Exception { + //given + Long groupId = 1L; + int size = 20; + given(memberGroupRepository.existMemberGroupByMemberIdAndGroupId(memberId, groupId)) + .willReturn(true); + given(groupCapsuleOpenQueryRepository.findGroupMemberCapsuleOpenStatus(capsuleId, groupId)) + .willReturn( + GroupMemberCapsuleOpenStatusDtoFixture.groupMemberCapsuleOpenStatusDto(memberId, + size)); + + //when + List groupMemberCapsuleOpenStatus = groupCapsuleService.findGroupMemberCapsuleOpenStatus( + memberId, capsuleId, groupId); + + //then + assertThat(groupMemberCapsuleOpenStatus).isNotEmpty(); + } }