From 4d810a143819c3dfdaff95567f86df89d342e8a1 Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 15:39:00 +0900 Subject: [PATCH 01/28] =?UTF-8?q?[feat]=20=ED=8C=8C=EB=9D=BC=EB=AF=B8?= =?UTF-8?q?=ED=84=B0=EB=A1=9C=20=EB=93=A4=EC=96=B4=EC=98=A4=EB=8A=94=20?= =?UTF-8?q?=EB=B0=A9=20=EC=B0=B8=EC=97=AC/=EC=B7=A8=EC=86=8C=20=EC=A2=85?= =?UTF-8?q?=EB=A5=98=20=EC=83=81=EC=88=98=ED=99=94=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../konkuk/thip/room/domain/RoomJoinType.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/main/java/konkuk/thip/room/domain/RoomJoinType.java diff --git a/src/main/java/konkuk/thip/room/domain/RoomJoinType.java b/src/main/java/konkuk/thip/room/domain/RoomJoinType.java new file mode 100644 index 000000000..a0cd7dad8 --- /dev/null +++ b/src/main/java/konkuk/thip/room/domain/RoomJoinType.java @@ -0,0 +1,30 @@ +package konkuk.thip.room.domain; + +import konkuk.thip.common.exception.InvalidStateException; +import konkuk.thip.common.exception.code.ErrorCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +@Getter +@RequiredArgsConstructor +public enum RoomJoinType { + JOIN("join"), + CANCEL("cancel"); + + private final String type; + + public static RoomJoinType from(String type) { + return Arrays.stream(RoomJoinType.values()) + .filter(param -> param.getType().equals(type)) + .findFirst() + .orElseThrow( + () -> new InvalidStateException(ErrorCode.ROOM_JOIN_TYPE_NOT_MATCH) + ); + } + + public boolean isJoinType() { + return JOIN.equals(this); + } +} From 171fe9738141a18b71f9ee19885bf2536dd75fd6 Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 15:39:08 +0900 Subject: [PATCH 02/28] =?UTF-8?q?[feat]=20=ED=95=84=EC=9A=94=ED=95=9C=20dt?= =?UTF-8?q?o=20=EC=84=A0=EC=96=B8=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adapter/in/web/request/RoomJoinRequest.java | 13 +++++++++++++ .../application/port/in/dto/RoomJoinCommand.java | 8 ++++++++ 2 files changed, 21 insertions(+) create mode 100644 src/main/java/konkuk/thip/room/adapter/in/web/request/RoomJoinRequest.java create mode 100644 src/main/java/konkuk/thip/room/application/port/in/dto/RoomJoinCommand.java diff --git a/src/main/java/konkuk/thip/room/adapter/in/web/request/RoomJoinRequest.java b/src/main/java/konkuk/thip/room/adapter/in/web/request/RoomJoinRequest.java new file mode 100644 index 000000000..d58ff3380 --- /dev/null +++ b/src/main/java/konkuk/thip/room/adapter/in/web/request/RoomJoinRequest.java @@ -0,0 +1,13 @@ +package konkuk.thip.room.adapter.in.web.request; + +import jakarta.validation.constraints.NotBlank; +import konkuk.thip.room.application.port.in.dto.RoomJoinCommand; + +public record RoomJoinRequest( + @NotBlank(message = "방 참여 유형 파라미터는 필수입니다..") + String type +) { + public RoomJoinCommand toCommand(Long userId, Long roomId) { + return new RoomJoinCommand(userId, roomId, type); + } +} diff --git a/src/main/java/konkuk/thip/room/application/port/in/dto/RoomJoinCommand.java b/src/main/java/konkuk/thip/room/application/port/in/dto/RoomJoinCommand.java new file mode 100644 index 000000000..4a9a79f9f --- /dev/null +++ b/src/main/java/konkuk/thip/room/application/port/in/dto/RoomJoinCommand.java @@ -0,0 +1,8 @@ +package konkuk.thip.room.application.port.in.dto; + +public record RoomJoinCommand( + Long userId, + Long roomId, + String type +) { +} From 032a4dedfda7bccb6706e7991e726817a4561fad Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 15:39:31 +0900 Subject: [PATCH 03/28] =?UTF-8?q?[feat]=20=ED=95=84=EC=9A=94=ED=95=9C=20in?= =?UTF-8?q?terface(usecase,=20port)=20=EC=84=A0=EC=96=B8=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../thip/room/application/port/in/RoomJoinUsecase.java | 9 +++++++++ .../thip/room/application/port/out/RoomCommandPort.java | 2 ++ 2 files changed, 11 insertions(+) create mode 100644 src/main/java/konkuk/thip/room/application/port/in/RoomJoinUsecase.java diff --git a/src/main/java/konkuk/thip/room/application/port/in/RoomJoinUsecase.java b/src/main/java/konkuk/thip/room/application/port/in/RoomJoinUsecase.java new file mode 100644 index 000000000..13b913a7e --- /dev/null +++ b/src/main/java/konkuk/thip/room/application/port/in/RoomJoinUsecase.java @@ -0,0 +1,9 @@ +package konkuk.thip.room.application.port.in; + +import konkuk.thip.room.application.port.in.dto.RoomJoinCommand; + +public interface RoomJoinUsecase { + + void changeJoinState(RoomJoinCommand roomJoinCommand); + +} diff --git a/src/main/java/konkuk/thip/room/application/port/out/RoomCommandPort.java b/src/main/java/konkuk/thip/room/application/port/out/RoomCommandPort.java index 57cdafd88..77cfc0e3d 100644 --- a/src/main/java/konkuk/thip/room/application/port/out/RoomCommandPort.java +++ b/src/main/java/konkuk/thip/room/application/port/out/RoomCommandPort.java @@ -7,4 +7,6 @@ public interface RoomCommandPort { Room findById(Long id); Long save(Room room); + + void updateMemberCount(Room room); } From e88c948e1e16ff58f665e1d60902ab6a299066ca Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 15:39:50 +0900 Subject: [PATCH 04/28] =?UTF-8?q?[feat]=20Room=EC=97=90=20=EB=A9=A4?= =?UTF-8?q?=EB=B2=84=20=EC=88=98=20=EA=B4=80=EB=A0=A8=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EA=B7=9C=EC=B9=99=20=EC=B6=94=EA=B0=80=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/konkuk/thip/room/domain/Room.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/main/java/konkuk/thip/room/domain/Room.java b/src/main/java/konkuk/thip/room/domain/Room.java index ffa4b52fa..188b51c8f 100644 --- a/src/main/java/konkuk/thip/room/domain/Room.java +++ b/src/main/java/konkuk/thip/room/domain/Room.java @@ -145,4 +145,27 @@ public boolean isRecruitmentPeriodExpired() { return today.isAfter(this.startDate.minusDays(1)); } + public void increaseMemberCount() { + checkJoinPossible(); + memberCount++; + } + + public void decreaseMemberCount() { + checkCancelPossible(); + memberCount--; + } + + private void checkJoinPossible() { + if (memberCount >= recruitCount) { + throw new InvalidStateException(ErrorCode.ROOM_MEMBER_COUNT_EXCEEDED); + } + } + + private void checkCancelPossible() { + if (memberCount <= 1) { // 방장 포함 항상 1명 이상이어야 함 + throw new InvalidStateException(ErrorCode.ROOM_MEMBER_COUNT_UNDERFLOW); + } + } + + } From 17dea36af825f76f22efe92ccdc372ec76a91552 Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 15:40:11 +0900 Subject: [PATCH 05/28] =?UTF-8?q?[feat]=20RoomParticipant=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../thip/room/domain/RoomParticipant.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/main/java/konkuk/thip/room/domain/RoomParticipant.java b/src/main/java/konkuk/thip/room/domain/RoomParticipant.java index f451e2a9c..7e07e744e 100644 --- a/src/main/java/konkuk/thip/room/domain/RoomParticipant.java +++ b/src/main/java/konkuk/thip/room/domain/RoomParticipant.java @@ -1,9 +1,14 @@ package konkuk.thip.room.domain; import konkuk.thip.common.entity.BaseDomainEntity; +import konkuk.thip.common.exception.BusinessException; +import konkuk.thip.common.exception.code.ErrorCode; +import konkuk.thip.room.adapter.out.jpa.RoomParticipantRole; import lombok.Getter; import lombok.experimental.SuperBuilder; +import java.util.Objects; + @Getter @SuperBuilder public class RoomParticipant extends BaseDomainEntity { @@ -20,6 +25,16 @@ public class RoomParticipant extends BaseDomainEntity { private Long roomId; + public static RoomParticipant withoutId(Long userId, Long roomId, String roomParticipantRole) { + return RoomParticipant.builder() + .currentPage(0) + .userPercentage(0.0) + .userId(userId) + .roomId(roomId) + .roomParticipantRole(roomParticipantRole) + .build(); + } + public boolean canWriteOverview() { return userPercentage >= 80; } @@ -34,4 +49,13 @@ public boolean updateUserProgress(int requestPage, int totalPageCount) { return false; } + + // 방장이 참여 취소를 요청한 경우 + public void validateHostCancelRoom() { + if (Objects.equals(this.roomParticipantRole, RoomParticipantRole.HOST.getType())) { + throw new BusinessException(ErrorCode.HOST_CANNOT_CANCEL); + } + } + + } From 73bf17478ff6317c92f2ac7d59ae8fec9e1d7bea Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 15:40:32 +0900 Subject: [PATCH 06/28] =?UTF-8?q?[feat]=20RoomParticipantJpaRepository=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RoomParticipantJpaRepository.java | 15 +++++++++++++-- .../RoomParticipantQueryRepository.java | 4 ++++ .../RoomParticipantQueryRepositoryImpl.java | 10 ++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantQueryRepository.java create mode 100644 src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantQueryRepositoryImpl.java diff --git a/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantJpaRepository.java b/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantJpaRepository.java index bcc0e88ad..a9b9337b3 100644 --- a/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantJpaRepository.java +++ b/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantJpaRepository.java @@ -2,12 +2,23 @@ import konkuk.thip.room.adapter.out.jpa.RoomParticipantJpaEntity; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import java.util.List; import java.util.Optional; -public interface RoomParticipantJpaRepository extends JpaRepository{ +public interface RoomParticipantJpaRepository extends JpaRepository, RoomParticipantQueryRepository{ + + @Query(value = "SELECT * FROM room_participants WHERE user_id = :userId AND room_id = :roomId", nativeQuery = true) + Optional findByUserIdAndRoomId(@Param("userId") Long userId, @Param("roomId") Long roomId); - Optional findByUserJpaEntity_UserIdAndRoomJpaEntity_RoomId(Long userId, Long roomId); List findAllByRoomJpaEntity_RoomId(Long roomId); + + @Query( + value = "SELECT EXISTS (SELECT 1 FROM room_participants rp WHERE rp.user_id = :userId AND rp.room_id = :roomId AND rp.status = 'ACTIVE')", + nativeQuery = true + ) + boolean existByUserIdAndRoomId(@Param("userId") Long userId, @Param("roomId") Long roomId); + } diff --git a/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantQueryRepository.java b/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantQueryRepository.java new file mode 100644 index 000000000..37494f0b0 --- /dev/null +++ b/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantQueryRepository.java @@ -0,0 +1,4 @@ +package konkuk.thip.room.adapter.out.persistence.repository.roomparticipant; + +public interface RoomParticipantQueryRepository { +} diff --git a/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantQueryRepositoryImpl.java b/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantQueryRepositoryImpl.java new file mode 100644 index 000000000..7a04b36be --- /dev/null +++ b/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantQueryRepositoryImpl.java @@ -0,0 +1,10 @@ +package konkuk.thip.room.adapter.out.persistence.repository.roomparticipant; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class RoomParticipantQueryRepositoryImpl implements RoomParticipantQueryRepository{ + +} From 9b7b8915e641345dc26dfd794bb7c4fb9bba52d9 Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 15:40:47 +0900 Subject: [PATCH 07/28] =?UTF-8?q?[feat]=20RoomParticipant=20=EC=A1=B4?= =?UTF-8?q?=EC=9E=AC=20=EC=97=AC=EB=B6=80=20=EC=BF=BC=EB=A6=AC=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...oomParticipantQueryPersistenceAdapter.java | 20 +++++++++++++++++++ .../port/out/RoomParticipantQueryPort.java | 2 ++ 2 files changed, 22 insertions(+) create mode 100644 src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantQueryPersistenceAdapter.java diff --git a/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantQueryPersistenceAdapter.java b/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantQueryPersistenceAdapter.java new file mode 100644 index 000000000..be0761aa1 --- /dev/null +++ b/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantQueryPersistenceAdapter.java @@ -0,0 +1,20 @@ +package konkuk.thip.room.adapter.out.persistence; + +import konkuk.thip.room.adapter.out.persistence.repository.roomparticipant.RoomParticipantJpaRepository; +import konkuk.thip.room.application.port.out.RoomParticipantQueryPort; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class RoomParticipantQueryPersistenceAdapter implements RoomParticipantQueryPort { + + private final RoomParticipantJpaRepository roomParticipantJpaRepository; + + @Override + public boolean existByUserIdAndRoomId(Long userId, Long roomId) { + return roomParticipantJpaRepository.existByUserIdAndRoomId(userId, roomId); + } + + +} diff --git a/src/main/java/konkuk/thip/room/application/port/out/RoomParticipantQueryPort.java b/src/main/java/konkuk/thip/room/application/port/out/RoomParticipantQueryPort.java index 2799e04cd..de1cb1372 100644 --- a/src/main/java/konkuk/thip/room/application/port/out/RoomParticipantQueryPort.java +++ b/src/main/java/konkuk/thip/room/application/port/out/RoomParticipantQueryPort.java @@ -1,4 +1,6 @@ package konkuk.thip.room.application.port.out; + public interface RoomParticipantQueryPort { + boolean existByUserIdAndRoomId(Long userId, Long roomId); } From db8757c3e6bac511b3a85bb57452ac31432a9a0a Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 15:41:04 +0900 Subject: [PATCH 08/28] =?UTF-8?q?[feat]=20=EB=B0=A9=20=EC=B0=B8=EC=97=AC?= =?UTF-8?q?=20=EC=97=AD=ED=95=A0=20type=20final=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../konkuk/thip/room/adapter/out/jpa/RoomParticipantRole.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/konkuk/thip/room/adapter/out/jpa/RoomParticipantRole.java b/src/main/java/konkuk/thip/room/adapter/out/jpa/RoomParticipantRole.java index 6639c6135..9c818af65 100644 --- a/src/main/java/konkuk/thip/room/adapter/out/jpa/RoomParticipantRole.java +++ b/src/main/java/konkuk/thip/room/adapter/out/jpa/RoomParticipantRole.java @@ -11,7 +11,7 @@ public enum RoomParticipantRole { HOST("호스트"), MEMBER("팀원"); - private String type; + private final String type; RoomParticipantRole(String type) { this.type = type; From 82989e99ae87d6384e38b8813d8772ca2e6c2341 Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 15:41:41 +0900 Subject: [PATCH 09/28] =?UTF-8?q?[feat]=20RoomParticipant=EC=97=90=20Soft?= =?UTF-8?q?=20Delete=20=EC=A0=81=EC=9A=A9=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../thip/room/adapter/out/jpa/RoomParticipantJpaEntity.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/konkuk/thip/room/adapter/out/jpa/RoomParticipantJpaEntity.java b/src/main/java/konkuk/thip/room/adapter/out/jpa/RoomParticipantJpaEntity.java index 608a8ec8d..861425f0a 100644 --- a/src/main/java/konkuk/thip/room/adapter/out/jpa/RoomParticipantJpaEntity.java +++ b/src/main/java/konkuk/thip/room/adapter/out/jpa/RoomParticipantJpaEntity.java @@ -4,10 +4,12 @@ import konkuk.thip.common.entity.BaseJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; import lombok.*; +import org.hibernate.annotations.SQLDelete; @Entity @Table(name = "room_participants") @Getter +@SQLDelete(sql = "UPDATE room_participants SET status = 'INACTIVE' WHERE room_participant_id = ?") @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor @Builder From 88fb7b0737d8c7b5b27527826eb67ce2074984a8 Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 15:42:47 +0900 Subject: [PATCH 10/28] =?UTF-8?q?[feat]=20insert=20=EC=BF=BC=EB=A6=AC=20?= =?UTF-8?q?=EB=B0=8F=20=EC=82=AD=EC=A0=9C=20=EC=BF=BC=EB=A6=AC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...mParticipantCommandPersistenceAdapter.java | 35 ++++++++++++++++++- .../port/out/RoomParticipantCommandPort.java | 4 +++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantCommandPersistenceAdapter.java b/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantCommandPersistenceAdapter.java index c58543572..de3190bc7 100644 --- a/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantCommandPersistenceAdapter.java +++ b/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantCommandPersistenceAdapter.java @@ -2,16 +2,23 @@ import konkuk.thip.common.exception.EntityNotFoundException; import konkuk.thip.common.exception.code.ErrorCode; +import konkuk.thip.room.adapter.out.jpa.RoomJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomParticipantJpaEntity; import konkuk.thip.room.adapter.out.mapper.RoomParticipantMapper; +import konkuk.thip.room.adapter.out.persistence.repository.RoomJpaRepository; import konkuk.thip.room.adapter.out.persistence.repository.roomparticipant.RoomParticipantJpaRepository; import konkuk.thip.room.application.port.out.RoomParticipantCommandPort; import konkuk.thip.room.domain.RoomParticipant; +import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; +import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; import java.util.List; +import static konkuk.thip.common.exception.code.ErrorCode.ROOM_NOT_FOUND; +import static konkuk.thip.common.exception.code.ErrorCode.USER_NOT_FOUND; + @Repository @RequiredArgsConstructor public class RoomParticipantCommandPersistenceAdapter implements RoomParticipantCommandPort { @@ -19,9 +26,12 @@ public class RoomParticipantCommandPersistenceAdapter implements RoomParticipant private final RoomParticipantJpaRepository roomParticipantJpaRepository; private final RoomParticipantMapper roomParticipantMapper; + private final UserJpaRepository userJpaRepository; + private final RoomJpaRepository roomJpaRepository; + @Override public RoomParticipant findByUserIdAndRoomId(Long userId, Long roomId) { - RoomParticipantJpaEntity roomParticipantJpaEntity = roomParticipantJpaRepository.findByUserJpaEntity_UserIdAndRoomJpaEntity_RoomId(userId, roomId).orElseThrow( + RoomParticipantJpaEntity roomParticipantJpaEntity = roomParticipantJpaRepository.findByUserIdAndRoomId(userId, roomId).orElseThrow( () -> new EntityNotFoundException(ErrorCode.ROOM_PARTICIPANT_NOT_FOUND) ); @@ -34,4 +44,27 @@ public List findAllByRoomId(Long roomId) { .map(roomParticipantMapper::toDomainEntity) .toList(); } + + @Override + public void save(RoomParticipant roomParticipant) { + UserJpaEntity userJpaEntity = userJpaRepository.findById(roomParticipant.getUserId()).orElseThrow( + () -> new EntityNotFoundException(USER_NOT_FOUND)); + + RoomJpaEntity roomJpaEntity = roomJpaRepository.findById(roomParticipant.getRoomId()).orElseThrow( + () -> new EntityNotFoundException(ROOM_NOT_FOUND) + ); + + roomParticipantJpaRepository.save(roomParticipantMapper.toJpaEntity( + roomParticipant, userJpaEntity, roomJpaEntity + )); + } + + @Override + public void deleteByUserIdAndRoomId(Long userId, Long roomId) { + RoomParticipantJpaEntity roomParticipantJpaEntity = roomParticipantJpaRepository.findByUserIdAndRoomId(userId, roomId).orElseThrow( + () -> new EntityNotFoundException(ErrorCode.ROOM_PARTICIPANT_NOT_FOUND) + ); + + roomParticipantJpaRepository.delete(roomParticipantJpaEntity); + } } diff --git a/src/main/java/konkuk/thip/room/application/port/out/RoomParticipantCommandPort.java b/src/main/java/konkuk/thip/room/application/port/out/RoomParticipantCommandPort.java index c8edc43aa..22a523ed8 100644 --- a/src/main/java/konkuk/thip/room/application/port/out/RoomParticipantCommandPort.java +++ b/src/main/java/konkuk/thip/room/application/port/out/RoomParticipantCommandPort.java @@ -9,4 +9,8 @@ public interface RoomParticipantCommandPort { RoomParticipant findByUserIdAndRoomId(Long userId, Long roomId); List findAllByRoomId(Long roomId); + void save(RoomParticipant roomParticipant); + + void deleteByUserIdAndRoomId(Long userId, Long roomId); + } From 8b0ad9c2c745fb92841d6f21f0d480dd5310da48 Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 15:42:57 +0900 Subject: [PATCH 11/28] =?UTF-8?q?[feat]=20RoomJpaEntity=20=EB=A9=A4?= =?UTF-8?q?=EB=B2=84=EC=88=98=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntity.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntity.java b/src/main/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntity.java index c28a1e056..e8b44cfe7 100644 --- a/src/main/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntity.java +++ b/src/main/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntity.java @@ -55,4 +55,8 @@ public class RoomJpaEntity extends BaseJpaEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "category_id", nullable = false) private CategoryJpaEntity categoryJpaEntity; + + public void updateMemberCount(int count) { + this.memberCount = count; + } } \ No newline at end of file From c828d0445d59846503742f6ffd00dc82b80567d8 Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 15:43:27 +0900 Subject: [PATCH 12/28] =?UTF-8?q?[feat]=20RoomJpaEntity=20=EB=A9=A4?= =?UTF-8?q?=EB=B2=84=EC=88=98=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20?= =?UTF-8?q?=EC=BF=BC=EB=A6=AC=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../persistence/RoomCommandPersistenceAdapter.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomCommandPersistenceAdapter.java b/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomCommandPersistenceAdapter.java index 2ed339ac2..85901e5c5 100644 --- a/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomCommandPersistenceAdapter.java +++ b/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomCommandPersistenceAdapter.java @@ -47,4 +47,15 @@ public Long save(Room room) { RoomJpaEntity roomJpaEntity = roomMapper.toJpaEntity(room, bookJpaEntity, categoryJpaEntity); return roomJpaRepository.save(roomJpaEntity).getRoomId(); } + + @Override + public void updateMemberCount(Room room) { + RoomJpaEntity roomJpaEntity = roomJpaRepository.findById(room.getId()).orElseThrow( + () -> new EntityNotFoundException(ROOM_NOT_FOUND) + ); + + roomJpaEntity.updateMemberCount(room.getMemberCount()); + + roomJpaRepository.save(roomJpaEntity); + } } From ef01f189989a6834ce0314d1d57357ea42c70c3a Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 15:43:35 +0900 Subject: [PATCH 13/28] =?UTF-8?q?[feat]=20=EB=B0=A9=20=EC=B0=B8=EC=97=AC/?= =?UTF-8?q?=EC=B7=A8=EC=86=8C=20=EA=B4=80=EB=A0=A8=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/konkuk/thip/common/exception/code/ErrorCode.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/konkuk/thip/common/exception/code/ErrorCode.java b/src/main/java/konkuk/thip/common/exception/code/ErrorCode.java index 6d94870e1..350539c4c 100644 --- a/src/main/java/konkuk/thip/common/exception/code/ErrorCode.java +++ b/src/main/java/konkuk/thip/common/exception/code/ErrorCode.java @@ -82,6 +82,8 @@ public enum ErrorCode implements ResponseCode { ROOM_PASSWORD_NOT_REQUIRED(HttpStatus.BAD_REQUEST, 100003, "공개방은 비밀번호가 필요하지 않습니다."), ROOM_RECRUITMENT_PERIOD_EXPIRED(HttpStatus.BAD_REQUEST, 100004, "모집기간이 만료된 방입니다."), INVALID_ROOM_SEARCH_SORT(HttpStatus.BAD_REQUEST, 100005, "방 검색 시 정렬 조건이 잘못되었습니다."), + ROOM_MEMBER_COUNT_EXCEEDED(HttpStatus.BAD_REQUEST, 100006, "방의 최대 인원 수를 초과했습니다."), + ROOM_MEMBER_COUNT_UNDERFLOW(HttpStatus.BAD_REQUEST, 100007, "방의 인원 수가 1 이하(방장 포함)입니다."), /** * 110000 : vote error @@ -109,6 +111,11 @@ public enum ErrorCode implements ResponseCode { ROOM_PARTICIPANT_NOT_FOUND(HttpStatus.NOT_FOUND, 140000, "존재하지 않는 RoomParticipant (방과 사용자 관계) 입니다."), USER_NOT_BELONG_TO_ROOM(HttpStatus.BAD_REQUEST, 140001, "현재 모임방에 속하지 않는 유저입니다."), ROOM_PARTICIPANT_ROLE_NOT_MATCH(HttpStatus.BAD_REQUEST, 140002, "일치하는 방에서의 사용자 역할이 없습니다."), + ROOM_JOIN_TYPE_NOT_MATCH(HttpStatus.BAD_REQUEST, 140003, "일치하는 방 참여 상태가 없습니다."), + USER_CANNOT_JOIN_OR_CANCEL(HttpStatus.BAD_REQUEST, 140004, "존재하지 않는 방은 참여하기 또는 취소하기가 불가능합니다."), + USER_ALREADY_PARTICIPATE(HttpStatus.BAD_REQUEST, 140005, "사용자가 이미 방에 참여한 상태입니다."), + USER_NOT_PARTICIPATED(HttpStatus.BAD_REQUEST, 140006, "사용자가 방에 참여하지 않은 상태에서 취소하기는 불가합니다."), + HOST_CANNOT_CANCEL(HttpStatus.BAD_REQUEST, 140007, "방장은 참여 취소를 할 수 없습니다."), /** * 150000 : Category error From 7fc67a36aedc40d7252db9bfafa405b8a4797305 Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 15:43:47 +0900 Subject: [PATCH 14/28] =?UTF-8?q?[feat]=20=EB=B0=A9=20=EC=B0=B8=EC=97=AC/?= =?UTF-8?q?=EC=B7=A8=EC=86=8C=20api=20=ED=95=B8=EB=93=A4=EB=9F=AC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adapter/in/web/RoomCommandController.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/main/java/konkuk/thip/room/adapter/in/web/RoomCommandController.java b/src/main/java/konkuk/thip/room/adapter/in/web/RoomCommandController.java index acfd5076f..e2a82fe57 100644 --- a/src/main/java/konkuk/thip/room/adapter/in/web/RoomCommandController.java +++ b/src/main/java/konkuk/thip/room/adapter/in/web/RoomCommandController.java @@ -4,9 +4,12 @@ import konkuk.thip.common.dto.BaseResponse; import konkuk.thip.common.security.annotation.UserId; import konkuk.thip.room.adapter.in.web.request.RoomCreateRequest; +import konkuk.thip.room.adapter.in.web.request.RoomJoinRequest; import konkuk.thip.room.adapter.in.web.response.RoomCreateResponse; import konkuk.thip.room.application.port.in.RoomCreateUseCase; +import konkuk.thip.room.application.port.in.RoomJoinUsecase; import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @@ -16,11 +19,27 @@ public class RoomCommandController { private final RoomCreateUseCase roomCreateUseCase; + private final RoomJoinUsecase roomJoinUsecase; + /** + * 방 생성 요청 + */ @PostMapping("/rooms") public BaseResponse createRoom(@Valid @RequestBody RoomCreateRequest request, @UserId Long userId) { return BaseResponse.ok(RoomCreateResponse.of( roomCreateUseCase.createRoom(request.toCommand(), userId) )); } + + /** + * 방 참여하기/취소하기 요청 + */ + @PostMapping("/rooms/{roomId}/join") + public BaseResponse joinRoom(@Valid @RequestBody final RoomJoinRequest request, + @UserId final Long userId, + @PathVariable final Long roomId) { + + roomJoinUsecase.changeJoinState(request.toCommand(userId, roomId)); + return BaseResponse.ok(null); + } } From bbfd174336090b30873225bc9c25803319b557b1 Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 15:43:51 +0900 Subject: [PATCH 15/28] =?UTF-8?q?[feat]=20=EB=B0=A9=20=EC=B0=B8=EC=97=AC/?= =?UTF-8?q?=EC=B7=A8=EC=86=8C=20api=20=EC=84=9C=EB=B9=84=EC=8A=A4=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/service/RoomJoinService.java | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 src/main/java/konkuk/thip/room/application/service/RoomJoinService.java diff --git a/src/main/java/konkuk/thip/room/application/service/RoomJoinService.java b/src/main/java/konkuk/thip/room/application/service/RoomJoinService.java new file mode 100644 index 000000000..5a4eef6d8 --- /dev/null +++ b/src/main/java/konkuk/thip/room/application/service/RoomJoinService.java @@ -0,0 +1,79 @@ +package konkuk.thip.room.application.service; + +import konkuk.thip.common.exception.EntityNotFoundException; +import konkuk.thip.common.exception.InvalidStateException; +import konkuk.thip.common.exception.code.ErrorCode; +import konkuk.thip.room.application.port.in.RoomJoinUsecase; +import konkuk.thip.room.application.port.in.dto.RoomJoinCommand; +import konkuk.thip.room.application.port.out.RoomCommandPort; +import konkuk.thip.room.application.port.out.RoomParticipantCommandPort; +import konkuk.thip.room.application.port.out.RoomParticipantQueryPort; +import konkuk.thip.room.domain.Room; +import konkuk.thip.room.domain.RoomJoinType; +import konkuk.thip.room.domain.RoomParticipant; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import static konkuk.thip.room.adapter.out.jpa.RoomParticipantRole.MEMBER; + +@Service +@RequiredArgsConstructor +public class RoomJoinService implements RoomJoinUsecase { + + private final RoomParticipantQueryPort roomParticipantQueryPort; + private final RoomCommandPort roomCommandPort; + private final RoomParticipantCommandPort roomParticipantCommandPort; + + @Override + @Transactional + public void changeJoinState(RoomJoinCommand roomJoinCommand) { + RoomJoinType type = RoomJoinType.from(roomJoinCommand.type()); + + // 방이 존재하지 않거나 만료된 경우 + Room room; + try { + room = roomCommandPort.findById(roomJoinCommand.roomId()); + } catch (EntityNotFoundException e) { + throw new InvalidStateException(ErrorCode.USER_CANNOT_JOIN_OR_CANCEL); + } + + boolean isParticipate = roomParticipantQueryPort.existByUserIdAndRoomId(roomJoinCommand.userId(), roomJoinCommand.roomId()); + + // 참여하기 요청 + if(type.isJoinType()) { + // 이미 참여한 상태 + if(isParticipate) { + throw new InvalidStateException(ErrorCode.USER_ALREADY_PARTICIPATE); + } + + RoomParticipant roomParticipant = RoomParticipant.withoutId(roomJoinCommand.userId(), roomJoinCommand.roomId(), MEMBER.getType()); + roomParticipantCommandPort.save(roomParticipant); + + //Room의 memberCount 업데이트 + room.increaseMemberCount(); + } + + // 취소하기 요청 + if(!type.isJoinType()) { + // 참여하지 않은 상태 + if(!isParticipate) { + throw new InvalidStateException(ErrorCode.USER_NOT_PARTICIPATED); + } + + // 방장이 참여 취소를 요청한 경우 + RoomParticipant roomParticipant = roomParticipantCommandPort.findByUserIdAndRoomId(roomJoinCommand.userId(), roomJoinCommand.roomId()); + roomParticipant.validateHostCancelRoom(); + + roomParticipantCommandPort.deleteByUserIdAndRoomId(roomJoinCommand.userId(), roomJoinCommand.roomId()); + + //Room의 memberCount 업데이트 + room.decreaseMemberCount(); + } + + // 방의 상태 업데이트 + roomCommandPort.updateMemberCount(room); + } + + +} From 539ced969e37948f143c5c7e818770ff6fcbf412 Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 15:44:08 +0900 Subject: [PATCH 16/28] =?UTF-8?q?[test]=20=EB=B0=A9=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=20=ED=86=B5=ED=95=A9=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20displayna?= =?UTF-8?q?me=20=EC=88=98=EC=A0=95=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/konkuk/thip/room/adapter/in/web/RoomCreateAPITest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/konkuk/thip/room/adapter/in/web/RoomCreateAPITest.java b/src/test/java/konkuk/thip/room/adapter/in/web/RoomCreateAPITest.java index 5b91b716a..79382d9b7 100644 --- a/src/test/java/konkuk/thip/room/adapter/in/web/RoomCreateAPITest.java +++ b/src/test/java/konkuk/thip/room/adapter/in/web/RoomCreateAPITest.java @@ -39,7 +39,7 @@ @SpringBootTest @ActiveProfiles("test") @AutoConfigureMockMvc(addFilters = false) -@DisplayName("방 생성 api 통합 테스트") +@DisplayName("[통합] 방 생성 api 통합 테스트") class RoomCreateAPITest { @Autowired From 467af614a3fa2aadbcfa8488563b5f4409cf924d Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 15:44:19 +0900 Subject: [PATCH 17/28] =?UTF-8?q?[test]=20=EB=B0=A9=20=EC=B0=B8=EC=97=AC/?= =?UTF-8?q?=EC=B7=A8=EC=86=8C=20api=20=ED=86=B5=ED=95=A9=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../room/adapter/in/web/RoomJoinApiTest.java | 204 ++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 src/test/java/konkuk/thip/room/adapter/in/web/RoomJoinApiTest.java diff --git a/src/test/java/konkuk/thip/room/adapter/in/web/RoomJoinApiTest.java b/src/test/java/konkuk/thip/room/adapter/in/web/RoomJoinApiTest.java new file mode 100644 index 000000000..9240a3e4d --- /dev/null +++ b/src/test/java/konkuk/thip/room/adapter/in/web/RoomJoinApiTest.java @@ -0,0 +1,204 @@ +package konkuk.thip.room.adapter.in.web; + +import com.fasterxml.jackson.databind.ObjectMapper; +import konkuk.thip.book.adapter.out.jpa.BookJpaEntity; +import konkuk.thip.book.adapter.out.persistence.repository.BookJpaRepository; +import konkuk.thip.common.util.TestEntityFactory; +import konkuk.thip.room.adapter.out.jpa.CategoryJpaEntity; +import konkuk.thip.room.adapter.out.jpa.RoomJpaEntity; +import konkuk.thip.room.adapter.out.jpa.RoomParticipantJpaEntity; +import konkuk.thip.room.adapter.out.jpa.RoomParticipantRole; +import konkuk.thip.room.adapter.out.persistence.repository.RoomJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.category.CategoryJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.roomparticipant.RoomParticipantJpaRepository; +import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; +import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; +import konkuk.thip.user.adapter.out.jpa.UserRole; +import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; + +import java.time.LocalDate; +import java.util.HashMap; +import java.util.Map; + +import static konkuk.thip.room.domain.RoomJoinType.CANCEL; +import static konkuk.thip.room.domain.RoomJoinType.JOIN; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest +@ActiveProfiles("test") +@AutoConfigureMockMvc(addFilters = false) +@DisplayName("방 참여/취소 API 통합 테스트") +class RoomJoinApiTest { + + @Autowired private MockMvc mockMvc; + @Autowired private ObjectMapper objectMapper; + @Autowired private RoomJpaRepository roomJpaRepository; + @Autowired private RoomParticipantJpaRepository roomParticipantJpaRepository; + @Autowired private BookJpaRepository bookJpaRepository; + @Autowired private CategoryJpaRepository categoryJpaRepository; + @Autowired private UserJpaRepository userJpaRepository; + @Autowired private AliasJpaRepository aliasJpaRepository; + + private RoomJpaEntity room; + private UserJpaEntity host; + private UserJpaEntity participant; + + private void setUpWithOnlyHost() { + AliasJpaEntity alias = aliasJpaRepository.save(TestEntityFactory.createLiteratureAlias()); + createUsers(alias); + + BookJpaEntity book = bookJpaRepository.save(TestEntityFactory.createBook()); + CategoryJpaEntity category = categoryJpaRepository.save(TestEntityFactory.createLiteratureCategory(alias)); + createRoom(book, category,1); // 방장만 포함 + roomParticipantJpaRepository.save(TestEntityFactory.createUserRoom(room, host, RoomParticipantRole.HOST, 0.0)); + } + + private void setUpWithParticipant() { + AliasJpaEntity alias = aliasJpaRepository.save(TestEntityFactory.createLiteratureAlias()); + createUsers(alias); + + BookJpaEntity book = bookJpaRepository.save(TestEntityFactory.createBook()); + CategoryJpaEntity category = categoryJpaRepository.save(TestEntityFactory.createLiteratureCategory(alias)); + createRoom(book, category,2); // 방장과 참여자 포함 + roomParticipantJpaRepository.save(TestEntityFactory.createUserRoom(room, host, RoomParticipantRole.HOST, 0.0)); + roomParticipantJpaRepository.save(TestEntityFactory.createUserRoom(room, participant, RoomParticipantRole.MEMBER, 0.0)); + } + + private void createRoom(BookJpaEntity book, CategoryJpaEntity category, int memberCount) { + room = roomJpaRepository.save(RoomJpaEntity.builder() + .title("방이름") + .description("설명") + .isPublic(true) + .startDate(LocalDate.now()) + .endDate(LocalDate.now().plusDays(5)) + .recruitCount(3) + .bookJpaEntity(book) + .categoryJpaEntity(category) + .memberCount(memberCount) // 방장과 참여자 포함 + .build()); + } + + private void createUsers(AliasJpaEntity alias) { + host = userJpaRepository.save(UserJpaEntity.builder() + .oauth2Id("kakao_432708231") + .nickname("user") + .imageUrl("img") + .role(UserRole.USER) + .aliasForUserJpaEntity(alias) + .build()); + + participant = userJpaRepository.save(UserJpaEntity.builder() + .oauth2Id("kakao_12345678") + .nickname("user123") + .imageUrl("img") + .role(UserRole.USER) + .aliasForUserJpaEntity(alias) + .build()); + } + + @AfterEach + void tearDown() { + roomParticipantJpaRepository.deleteAllInBatch(); + roomJpaRepository.deleteAll(); + categoryJpaRepository.deleteAll(); + bookJpaRepository.deleteAll(); + userJpaRepository.deleteAll(); + aliasJpaRepository.deleteAll(); + } + + @Test + @DisplayName("방 참여 성공 - 참여자 저장 및 인원수 증가 확인") + void joinRoom_success() throws Exception { + setUpWithOnlyHost(); + Map request = new HashMap<>(); + request.put("type", JOIN.getType()); + + mockMvc.perform(post("/rooms/" + room.getRoomId() + "/join") + .requestAttr("userId", participant.getUserId()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isOk()); + + // 참여자 저장 확인 + RoomParticipantJpaEntity roomParticipantJpaEntity = roomParticipantJpaRepository + .findByUserIdAndRoomId(participant.getUserId(), room.getRoomId()) + .orElse(null); + assertThat(roomParticipantJpaEntity).isNotNull(); + + // 인원수 증가 확인 + room = roomJpaRepository.findById(room.getRoomId()).orElseThrow(); + assertThat(room.getMemberCount()).isEqualTo(2); // 방 생성 시 1명 + 참여 1명 + } + + + @Test + @DisplayName("방 중복 참여 실패") + void joinRoom_alreadyParticipated() throws Exception { + // 이미 참여한 상태로 설정 + setUpWithParticipant(); + + Map request = new HashMap<>(); + request.put("type", JOIN.getType()); + + ResultActions result = mockMvc.perform(post("/rooms/" + room.getRoomId() + "/join") + .requestAttr("userId", participant.getUserId()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))); + + result.andExpect(status().isBadRequest()); + } + + @Test + @DisplayName("방 참여 취소 성공 - 참여자 제거 및 인원수 감소 확인") + void cancelJoin_success() throws Exception { + // 이미 참여한 상태로 설정 + setUpWithParticipant(); + + Map request = new HashMap<>(); + request.put("type", CANCEL.getType()); + + mockMvc.perform(post("/rooms/" + room.getRoomId() + "/join") + .requestAttr("userId", participant.getUserId()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isOk()); + + // 참여자 삭제 확인 + boolean exists = roomParticipantJpaRepository + .existByUserIdAndRoomId(participant.getUserId(), room.getRoomId()); + assertThat(exists).isFalse(); + + // 인원수 감소 확인 + room = roomJpaRepository.findById(room.getRoomId()).orElseThrow(); + assertThat(room.getMemberCount()).isEqualTo(1); // 다시 원래 인원 + } + + @Test + @DisplayName("방 미참여자 취소 실패") + void cancelJoin_notParticipated() throws Exception { + setUpWithOnlyHost(); + + Map request = new HashMap<>(); + request.put("type", CANCEL.getType()); + + ResultActions result = mockMvc.perform(post("/rooms/" + room.getRoomId() + "/join") + .requestAttr("userId", participant.getUserId()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))); + + result.andExpect(status().isBadRequest()); + } +} \ No newline at end of file From 82f93ce34d786836d10c1757bc8d95b5a90f06ef Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 15:44:25 +0900 Subject: [PATCH 18/28] =?UTF-8?q?[test]=20=EB=B0=A9=20=EC=B0=B8=EC=97=AC/?= =?UTF-8?q?=EC=B7=A8=EC=86=8C=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=EB=8B=A8?= =?UTF-8?q?=EC=9C=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1=20?= =?UTF-8?q?(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/RoomJoinServiceTest.java | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 src/test/java/konkuk/thip/room/application/service/RoomJoinServiceTest.java diff --git a/src/test/java/konkuk/thip/room/application/service/RoomJoinServiceTest.java b/src/test/java/konkuk/thip/room/application/service/RoomJoinServiceTest.java new file mode 100644 index 000000000..57a585506 --- /dev/null +++ b/src/test/java/konkuk/thip/room/application/service/RoomJoinServiceTest.java @@ -0,0 +1,118 @@ +package konkuk.thip.room.application.service; + +import konkuk.thip.common.exception.InvalidStateException; +import konkuk.thip.common.exception.code.ErrorCode; +import konkuk.thip.room.application.port.in.dto.RoomJoinCommand; +import konkuk.thip.room.application.port.out.RoomCommandPort; +import konkuk.thip.room.application.port.out.RoomParticipantCommandPort; +import konkuk.thip.room.application.port.out.RoomParticipantQueryPort; +import konkuk.thip.room.domain.Room; +import konkuk.thip.room.domain.RoomParticipant; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; + +import static konkuk.thip.room.adapter.out.jpa.RoomParticipantRole.MEMBER; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.BDDMockito.*; +import static org.mockito.Mockito.mock; + +@DisplayName("[단위] 방 참여/취소 서비스 단위 테스트") +class RoomJoinServiceTest { + private RoomParticipantQueryPort roomParticipantQueryPort; + private RoomCommandPort roomCommandPort; + private RoomParticipantCommandPort roomParticipantCommandPort; + private RoomJoinService roomJoinService; + + private final Long ROOM_ID = 1L; + private final Long USER_ID = 2L; + private final Room room = Room.withoutId("제목", "설명", true, null, + LocalDate.now().plusDays(1), + LocalDate.now().plusDays(30), + 5, 100L, null); + + @BeforeEach + void setUp() { + roomParticipantQueryPort = mock(RoomParticipantQueryPort.class); + roomCommandPort = mock(RoomCommandPort.class); + roomParticipantCommandPort = mock(RoomParticipantCommandPort.class); + + roomJoinService = new RoomJoinService( + roomParticipantQueryPort, + roomCommandPort, + roomParticipantCommandPort + ); + } + + @Nested + @DisplayName("참여하기 요청") + class Join { + + @Test + @DisplayName("이미 참여한 경우 예외 발생") + void alreadyParticipated() { + RoomJoinCommand command = new RoomJoinCommand(USER_ID, ROOM_ID, "join"); + + given(roomCommandPort.findById(ROOM_ID)).willReturn(room); + given(roomParticipantQueryPort.existByUserIdAndRoomId(USER_ID, ROOM_ID)).willReturn(true); + + assertThatThrownBy(() -> roomJoinService.changeJoinState(command)) + .isInstanceOf(InvalidStateException.class) + .hasFieldOrPropertyWithValue("errorCode", ErrorCode.USER_ALREADY_PARTICIPATE); + } + + @Test + @DisplayName("정상적으로 참여 시 참여자 저장 및 인원수 증가") + void successJoin() { + RoomJoinCommand command = new RoomJoinCommand(USER_ID, ROOM_ID, "join"); + + given(roomCommandPort.findById(ROOM_ID)).willReturn(room); + given(roomParticipantQueryPort.existByUserIdAndRoomId(USER_ID, ROOM_ID)).willReturn(false); + + roomJoinService.changeJoinState(command); + + then(roomParticipantCommandPort).should().save(any(RoomParticipant.class)); + then(roomCommandPort).should().updateMemberCount(any(Room.class)); + } + } + + @Nested + @DisplayName("취소하기 요청") + class Cancel { + + @Test + @DisplayName("참여하지 않은 경우 예외 발생") + void notParticipated() { + RoomJoinCommand command = new RoomJoinCommand(USER_ID, ROOM_ID, "cancel"); + + given(roomCommandPort.findById(ROOM_ID)).willReturn(room); + given(roomParticipantQueryPort.existByUserIdAndRoomId(USER_ID, ROOM_ID)).willReturn(false); + + assertThatThrownBy(() -> roomJoinService.changeJoinState(command)) + .isInstanceOf(InvalidStateException.class) + .hasFieldOrPropertyWithValue("errorCode", ErrorCode.USER_NOT_PARTICIPATED); + } + + @Test + @DisplayName("정상적으로 취소 시 참여자 제거 및 인원수 감소") + void successCancel() { + RoomJoinCommand command = new RoomJoinCommand(USER_ID, ROOM_ID, "cancel"); + RoomParticipant participant = RoomParticipant.withoutId(USER_ID, ROOM_ID, MEMBER.getType()); + + given(roomCommandPort.findById(ROOM_ID)).willReturn(room); + given(roomParticipantQueryPort.existByUserIdAndRoomId(USER_ID, ROOM_ID)).willReturn(true); + given(roomParticipantCommandPort.findByUserIdAndRoomId(USER_ID, ROOM_ID)).willReturn(participant); + + room.increaseMemberCount(); // 현재 2명 이상으로 만들어 줌 + + roomJoinService.changeJoinState(command); + + then(roomParticipantCommandPort).should().deleteByUserIdAndRoomId(USER_ID, ROOM_ID); + then(roomCommandPort).should().updateMemberCount(any(Room.class)); + } + } + +} \ No newline at end of file From 57587f2b74d699dce82bd5dcda1097e5ad72ae10 Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 15:44:37 +0900 Subject: [PATCH 19/28] =?UTF-8?q?[test]=20Room=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EA=B7=9C=EC=B9=99=20=EB=8B=A8=EC=9C=84=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../konkuk/thip/room/domain/RoomTest.java | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/test/java/konkuk/thip/room/domain/RoomTest.java b/src/test/java/konkuk/thip/room/domain/RoomTest.java index 1c532a351..b25b1e9f0 100644 --- a/src/test/java/konkuk/thip/room/domain/RoomTest.java +++ b/src/test/java/konkuk/thip/room/domain/RoomTest.java @@ -5,7 +5,6 @@ import konkuk.thip.common.exception.code.ErrorCode; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.springframework.context.annotation.Primary; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @@ -241,4 +240,28 @@ void verifyPassword_success() { assertDoesNotThrow(() -> room.verifyPassword("1234")); } + @Test + @DisplayName("increaseMemberCount: 정원이 다 찬 상태에서 호출하면 InvalidStateException 발생") + void increaseMemberCount_exceed_limit() { + Room room = Room.withoutId( + "제목", "설명", false, "1234", + START, END, 1, 123L, validCategory // recruitCount = 1 (방장 포함) + ); + // 이미 memberCount = 1 이므로 더 이상 참여 불가 + InvalidStateException ex = assertThrows(InvalidStateException.class, room::increaseMemberCount); + assertEquals(ErrorCode.ROOM_MEMBER_COUNT_EXCEEDED, ex.getErrorCode()); + } + + @Test + @DisplayName("decreaseMemberCount: 인원이 1명(방장만 존재)일 때 호출하면 InvalidStateException 발생") + void decreaseMemberCount_underflow() { + Room room = Room.withoutId( + "제목", "설명", false, "1234", + START, END, 5, 123L, validCategory + ); + // memberCount = 1 인 상태에서 감소 시도 + InvalidStateException ex = assertThrows(InvalidStateException.class, room::decreaseMemberCount); + assertEquals(ErrorCode.ROOM_MEMBER_COUNT_UNDERFLOW, ex.getErrorCode()); + } + } From 7b134dcdf5967f546d3c76e94f7742443888a30f Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 15:44:56 +0900 Subject: [PATCH 20/28] =?UTF-8?q?[test]=20Book=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=EC=8B=9C=20ISBN=20=EB=9E=9C=EB=8D=A4=20UUID=20=EA=B0=96?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95=20(unique=20=EC=86=8D?= =?UTF-8?q?=EC=84=B1)=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../konkuk/thip/common/util/TestEntityFactory.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/test/java/konkuk/thip/common/util/TestEntityFactory.java b/src/test/java/konkuk/thip/common/util/TestEntityFactory.java index a964f4da2..464bceab9 100644 --- a/src/test/java/konkuk/thip/common/util/TestEntityFactory.java +++ b/src/test/java/konkuk/thip/common/util/TestEntityFactory.java @@ -1,17 +1,21 @@ package konkuk.thip.common.util; import konkuk.thip.book.adapter.out.jpa.BookJpaEntity; +import konkuk.thip.comment.adapter.out.jpa.CommentJpaEntity; +import konkuk.thip.post.adapter.out.jpa.PostJpaEntity; import konkuk.thip.record.adapter.out.jpa.RecordJpaEntity; import konkuk.thip.room.adapter.out.jpa.CategoryJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomParticipantJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomParticipantRole; -import konkuk.thip.user.adapter.out.jpa.*; +import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; +import konkuk.thip.user.adapter.out.jpa.FollowingJpaEntity; +import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; +import konkuk.thip.user.adapter.out.jpa.UserRole; import konkuk.thip.vote.adapter.out.jpa.VoteJpaEntity; -import konkuk.thip.comment.adapter.out.jpa.CommentJpaEntity; -import konkuk.thip.post.adapter.out.jpa.PostJpaEntity; import java.time.LocalDate; +import java.util.UUID; public class TestEntityFactory { @@ -65,7 +69,7 @@ public static BookJpaEntity createBook() { return BookJpaEntity.builder() .title("책제목") .authorName("저자") - .isbn("isbn") + .isbn(UUID.randomUUID().toString().replace("-", "").substring(0, 13)) .bestSeller(false) .publisher("출판사") .imageUrl("img") From fa96e99ce9dfe83a003a405480a9f72e141c973b Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 15:59:14 +0900 Subject: [PATCH 21/28] =?UTF-8?q?[refactor]=20=EC=82=AC=EC=9A=A9=EB=90=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20count=20=EC=BF=BC=EB=A6=AC=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0=20(followerCount=EB=A1=9C=20=EB=8C=80?= =?UTF-8?q?=EC=B2=B4=EB=90=A8)=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../following/FollowingQueryRepository.java | 2 -- .../FollowingQueryRepositoryImpl.java | 23 ------------------- 2 files changed, 25 deletions(-) diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/following/FollowingQueryRepository.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/following/FollowingQueryRepository.java index 882b80bce..cfe0c1253 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/following/FollowingQueryRepository.java +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/following/FollowingQueryRepository.java @@ -4,11 +4,9 @@ import java.time.LocalDateTime; import java.util.List; -import java.util.Map; import java.util.Optional; public interface FollowingQueryRepository { - Map countByFollowingUserIds(List userIds); Optional findByUserAndTargetUser(Long userId, Long targetUserId); List findFollowersByUserIdBeforeCreatedAt(Long userId, LocalDateTime cursor, int size); diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/following/FollowingQueryRepositoryImpl.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/following/FollowingQueryRepositoryImpl.java index 9b50430d9..ec2a2a118 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/following/FollowingQueryRepositoryImpl.java +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/repository/following/FollowingQueryRepositoryImpl.java @@ -1,7 +1,6 @@ package konkuk.thip.user.adapter.out.persistence.repository.following; import com.querydsl.core.BooleanBuilder; -import com.querydsl.core.Tuple; import com.querydsl.jpa.impl.JPAQueryFactory; import konkuk.thip.common.entity.StatusType; import konkuk.thip.user.adapter.out.jpa.FollowingJpaEntity; @@ -13,9 +12,7 @@ import java.time.LocalDateTime; import java.util.List; -import java.util.Map; import java.util.Optional; -import java.util.stream.Collectors; @Repository @RequiredArgsConstructor @@ -23,26 +20,6 @@ public class FollowingQueryRepositoryImpl implements FollowingQueryRepository { private final JPAQueryFactory jpaQueryFactory; - // 주어진 userId 리스트에 대해 각 userId의 팔로워(구독자) 수를 집계하여 Map으로 반환 - public Map countByFollowingUserIds(List userIds) { - - QFollowingJpaEntity following = QFollowingJpaEntity.followingJpaEntity; - - List results = jpaQueryFactory - .select(following.followingUserJpaEntity.userId, following.count()) - .from(following) - .where(following.followingUserJpaEntity.userId.in(userIds)) - .groupBy(following.followingUserJpaEntity.userId) - .fetch(); - - // 결과를 Map로 변환 - return results.stream() - .collect(Collectors.toMap( - tuple -> tuple.get(following.followingUserJpaEntity.userId), - tuple -> tuple.get(following.count()).intValue() - )); - } - @Override public Optional findByUserAndTargetUser(Long userId, Long targetUserId) { QFollowingJpaEntity following = QFollowingJpaEntity.followingJpaEntity; From 4ade6e4bc6e56b5a3299a71e15fe0cb07368ac32 Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 16:22:49 +0900 Subject: [PATCH 22/28] =?UTF-8?q?[fix]=20native=20query=EC=9D=B4=EB=AF=80?= =?UTF-8?q?=EB=A1=9C=20boolean=EC=9D=B4=20=EC=95=84=EB=8B=8C=20Long?= =?UTF-8?q?=EC=9D=84=20=EB=B0=98=ED=99=98=EB=B0=9B=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../out/persistence/RoomParticipantQueryPersistenceAdapter.java | 2 +- .../roomparticipant/RoomParticipantJpaRepository.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantQueryPersistenceAdapter.java b/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantQueryPersistenceAdapter.java index be0761aa1..54abe59e7 100644 --- a/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantQueryPersistenceAdapter.java +++ b/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantQueryPersistenceAdapter.java @@ -13,7 +13,7 @@ public class RoomParticipantQueryPersistenceAdapter implements RoomParticipantQu @Override public boolean existByUserIdAndRoomId(Long userId, Long roomId) { - return roomParticipantJpaRepository.existByUserIdAndRoomId(userId, roomId); + return roomParticipantJpaRepository.existByUserIdAndRoomId(userId, roomId) == 1; } diff --git a/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantJpaRepository.java b/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantJpaRepository.java index a9b9337b3..3ea0e73b0 100644 --- a/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantJpaRepository.java +++ b/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantJpaRepository.java @@ -19,6 +19,6 @@ public interface RoomParticipantJpaRepository extends JpaRepository Date: Fri, 18 Jul 2025 16:23:22 +0900 Subject: [PATCH 23/28] =?UTF-8?q?[fix]=20=EB=B0=A9=20=EB=A7=8C=EB=A3=8C=20?= =?UTF-8?q?=EC=97=AC=EB=B6=80=20=EA=B2=80=EC=A6=9D=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/service/RoomJoinService.java | 1 + .../java/konkuk/thip/room/domain/Room.java | 20 +++++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/main/java/konkuk/thip/room/application/service/RoomJoinService.java b/src/main/java/konkuk/thip/room/application/service/RoomJoinService.java index 5a4eef6d8..eddfa5fe2 100644 --- a/src/main/java/konkuk/thip/room/application/service/RoomJoinService.java +++ b/src/main/java/konkuk/thip/room/application/service/RoomJoinService.java @@ -39,6 +39,7 @@ public void changeJoinState(RoomJoinCommand roomJoinCommand) { } boolean isParticipate = roomParticipantQueryPort.existByUserIdAndRoomId(roomJoinCommand.userId(), roomJoinCommand.roomId()); + room.validateRoomExpired(); // 참여하기 요청 if(type.isJoinType()) { diff --git a/src/main/java/konkuk/thip/room/domain/Room.java b/src/main/java/konkuk/thip/room/domain/Room.java index 188b51c8f..1e190ba63 100644 --- a/src/main/java/konkuk/thip/room/domain/Room.java +++ b/src/main/java/konkuk/thip/room/domain/Room.java @@ -119,14 +119,7 @@ public boolean matchesPassword(String rawPassword) { public void verifyPassword(String rawPassword) { - // 모집기간 만료 체크 - LocalDate deadline = this.startDate.minusDays(1); - if (isRecruitmentPeriodExpired()) { - String message = String.format("모집기간(%s까지)이 만료된 방에는 참여할 수 없습니다.", deadline); - throw new BusinessException( - ErrorCode.ROOM_RECRUITMENT_PERIOD_EXPIRED, new IllegalArgumentException(message) - ); - } + validateRoomExpired(); // 공개방일 경우 비밀번호 입력 요청 예외 처리 if (this.isPublic()) { @@ -139,6 +132,17 @@ ErrorCode.ROOM_RECRUITMENT_PERIOD_EXPIRED, new IllegalArgumentException(message) } } + public void validateRoomExpired() { + // 모집기간 만료 체크 + LocalDate deadline = this.startDate.minusDays(1); + if (isRecruitmentPeriodExpired()) { + String message = String.format("모집기간(%s까지)이 만료된 방에는 참여할 수 없습니다.", deadline); + throw new BusinessException( + ErrorCode.ROOM_RECRUITMENT_PERIOD_EXPIRED, new IllegalArgumentException(message) + ); + } + } + public boolean isRecruitmentPeriodExpired() { LocalDate today = LocalDate.now(); // 모집 마감일: startDate.minusDays(1) From e4b5b0149c63785b3a132cf1fd44d9eddc1fa279 Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 16:34:07 +0900 Subject: [PATCH 24/28] =?UTF-8?q?[fix]=20BaseResponse=20=EC=A0=9C=EB=84=88?= =?UTF-8?q?=EB=A6=AD=20=ED=83=80=EC=9E=85=20Void=EB=A1=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../konkuk/thip/room/adapter/in/web/RoomCommandController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/konkuk/thip/room/adapter/in/web/RoomCommandController.java b/src/main/java/konkuk/thip/room/adapter/in/web/RoomCommandController.java index e2a82fe57..09dfe1db8 100644 --- a/src/main/java/konkuk/thip/room/adapter/in/web/RoomCommandController.java +++ b/src/main/java/konkuk/thip/room/adapter/in/web/RoomCommandController.java @@ -35,7 +35,7 @@ public BaseResponse createRoom(@Valid @RequestBody RoomCreat * 방 참여하기/취소하기 요청 */ @PostMapping("/rooms/{roomId}/join") - public BaseResponse joinRoom(@Valid @RequestBody final RoomJoinRequest request, + public BaseResponse joinRoom(@Valid @RequestBody final RoomJoinRequest request, @UserId final Long userId, @PathVariable final Long roomId) { From 46bf492e7eeb8ad59a17acb867b9ea9b6df02e0b Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 16:51:22 +0900 Subject: [PATCH 25/28] =?UTF-8?q?[fix]=20exist=20=EC=BF=BC=EB=A6=AC=201=20?= =?UTF-8?q?=EB=B0=98=ED=99=98=EC=97=90=20=EB=94=B0=EB=A5=B8=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/konkuk/thip/room/adapter/in/web/RoomJoinApiTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/konkuk/thip/room/adapter/in/web/RoomJoinApiTest.java b/src/test/java/konkuk/thip/room/adapter/in/web/RoomJoinApiTest.java index 9240a3e4d..2e1887dff 100644 --- a/src/test/java/konkuk/thip/room/adapter/in/web/RoomJoinApiTest.java +++ b/src/test/java/konkuk/thip/room/adapter/in/web/RoomJoinApiTest.java @@ -178,7 +178,7 @@ void cancelJoin_success() throws Exception { // 참여자 삭제 확인 boolean exists = roomParticipantJpaRepository - .existByUserIdAndRoomId(participant.getUserId(), room.getRoomId()); + .existByUserIdAndRoomId(participant.getUserId(), room.getRoomId()) == 1; assertThat(exists).isFalse(); // 인원수 감소 확인 From 35d1baa957bef1b51bbfe5abf47ca542f3f5096c Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 17:34:03 +0900 Subject: [PATCH 26/28] =?UTF-8?q?[refactor]=20statuc=20=ED=95=84=ED=84=B0?= =?UTF-8?q?=EB=A7=81=20=ED=8F=AC=ED=95=A8=ED=95=B4=EC=84=9C=20=EB=84=A4?= =?UTF-8?q?=EC=9D=B4=ED=8B=B0=EB=B8=8C=20=EC=BF=BC=EB=A6=AC=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../roomparticipant/RoomParticipantJpaRepository.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantJpaRepository.java b/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantJpaRepository.java index 3ea0e73b0..987aeda67 100644 --- a/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantJpaRepository.java +++ b/src/main/java/konkuk/thip/room/adapter/out/persistence/repository/roomparticipant/RoomParticipantJpaRepository.java @@ -10,15 +10,16 @@ public interface RoomParticipantJpaRepository extends JpaRepository, RoomParticipantQueryRepository{ - @Query(value = "SELECT * FROM room_participants WHERE user_id = :userId AND room_id = :roomId", nativeQuery = true) + @Query(value = "SELECT * FROM room_participants WHERE user_id = :userId AND room_id = :roomId AND status = 'ACTIVE'", nativeQuery = true) Optional findByUserIdAndRoomId(@Param("userId") Long userId, @Param("roomId") Long roomId); - List findAllByRoomJpaEntity_RoomId(Long roomId); + @Query(value = "SELECT * FROM room_participants WHERE room_id = :roomId AND status = 'ACTIVE'", nativeQuery = true) + List findAllByRoomId(Long roomId); @Query( value = "SELECT EXISTS (SELECT 1 FROM room_participants rp WHERE rp.user_id = :userId AND rp.room_id = :roomId AND rp.status = 'ACTIVE')", nativeQuery = true ) - Long existByUserIdAndRoomId(@Param("userId") Long userId, @Param("roomId") Long roomId); + boolean existByUserIdAndRoomId(@Param("userId") Long userId, @Param("roomId") Long roomId); } From f4b4130ce6f6c3a3860015da820ca1ba1da347de Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 17:34:13 +0900 Subject: [PATCH 27/28] =?UTF-8?q?[refactor]=20statuc=20=ED=95=84=ED=84=B0?= =?UTF-8?q?=EB=A7=81=20=ED=8F=AC=ED=95=A8=ED=95=B4=EC=84=9C=20=EB=84=A4?= =?UTF-8?q?=EC=9D=B4=ED=8B=B0=EB=B8=8C=20=EC=BF=BC=EB=A6=AC=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../persistence/RoomParticipantCommandPersistenceAdapter.java | 2 +- .../out/persistence/RoomParticipantQueryPersistenceAdapter.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantCommandPersistenceAdapter.java b/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantCommandPersistenceAdapter.java index de3190bc7..d5aaf0890 100644 --- a/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantCommandPersistenceAdapter.java +++ b/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantCommandPersistenceAdapter.java @@ -40,7 +40,7 @@ public RoomParticipant findByUserIdAndRoomId(Long userId, Long roomId) { @Override public List findAllByRoomId(Long roomId) { - return roomParticipantJpaRepository.findAllByRoomJpaEntity_RoomId(roomId).stream() + return roomParticipantJpaRepository.findAllByRoomId(roomId).stream() .map(roomParticipantMapper::toDomainEntity) .toList(); } diff --git a/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantQueryPersistenceAdapter.java b/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantQueryPersistenceAdapter.java index 54abe59e7..be0761aa1 100644 --- a/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantQueryPersistenceAdapter.java +++ b/src/main/java/konkuk/thip/room/adapter/out/persistence/RoomParticipantQueryPersistenceAdapter.java @@ -13,7 +13,7 @@ public class RoomParticipantQueryPersistenceAdapter implements RoomParticipantQu @Override public boolean existByUserIdAndRoomId(Long userId, Long roomId) { - return roomParticipantJpaRepository.existByUserIdAndRoomId(userId, roomId) == 1; + return roomParticipantJpaRepository.existByUserIdAndRoomId(userId, roomId); } From e30c759d20ce68fffd1c7139907a18d7e0688831 Mon Sep 17 00:00:00 2001 From: janghyunjun Date: Fri, 18 Jul 2025 17:34:49 +0900 Subject: [PATCH 28/28] =?UTF-8?q?[fix]=20RoomParticipant=20=EC=86=8C?= =?UTF-8?q?=ED=94=84=ED=8A=B8=20=EB=94=9C=EB=A6=AC=ED=8A=B8=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=EC=9C=BC=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20=ED=86=B5?= =?UTF-8?q?=ED=95=A9=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=8B=9C=EC=97=90=20?= =?UTF-8?q?deleteAll()=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=8C=80=EC=8B=A0?= =?UTF-8?q?=20deleteAllInBatch()=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=20(#84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/BookDetailSearchControllerTest.java | 31 ++++++++++--------- .../in/web/RecordCreateControllerTest.java | 2 +- .../in/web/RoomGetHomeJoinedRoomsApiTest.java | 2 +- .../in/web/RoomGetMemberListApiTest.java | 2 +- .../room/adapter/in/web/RoomJoinApiTest.java | 6 ++-- .../in/web/RoomPlayingDetailViewApiTest.java | 23 +++++++------- .../web/RoomRecruitingDetailViewApiTest.java | 10 +++--- .../adapter/in/web/RoomSearchApiTest.java | 2 +- .../adapter/out/jpa/RoomJpaEntityTest.java | 5 +-- 9 files changed, 44 insertions(+), 39 deletions(-) diff --git a/src/test/java/konkuk/thip/book/adapter/in/web/BookDetailSearchControllerTest.java b/src/test/java/konkuk/thip/book/adapter/in/web/BookDetailSearchControllerTest.java index 26993b81a..9e0bdf3fd 100644 --- a/src/test/java/konkuk/thip/book/adapter/in/web/BookDetailSearchControllerTest.java +++ b/src/test/java/konkuk/thip/book/adapter/in/web/BookDetailSearchControllerTest.java @@ -1,30 +1,33 @@ package konkuk.thip.book.adapter.in.web; +import konkuk.thip.book.adapter.out.jpa.BookJpaEntity; import konkuk.thip.book.adapter.out.persistence.repository.BookJpaRepository; import konkuk.thip.book.application.service.BookSearchService; -import konkuk.thip.book.adapter.out.jpa.BookJpaEntity; -import konkuk.thip.common.security.util.JwtUtil; import konkuk.thip.common.util.TestEntityFactory; +import konkuk.thip.feed.adapter.out.jpa.FeedJpaEntity; +import konkuk.thip.feed.adapter.out.persistence.repository.FeedJpaRepository; import konkuk.thip.room.adapter.out.jpa.CategoryJpaEntity; +import konkuk.thip.room.adapter.out.jpa.RoomJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomParticipantJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomParticipantRole; -import konkuk.thip.room.adapter.out.persistence.repository.category.CategoryJpaRepository; -import konkuk.thip.user.adapter.out.jpa.*; -import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; -import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; -import konkuk.thip.room.adapter.out.jpa.RoomJpaEntity; import konkuk.thip.room.adapter.out.persistence.repository.RoomJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.category.CategoryJpaRepository; import konkuk.thip.room.adapter.out.persistence.repository.roomparticipant.RoomParticipantJpaRepository; -import konkuk.thip.feed.adapter.out.jpa.FeedJpaEntity; -import konkuk.thip.feed.adapter.out.persistence.repository.FeedJpaRepository; import konkuk.thip.saved.adapter.out.jpa.SavedBookJpaEntity; import konkuk.thip.saved.adapter.out.persistence.repository.SavedBookJpaRepository; -import org.junit.jupiter.api.*; +import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; +import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; +import konkuk.thip.user.adapter.out.jpa.UserRole; +import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.web.servlet.MockMvc; import java.time.LocalDate; @@ -119,7 +122,7 @@ void setup() { void tearDown() { savedBookJpaRepository.deleteAll(); feedJpaRepository.deleteAll(); - roomParticipantJpaRepository.deleteAll(); + roomParticipantJpaRepository.deleteAllInBatch(); roomJpaRepository.deleteAll(); bookJpaRepository.deleteAll(); userJpaRepository.deleteAll(); @@ -150,7 +153,7 @@ void searchDetailBooks_NoRecruitingRooms_ReturnsZero() { BookJpaEntity book = bookJpaRepository.findAll().get(0); // 기존 방 삭제 - roomParticipantJpaRepository.deleteAll(); + roomParticipantJpaRepository.deleteAllInBatch(); roomJpaRepository.deleteAll(); // startDate가 과거인 새로운 방 생성 (모집 중 아님) @@ -179,7 +182,7 @@ void searchDetailBooks_NoFeedOrRoomParticipants_ReturnsZero() { UserJpaEntity user = userJpaRepository.findAll().get(0); feedJpaRepository.deleteAll(); - roomParticipantJpaRepository.deleteAll(); + roomParticipantJpaRepository.deleteAllInBatch(); var result = bookSearchService.searchDetailBooks(isbn, user.getUserId()); assertThat(result.recruitingReadCount()).isEqualTo(0); diff --git a/src/test/java/konkuk/thip/record/adapter/in/web/RecordCreateControllerTest.java b/src/test/java/konkuk/thip/record/adapter/in/web/RecordCreateControllerTest.java index 1c1037fc8..551063a33 100644 --- a/src/test/java/konkuk/thip/record/adapter/in/web/RecordCreateControllerTest.java +++ b/src/test/java/konkuk/thip/record/adapter/in/web/RecordCreateControllerTest.java @@ -74,7 +74,7 @@ class RecordCreateControllerTest { @AfterEach void tearDown() { recordJpaRepository.deleteAll(); - roomParticipantJpaRepository.deleteAll(); + roomParticipantJpaRepository.deleteAllInBatch(); roomJpaRepository.deleteAll(); bookJpaRepository.deleteAll(); categoryJpaRepository.deleteAll(); diff --git a/src/test/java/konkuk/thip/room/adapter/in/web/RoomGetHomeJoinedRoomsApiTest.java b/src/test/java/konkuk/thip/room/adapter/in/web/RoomGetHomeJoinedRoomsApiTest.java index 1c56de3ed..058cdd1e7 100644 --- a/src/test/java/konkuk/thip/room/adapter/in/web/RoomGetHomeJoinedRoomsApiTest.java +++ b/src/test/java/konkuk/thip/room/adapter/in/web/RoomGetHomeJoinedRoomsApiTest.java @@ -93,7 +93,7 @@ void setUp() { @AfterEach void tearDown() { - roomParticipantJpaRepository.deleteAll(); + roomParticipantJpaRepository.deleteAllInBatch(); roomJpaRepository.deleteAll(); bookJpaRepository.deleteAll(); userJpaRepository.deleteAll(); diff --git a/src/test/java/konkuk/thip/room/adapter/in/web/RoomGetMemberListApiTest.java b/src/test/java/konkuk/thip/room/adapter/in/web/RoomGetMemberListApiTest.java index b7b4ffc2e..8f58228f7 100644 --- a/src/test/java/konkuk/thip/room/adapter/in/web/RoomGetMemberListApiTest.java +++ b/src/test/java/konkuk/thip/room/adapter/in/web/RoomGetMemberListApiTest.java @@ -125,7 +125,7 @@ void setUp() { @AfterEach void tearDown() { followingJpaRepository.deleteAllInBatch(); - roomParticipantJpaRepository.deleteAll(); + roomParticipantJpaRepository.deleteAllInBatch(); roomJpaRepository.deleteAll(); bookJpaRepository.deleteAll(); userJpaRepository.deleteAll(); diff --git a/src/test/java/konkuk/thip/room/adapter/in/web/RoomJoinApiTest.java b/src/test/java/konkuk/thip/room/adapter/in/web/RoomJoinApiTest.java index 2e1887dff..80c3a9d9d 100644 --- a/src/test/java/konkuk/thip/room/adapter/in/web/RoomJoinApiTest.java +++ b/src/test/java/konkuk/thip/room/adapter/in/web/RoomJoinApiTest.java @@ -82,8 +82,8 @@ private void createRoom(BookJpaEntity book, CategoryJpaEntity category, int memb .title("방이름") .description("설명") .isPublic(true) - .startDate(LocalDate.now()) - .endDate(LocalDate.now().plusDays(5)) + .startDate(LocalDate.now().plusDays(1)) + .endDate(LocalDate.now().plusDays(30)) .recruitCount(3) .bookJpaEntity(book) .categoryJpaEntity(category) @@ -178,7 +178,7 @@ void cancelJoin_success() throws Exception { // 참여자 삭제 확인 boolean exists = roomParticipantJpaRepository - .existByUserIdAndRoomId(participant.getUserId(), room.getRoomId()) == 1; + .existByUserIdAndRoomId(participant.getUserId(), room.getRoomId()); assertThat(exists).isFalse(); // 인원수 감소 확인 diff --git a/src/test/java/konkuk/thip/room/adapter/in/web/RoomPlayingDetailViewApiTest.java b/src/test/java/konkuk/thip/room/adapter/in/web/RoomPlayingDetailViewApiTest.java index 80e5e1e53..b82f16912 100644 --- a/src/test/java/konkuk/thip/room/adapter/in/web/RoomPlayingDetailViewApiTest.java +++ b/src/test/java/konkuk/thip/room/adapter/in/web/RoomPlayingDetailViewApiTest.java @@ -8,12 +8,14 @@ import konkuk.thip.room.adapter.out.jpa.RoomJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomParticipantJpaEntity; import konkuk.thip.room.adapter.out.jpa.RoomParticipantRole; -import konkuk.thip.room.adapter.out.persistence.repository.category.CategoryJpaRepository; import konkuk.thip.room.adapter.out.persistence.repository.RoomJpaRepository; -import konkuk.thip.user.adapter.out.jpa.*; -import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; -import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; +import konkuk.thip.room.adapter.out.persistence.repository.category.CategoryJpaRepository; import konkuk.thip.room.adapter.out.persistence.repository.roomparticipant.RoomParticipantJpaRepository; +import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; +import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; +import konkuk.thip.user.adapter.out.jpa.UserRole; +import konkuk.thip.user.adapter.out.persistence.repository.UserJpaRepository; +import konkuk.thip.user.adapter.out.persistence.repository.alias.AliasJpaRepository; import konkuk.thip.vote.adapter.out.jpa.VoteItemJpaEntity; import konkuk.thip.vote.adapter.out.jpa.VoteJpaEntity; import konkuk.thip.vote.adapter.out.persistence.repository.VoteItemJpaRepository; @@ -34,7 +36,6 @@ import static konkuk.thip.common.exception.code.ErrorCode.USER_NOT_BELONG_TO_ROOM; import static org.hamcrest.Matchers.*; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -76,7 +77,7 @@ class RoomPlayingDetailViewApiTest { void tearDown() { voteItemJpaRepository.deleteAll(); voteJpaRepository.deleteAll(); - roomParticipantJpaRepository.deleteAll(); + roomParticipantJpaRepository.deleteAllInBatch(); roomJpaRepository.deleteAll(); bookJpaRepository.deleteAll(); userJpaRepository.deleteAll(); @@ -173,7 +174,7 @@ void get_playing_room_detail() throws Exception { //given RoomJpaEntity room = saveScienceRoom("과학-책", "isbn1", "과학-방-1일뒤-활동시작", LocalDate.now().plusDays(1), 10); saveUsersToRoom(room, 4); - RoomParticipantJpaEntity roomParticipantJpaEntity = roomParticipantJpaRepository.findAllByRoomJpaEntity_RoomId(room.getRoomId()).get(0); + RoomParticipantJpaEntity roomParticipantJpaEntity = roomParticipantJpaRepository.findAllByRoomId(room.getRoomId()).get(0); roomParticipantJpaRepository.delete(roomParticipantJpaEntity); RoomParticipantJpaEntity joiningMember = roomParticipantJpaRepository.save(RoomParticipantJpaEntity.builder() .userJpaEntity(roomParticipantJpaEntity.getUserJpaEntity()) @@ -221,7 +222,7 @@ void get_playing_room_detail_host() throws Exception { //given RoomJpaEntity room = saveScienceRoom("과학-책", "isbn1", "과학-방-1일뒤-활동시작", LocalDate.now().plusDays(1), 10); saveUsersToRoom(room, 4); - RoomParticipantJpaEntity roomParticipantJpaEntity = roomParticipantJpaRepository.findAllByRoomJpaEntity_RoomId(room.getRoomId()).get(0); + RoomParticipantJpaEntity roomParticipantJpaEntity = roomParticipantJpaRepository.findAllByRoomId(room.getRoomId()).get(0); roomParticipantJpaRepository.delete(roomParticipantJpaEntity); RoomParticipantJpaEntity roomHost = roomParticipantJpaRepository.save(RoomParticipantJpaEntity.builder() .userJpaEntity(roomParticipantJpaEntity.getUserJpaEntity()) @@ -269,7 +270,7 @@ void get_playing_room_detail_not_belong_to_room() throws Exception { //given RoomJpaEntity room = saveScienceRoom("과학-책", "isbn1", "과학-방-1일뒤-활동시작", LocalDate.now().plusDays(1), 10); saveUsersToRoom(room, 4); - RoomParticipantJpaEntity roomParticipantJpaEntity = roomParticipantJpaRepository.findAllByRoomJpaEntity_RoomId(room.getRoomId()).get(0); + RoomParticipantJpaEntity roomParticipantJpaEntity = roomParticipantJpaRepository.findAllByRoomId(room.getRoomId()).get(0); roomParticipantJpaRepository.delete(roomParticipantJpaEntity); RoomParticipantJpaEntity joiningMember = roomParticipantJpaRepository.save(RoomParticipantJpaEntity.builder() .userJpaEntity(roomParticipantJpaEntity.getUserJpaEntity()) @@ -295,7 +296,7 @@ void get_playing_room_detail_too_many_votes() throws Exception { //given RoomJpaEntity room = saveScienceRoom("과학-책", "isbn1", "과학-방-1일뒤-활동시작", LocalDate.now().plusDays(1), 10); saveUsersToRoom(room, 4); - RoomParticipantJpaEntity roomParticipantJpaEntity = roomParticipantJpaRepository.findAllByRoomJpaEntity_RoomId(room.getRoomId()).get(0); + RoomParticipantJpaEntity roomParticipantJpaEntity = roomParticipantJpaRepository.findAllByRoomId(room.getRoomId()).get(0); roomParticipantJpaRepository.delete(roomParticipantJpaEntity); RoomParticipantJpaEntity joiningMember = roomParticipantJpaRepository.save(RoomParticipantJpaEntity.builder() .userJpaEntity(roomParticipantJpaEntity.getUserJpaEntity()) @@ -347,7 +348,7 @@ void get_playing_room_detail_no_votes() throws Exception { //given RoomJpaEntity room = saveScienceRoom("과학-책", "isbn1", "과학-방-1일뒤-활동시작", LocalDate.now().plusDays(1), 10); saveUsersToRoom(room, 4); - RoomParticipantJpaEntity roomParticipantJpaEntity = roomParticipantJpaRepository.findAllByRoomJpaEntity_RoomId(room.getRoomId()).get(0); + RoomParticipantJpaEntity roomParticipantJpaEntity = roomParticipantJpaRepository.findAllByRoomId(room.getRoomId()).get(0); roomParticipantJpaRepository.delete(roomParticipantJpaEntity); RoomParticipantJpaEntity joiningMember = roomParticipantJpaRepository.save(RoomParticipantJpaEntity.builder() .userJpaEntity(roomParticipantJpaEntity.getUserJpaEntity()) diff --git a/src/test/java/konkuk/thip/room/adapter/in/web/RoomRecruitingDetailViewApiTest.java b/src/test/java/konkuk/thip/room/adapter/in/web/RoomRecruitingDetailViewApiTest.java index 3e2a8c575..397531726 100644 --- a/src/test/java/konkuk/thip/room/adapter/in/web/RoomRecruitingDetailViewApiTest.java +++ b/src/test/java/konkuk/thip/room/adapter/in/web/RoomRecruitingDetailViewApiTest.java @@ -63,7 +63,7 @@ class RoomRecruitingDetailViewApiTest { @AfterEach void tearDown() { - roomParticipantJpaRepository.deleteAll(); + roomParticipantJpaRepository.deleteAllInBatch(); roomJpaRepository.deleteAll(); bookJpaRepository.deleteAll(); userJpaRepository.deleteAll(); @@ -163,7 +163,7 @@ void get_recruiting_room_detail() throws Exception { //given RoomJpaEntity targetRoom = saveScienceRoom("과학-책", "isbn1", "과학-방-1일뒤-활동시작", LocalDate.now().plusDays(1), 10); saveUsersToRoom(targetRoom, 4); - UserJpaEntity joiningUser = roomParticipantJpaRepository.findAllByRoomJpaEntity_RoomId(targetRoom.getRoomId()).get(1).getUserJpaEntity(); + UserJpaEntity joiningUser = roomParticipantJpaRepository.findAllByRoomId(targetRoom.getRoomId()).get(1).getUserJpaEntity(); RoomJpaEntity science_room_2 = saveScienceRoom("과학-책", "isbn2", "방이름입니다", LocalDate.now().plusDays(1), 10); saveUsersToRoom(science_room_2, 5); @@ -211,7 +211,7 @@ void get_recruiting_room_detail_host() throws Exception { //given RoomJpaEntity targetRoom = saveScienceRoom("과학-책", "isbn1", "과학-방-1일뒤-활동시작", LocalDate.now().plusDays(1), 10); saveUsersToRoom(targetRoom, 4); - RoomParticipantJpaEntity firstMember = roomParticipantJpaRepository.findAllByRoomJpaEntity_RoomId(targetRoom.getRoomId()).get(1); + RoomParticipantJpaEntity firstMember = roomParticipantJpaRepository.findAllByRoomId(targetRoom.getRoomId()).get(1); roomParticipantJpaRepository.delete(firstMember); RoomParticipantJpaEntity roomCreator = roomParticipantJpaRepository.save(RoomParticipantJpaEntity.builder() .userJpaEntity(firstMember.getUserJpaEntity()) @@ -264,7 +264,7 @@ void get_recruiting_room_detail_too_many_recommend_rooms() throws Exception { //given RoomJpaEntity targetRoom = saveScienceRoom("과학-책", "isbn1", "과학-방-1일뒤-활동시작", LocalDate.now().plusDays(1), 10); saveUsersToRoom(targetRoom, 4); - UserJpaEntity joiningUser = roomParticipantJpaRepository.findAllByRoomJpaEntity_RoomId(targetRoom.getRoomId()).get(1).getUserJpaEntity(); + UserJpaEntity joiningUser = roomParticipantJpaRepository.findAllByRoomId(targetRoom.getRoomId()).get(1).getUserJpaEntity(); RoomJpaEntity science_room_2 = saveScienceRoom("과학-책", "isbn2", "방이름입니다", LocalDate.now().plusDays(1), 10); saveUsersToRoom(science_room_2, 5); @@ -316,7 +316,7 @@ void get_recruiting_room_detail_no_recommend_rooms() throws Exception { //given RoomJpaEntity targetRoom = saveScienceRoom("과학-책", "isbn1", "과학-방-1일뒤-활동시작", LocalDate.now().plusDays(1), 10); saveUsersToRoom(targetRoom, 4); - UserJpaEntity joiningUser = roomParticipantJpaRepository.findAllByRoomJpaEntity_RoomId(targetRoom.getRoomId()).get(1).getUserJpaEntity(); + UserJpaEntity joiningUser = roomParticipantJpaRepository.findAllByRoomId(targetRoom.getRoomId()).get(1).getUserJpaEntity(); RoomJpaEntity room_3 = saveLiteratureRoom("문학-책", "isbn5", "방제목에-과학-포함된-문학방", LocalDate.now().plusDays(10), 8); saveUsersToRoom(room_3, 6); diff --git a/src/test/java/konkuk/thip/room/adapter/in/web/RoomSearchApiTest.java b/src/test/java/konkuk/thip/room/adapter/in/web/RoomSearchApiTest.java index 1ff8b70cb..94eccf5e4 100644 --- a/src/test/java/konkuk/thip/room/adapter/in/web/RoomSearchApiTest.java +++ b/src/test/java/konkuk/thip/room/adapter/in/web/RoomSearchApiTest.java @@ -62,7 +62,7 @@ class RoomSearchApiTest { @AfterEach void tearDown() { - roomParticipantJpaRepository.deleteAll(); + roomParticipantJpaRepository.deleteAllInBatch(); roomJpaRepository.deleteAll(); bookJpaRepository.deleteAll(); userJpaRepository.deleteAll(); diff --git a/src/test/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntityTest.java b/src/test/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntityTest.java index fdc7b5c19..7d5194580 100644 --- a/src/test/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntityTest.java +++ b/src/test/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntityTest.java @@ -43,7 +43,8 @@ class RoomJpaEntityTest { @DisplayName("RoomJpaEntity 저장 및 조회 테스트") void saveAndFindRoom() { // given - BookJpaEntity book = bookRepository.save(TestEntityFactory.createBook()); + String isbn = "1234567890"; + BookJpaEntity book = bookRepository.save(TestEntityFactory.createBookWithISBN(isbn)); AliasJpaEntity alias = aliasRepository.save(TestEntityFactory.createLiteratureAlias()); CategoryJpaEntity category = categoryRepository.save(TestEntityFactory.createLiteratureCategory(alias)); RoomJpaEntity room = roomRepository.save(TestEntityFactory.createRoom(book, category)); @@ -61,6 +62,6 @@ void saveAndFindRoom() { assertThat(foundRoom.getRecruitCount()).isEqualTo(3); assertThat(foundRoom.getBookJpaEntity().getTitle()).isEqualTo("책제목"); assertThat(foundRoom.getBookJpaEntity().getAuthorName()).isEqualTo("저자"); - assertThat(foundRoom.getBookJpaEntity().getIsbn()).isEqualTo("isbn"); + assertThat(foundRoom.getBookJpaEntity().getIsbn()).isEqualTo(isbn); } } \ No newline at end of file