From b8f5d7317c99e5367e3bad61b816f8acd336d96a Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 11 May 2024 22:49:07 +0900 Subject: [PATCH 1/5] =?UTF-8?q?feat=20:=20=EA=B7=B8=EB=A3=B9=20=EC=BA=A1?= =?UTF-8?q?=EC=8A=90=20=EA=B0=9C=EB=B4=89=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../capsule/entity/GroupCapsuleOpen.java | 8 +++++ .../exception/GroupCapsuleOpenException.java | 11 +++++++ .../GroupCapsuleOpenNotFoundException.java | 11 +++++++ .../group_capsule/api/GroupCapsuleApi.java | 26 ++++++++++++++++ .../api/GroupCapsuleApiController.java | 13 +++++++- .../GroupCapsuleOpenQueryRepository.java | 12 +++++++ .../GroupCapsuleOpenRepository.java | 4 +++ .../service/GroupCapsuleService.java | 31 +++++++++++++++++++ .../core/global/error/ErrorCode.java | 3 ++ 9 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/exception/GroupCapsuleOpenException.java create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/exception/GroupCapsuleOpenNotFoundException.java 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 b2c08a19e..d1e94f550 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 @@ -45,4 +45,12 @@ private GroupCapsuleOpen(Boolean isOpened, Capsule capsule, Member member) { 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); + } + + public void open() { + this.isOpened = Boolean.TRUE; + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/exception/GroupCapsuleOpenException.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/exception/GroupCapsuleOpenException.java new file mode 100644 index 000000000..3c1f9a59d --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/exception/GroupCapsuleOpenException.java @@ -0,0 +1,11 @@ +package site.timecapsulearchive.core.domain.capsule.exception; + +import site.timecapsulearchive.core.global.error.ErrorCode; +import site.timecapsulearchive.core.global.error.exception.BusinessException; + +public class GroupCapsuleOpenException extends BusinessException { + + public GroupCapsuleOpenException() { + super(ErrorCode.NOT_GROUP_CAPSULE_ERROR); + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/exception/GroupCapsuleOpenNotFoundException.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/exception/GroupCapsuleOpenNotFoundException.java new file mode 100644 index 000000000..fe59e10c2 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/exception/GroupCapsuleOpenNotFoundException.java @@ -0,0 +1,11 @@ +package site.timecapsulearchive.core.domain.capsule.exception; + +import site.timecapsulearchive.core.global.error.ErrorCode; +import site.timecapsulearchive.core.global.error.exception.BusinessException; + +public class GroupCapsuleOpenNotFoundException extends BusinessException { + + public GroupCapsuleOpenNotFoundException() { + super(ErrorCode.GROUP_CAPSULE_OPEN_NOT_FOUND_ERROR); + } +} 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 38a4fa382..d1647f8d7 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 @@ -153,6 +153,32 @@ 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> openCapsule( + Long memberId, + + @Parameter(in = ParameterIn.PATH, description = "개봉할 그룹 캡슐 아이디", required = true) + @PathVariable("capsule_id") Long capsuleId + ); + @Operation( summary = "그룹 캡슐 24시간 이내 수정", description = "사용자가 생성한 그룹 캡슐의 생성 시간이 24시간 이내라면 수정한다.", 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 c7e7f6af1..9b6089e3a 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 @@ -30,7 +30,7 @@ import site.timecapsulearchive.core.infra.s3.manager.S3PreSignedUrlManager; @RestController -@RequestMapping("/groups-capsules") +@RequestMapping("/group-capsules") @RequiredArgsConstructor public class GroupCapsuleApiController implements GroupCapsuleApi { @@ -137,6 +137,17 @@ public ResponseEntity> getMyGroupCapsules( ); } + @PostMapping("/{capsule_id}/open") + @Override + public ResponseEntity> openCapsule( + @AuthenticationPrincipal final Long memberId, + @PathVariable(value = "capsule_id") final Long capsuleId + ) { + groupCapsuleService.openGroupCapsule(memberId, capsuleId); + + return ResponseEntity.ok(ApiSpec.empty(SuccessCode.SUCCESS)); + } + @Override public ResponseEntity updateGroupCapsuleByIdAndGroupId( Long groupId, Long capsuleId, GroupCapsuleUpdateRequest request) { 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 5a9bacd2b..acf0a17a2 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,8 @@ package site.timecapsulearchive.core.domain.capsule.group_capsule.repository; +import static site.timecapsulearchive.core.domain.capsule.entity.QGroupCapsuleOpen.groupCapsuleOpen; + +import com.querydsl.jpa.impl.JPAQueryFactory; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Timestamp; @@ -17,6 +20,7 @@ public class GroupCapsuleOpenQueryRepository { private final JdbcTemplate jdbcTemplate; + private final JPAQueryFactory jpaQueryFactory; public void bulkSave(final List groupMemberIds, final Capsule capsule) { jdbcTemplate.batchUpdate( @@ -43,4 +47,12 @@ public int getBatchSize() { } ); } + + public List findIsOpenedByMemberIdAndCapsuleId(final Long capsuleId) { + return jpaQueryFactory + .select(groupCapsuleOpen.isOpened) + .from(groupCapsuleOpen) + .where(groupCapsuleOpen.capsule.id.eq(capsuleId)) + .fetch(); + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/repository/GroupCapsuleOpenRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/repository/GroupCapsuleOpenRepository.java index a46f6209c..ce02c9eee 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/repository/GroupCapsuleOpenRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/group_capsule/repository/GroupCapsuleOpenRepository.java @@ -1,8 +1,12 @@ package site.timecapsulearchive.core.domain.capsule.group_capsule.repository; +import java.util.Optional; import org.springframework.data.repository.Repository; import site.timecapsulearchive.core.domain.capsule.entity.GroupCapsuleOpen; public interface GroupCapsuleOpenRepository extends Repository { + void save(GroupCapsuleOpen groupCapsuleOpen); + + Optional findByMemberIdAndCapsuleId(Long memberId, Long capsuleId); } 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 fa264165a..709c8e2b7 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; @@ -9,12 +10,16 @@ import org.springframework.transaction.annotation.Transactional; 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.exception.CapsuleNotFondException; +import site.timecapsulearchive.core.domain.capsule.exception.GroupCapsuleOpenNotFoundException; import site.timecapsulearchive.core.domain.capsule.generic_capsule.repository.CapsuleRepository; 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.repository.GroupCapsuleOpenQueryRepository; +import site.timecapsulearchive.core.domain.capsule.group_capsule.repository.GroupCapsuleOpenRepository; 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; @@ -27,6 +32,8 @@ public class GroupCapsuleService { private final CapsuleRepository capsuleRepository; private final GroupCapsuleQueryRepository groupCapsuleQueryRepository; + private final GroupCapsuleOpenRepository groupCapsuleOpenRepository; + private final GroupCapsuleOpenQueryRepository groupCapsuleOpenQueryRepository; @Transactional public Capsule saveGroupCapsule( @@ -88,5 +95,29 @@ public Slice findMyGroupCapsuleSlice( ) { return groupCapsuleQueryRepository.findMyGroupCapsuleSlice(memberId, size, createdAt); } + + /** + * 해당 그룹원이 그룹 캡슐을 개봉한다. 모든 그룹원이 개봉하면 캡슐이 개봉된다. + * + * @param memberId 캡슐을 개봉할 그룹원 + * @param capsuleId 개봉할 캡슐 아이디 + */ + @Transactional + public void openGroupCapsule(final Long memberId, final Long capsuleId) { + GroupCapsuleOpen groupCapsuleOpen = groupCapsuleOpenRepository.findByMemberIdAndCapsuleId( + memberId, + capsuleId) + .orElseThrow(GroupCapsuleOpenNotFoundException::new); + groupCapsuleOpen.open(); + + List capsuleOpens = groupCapsuleOpenQueryRepository.findIsOpenedByMemberIdAndCapsuleId( + capsuleId); + + boolean allGroupMemberOpened = capsuleOpens.stream() + .allMatch(isOpened -> isOpened.equals(Boolean.TRUE)); + if (allGroupMemberOpened) { + capsuleRepository.updateIsOpenedTrue(memberId, capsuleId); + } + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java index d1f5dffa2..29a741814 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java @@ -52,6 +52,9 @@ public enum ErrorCode { //capsule CAPSULE_NOT_FOUND_ERROR(404, "CAPSULE-001", "캡슐을 찾지 못하였습니다."), NO_CAPSULE_AUTHORITY_ERROR(403, "CAPSULE-002", "캡슐에 접근 권한이 없습니다."), + NOT_GROUP_CAPSULE_ERROR(400, "CAPSULE-003", + "그룹 캡슐이 아니라 그룹 캡슐 개봉을 할 수 없습니다. 비밀, 친구 캡슐 개봉을 사용하세요"), + GROUP_CAPSULE_OPEN_NOT_FOUND_ERROR(404, "CAPSULE-004", "그룹 캡슐 개봉상태를 찾을 수 없습니다."), //friend FRIEND_NOT_FOUND_ERROR(404, "FRIEND-001", "친구를 찾지 못하였습니다"), From 620df4eced94ff12df87d22fd78560a18167c7bc Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sun, 12 May 2024 12:45:32 +0900 Subject: [PATCH 2/5] =?UTF-8?q?test=20:=20=EA=B7=B8=EB=A3=B9=20=EC=BA=A1?= =?UTF-8?q?=EC=8A=90=20=EA=B0=9C=EB=B4=89=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 --- .../domain/GroupCapsuleOpenFixture.java | 4 + .../service/GroupCapsuleServiceTest.java | 109 +++++++++++++++--- .../GroupCapsuleOpenQueryRepositoryTest.java | 4 +- 3 files changed, 101 insertions(+), 16 deletions(-) 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 7ee3e0029..f555ad68a 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 @@ -18,4 +18,8 @@ public static List groupCapsuleOpens(Boolean isOpened, Capsule ).toList(); } + public static GroupCapsuleOpen groupCapsuleOpen(Member member, Capsule capsule, + Boolean isOpened) { + return GroupCapsuleOpen.createOf(member, capsule, isOpened); + } } 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 83864e475..f2c95ac23 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,34 +1,55 @@ package site.timecapsulearchive.core.domain.capsule.group_capsule.service; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; import java.time.ZonedDateTime; import java.util.List; +import java.util.Optional; import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +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.MemberFixture; import site.timecapsulearchive.core.common.fixture.dto.CapsuleDtoFixture; +import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; +import site.timecapsulearchive.core.domain.capsule.entity.GroupCapsuleOpen; +import site.timecapsulearchive.core.domain.capsule.exception.GroupCapsuleOpenNotFoundException; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.generic_capsule.repository.CapsuleRepository; import site.timecapsulearchive.core.domain.capsule.group_capsule.data.dto.GroupCapsuleDetailDto; +import site.timecapsulearchive.core.domain.capsule.group_capsule.repository.GroupCapsuleOpenQueryRepository; +import site.timecapsulearchive.core.domain.capsule.group_capsule.repository.GroupCapsuleOpenRepository; import site.timecapsulearchive.core.domain.capsule.group_capsule.repository.GroupCapsuleQueryRepository; -import site.timecapsulearchive.core.domain.capsule.group_capsule.service.GroupCapsuleService; +import site.timecapsulearchive.core.domain.capsuleskin.entity.CapsuleSkin; import site.timecapsulearchive.core.domain.group.data.dto.GroupMemberSummaryDto; +import site.timecapsulearchive.core.domain.member.entity.Member; +import site.timecapsulearchive.core.global.error.ErrorCode; class GroupCapsuleServiceTest { private final Long capsuleId = 1L; private final int groupMemberCount = 3; + private final CapsuleRepository capsuleRepository = mock(CapsuleRepository.class); private final GroupCapsuleQueryRepository groupCapsuleQueryRepository = mock( GroupCapsuleQueryRepository.class); - private final GroupCapsuleService groupCapsuleService; + private final GroupCapsuleOpenRepository groupCapsuleOpenRepository = mock( + GroupCapsuleOpenRepository.class); + private final GroupCapsuleOpenQueryRepository groupCapsuleOpenQueryRepository = mock( + GroupCapsuleOpenQueryRepository.class); - public GroupCapsuleServiceTest() { - CapsuleRepository capsuleRepository = mock(CapsuleRepository.class); - this.groupCapsuleService = new GroupCapsuleService(capsuleRepository, groupCapsuleQueryRepository); - } + private final GroupCapsuleService groupCapsuleService = new GroupCapsuleService( + capsuleRepository, groupCapsuleQueryRepository, groupCapsuleOpenRepository, + groupCapsuleOpenQueryRepository + ); @Test void 개봉된_그룹_캡슐의_상세_내용을_볼_수_있다() { @@ -42,7 +63,6 @@ public GroupCapsuleServiceTest() { GroupCapsuleDetailDto response = groupCapsuleService.findGroupCapsuleDetailByGroupIdAndCapsuleId( capsuleId); - //then SoftAssertions.assertSoftly(softly -> { CapsuleDetailDto detailDto = response.capsuleDetailDto(); @@ -69,7 +89,6 @@ public GroupCapsuleServiceTest() { GroupCapsuleDetailDto response = groupCapsuleService.findGroupCapsuleDetailByGroupIdAndCapsuleId( capsuleId); - //then SoftAssertions.assertSoftly(softly -> { CapsuleDetailDto detailDto = response.capsuleDetailDto(); @@ -96,7 +115,6 @@ public GroupCapsuleServiceTest() { GroupCapsuleDetailDto response = groupCapsuleService.findGroupCapsuleDetailByGroupIdAndCapsuleId( capsuleId); - //then SoftAssertions.assertSoftly(softly -> { CapsuleDetailDto detailDto = response.capsuleDetailDto(); @@ -116,14 +134,14 @@ public GroupCapsuleServiceTest() { //given given( groupCapsuleQueryRepository.findGroupCapsuleDetailDtoByCapsuleId(anyLong())).willReturn( - CapsuleDtoFixture.getGroupCapsuleDetailDto(capsuleId, false, ZonedDateTime.now().minusDays(5), 3) + CapsuleDtoFixture.getGroupCapsuleDetailDto(capsuleId, false, + ZonedDateTime.now().minusDays(5), 3) ); //when GroupCapsuleDetailDto response = groupCapsuleService.findGroupCapsuleDetailByGroupIdAndCapsuleId( capsuleId); - //then SoftAssertions.assertSoftly(softly -> { CapsuleDetailDto detailDto = response.capsuleDetailDto(); @@ -141,14 +159,14 @@ public GroupCapsuleServiceTest() { //given given( groupCapsuleQueryRepository.findGroupCapsuleDetailDtoByCapsuleId(anyLong())).willReturn( - CapsuleDtoFixture.getGroupCapsuleDetailDto(capsuleId, false, ZonedDateTime.now().plusDays(5), 3) + CapsuleDtoFixture.getGroupCapsuleDetailDto(capsuleId, false, + ZonedDateTime.now().plusDays(5), 3) ); //when GroupCapsuleDetailDto response = groupCapsuleService.findGroupCapsuleDetailByGroupIdAndCapsuleId( capsuleId); - //then SoftAssertions.assertSoftly(softly -> { CapsuleDetailDto detailDto = response.capsuleDetailDto(); @@ -166,14 +184,14 @@ public GroupCapsuleServiceTest() { //given given( groupCapsuleQueryRepository.findGroupCapsuleDetailDtoByCapsuleId(anyLong())).willReturn( - CapsuleDtoFixture.getGroupCapsuleDetailDto(capsuleId, true, ZonedDateTime.now().plusDays(5), 3) + CapsuleDtoFixture.getGroupCapsuleDetailDto(capsuleId, true, + ZonedDateTime.now().plusDays(5), 3) ); //when GroupCapsuleDetailDto response = groupCapsuleService.findGroupCapsuleDetailByGroupIdAndCapsuleId( capsuleId); - //then SoftAssertions.assertSoftly(softly -> { CapsuleDetailDto detailDto = response.capsuleDetailDto(); @@ -186,4 +204,65 @@ public GroupCapsuleServiceTest() { }); } + @Test + void 그룹_캡슐_개봉이_없는_캡슐을_개봉하려는_경우_예외가_발생한다() { + //given + Long memberId = 1L; + Long capsuleId = 1L; + given(groupCapsuleOpenRepository.findByMemberIdAndCapsuleId(anyLong(), anyLong())) + .willReturn(Optional.empty()); + + //when + //then + assertThatThrownBy(() -> groupCapsuleService.openGroupCapsule(memberId, capsuleId)) + .isInstanceOf(GroupCapsuleOpenNotFoundException.class) + .hasMessageContaining(ErrorCode.GROUP_CAPSULE_OPEN_NOT_FOUND_ERROR.getMessage()); + } + + @Test + void 모든_그룹원이_캡슐을_개봉하지_않은_경우_캡슐은_개봉되지_않는다() { + //given + Long memberId = 1L; + Long capsuleId = 1L; + given(groupCapsuleOpenRepository.findByMemberIdAndCapsuleId(anyLong(), anyLong())) + .willReturn(groupCapsuleOpen()); + given(groupCapsuleOpenQueryRepository.findIsOpenedByMemberIdAndCapsuleId(anyLong())) + .willReturn(List.of(Boolean.FALSE, Boolean.FALSE, Boolean.TRUE)); + + //when + groupCapsuleService.openGroupCapsule(memberId, capsuleId); + + //then + verifyNoInteractions(capsuleRepository); + } + + private Optional groupCapsuleOpen() { + Member member = MemberFixture.member(0); + CapsuleSkin capsuleSkin = CapsuleSkinFixture.capsuleSkin(member); + + return Optional.of( + GroupCapsuleOpenFixture.groupCapsuleOpen( + MemberFixture.member(0), + CapsuleFixture.capsule(member, capsuleSkin, CapsuleType.GROUP), + Boolean.FALSE + ) + ); + } + + @Test + void 모든_그룹원이_캡슐을_개봉한_경우_캡슐은_개봉된다() { + //given + Long memberId = 1L; + Long capsuleId = 1L; + given(groupCapsuleOpenRepository.findByMemberIdAndCapsuleId(anyLong(), anyLong())) + .willReturn(groupCapsuleOpen()); + given(groupCapsuleOpenQueryRepository.findIsOpenedByMemberIdAndCapsuleId(anyLong())) + .willReturn(List.of(Boolean.TRUE, Boolean.TRUE, Boolean.TRUE)); + + //when + groupCapsuleService.openGroupCapsule(memberId, capsuleId); + + //then + verify(capsuleRepository, times(1)).updateIsOpenedTrue(anyLong(), anyLong()); + } } diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/capsule/repository/GroupCapsuleOpenQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/capsule/repository/GroupCapsuleOpenQueryRepositoryTest.java index ccb33429c..f9dd6ed0b 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/capsule/repository/GroupCapsuleOpenQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/capsule/repository/GroupCapsuleOpenQueryRepositoryTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; import java.util.List; import javax.sql.DataSource; @@ -36,11 +37,12 @@ class GroupCapsuleOpenQueryRepositoryTest extends RepositoryTest { private List groupCapsuleOpens; public GroupCapsuleOpenQueryRepositoryTest( + JPAQueryFactory jpaQueryFactory, JdbcTemplate jdbcTemplate, DataSource dataSource ) { this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); - this.groupCapsuleOpenRepository = new GroupCapsuleOpenQueryRepository(jdbcTemplate); + this.groupCapsuleOpenRepository = new GroupCapsuleOpenQueryRepository(jdbcTemplate, jpaQueryFactory); } @Transactional From fa2ada0bfb587781f0c656b1baa67ad1f90150cb Mon Sep 17 00:00:00 2001 From: hong seokho Date: Wed, 15 May 2024 14:55:39 +0900 Subject: [PATCH 3/5] =?UTF-8?q?fix=20:=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/GroupCapsuleOpenQueryRepository.java | 2 +- .../capsule/group_capsule/service/GroupCapsuleService.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 acf0a17a2..d6e6d03f2 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 @@ -48,7 +48,7 @@ public int getBatchSize() { ); } - public List findIsOpenedByMemberIdAndCapsuleId(final Long capsuleId) { + public List findIsOpenedByCapsuleId(final Long capsuleId) { return jpaQueryFactory .select(groupCapsuleOpen.isOpened) .from(groupCapsuleOpen) 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 709c8e2b7..e074314b5 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 @@ -110,7 +110,7 @@ public void openGroupCapsule(final Long memberId, final Long capsuleId) { .orElseThrow(GroupCapsuleOpenNotFoundException::new); groupCapsuleOpen.open(); - List capsuleOpens = groupCapsuleOpenQueryRepository.findIsOpenedByMemberIdAndCapsuleId( + List capsuleOpens = groupCapsuleOpenQueryRepository.findIsOpenedByCapsuleId( capsuleId); boolean allGroupMemberOpened = capsuleOpens.stream() From b07c0ca4b3f26de72667ca04ee2c017ecdc03b9c Mon Sep 17 00:00:00 2001 From: hong seokho Date: Wed, 15 May 2024 14:55:51 +0900 Subject: [PATCH 4/5] =?UTF-8?q?fix=20:=20=EC=97=90=EB=9F=AC=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EB=B0=8F=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../capsule/exception/GroupCapsuleOpenException.java | 11 ----------- .../core/global/error/ErrorCode.java | 4 +--- 2 files changed, 1 insertion(+), 14 deletions(-) delete mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/exception/GroupCapsuleOpenException.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/exception/GroupCapsuleOpenException.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/exception/GroupCapsuleOpenException.java deleted file mode 100644 index 3c1f9a59d..000000000 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/exception/GroupCapsuleOpenException.java +++ /dev/null @@ -1,11 +0,0 @@ -package site.timecapsulearchive.core.domain.capsule.exception; - -import site.timecapsulearchive.core.global.error.ErrorCode; -import site.timecapsulearchive.core.global.error.exception.BusinessException; - -public class GroupCapsuleOpenException extends BusinessException { - - public GroupCapsuleOpenException() { - super(ErrorCode.NOT_GROUP_CAPSULE_ERROR); - } -} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java index 929fc369d..0c60db255 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java @@ -52,9 +52,7 @@ public enum ErrorCode { //capsule CAPSULE_NOT_FOUND_ERROR(404, "CAPSULE-001", "캡슐을 찾지 못하였습니다."), NO_CAPSULE_AUTHORITY_ERROR(403, "CAPSULE-002", "캡슐에 접근 권한이 없습니다."), - NOT_GROUP_CAPSULE_ERROR(400, "CAPSULE-003", - "그룹 캡슐이 아니라 그룹 캡슐 개봉을 할 수 없습니다. 비밀, 친구 캡슐 개봉을 사용하세요"), - GROUP_CAPSULE_OPEN_NOT_FOUND_ERROR(404, "CAPSULE-004", "그룹 캡슐 개봉상태를 찾을 수 없습니다."), + GROUP_CAPSULE_OPEN_NOT_FOUND_ERROR(404, "CAPSULE-003", "그룹 캡슐 개봉상태를 찾을 수 없습니다."), //friend FRIEND_NOT_FOUND_ERROR(404, "FRIEND-001", "친구를 찾지 못하였습니다"), From 17d1462af29b472069da082f9e47cccef208a0f1 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Wed, 15 May 2024 14:56:15 +0900 Subject: [PATCH 5/5] =?UTF-8?q?test=20:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=ED=94=BD=EC=8A=A4=EC=B2=98=EB=A1=9C=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/GroupCapsuleOpenFixture.java | 17 +++++++++-- .../service/GroupCapsuleServiceTest.java | 30 ++++--------------- 2 files changed, 19 insertions(+), 28 deletions(-) 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 f555ad68a..795913fd7 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,8 +1,11 @@ package site.timecapsulearchive.core.common.fixture.domain; import java.util.List; +import java.util.Optional; 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.member.entity.Member; public class GroupCapsuleOpenFixture { @@ -18,8 +21,16 @@ public static List groupCapsuleOpens(Boolean isOpened, Capsule ).toList(); } - public static GroupCapsuleOpen groupCapsuleOpen(Member member, Capsule capsule, - Boolean isOpened) { - return GroupCapsuleOpen.createOf(member, capsule, isOpened); + public static Optional groupCapsuleOpen(int dataPrefix) { + Member member = MemberFixture.member(dataPrefix); + CapsuleSkin capsuleSkin = CapsuleSkinFixture.capsuleSkin(member); + + return Optional.of( + GroupCapsuleOpen.createOf( + MemberFixture.member(dataPrefix), + CapsuleFixture.capsule(member, capsuleSkin, CapsuleType.GROUP), + Boolean.FALSE + ) + ); } } 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 f2c95ac23..c6caa072a 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 @@ -13,14 +13,8 @@ import java.util.Optional; import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; -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.MemberFixture; import site.timecapsulearchive.core.common.fixture.dto.CapsuleDtoFixture; -import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; -import site.timecapsulearchive.core.domain.capsule.entity.GroupCapsuleOpen; import site.timecapsulearchive.core.domain.capsule.exception.GroupCapsuleOpenNotFoundException; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.generic_capsule.repository.CapsuleRepository; @@ -28,9 +22,7 @@ import site.timecapsulearchive.core.domain.capsule.group_capsule.repository.GroupCapsuleOpenQueryRepository; import site.timecapsulearchive.core.domain.capsule.group_capsule.repository.GroupCapsuleOpenRepository; import site.timecapsulearchive.core.domain.capsule.group_capsule.repository.GroupCapsuleQueryRepository; -import site.timecapsulearchive.core.domain.capsuleskin.entity.CapsuleSkin; import site.timecapsulearchive.core.domain.group.data.dto.GroupMemberSummaryDto; -import site.timecapsulearchive.core.domain.member.entity.Member; import site.timecapsulearchive.core.global.error.ErrorCode; class GroupCapsuleServiceTest { @@ -225,8 +217,9 @@ class GroupCapsuleServiceTest { Long memberId = 1L; Long capsuleId = 1L; given(groupCapsuleOpenRepository.findByMemberIdAndCapsuleId(anyLong(), anyLong())) - .willReturn(groupCapsuleOpen()); - given(groupCapsuleOpenQueryRepository.findIsOpenedByMemberIdAndCapsuleId(anyLong())) + + .willReturn(GroupCapsuleOpenFixture.groupCapsuleOpen(memberId.intValue())); + given(groupCapsuleOpenQueryRepository.findIsOpenedByCapsuleId(anyLong())) .willReturn(List.of(Boolean.FALSE, Boolean.FALSE, Boolean.TRUE)); //when @@ -236,27 +229,14 @@ class GroupCapsuleServiceTest { verifyNoInteractions(capsuleRepository); } - private Optional groupCapsuleOpen() { - Member member = MemberFixture.member(0); - CapsuleSkin capsuleSkin = CapsuleSkinFixture.capsuleSkin(member); - - return Optional.of( - GroupCapsuleOpenFixture.groupCapsuleOpen( - MemberFixture.member(0), - CapsuleFixture.capsule(member, capsuleSkin, CapsuleType.GROUP), - Boolean.FALSE - ) - ); - } - @Test void 모든_그룹원이_캡슐을_개봉한_경우_캡슐은_개봉된다() { //given Long memberId = 1L; Long capsuleId = 1L; given(groupCapsuleOpenRepository.findByMemberIdAndCapsuleId(anyLong(), anyLong())) - .willReturn(groupCapsuleOpen()); - given(groupCapsuleOpenQueryRepository.findIsOpenedByMemberIdAndCapsuleId(anyLong())) + .willReturn(GroupCapsuleOpenFixture.groupCapsuleOpen(memberId.intValue())); + given(groupCapsuleOpenQueryRepository.findIsOpenedByCapsuleId(anyLong())) .willReturn(List.of(Boolean.TRUE, Boolean.TRUE, Boolean.TRUE)); //when