From 51cdc822aa00def185d586c19e9450f5848d079c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=EC=98=88=EC=A7=84?= <96688810+kwonyj1022@users.noreply.github.com> Date: Wed, 11 Oct 2023 15:55:54 +0900 Subject: [PATCH 01/37] =?UTF-8?q?comment:=20#617=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20todo=20=EC=82=AD=EC=A0=9C=20(#618)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../persistence/dto/AuctionAndImageQueryProjectionDto.java | 1 - .../auction/presentation/dto/response/ReadAuctionResponse.java | 1 - .../persistence/dto/ChatRoomAndImageQueryProjectionDto.java | 1 - .../dto/ChatRoomAndMessageAndImageQueryProjectionDto.java | 1 - .../src/main/java/com/ddang/ddang/image/domain/AuctionImage.java | 1 - .../notification/application/util/NotificationProperty.java | 1 - .../java/com/ddang/ddang/bid/presentation/BidControllerTest.java | 1 - 7 files changed, 7 deletions(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/dto/AuctionAndImageQueryProjectionDto.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/dto/AuctionAndImageQueryProjectionDto.java index 85300e897..80b2e77e1 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/dto/AuctionAndImageQueryProjectionDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/dto/AuctionAndImageQueryProjectionDto.java @@ -10,7 +10,6 @@ public record AuctionAndImageQueryProjectionDto(Auction auction, AuctionImage au public AuctionAndImageQueryProjectionDto { } - // TODO: 2023/09/22 dto이름 정해지면 명확한 dto이름으로 바꾸기 public AuctionAndImageDto toDto() { return new AuctionAndImageDto(this.auction, this.auctionImage); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadAuctionResponse.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadAuctionResponse.java index a11aaaf06..4eee887ff 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadAuctionResponse.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadAuctionResponse.java @@ -4,7 +4,6 @@ import com.ddang.ddang.image.presentation.util.ImageRelativeUrl; import com.ddang.ddang.image.presentation.util.ImageUrlCalculator; -// TODO: 9/29/23 추후 대표 이미지 관련 필드 추가 public record ReadAuctionResponse( Long id, String title, diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndImageQueryProjectionDto.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndImageQueryProjectionDto.java index 4e52de7c8..dd320738c 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndImageQueryProjectionDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndImageQueryProjectionDto.java @@ -6,7 +6,6 @@ public record ChatRoomAndImageQueryProjectionDto(ChatRoom chatRoom, AuctionImage auctionImage) { - // TODO: 2023/09/19 네이밍 컨벤션 회의 후 리팩토링 예정 @QueryProjection public ChatRoomAndImageQueryProjectionDto { } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndMessageAndImageQueryProjectionDto.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndMessageAndImageQueryProjectionDto.java index a20e2b827..5776bd1fc 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndMessageAndImageQueryProjectionDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndMessageAndImageQueryProjectionDto.java @@ -7,7 +7,6 @@ public record ChatRoomAndMessageAndImageQueryProjectionDto(ChatRoom chatRoom, Message message, AuctionImage auctionImage) { - // TODO: 2023/09/19 네이밍 컨벤션 회의 후 리팩토링 예정 @QueryProjection public ChatRoomAndMessageAndImageQueryProjectionDto { } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/image/domain/AuctionImage.java b/backend/ddang/src/main/java/com/ddang/ddang/image/domain/AuctionImage.java index dcc81b34b..a937fd272 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/image/domain/AuctionImage.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/image/domain/AuctionImage.java @@ -21,7 +21,6 @@ @Getter @EqualsAndHashCode(of = "id") @ToString(of = {"id", "image", "authenticated"}) -// TODO: 9/29/23 추후 대표 이미지 구분을 위한 필드 추가 public class AuctionImage { @Id diff --git a/backend/ddang/src/main/java/com/ddang/ddang/notification/application/util/NotificationProperty.java b/backend/ddang/src/main/java/com/ddang/ddang/notification/application/util/NotificationProperty.java index 7b8c8ac3a..326cc2082 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/notification/application/util/NotificationProperty.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/notification/application/util/NotificationProperty.java @@ -2,7 +2,6 @@ import lombok.Getter; -// TODO: 2023/09/30 안드로이드분들께 image -> imageUrl로 변경 가능한지 여쭤보기 @Getter public enum NotificationProperty { diff --git a/backend/ddang/src/test/java/com/ddang/ddang/bid/presentation/BidControllerTest.java b/backend/ddang/src/test/java/com/ddang/ddang/bid/presentation/BidControllerTest.java index 13b617c15..5a37badd4 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/bid/presentation/BidControllerTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/bid/presentation/BidControllerTest.java @@ -99,7 +99,6 @@ void setUp() { create_문서화(resultActions); } - // TODO: 2023-08-06 예외 케이스 api 문서화의 경우 예외에 대한 변경이 없을 때 추가할 것 @Test void 해당_경매가_없는_경우_입찰시_404를_반환한다() throws Exception { // given From 29d58db801092495a8a72502f716a8922b8593c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=EC=98=88=EC=A7=84?= <96688810+kwonyj1022@users.noreply.github.com> Date: Thu, 12 Oct 2023 13:56:33 +0900 Subject: [PATCH 02/37] =?UTF-8?q?cd:=20#619=20=EC=9A=B4=EC=98=81=20?= =?UTF-8?q?=EC=84=9C=EB=B2=84=20=EB=B0=B0=ED=8F=AC=20=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A6=BD=ED=8A=B8=EC=97=90=20=EB=AC=B4=EC=A4=91=EB=8B=A8=20?= =?UTF-8?q?=EB=B0=B0=ED=8F=AC=20=EC=A0=81=EC=9A=A9=20(#624)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/ddang/script/prod-deploy-script.sh | 65 +++++++++++++++++++--- 1 file changed, 57 insertions(+), 8 deletions(-) diff --git a/backend/ddang/script/prod-deploy-script.sh b/backend/ddang/script/prod-deploy-script.sh index c60842338..70da32af3 100644 --- a/backend/ddang/script/prod-deploy-script.sh +++ b/backend/ddang/script/prod-deploy-script.sh @@ -4,17 +4,66 @@ ABSPATH=$(readlink -f $0) # /home/ubuntu/prod-deploy-script.sh ABSDIR=$(dirname $ABSPATH) # /home/ubuntu APPNAME="ddang-0.0.1-SNAPSHOT" APPDIR=${ABSDIR}/${APPNAME} # /home/ubuntu/ddang-0.0.1-SNAPSHOT +PORT_A=8080 +PORT_B=8081 +DEFAULT_ACTUATOR_PORT=$DEFAULT_ACTUATOR_PORT -echo "구동중인 애플리케이션을 확인합니다." +if curl -s "http://localhost:${PORT_A}" > /dev/null +then + green_port=${PORT_B} + blue_port=${PORT_A} +else + green_port=${PORT_A} + blue_port=${PORT_B} +fi -CURRENT_PID=$(pgrep -f ${APPNAME}.jar) # ddang-0.0.1-SNAPSHOT.jar +if curl -s "http://localhost:${green_port}" > /dev/null +then + echo "그린 서버가 이미 동작 중입니다." + exit 255 +fi -if [ ! -z ${CURRENT_PID} ]; then - echo "기존 애플리케이션이 실행중이므로 종료합니다." - kill -15 ${CURRENT_PID} - sleep 5 +if curl -s "http://localhost:${DEFAULT_ACTUATOR_PORT}" > /dev/null +then + actuator_port=${ANOTHER_ACTUATOR_PORT} +else + actuator_port=${DEFAULT_ACTUATOR_PORT} fi -echo "애플리케이션을 실행합니다." +echo "그린 서버를 실행합니다. port number: ${green_port}" + +nohup java -jar ${ABSDIR}/${APPNAME}.jar --server.port=${green_port} --spring.profiles.active=prod --management.server.port=${actuator_port} 1>> prod.log 2>> prod_error.log & # /home/ubuntu/ddang-0.0.1-SNAPSHOT.jar + +for retry_count in $(seq 10) +do + if curl -s "http://localhost:${green_port}" > /dev/null + then + echo "Health check success ✅ port number: ${green_port}" + break + fi + + if [ $retry_count -eq 10 ] + then + echo "Health check failed ❌ port number: ${green_port}" + exit 1 + fi -nohup java -jar ${ABSDIR}/${APPNAME}.jar --spring.profiles.active=prod 1>> prod.log 2>> prod_error.log & # /home/ubuntu/ddang-0.0.1-SNAPSHOT.jar + echo "서버가 아직 실행되지 않았습니다... 시도 횟수: ${retry_count}" + sleep 10 +done + +echo "set \$service_port ${green_port};" | sudo tee /etc/nginx/conf.d/service-port.inc +echo "set \$actuator_port ${actuator_port};" | sudo tee /etc/nginx/conf.d/actuator-port.inc +sudo systemctl restart nginx + +echo "블루 서버를 종료합니다. port number: ${blue_port}" +fuser -s -k ${blue_port}/tcp + +if curl -s "http://localhost:${blue_port}" > /dev/null +then + echo "블루 서버가 아직 종료되지 않았습니다... 시도 횟수: ${blue_port}" + sleep 10 +else + echo "블루 서버가 종료되었습니다. port number: ${blue_port}" + break; +fi From fdcaeb2e6470b62f7763d7cc9d283645f08153e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=EC=98=88=EC=A7=84?= <96688810+kwonyj1022@users.noreply.github.com> Date: Thu, 12 Oct 2023 16:08:53 +0900 Subject: [PATCH 03/37] =?UTF-8?q?feat:=20#603=20=EA=B2=BD=EB=A7=A4=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=20=EC=A1=B0=ED=9A=8C=20=EC=8B=9C=20=EA=B2=BD?= =?UTF-8?q?=EB=A7=A4=EA=B8=80=EC=9D=84=20=EC=B0=BE=EC=9D=84=20=EC=88=98=20?= =?UTF-8?q?=EC=97=86=EC=9D=84=20=EB=95=8C=EB=A7=8C=20404=EB=A5=BC=20?= =?UTF-8?q?=EB=B3=B4=EB=82=B4=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95=20(#6?= =?UTF-8?q?04)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 경매 상세 조회 시 경매글을 찾을 수 없을 때만 404를 보내도록 수정 * refactor: 빈 유저와 빈 경매 상수 추가 및 적용 * refactor: 지정한 경매 아이디와 관련된 채팅방을 조회할 때 경매를 찾을 수 없을 때 예외를 던지도록 다시 변경 * test: 테스트 메서드 이름 명확하게 변경 --- .../auction/application/dto/ReadChatRoomDto.java | 2 ++ .../ddang/chat/application/ChatRoomService.java | 7 ++++++- .../main/java/com/ddang/ddang/user/domain/User.java | 1 + .../ddang/chat/application/ChatRoomServiceTest.java | 13 +++++++------ .../application/fixture/ChatRoomServiceFixture.java | 2 ++ 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/application/dto/ReadChatRoomDto.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/application/dto/ReadChatRoomDto.java index 173ad3596..42125823c 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/application/dto/ReadChatRoomDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/application/dto/ReadChatRoomDto.java @@ -1,4 +1,6 @@ package com.ddang.ddang.auction.application.dto; public record ReadChatRoomDto(Long id, boolean isChatParticipant) { + + public static ReadChatRoomDto CANNOT_CHAT_DTO = new ReadChatRoomDto(null, false); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java index d723e9f84..abeea1041 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java @@ -115,11 +115,16 @@ private void checkAccessible(final User findUser, final ChatRoom chatRoom) { public ReadChatRoomDto readChatInfoByAuctionId(final Long auctionId, final AuthenticationUserInfo userInfo) { final User findUser = userRepository.findById(userInfo.userId()) - .orElseThrow(() -> new UserNotFoundException("회원 정보를 찾을 수 없습니다.")); + .orElse(User.EMPTY_USER); final Auction findAuction = auctionRepository.findAuctionById(auctionId) .orElseThrow(() -> new AuctionNotFoundException( "지정한 아이디에 대한 경매를 찾을 수 없습니다." )); + + if (findUser == User.EMPTY_USER) { + return ReadChatRoomDto.CANNOT_CHAT_DTO; + } + final Long chatRoomId = chatRoomRepository.findChatRoomIdByAuctionId(findAuction.getId()) .orElse(DEFAULT_CHAT_ROOM_ID); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/User.java b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/User.java index b6bcf6278..2bee553ec 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/User.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/User.java @@ -33,6 +33,7 @@ @Table(name = "users") public class User extends BaseTimeEntity { + public static final User EMPTY_USER = null; private static final boolean DELETED_STATUS = true; private static final String UNKOWN_NAME = "알 수 없음"; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java index 4ce53a7a7..de0cccb21 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/ChatRoomServiceTest.java @@ -164,11 +164,12 @@ class ChatRoomServiceTest extends ChatRoomServiceFixture { } @Test - void 지정한_경매_아이디와_관련된_채팅방을_조회할_때_조회를_요청한_사용자_정보를_찾을_수_없다면_예외가_발생한다() { - // when & then - assertThatThrownBy(() -> chatRoomService.readChatInfoByAuctionId(판매자_엔초_구매자_지토_경매.getId(), 존재하지_않는_사용자_정보)) - .isInstanceOf(UserNotFoundException.class) - .hasMessage("회원 정보를 찾을 수 없습니다."); + void 지정한_경매_아이디와_관련된_채팅방을_조회할_때_조회를_요청한_사용자_정보를_찾을_수_없다면_무조건_채팅방_아이디_null과_참여가능여부_거짓을_반환한다() { + // when + final ReadChatRoomDto actual = chatRoomService.readChatInfoByAuctionId(판매자_엔초_구매자_지토_경매.getId(), 존재하지_않는_사용자_정보); + + // then + assertThat(actual).isEqualTo(채팅방_없고_참여_불가능); } @Test @@ -180,7 +181,7 @@ class ChatRoomServiceTest extends ChatRoomServiceFixture { } @Test - void 지정한_경매_아이디와_관련된_채팅방을_조회할_때_채팅방을_찾을_수_없다면_채팅방_아이디_null과_참여가능여부를_반환한다() { + void 지정한_경매_아이디와_관련된_채팅방을_조회할_때_채팅방을_찾을_수_없다면_채팅방_아이디_null과_참여가능을_반환한다() { // when final ReadChatRoomDto actual = chatRoomService.readChatInfoByAuctionId(채팅방이_없는_경매.getId(), 판매자_회원_정보); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java index 9d3adcd1d..1ec29707a 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java @@ -82,6 +82,7 @@ public class ChatRoomServiceFixture { protected ReadChatRoomDto 엔초_지토_채팅방_정보_및_참여_가능; protected ReadChatRoomDto 엔초_지토_채팅방_정보_및_참여_불가능; protected ReadChatRoomDto 채팅방은_아직_없지만_참여_가능; + protected ReadChatRoomDto 채팅방_없고_참여_불가능; protected ReadChatRoomWithLastMessageDto 엔초_채팅_목록의_제이미_엔초_채팅방_정보; protected ReadChatRoomWithLastMessageDto 엔초_채팅_목록의_엔초_지토_채팅방_정보; @@ -233,6 +234,7 @@ void setUp() { 엔초_지토_채팅방_정보_및_참여_가능 = new ReadChatRoomDto(엔초_지토_채팅방.getId(), true); 엔초_지토_채팅방_정보_및_참여_불가능 = new ReadChatRoomDto(엔초_지토_채팅방.getId(), false); 채팅방은_아직_없지만_참여_가능 = new ReadChatRoomDto(null, true); + 채팅방_없고_참여_불가능 = new ReadChatRoomDto(null, false); 엔초_채팅_목록의_제이미_엔초_채팅방_정보 = new ReadChatRoomWithLastMessageDto( 제이미_엔초_채팅방.getId(), ReadAuctionInChatRoomDto.of(판매자_제이미_구매자_엔초_경매, 제이미의_경매_대표_이미지), From fe25e4a9e61b24b29a08c810b0eacd42d9b9b55e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=8A=B9=EC=9B=90=20Merry?= Date: Thu, 12 Oct 2023 20:35:31 +0900 Subject: [PATCH 04/37] =?UTF-8?q?fix:=20=EB=A9=94=EC=8B=9C=EC=A7=80=20?= =?UTF-8?q?=EC=A0=84=EC=86=A1=20=EC=8B=9C=20=EC=9E=91=EC=84=B1=EC=9E=90=20?= =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=EA=B0=80=20=EC=A0=84=EC=86=A1?= =?UTF-8?q?=EB=90=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95=20(#634)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notification/application/NotificationEventListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/notification/application/NotificationEventListener.java b/backend/ddang/src/main/java/com/ddang/ddang/notification/application/NotificationEventListener.java index d75990490..345db4213 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/notification/application/NotificationEventListener.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/notification/application/NotificationEventListener.java @@ -32,7 +32,7 @@ public class NotificationEventListener { public void sendMessageNotification(final MessageNotificationEvent messageNotificationEvent) { try { final MessageDto messageDto = messageNotificationEvent.messageDto(); - final ProfileImage profileImage = messageDto.receiver().getProfileImage(); + final ProfileImage profileImage = messageDto.writer().getProfileImage(); final CreateNotificationDto createNotificationDto = new CreateNotificationDto( NotificationType.MESSAGE, messageDto.receiver().getId(), From c2ab4b35196790804c29c69e9bbb2b977eb1175b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=EC=98=88=EC=A7=84?= <96688810+kwonyj1022@users.noreply.github.com> Date: Thu, 12 Oct 2023 21:07:08 +0900 Subject: [PATCH 05/37] =?UTF-8?q?!hotfix:=20actuator=20=EA=B4=80=EB=A0=A8?= =?UTF-8?q?=20=EB=B3=80=EC=88=98=20=EC=B6=94=EA=B0=80=20(#636)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/ddang/script/prod-deploy-script.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/ddang/script/prod-deploy-script.sh b/backend/ddang/script/prod-deploy-script.sh index 70da32af3..33633d132 100644 --- a/backend/ddang/script/prod-deploy-script.sh +++ b/backend/ddang/script/prod-deploy-script.sh @@ -7,6 +7,7 @@ APPDIR=${ABSDIR}/${APPNAME} # /home/ubuntu/ddang-0.0.1-SNAPSHOT PORT_A=8080 PORT_B=8081 DEFAULT_ACTUATOR_PORT=$DEFAULT_ACTUATOR_PORT +ANOTHER_ACTUATOR_PORT=$ANOTHER_ACTUATOR_PORT if curl -s "http://localhost:${PORT_A}" > /dev/null then From 08c40c9aca71080084fd61e9beed786bb07a9372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=EC=98=88=EC=A7=84?= <96688810+kwonyj1022@users.noreply.github.com> Date: Thu, 12 Oct 2023 21:50:01 +0900 Subject: [PATCH 06/37] =?UTF-8?q?fix:=20actuator=20=EB=B3=80=EC=88=98=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20(#638)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/ddang/script/prod-deploy-script.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/ddang/script/prod-deploy-script.sh b/backend/ddang/script/prod-deploy-script.sh index 33633d132..e96342c60 100644 --- a/backend/ddang/script/prod-deploy-script.sh +++ b/backend/ddang/script/prod-deploy-script.sh @@ -6,8 +6,8 @@ APPNAME="ddang-0.0.1-SNAPSHOT" APPDIR=${ABSDIR}/${APPNAME} # /home/ubuntu/ddang-0.0.1-SNAPSHOT PORT_A=8080 PORT_B=8081 -DEFAULT_ACTUATOR_PORT=$DEFAULT_ACTUATOR_PORT -ANOTHER_ACTUATOR_PORT=$ANOTHER_ACTUATOR_PORT +DEFAULT_ACTUATOR_PORT=3000 +ANOTHER_ACTUATOR_PORT=3001 if curl -s "http://localhost:${PORT_A}" > /dev/null then From 282e9a6e1e2d7f686d958499ab23f061ce055c72 Mon Sep 17 00:00:00 2001 From: apptie <57691173+apptie@users.noreply.github.com> Date: Fri, 13 Oct 2023 10:01:37 +0900 Subject: [PATCH 07/37] =?UTF-8?q?refactor:=20#605=20=EA=B2=BD=EB=A7=A4=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=EC=8B=9C=20=EB=A7=88?= =?UTF-8?q?=EA=B0=90=EB=90=9C=20=EA=B2=BD=EB=A7=A4=EC=9D=98=20=EC=A0=95?= =?UTF-8?q?=EB=A0=AC=20=EC=88=9C=EC=84=9C=EB=A5=BC=20=ED=9B=84=EC=88=9C?= =?UTF-8?q?=EC=9C=84=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20(#608)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 경매 목록 조회 시 마감된 경매의 정렬 순서를 후순위로 변경 * test: 정렬 조건 변경으로 인한 테스트 케이스 변경 * refactor: 복잡하지 않은 쿼리를 querydsl로 표현하지 않고 JPQL로 표현 * refactor: left outer join이 필요하지 않은 경우를 inner join으로 변경 * refactor: 모든 관계를 fetch join하는 Auction 조회 메서드 네이밍 변경 * feat: Auction만을 조회하는 메서드 추가 * refactor: Auction의 정보만이 필요한 비즈니스 로직에서 fetch join을 하지 않도록 변경 * chore: 배포 스크립트 의미 없는 break 키워드 삭제 --- backend/ddang/script/prod-deploy-script.sh | 1 - .../auction/application/AuctionService.java | 4 +- .../persistence/JpaAuctionRepository.java | 19 +++- .../QuerydslAuctionRepository.java | 3 - .../QuerydslAuctionRepositoryImpl.java | 38 +++----- .../chat/application/ChatRoomService.java | 4 +- .../qna/application/QuestionService.java | 2 +- .../fixture/AuctionServiceFixture.java | 5 + ...onForListSearchByTitleAndSortByIdTest.java | 28 +++--- .../AuctionForListSearchByTitleTest.java | 28 +++--- .../AuctionForListSortByIdTest.java | 32 +++---- .../persistence/JpaAuctionRepositoryTest.java | 36 ++++++-- ...dslAuctionRepositoryImplForObjectTest.java | 78 ---------------- ...orListSearchByTitleAndSortByIdFixture.java | 56 +++++------ .../AuctionForListSearchByTitleFixture.java | 56 +++++------ .../AuctionForListSortByIdFixture.java | 64 ++++++------- .../fixture/JpaAuctionRepositoryFixture.java | 92 +++++++++++++++---- ...slAuctionRepositoryImplForListFixture.java | 26 +++++- .../fixture/QuestionServiceFixture.java | 30 ++++++ 19 files changed, 324 insertions(+), 278 deletions(-) delete mode 100644 backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepositoryImplForObjectTest.java diff --git a/backend/ddang/script/prod-deploy-script.sh b/backend/ddang/script/prod-deploy-script.sh index e96342c60..4bc7e9f00 100644 --- a/backend/ddang/script/prod-deploy-script.sh +++ b/backend/ddang/script/prod-deploy-script.sh @@ -66,5 +66,4 @@ then sleep 10 else echo "블루 서버가 종료되었습니다. port number: ${blue_port}" - break; fi diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/application/AuctionService.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/application/AuctionService.java index 725365c48..1131ec206 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/application/AuctionService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/application/AuctionService.java @@ -79,7 +79,7 @@ private void validateAuctionRegions(final List thirdRegions) { } public ReadAuctionDto readByAuctionId(final Long auctionId) { - final Auction findAuction = auctionRepository.findAuctionById(auctionId) + final Auction findAuction = auctionRepository.findTotalAuctionById(auctionId) .orElseThrow(() -> new AuctionNotFoundException( "지정한 아이디에 대한 경매를 찾을 수 없습니다." )); @@ -112,7 +112,7 @@ public ReadAuctionsDto readAllByBidderId(final Long userId, final Pageable pagea @Transactional public void deleteByAuctionId(final Long auctionId, final Long userId) { - final Auction auction = auctionRepository.findAuctionById(auctionId) + final Auction auction = auctionRepository.findTotalAuctionById(auctionId) .orElseThrow(() -> new AuctionNotFoundException( "지정한 아이디에 대한 경매를 찾을 수 없습니다." )); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepository.java index bc6352f8c..184a21853 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepository.java @@ -4,8 +4,25 @@ import org.springframework.data.jpa.repository.JpaRepository; import java.util.Optional; +import org.springframework.data.jpa.repository.Query; public interface JpaAuctionRepository extends JpaRepository, QuerydslAuctionRepository, QuerydslAuctionAndImageRepository { - Optional findByIdAndDeletedIsFalse(final Long id); + @Query(""" + SELECT a + FROM Auction a + LEFT JOIN FETCH a.auctionRegions ar + LEFT JOIN FETCh ar.thirdRegion tr + LEFT JOIN FETCH tr.firstRegion + LEFT JOIN FETCH tr.secondRegion + LEFT JOIN FETCH a.lastBid + JOIN FETCH a.subCategory sc + JOIN FETCH sc.mainCategory + JOIN FETCH a.seller + WHERE a.deleted = false AND a.id = :id + """) + Optional findTotalAuctionById(final Long id); + + @Query("SELECT a FROM Auction a WHERE a.deleted = false AND a.id = :id") + Optional findPureAuctionById(final Long id); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepository.java index 593ae4257..53bf948c2 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepository.java @@ -2,7 +2,6 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.presentation.dto.request.ReadAuctionSearchCondition; -import java.util.Optional; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; @@ -13,8 +12,6 @@ Slice findAuctionsAllByCondition( final ReadAuctionSearchCondition readAuctionSearchCondition ); - Optional findAuctionById(final Long auctionId); - Slice findAuctionsAllByUserId(final Long userId, final Pageable pageable); Slice findAuctionsAllByBidderId(final Long bidderId, final Pageable pageable); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepositoryImpl.java index d6a9aa6e0..b859bdc0e 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepositoryImpl.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepositoryImpl.java @@ -19,7 +19,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; @@ -51,8 +50,10 @@ public Slice findAuctionsAllByCondition( } private List> calculateOrderSpecifiers(final Pageable pageable) { - final List> orderSpecifiers = new ArrayList<>(processOrderSpecifiers(pageable)); + final List> orderSpecifiers = new ArrayList<>(); + orderSpecifiers.add(closingTimeOrderSpecifier()); + orderSpecifiers.addAll(processOrderSpecifiers(pageable)); orderSpecifiers.add(auction.id.desc()); return orderSpecifiers; @@ -67,21 +68,21 @@ private List> processOrderSpecifiers(final Pageable pageable) return Collections.emptyList(); } - orderSpecifiers.addAll(processOrderSpecifierByCondition(order)); + orderSpecifiers.add(processOrderSpecifierByCondition(order)); } return orderSpecifiers; } - private List> processOrderSpecifierByCondition(final Order order) { + private OrderSpecifier processOrderSpecifierByCondition(final Order order) { if (AuctionSortConditionConsts.RELIABILITY.equals(order.getProperty())) { - return List.of(closingTimeOrderSpecifier(), auction.seller.reliability.value.desc()); + return auction.seller.reliability.value.desc(); } if (AuctionSortConditionConsts.AUCTIONEER_COUNT.equals(order.getProperty())) { - return List.of(closingTimeOrderSpecifier(), auction.auctioneerCount.desc()); + return auction.auctioneerCount.desc(); } if (AuctionSortConditionConsts.CLOSING_TINE.equals(order.getProperty())) { - return List.of(closingTimeOrderSpecifier(), auction.closingTime.asc()); + return auction.closingTime.asc(); } throw new UnsupportedSortConditionException("지원하지 않는 정렬 방식입니다."); @@ -143,32 +144,15 @@ private List findAuctionsByIdsAndOrderSpecifiers( .leftJoin(auctionRegion.thirdRegion, region).fetchJoin() .leftJoin(region.firstRegion).fetchJoin() .leftJoin(region.secondRegion).fetchJoin() - .leftJoin(auction.subCategory, category).fetchJoin() - .leftJoin(category.mainCategory).fetchJoin() - .leftJoin(auction.seller).fetchJoin() .leftJoin(auction.lastBid).fetchJoin() + .join(auction.subCategory, category).fetchJoin() + .join(category.mainCategory).fetchJoin() + .join(auction.seller).fetchJoin() .where(auction.id.in(targetIds.toArray(Long[]::new))) .orderBy(orderSpecifiers.toArray(OrderSpecifier[]::new)) .fetch(); } - @Override - public Optional findAuctionById(final Long auctionId) { - final Auction findAuction = queryFactory.selectFrom(auction) - .leftJoin(auction.auctionRegions, auctionRegion).fetchJoin() - .leftJoin(auctionRegion.thirdRegion, region).fetchJoin() - .leftJoin(region.firstRegion).fetchJoin() - .leftJoin(region.secondRegion).fetchJoin() - .leftJoin(auction.subCategory, category).fetchJoin() - .leftJoin(category.mainCategory).fetchJoin() - .leftJoin(auction.seller).fetchJoin() - .leftJoin(auction.lastBid).fetchJoin() - .where(auction.deleted.isFalse(), auction.id.eq(auctionId)) - .fetchOne(); - - return Optional.ofNullable(findAuction); - } - @Override public Slice findAuctionsAllByUserId(final Long userId, final Pageable pageable) { final List booleanExpressions = List.of( diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java index abeea1041..168736232 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java @@ -45,7 +45,7 @@ public class ChatRoomService { public Long create(final Long userId, final CreateChatRoomDto chatRoomDto) { final User findUser = userRepository.findById(userId) .orElseThrow(() -> new UserNotFoundException("사용자 정보를 찾을 수 없습니다.")); - final Auction findAuction = auctionRepository.findAuctionById(chatRoomDto.auctionId()) + final Auction findAuction = auctionRepository.findTotalAuctionById(chatRoomDto.auctionId()) .orElseThrow(() -> new AuctionNotFoundException("해당 경매를 찾을 수 없습니다.") ); @@ -116,7 +116,7 @@ private void checkAccessible(final User findUser, final ChatRoom chatRoom) { public ReadChatRoomDto readChatInfoByAuctionId(final Long auctionId, final AuthenticationUserInfo userInfo) { final User findUser = userRepository.findById(userInfo.userId()) .orElse(User.EMPTY_USER); - final Auction findAuction = auctionRepository.findAuctionById(auctionId) + final Auction findAuction = auctionRepository.findTotalAuctionById(auctionId) .orElseThrow(() -> new AuctionNotFoundException( "지정한 아이디에 대한 경매를 찾을 수 없습니다." )); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java index e2462238f..50f9dd2a5 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java @@ -34,7 +34,7 @@ public class QuestionService { public Long create(final CreateQuestionDto questionDto) { final User questioner = userRepository.findByIdAndDeletedIsFalse(questionDto.userId()) .orElseThrow(() -> new UserNotFoundException("해당 사용자를 찾을 수 없습니다.")); - final Auction auction = auctionRepository.findByIdAndDeletedIsFalse(questionDto.auctionId()) + final Auction auction = auctionRepository.findPureAuctionById(questionDto.auctionId()) .orElseThrow(() -> new AuctionNotFoundException("해당 경매를 찾을 수 없습니다.")); checkInvalidAuction(auction); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/application/fixture/AuctionServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/application/fixture/AuctionServiceFixture.java index 271e86d44..d0324cc7a 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/application/fixture/AuctionServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/application/fixture/AuctionServiceFixture.java @@ -10,6 +10,7 @@ import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.image.domain.dto.StoreImageDto; +import com.ddang.ddang.region.domain.AuctionRegion; import com.ddang.ddang.region.domain.Region; import com.ddang.ddang.region.infrastructure.persistence.JpaRegionRepository; import com.ddang.ddang.user.domain.Reliability; @@ -217,6 +218,10 @@ void setUp() { 구매자가_입찰한_경매1.updateLastBid(구매자가_입찰한_경매1_입찰); 구매자가_입찰한_경매2.updateLastBid(구매자가_입찰한_경매2_입찰); + 구매자가_입찰한_경매1.addAuctionRegions(List.of(new AuctionRegion(역삼동))); + 구매자가_입찰한_경매2.addAuctionRegions(List.of(new AuctionRegion(역삼동))); + 종료되는_날이_3일_뒤인_경매.addAuctionRegions(List.of(new AuctionRegion(역삼동))); + 종료된_경매.addAuctionRegions(List.of(new AuctionRegion(역삼동))); auctionRepository.saveAll(List.of(구매자가_입찰한_경매1, 구매자가_입찰한_경매2, 종료되는_날이_3일_뒤인_경매, 종료된_경매)); } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleAndSortByIdTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleAndSortByIdTest.java index cbc0926b8..da1762e59 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleAndSortByIdTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleAndSortByIdTest.java @@ -40,9 +40,9 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { // then SoftAssertions.assertSoftly(softAssertions -> { softAssertions.assertThat(actual).hasSize(3); - softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(첫번째_페이지_인덱스_0_id_16); - softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(첫번째_페이지_인덱스_1_id_15); - softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(첫번째_페이지_인덱스_2_id_14); + softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(첫번째_페이지_인덱스_0_4일_후_마감_id_15); + softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(첫번째_페이지_인덱스_1_4일_후_마감_id_14); + softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(첫번째_페이지_인덱스_2_4일_후_마감_id_12); softAssertions.assertThat(actual.hasNext()).isTrue(); }); } @@ -58,9 +58,9 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { // then SoftAssertions.assertSoftly(softAssertions -> { softAssertions.assertThat(actual).hasSize(3); - softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(두번째_페이지_인덱스_0_id_13); - softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(두번째_페이지_인덱스_1_id_12); - softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(두번째_페이지_인덱스_2_id_11); + softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(두번째_페이지_인덱스_0_4일_후_마감_id_11); + softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(두번째_페이지_인덱스_1_4일_후_마감_id_10); + softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(두번째_페이지_인덱스_2_2일_후_마감_id_4); softAssertions.assertThat(actual.hasNext()).isTrue(); }); } @@ -76,9 +76,9 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { // then SoftAssertions.assertSoftly(softAssertions -> { softAssertions.assertThat(actual).hasSize(3); - softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(세번째_페이지_인덱스_0_id_10); - softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(세번째_페이지_인덱스_1_id_9); - softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(세번째_페이지_인덱스_2_id_8); + softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(세번째_페이지_인덱스_0_3일_후_마감_id_3); + softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(세번째_페이지_인덱스_1_4일_후_마감_id_2); + softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(세번째_페이지_인덱스_2_4일_전_마감_id_16); softAssertions.assertThat(actual.hasNext()).isTrue(); }); } @@ -94,9 +94,9 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { // then SoftAssertions.assertSoftly(softAssertions -> { softAssertions.assertThat(actual).hasSize(3); - softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(네번째_페이지_인덱스_0_id_7); - softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(네번째_페이지_인덱스_1_id_4); - softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(네번째_페이지_인덱스_2_id_3); + softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(네번째_페이지_인덱스_0_4일_전_마감_id_13); + softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(네번째_페이지_인덱스_1_4일_전_마감_id_9); + softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(네번째_페이지_인덱스_2_4일_전_마감_id_8); softAssertions.assertThat(actual.hasNext()).isTrue(); }); } @@ -111,8 +111,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { SoftAssertions.assertSoftly(softAssertions -> { softAssertions.assertThat(actual).hasSize(2); - softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(다섯번째_페이지_인덱스_0_id_2); - softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(다섯번째_페이지_인덱스_1_id_1); + softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(다섯번째_페이지_인덱스_0_4일_전_마감_id_7); + softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(다섯번째_페이지_인덱스_1_5일_전_마감_id_1); softAssertions.assertThat(actual.hasNext()).isFalse(); }); } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleTest.java index 0364d7c8d..443353f7f 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleTest.java @@ -44,9 +44,9 @@ class 검색_결과가_14개인_검색어_테스트 { // then SoftAssertions.assertSoftly(softAssertions -> { softAssertions.assertThat(actual).hasSize(3); - softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(첫번째_페이지_인덱스_0_맥북_검색_id_16); - softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(첫번째_페이지_인덱스_1_맥북_검색_id_15); - softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(첫번째_페이지_인덱스_2_맥북_검색_id_14); + softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(첫번째_페이지_인덱스_0_맥북_검색_4일_후_마감_id_15); + softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(첫번째_페이지_인덱스_1_맥북_검색_4일_후_마감_id_14); + softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(첫번째_페이지_인덱스_2_맥북_검색_4일_후_마감_id_12); softAssertions.assertThat(actual.hasNext()).isTrue(); }); } @@ -62,9 +62,9 @@ class 검색_결과가_14개인_검색어_테스트 { // then SoftAssertions.assertSoftly(softAssertions -> { softAssertions.assertThat(actual).hasSize(3); - softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(두번째_페이지_인덱스_0_맥북_검색_id_13); - softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(두번째_페이지_인덱스_1_맥북_검색_id_12); - softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(두번째_페이지_인덱스_2_맥북_검색_id_11); + softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(두번째_페이지_인덱스_0_맥북_검색_4일_후_마감_id_11); + softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(두번째_페이지_인덱스_1_맥북_검색_4일_후_마감_id_10); + softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(두번째_페이지_인덱스_2_맥북_검색_2일_후_마감_id_4); softAssertions.assertThat(actual.hasNext()).isTrue(); }); } @@ -80,9 +80,9 @@ class 검색_결과가_14개인_검색어_테스트 { // then SoftAssertions.assertSoftly(softAssertions -> { softAssertions.assertThat(actual).hasSize(3); - softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(세번째_페이지_인덱스_0_맥북_검색_id_10); - softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(세번째_페이지_인덱스_1_맥북_검색_id_9); - softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(세번째_페이지_인덱스_2_맥북_검색_id_8); + softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(세번째_페이지_인덱스_0_맥북_검색_3일_후_마감_id_3); + softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(세번째_페이지_인덱스_1_맥북_검색_4일_후_마감_id_2); + softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(세번째_페이지_인덱스_2_맥북_검색_4일_전_마감_id_16); softAssertions.assertThat(actual.hasNext()).isTrue(); }); } @@ -98,9 +98,9 @@ class 검색_결과가_14개인_검색어_테스트 { // then SoftAssertions.assertSoftly(softAssertions -> { softAssertions.assertThat(actual).hasSize(3); - softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(네번째_페이지_인덱스_0_맥북_검색_id_7); - softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(네번째_페이지_인덱스_1_맥북_검색_id_4); - softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(네번째_페이지_인덱스_2_맥북_검색_id_3); + softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(네번째_페이지_인덱스_0_맥북_검색_4일_전_마감_id_13); + softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(네번째_페이지_인덱스_1_맥북_검색_4일_전_마감_id_9); + softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(네번째_페이지_인덱스_2_맥북_검색_4일_전_마감_id_8); softAssertions.assertThat(actual.hasNext()).isTrue(); }); } @@ -116,8 +116,8 @@ class 검색_결과가_14개인_검색어_테스트 { // then SoftAssertions.assertSoftly(softAssertions -> { softAssertions.assertThat(actual).hasSize(2); - softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(다섯번째_페이지_인덱스_0_맥북_검색_id_2); - softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(다섯번째_페이지_인덱스_1_맥북_검색_id_1); + softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(다섯번째_페이지_인덱스_0_맥북_검색_4일_전_마감_id_7); + softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(다섯번째_페이지_인덱스_1_맥북_검색_5일_전_마감_id_1); softAssertions.assertThat(actual.hasNext()).isFalse(); }); } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSortByIdTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSortByIdTest.java index 64eae857f..f759c099d 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSortByIdTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSortByIdTest.java @@ -40,9 +40,9 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { // then SoftAssertions.assertSoftly(softAssertions -> { softAssertions.assertThat(actual).hasSize(3); - softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(첫번째_페이지_인덱스_0_id_16); - softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(첫번째_페이지_인덱스_1_id_15); - softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(첫번째_페이지_인덱스_2_id_14); + softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(첫번째_페이지_인덱스_0_4일_후_마감_id_15); + softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(첫번째_페이지_인덱스_1_4일_후_마감_id_14); + softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(첫번째_페이지_인덱스_2_4일_후_마감_id_12); softAssertions.assertThat(actual.hasNext()).isTrue(); }); } @@ -58,9 +58,9 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { // then SoftAssertions.assertSoftly(softAssertions -> { softAssertions.assertThat(actual).hasSize(3); - softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(두번째_페이지_인덱스_0_id_13); - softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(두번째_페이지_인덱스_1_id_12); - softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(두번째_페이지_인덱스_2_id_11); + softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(두번째_페이지_인덱스_0_4일_후_마감_id_11); + softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(두번째_페이지_인덱스_1_4일_후_마감_id_10); + softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(두번째_페이지_인덱스_2_1일_후_마감_id_5); softAssertions.assertThat(actual.hasNext()).isTrue(); }); } @@ -76,9 +76,9 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { // then SoftAssertions.assertSoftly(softAssertions -> { softAssertions.assertThat(actual).hasSize(3); - softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(세번째_페이지_인덱스_0_id_10); - softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(세번째_페이지_인덱스_1_id_9); - softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(세번째_페이지_인덱스_2_id_8); + softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(세번째_페이지_인덱스_0_2일_후_마감_id_4); + softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(세번째_페이지_인덱스_1_3일_후_마감_id_3); + softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(세번째_페이지_인덱스_2_4일_후_마감_id_2); softAssertions.assertThat(actual.hasNext()).isTrue(); }); } @@ -94,9 +94,9 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { // then SoftAssertions.assertSoftly(softAssertions -> { softAssertions.assertThat(actual).hasSize(3); - softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(네번째_페이지_인덱스_0_id_7); - softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(네번째_페이지_인덱스_1_id_6); - softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(네번째_페이지_인덱스_2_id_5); + softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(네번째_페이지_인덱스_0_4일_전_마감_id_16); + softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(네번째_페이지_인덱스_1_4일_전_마감_id_13); + softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(네번째_페이지_인덱스_2_4일_전_마감_id_9); softAssertions.assertThat(actual.hasNext()).isTrue(); }); } @@ -111,9 +111,9 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { SoftAssertions.assertSoftly(softAssertions -> { softAssertions.assertThat(actual).hasSize(3); - softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(다섯번째_페이지_인덱스_0_id_4); - softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(다섯번째_페이지_인덱스_1_id_3); - softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(다섯번째_페이지_인덱스_2_id_2); + softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(다섯번째_페이지_인덱스_0_4일_전_마감_id_8); + softAssertions.assertThat(actual.getContent().get(1)).isEqualTo(다섯번째_페이지_인덱스_1_4일_전_마감_id_7); + softAssertions.assertThat(actual.getContent().get(2)).isEqualTo(다섯번째_페이지_인덱스_2_2일_전_마감_id_6); softAssertions.assertThat(actual.hasNext()).isTrue(); }); } @@ -128,7 +128,7 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { SoftAssertions.assertSoftly(softAssertions -> { softAssertions.assertThat(actual).hasSize(1); - softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(여섯번째_페이지_인덱스_0_id_1); + softAssertions.assertThat(actual.getContent().get(0)).isEqualTo(여섯번째_페이지_인덱스_0_5일_전_마감_id_1); softAssertions.assertThat(actual.hasNext()).isFalse(); }); } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepositoryTest.java index dc415434e..b2909978a 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepositoryTest.java @@ -1,9 +1,12 @@ package com.ddang.ddang.auction.infrastructure.persistence; +import static org.assertj.core.api.Assertions.assertThat; + import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.infrastructure.persistence.fixture.JpaAuctionRepositoryFixture; import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; +import java.util.Optional; import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; @@ -12,10 +15,6 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.context.annotation.Import; -import java.util.Optional; - -import static org.assertj.core.api.Assertions.assertThat; - @DataJpaTest @Import({JpaConfiguration.class, QuerydslConfiguration.class}) @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @@ -33,10 +32,35 @@ class JpaAuctionRepositoryTest extends JpaAuctionRepositoryFixture { assertThat(actual.getId()).isPositive(); } + @Test + void 지정한_아이디에_대한_경매와_관련된_데이터를_모두_조회한다() { + // when + final Optional actual = auctionRepository.findTotalAuctionById(저장된_경매_엔티티.getId()); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).isPresent(); + softAssertions.assertThat(actual.get().getId()).isEqualTo(저장된_경매_엔티티.getId()); + softAssertions.assertThat(actual.get().getTitle()).isEqualTo(저장된_경매_엔티티.getTitle()); + softAssertions.assertThat(actual.get().getDescription()).isEqualTo(저장된_경매_엔티티.getDescription()); + softAssertions.assertThat(actual.get().getBidUnit()).isEqualTo(저장된_경매_엔티티.getBidUnit()); + softAssertions.assertThat(actual.get().getStartPrice()).isEqualTo(저장된_경매_엔티티.getStartPrice()); + softAssertions.assertThat(actual.get().getClosingTime()).isEqualTo(저장된_경매_엔티티.getClosingTime()); + softAssertions.assertThat(actual.get().getAuctionRegions()).isNotNull(); + softAssertions.assertThat(actual.get().getAuctionRegions().get(0)).isNotNull(); + softAssertions.assertThat(actual.get().getAuctionRegions().get(0).getThirdRegion()).isNotNull(); + softAssertions.assertThat(actual.get().getAuctionRegions().get(0).getThirdRegion().getFirstRegion()).isNotNull(); + softAssertions.assertThat(actual.get().getAuctionRegions().get(0).getThirdRegion().getSecondRegion()).isNotNull(); + softAssertions.assertThat(actual.get().getSubCategory()).isNotNull(); + softAssertions.assertThat(actual.get().getSubCategory().getMainCategory()).isNotNull(); + softAssertions.assertThat(actual.get().getSeller()).isNotNull(); + }); + } + @Test void 지정한_아이디에_대한_경매를_조회한다() { // when - final Optional actual = auctionRepository.findByIdAndDeletedIsFalse(저장된_경매_엔티티.getId()); + final Optional actual = auctionRepository.findPureAuctionById(저장된_경매_엔티티.getId()); // then SoftAssertions.assertSoftly(softAssertions -> { @@ -53,7 +77,7 @@ class JpaAuctionRepositoryTest extends JpaAuctionRepositoryFixture { @Test void 삭제된_아이디에_대한_경매_조회시_빈_optional을_반환한다() { // when - final Optional actual = auctionRepository.findByIdAndDeletedIsFalse(삭제된_경매_엔티티.getId()); + final Optional actual = auctionRepository.findTotalAuctionById(삭제된_경매_엔티티.getId()); // then assertThat(actual).isEmpty(); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepositoryImplForObjectTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepositoryImplForObjectTest.java deleted file mode 100644 index f7d2ed39f..000000000 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepositoryImplForObjectTest.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.ddang.ddang.auction.infrastructure.persistence; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.ddang.ddang.auction.domain.Auction; -import com.ddang.ddang.auction.infrastructure.persistence.fixture.QuerydslAuctionRepositoryImplForObjectFixture; -import com.ddang.ddang.category.domain.Category; -import com.ddang.ddang.configuration.JpaConfiguration; -import com.ddang.ddang.configuration.QuerydslConfiguration; -import com.ddang.ddang.region.domain.Region; -import com.ddang.ddang.user.domain.User; -import com.querydsl.jpa.impl.JPAQueryFactory; -import java.util.Optional; -import org.assertj.core.api.SoftAssertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayNameGeneration; -import org.junit.jupiter.api.DisplayNameGenerator; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.context.annotation.Import; - -@DataJpaTest -@Import({JpaConfiguration.class, QuerydslConfiguration.class}) -@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) -@SuppressWarnings("NonAsciiCharacters") -class QuerydslAuctionRepositoryImplForObjectTest extends QuerydslAuctionRepositoryImplForObjectFixture { - - QuerydslAuctionRepository querydslAuctionRepository; - - @BeforeEach - void setUp(@Autowired final JPAQueryFactory queryFactory) { - querydslAuctionRepository = new QuerydslAuctionRepositoryImpl(queryFactory); - } - - @Test - void 지정한_아이디에_대한_경매를_조회한다() { - // when - final Optional actual = querydslAuctionRepository.findAuctionById(경매.getId()); - - // then - SoftAssertions.assertSoftly(softAssertions -> { - softAssertions.assertThat(actual).isPresent(); - - final Auction actualAuction = actual.get(); - softAssertions.assertThat(actualAuction.getTitle()).isEqualTo(경매.getTitle()); - softAssertions.assertThat(actualAuction.getId()).isEqualTo(경매.getId()); - softAssertions.assertThat(actualAuction.getAuctionRegions()).hasSize(1); - - final Region actualThirdRegion = actualAuction.getAuctionRegions().get(0).getThirdRegion(); - softAssertions.assertThat(actualThirdRegion.getName()).isEqualTo(개포1동.getName()); - - final Region actualSecondRegion = actualThirdRegion.getSecondRegion(); - softAssertions.assertThat(actualSecondRegion.getName()).isEqualTo(강남구.getName()); - - final Region actualFirstRegion = actualSecondRegion.getFirstRegion(); - softAssertions.assertThat(actualFirstRegion.getName()).isEqualTo(서울특별시.getName()); - - final Category actualSubCategory = actual.get().getSubCategory(); - softAssertions.assertThat(actualSubCategory).isEqualTo(가구_서브_의자_카테고리); - - final Category mainCategory = actualSubCategory.getMainCategory(); - softAssertions.assertThat(mainCategory).isEqualTo(가구_카테고리); - - final User actualSeller = actual.get().getSeller(); - softAssertions.assertThat(actualSeller).isEqualTo(판매자); - }); - } - - @Test - void 지정한_아이디에_해당하는_경매가_없는_경우_빈_Optional을_조회한다() { - // when - final Optional actual = querydslAuctionRepository.findAuctionById(존재하지_않는_경매); - - // then - assertThat(actual).isEmpty(); - } -} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleAndSortByIdFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleAndSortByIdFixture.java index d580201a9..e673e5016 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleAndSortByIdFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleAndSortByIdFixture.java @@ -12,36 +12,36 @@ public class AuctionForListSearchByTitleAndSortByIdFixture extends QuerydslAucti protected Sort id순_정렬 = Sort.by(Order.asc("id")); protected ReadAuctionSearchCondition 검색어_맥북 = new ReadAuctionSearchCondition("맥북"); - protected Auction 첫번째_페이지_인덱스_0_id_16; - protected Auction 첫번째_페이지_인덱스_1_id_15; - protected Auction 첫번째_페이지_인덱스_2_id_14; - protected Auction 두번째_페이지_인덱스_0_id_13; - protected Auction 두번째_페이지_인덱스_1_id_12; - protected Auction 두번째_페이지_인덱스_2_id_11; - protected Auction 세번째_페이지_인덱스_0_id_10; - protected Auction 세번째_페이지_인덱스_1_id_9; - protected Auction 세번째_페이지_인덱스_2_id_8; - protected Auction 네번째_페이지_인덱스_0_id_7; - protected Auction 네번째_페이지_인덱스_1_id_4; - protected Auction 네번째_페이지_인덱스_2_id_3; - protected Auction 다섯번째_페이지_인덱스_0_id_2; - protected Auction 다섯번째_페이지_인덱스_1_id_1; + protected Auction 첫번째_페이지_인덱스_0_4일_후_마감_id_15; + protected Auction 첫번째_페이지_인덱스_1_4일_후_마감_id_14; + protected Auction 첫번째_페이지_인덱스_2_4일_후_마감_id_12; + protected Auction 두번째_페이지_인덱스_0_4일_후_마감_id_11; + protected Auction 두번째_페이지_인덱스_1_4일_후_마감_id_10; + protected Auction 두번째_페이지_인덱스_2_2일_후_마감_id_4; + protected Auction 세번째_페이지_인덱스_0_3일_후_마감_id_3; + protected Auction 세번째_페이지_인덱스_1_4일_후_마감_id_2; + protected Auction 세번째_페이지_인덱스_2_4일_전_마감_id_16; + protected Auction 네번째_페이지_인덱스_0_4일_전_마감_id_13; + protected Auction 네번째_페이지_인덱스_1_4일_전_마감_id_9; + protected Auction 네번째_페이지_인덱스_2_4일_전_마감_id_8; + protected Auction 다섯번째_페이지_인덱스_0_4일_전_마감_id_7; + protected Auction 다섯번째_페이지_인덱스_1_5일_전_마감_id_1; @BeforeEach void fixtureSetUp() { - 첫번째_페이지_인덱스_0_id_16 = 경매16; - 첫번째_페이지_인덱스_1_id_15 = 경매15; - 첫번째_페이지_인덱스_2_id_14 = 경매14; - 두번째_페이지_인덱스_0_id_13 = 경매13; - 두번째_페이지_인덱스_1_id_12 = 경매12; - 두번째_페이지_인덱스_2_id_11 = 경매11; - 세번째_페이지_인덱스_0_id_10 = 경매10; - 세번째_페이지_인덱스_1_id_9 = 경매9; - 세번째_페이지_인덱스_2_id_8 = 경매8; - 네번째_페이지_인덱스_0_id_7 = 경매7; - 네번째_페이지_인덱스_1_id_4 = 경매4; - 네번째_페이지_인덱스_2_id_3 = 경매3; - 다섯번째_페이지_인덱스_0_id_2 = 경매2; - 다섯번째_페이지_인덱스_1_id_1 = 경매1; + 첫번째_페이지_인덱스_0_4일_후_마감_id_15 = 경매15; + 첫번째_페이지_인덱스_1_4일_후_마감_id_14 = 경매14; + 첫번째_페이지_인덱스_2_4일_후_마감_id_12 = 경매12; + 두번째_페이지_인덱스_0_4일_후_마감_id_11 = 경매11; + 두번째_페이지_인덱스_1_4일_후_마감_id_10 = 경매10; + 두번째_페이지_인덱스_2_2일_후_마감_id_4 = 경매4; + 세번째_페이지_인덱스_0_3일_후_마감_id_3 = 경매3; + 세번째_페이지_인덱스_1_4일_후_마감_id_2 = 경매2; + 세번째_페이지_인덱스_2_4일_전_마감_id_16 = 경매16; + 네번째_페이지_인덱스_0_4일_전_마감_id_13 = 경매13; + 네번째_페이지_인덱스_1_4일_전_마감_id_9 = 경매9; + 네번째_페이지_인덱스_2_4일_전_마감_id_8 = 경매8; + 다섯번째_페이지_인덱스_0_4일_전_마감_id_7 = 경매7; + 다섯번째_페이지_인덱스_1_5일_전_마감_id_1 = 경매1; } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleFixture.java index 2c7928f3c..34a97da5b 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleFixture.java @@ -9,38 +9,38 @@ public class AuctionForListSearchByTitleFixture extends QuerydslAuctionRepositor protected ReadAuctionSearchCondition 검색어_맥북 = new ReadAuctionSearchCondition("맥북"); - protected Auction 첫번째_페이지_인덱스_0_맥북_검색_id_16; - protected Auction 첫번째_페이지_인덱스_1_맥북_검색_id_15; - protected Auction 첫번째_페이지_인덱스_2_맥북_검색_id_14; - protected Auction 두번째_페이지_인덱스_0_맥북_검색_id_13; - protected Auction 두번째_페이지_인덱스_1_맥북_검색_id_12; - protected Auction 두번째_페이지_인덱스_2_맥북_검색_id_11; - protected Auction 세번째_페이지_인덱스_0_맥북_검색_id_10; - protected Auction 세번째_페이지_인덱스_1_맥북_검색_id_9; - protected Auction 세번째_페이지_인덱스_2_맥북_검색_id_8; - protected Auction 네번째_페이지_인덱스_0_맥북_검색_id_7; - protected Auction 네번째_페이지_인덱스_1_맥북_검색_id_4; - protected Auction 네번째_페이지_인덱스_2_맥북_검색_id_3; - protected Auction 다섯번째_페이지_인덱스_0_맥북_검색_id_2; - protected Auction 다섯번째_페이지_인덱스_1_맥북_검색_id_1; + protected Auction 첫번째_페이지_인덱스_0_맥북_검색_4일_후_마감_id_15; + protected Auction 첫번째_페이지_인덱스_1_맥북_검색_4일_후_마감_id_14; + protected Auction 첫번째_페이지_인덱스_2_맥북_검색_4일_후_마감_id_12; + protected Auction 두번째_페이지_인덱스_0_맥북_검색_4일_후_마감_id_11; + protected Auction 두번째_페이지_인덱스_1_맥북_검색_4일_후_마감_id_10; + protected Auction 두번째_페이지_인덱스_2_맥북_검색_2일_후_마감_id_4; + protected Auction 세번째_페이지_인덱스_0_맥북_검색_3일_후_마감_id_3; + protected Auction 세번째_페이지_인덱스_1_맥북_검색_4일_후_마감_id_2; + protected Auction 세번째_페이지_인덱스_2_맥북_검색_4일_전_마감_id_16; + protected Auction 네번째_페이지_인덱스_0_맥북_검색_4일_전_마감_id_13; + protected Auction 네번째_페이지_인덱스_1_맥북_검색_4일_전_마감_id_9; + protected Auction 네번째_페이지_인덱스_2_맥북_검색_4일_전_마감_id_8; + protected Auction 다섯번째_페이지_인덱스_0_맥북_검색_4일_전_마감_id_7; + protected Auction 다섯번째_페이지_인덱스_1_맥북_검색_5일_전_마감_id_1; protected ReadAuctionSearchCondition 검색어_캐비어 = new ReadAuctionSearchCondition("캐비어"); @BeforeEach void fixtureSetUp() { - 첫번째_페이지_인덱스_0_맥북_검색_id_16 = 경매16; - 첫번째_페이지_인덱스_1_맥북_검색_id_15 = 경매15; - 첫번째_페이지_인덱스_2_맥북_검색_id_14 = 경매14; - 두번째_페이지_인덱스_0_맥북_검색_id_13 = 경매13; - 두번째_페이지_인덱스_1_맥북_검색_id_12 = 경매12; - 두번째_페이지_인덱스_2_맥북_검색_id_11 = 경매11; - 세번째_페이지_인덱스_0_맥북_검색_id_10 = 경매10; - 세번째_페이지_인덱스_1_맥북_검색_id_9 = 경매9; - 세번째_페이지_인덱스_2_맥북_검색_id_8 = 경매8; - 네번째_페이지_인덱스_0_맥북_검색_id_7 = 경매7; - 네번째_페이지_인덱스_1_맥북_검색_id_4 = 경매4; - 네번째_페이지_인덱스_2_맥북_검색_id_3 = 경매3; - 다섯번째_페이지_인덱스_0_맥북_검색_id_2 = 경매2; - 다섯번째_페이지_인덱스_1_맥북_검색_id_1 = 경매1; + 첫번째_페이지_인덱스_0_맥북_검색_4일_후_마감_id_15 = 경매15; + 첫번째_페이지_인덱스_1_맥북_검색_4일_후_마감_id_14 = 경매14; + 첫번째_페이지_인덱스_2_맥북_검색_4일_후_마감_id_12 = 경매12; + 두번째_페이지_인덱스_0_맥북_검색_4일_후_마감_id_11 = 경매11; + 두번째_페이지_인덱스_1_맥북_검색_4일_후_마감_id_10 = 경매10; + 두번째_페이지_인덱스_2_맥북_검색_2일_후_마감_id_4 = 경매4; + 세번째_페이지_인덱스_0_맥북_검색_3일_후_마감_id_3 = 경매3; + 세번째_페이지_인덱스_1_맥북_검색_4일_후_마감_id_2 = 경매2; + 세번째_페이지_인덱스_2_맥북_검색_4일_전_마감_id_16 = 경매16; + 네번째_페이지_인덱스_0_맥북_검색_4일_전_마감_id_13 = 경매13; + 네번째_페이지_인덱스_1_맥북_검색_4일_전_마감_id_9 = 경매9; + 네번째_페이지_인덱스_2_맥북_검색_4일_전_마감_id_8 = 경매8; + 다섯번째_페이지_인덱스_0_맥북_검색_4일_전_마감_id_7 = 경매7; + 다섯번째_페이지_인덱스_1_맥북_검색_5일_전_마감_id_1 = 경매1; } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSortByIdFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSortByIdFixture.java index bfae846c0..93c8137d0 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSortByIdFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSortByIdFixture.java @@ -12,40 +12,40 @@ public class AuctionForListSortByIdFixture extends QuerydslAuctionRepositoryImpl protected Sort id순_정렬 = Sort.by(Order.asc("id")); protected ReadAuctionSearchCondition 검색어_없음 = new ReadAuctionSearchCondition(null); - protected Auction 첫번째_페이지_인덱스_0_id_16; - protected Auction 첫번째_페이지_인덱스_1_id_15; - protected Auction 첫번째_페이지_인덱스_2_id_14; - protected Auction 두번째_페이지_인덱스_0_id_13; - protected Auction 두번째_페이지_인덱스_1_id_12; - protected Auction 두번째_페이지_인덱스_2_id_11; - protected Auction 세번째_페이지_인덱스_0_id_10; - protected Auction 세번째_페이지_인덱스_1_id_9; - protected Auction 세번째_페이지_인덱스_2_id_8; - protected Auction 네번째_페이지_인덱스_0_id_7; - protected Auction 네번째_페이지_인덱스_1_id_6; - protected Auction 네번째_페이지_인덱스_2_id_5; - protected Auction 다섯번째_페이지_인덱스_0_id_4; - protected Auction 다섯번째_페이지_인덱스_1_id_3; - protected Auction 다섯번째_페이지_인덱스_2_id_2; - protected Auction 여섯번째_페이지_인덱스_0_id_1; + protected Auction 첫번째_페이지_인덱스_0_4일_후_마감_id_15; + protected Auction 첫번째_페이지_인덱스_1_4일_후_마감_id_14; + protected Auction 첫번째_페이지_인덱스_2_4일_후_마감_id_12; + protected Auction 두번째_페이지_인덱스_0_4일_후_마감_id_11; + protected Auction 두번째_페이지_인덱스_1_4일_후_마감_id_10; + protected Auction 두번째_페이지_인덱스_2_1일_후_마감_id_5; + protected Auction 세번째_페이지_인덱스_0_2일_후_마감_id_4; + protected Auction 세번째_페이지_인덱스_1_3일_후_마감_id_3; + protected Auction 세번째_페이지_인덱스_2_4일_후_마감_id_2; + protected Auction 네번째_페이지_인덱스_0_4일_전_마감_id_16; + protected Auction 네번째_페이지_인덱스_1_4일_전_마감_id_13; + protected Auction 네번째_페이지_인덱스_2_4일_전_마감_id_9; + protected Auction 다섯번째_페이지_인덱스_0_4일_전_마감_id_8; + protected Auction 다섯번째_페이지_인덱스_1_4일_전_마감_id_7; + protected Auction 다섯번째_페이지_인덱스_2_2일_전_마감_id_6; + protected Auction 여섯번째_페이지_인덱스_0_5일_전_마감_id_1; @BeforeEach void fixtureSetUp() { - 첫번째_페이지_인덱스_0_id_16 = 경매16; - 첫번째_페이지_인덱스_1_id_15 = 경매15; - 첫번째_페이지_인덱스_2_id_14 = 경매14; - 두번째_페이지_인덱스_0_id_13 = 경매13; - 두번째_페이지_인덱스_1_id_12 = 경매12; - 두번째_페이지_인덱스_2_id_11 = 경매11; - 세번째_페이지_인덱스_0_id_10 = 경매10; - 세번째_페이지_인덱스_1_id_9 = 경매9; - 세번째_페이지_인덱스_2_id_8 = 경매8; - 네번째_페이지_인덱스_0_id_7 = 경매7; - 네번째_페이지_인덱스_1_id_6 = 경매6; - 네번째_페이지_인덱스_2_id_5 = 경매5; - 다섯번째_페이지_인덱스_0_id_4 = 경매4; - 다섯번째_페이지_인덱스_1_id_3 = 경매3; - 다섯번째_페이지_인덱스_2_id_2 = 경매2; - 여섯번째_페이지_인덱스_0_id_1 = 경매1; + 첫번째_페이지_인덱스_0_4일_후_마감_id_15 = 경매15; + 첫번째_페이지_인덱스_1_4일_후_마감_id_14 = 경매14; + 첫번째_페이지_인덱스_2_4일_후_마감_id_12 = 경매12; + 두번째_페이지_인덱스_0_4일_후_마감_id_11 = 경매11; + 두번째_페이지_인덱스_1_4일_후_마감_id_10 = 경매10; + 두번째_페이지_인덱스_2_1일_후_마감_id_5 = 경매5; + 세번째_페이지_인덱스_0_2일_후_마감_id_4 = 경매4; + 세번째_페이지_인덱스_1_3일_후_마감_id_3 = 경매3; + 세번째_페이지_인덱스_2_4일_후_마감_id_2 = 경매2; + 네번째_페이지_인덱스_0_4일_전_마감_id_16 = 경매16; + 네번째_페이지_인덱스_1_4일_전_마감_id_13 = 경매13; + 네번째_페이지_인덱스_2_4일_전_마감_id_9 = 경매9; + 다섯번째_페이지_인덱스_0_4일_전_마감_id_8 = 경매8; + 다섯번째_페이지_인덱스_1_4일_전_마감_id_7 = 경매7; + 여섯번째_페이지_인덱스_0_5일_전_마감_id_1 = 경매1; + 다섯번째_페이지_인덱스_2_2일_전_마감_id_6 = 경매6; } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/JpaAuctionRepositoryFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/JpaAuctionRepositoryFixture.java index 7e09374d8..2dacef8da 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/JpaAuctionRepositoryFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/JpaAuctionRepositoryFixture.java @@ -4,6 +4,15 @@ import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.category.domain.Category; +import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.region.domain.AuctionRegion; +import com.ddang.ddang.region.domain.Region; +import com.ddang.ddang.region.infrastructure.persistence.JpaRegionRepository; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; import java.time.Instant; @@ -20,36 +29,79 @@ public class JpaAuctionRepositoryFixture { @PersistenceContext private EntityManager em; + @Autowired + private JpaUserRepository userRepository; + @Autowired private JpaAuctionRepository auctionRepository; + @Autowired + private JpaRegionRepository regionRepository; + + @Autowired + private JpaCategoryRepository categoryRepository; + private Instant 시간 = Instant.parse("2023-07-08T22:21:20Z"); private ZoneId 위치 = ZoneId.of("UTC"); protected Auction 저장하기_전_경매_엔티티 = Auction.builder() - .title("제목") - .description("내용") - .bidUnit(new BidUnit(1_000)) - .startPrice(new Price(1_000)) - .closingTime(LocalDateTime.now()) - .build(); - protected Auction 저장된_경매_엔티티 = Auction.builder() - .title("경매 상품 1") - .description("이것은 경매 상품 1 입니다.") - .bidUnit(new BidUnit(1_000)) - .startPrice(new Price(1_000)) - .closingTime(시간.atZone(위치).toLocalDateTime()) - .build(); - protected Auction 삭제된_경매_엔티티 = Auction.builder() - .title("경매 상품 1") - .description("이것은 경매 상품 1 입니다.") - .bidUnit(new BidUnit(1_000)) - .startPrice(new Price(1_000)) - .closingTime(시간.atZone(위치).toLocalDateTime()) - .build(); + .title("제목") + .description("내용") + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(LocalDateTime.now()) + .build(); + protected Auction 저장된_경매_엔티티; + protected Auction 삭제된_경매_엔티티; @BeforeEach void setUp() { + final Region 서울특별시 = new Region("서울특별시"); + final Region 강남구 = new Region("강남구"); + final Region 역삼동 = new Region("역삼동"); + + 서울특별시.addSecondRegion(강남구); + 강남구.addThirdRegion(역삼동); + + regionRepository.save(서울특별시); + + final Category 가구_카테고리 = new Category("가구"); + final Category 가구_서브_의자_카테고리 = new Category("의자"); + + 가구_카테고리.addSubCategory(가구_서브_의자_카테고리); + + categoryRepository.save(가구_카테고리); + + final User 사용자 = User.builder() + .name("사용자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); + + userRepository.save(사용자); + + 저장된_경매_엔티티 = Auction.builder() + .title("경매 상품 1") + .description("이것은 경매 상품 1 입니다.") + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(시간.atZone(위치).toLocalDateTime()) + .subCategory(가구_서브_의자_카테고리) + .seller(사용자) + .build(); + 삭제된_경매_엔티티 = Auction.builder() + .title("경매 상품 1") + .description("이것은 경매 상품 1 입니다.") + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(시간.atZone(위치).toLocalDateTime()) + .subCategory(가구_서브_의자_카테고리) + .seller(사용자) + .build(); + + 삭제된_경매_엔티티.addAuctionRegions(List.of(new AuctionRegion(역삼동))); + 저장된_경매_엔티티.addAuctionRegions(List.of(new AuctionRegion(역삼동))); 삭제된_경매_엔티티.delete(); auctionRepository.saveAll(List.of(저장된_경매_엔티티, 삭제된_경매_엔티티)); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionRepositoryImplForListFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionRepositoryImplForListFixture.java index b293a72ed..2ec2f0507 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionRepositoryImplForListFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionRepositoryImplForListFixture.java @@ -129,6 +129,7 @@ void commonFixtureSetUp() { .startPrice(new Price(1_000)) .closingTime(현재시간.minusDays(2)) .seller(판매자_0_3점_1) + .subCategory(기타_서브_기타_카테고리) .build(); bidding(경매6, 판매자_4_7점); addAuctioneerCount(경매6, 7); @@ -138,7 +139,8 @@ void commonFixtureSetUp() { .bidUnit(new BidUnit(1_000)) .startPrice(new Price(1_000)) .closingTime(현재시간.minusDays(4)) - .seller(판매자_3_5점) // ㅇㅋ + .seller(판매자_3_5점) + .subCategory(기타_서브_기타_카테고리) .build(); bidding(경매8, 판매자_4_7점); addAuctioneerCount(경매8, 5); @@ -148,7 +150,8 @@ void commonFixtureSetUp() { .bidUnit(new BidUnit(1_000)) .startPrice(new Price(1_000)) .closingTime(현재시간.minusDays(4)) - .seller(판매자_3_5점) // ㅇㅋ + .seller(판매자_3_5점) + .subCategory(기타_서브_기타_카테고리) .build(); bidding(경매16, 판매자_4_7점); addAuctioneerCount(경매16, 4); @@ -159,6 +162,7 @@ void commonFixtureSetUp() { .startPrice(new Price(1_000)) .closingTime(현재시간.minusDays(4)) .seller(판매자_2_1점) + .subCategory(기타_서브_기타_카테고리) .build(); bidding(경매9, 판매자_4_7점); addAuctioneerCount(경매9, 5); @@ -169,6 +173,7 @@ void commonFixtureSetUp() { .startPrice(new Price(1_000)) .closingTime(현재시간.minusDays(4)) .seller(판매자_2_1점) + .subCategory(기타_서브_기타_카테고리) .build(); bidding(경매13, 판매자_4_7점); addAuctioneerCount(경매13, 5); @@ -179,6 +184,7 @@ void commonFixtureSetUp() { .startPrice(new Price(1_000)) .closingTime(현재시간.minusDays(3)) .seller(판매자_4_7점) + .subCategory(기타_서브_기타_카테고리) .build(); addAuctioneerCount(경매7, 3); 경매1 = Auction.builder() @@ -188,6 +194,7 @@ void commonFixtureSetUp() { .startPrice(new Price(1_000)) .closingTime(현재시간.minusDays(5)) .seller(판매자_4_7점) + .subCategory(기타_서브_기타_카테고리) .build(); addAuctioneerCount(경매1, 2); bidding(경매16, 판매자_4_7점); @@ -198,6 +205,7 @@ void commonFixtureSetUp() { .startPrice(new Price(1_000)) .closingTime(현재시간.plusDays(4)) .seller(판매자_2_1점) + .subCategory(기타_서브_기타_카테고리) .build(); addAuctioneerCount(경매2, 1); 경매3 = Auction.builder() @@ -207,6 +215,7 @@ void commonFixtureSetUp() { .startPrice(new Price(1_000)) .closingTime(현재시간.plusDays(3)) .seller(판매자_2_1점) + .subCategory(기타_서브_기타_카테고리) .build(); addAuctioneerCount(경매3, 4); 경매4 = Auction.builder() @@ -216,6 +225,7 @@ void commonFixtureSetUp() { .startPrice(new Price(1_000)) .closingTime(현재시간.plusDays(2)) .seller(판매자_5_0점) + .subCategory(기타_서브_기타_카테고리) .build(); addAuctioneerCount(경매4, 7); 경매5 = Auction.builder() @@ -225,6 +235,7 @@ void commonFixtureSetUp() { .startPrice(new Price(1_000)) .closingTime(현재시간.plusDays(1)) .seller(판매자_1_5점) + .subCategory(기타_서브_기타_카테고리) .build(); addAuctioneerCount(경매5, 4); 경매10 = Auction.builder() @@ -233,7 +244,8 @@ void commonFixtureSetUp() { .bidUnit(new BidUnit(1_000)) .startPrice(new Price(1_000)) .closingTime(현재시간.plusDays(4)) - .seller(판매자_3_5점) // ㅇㅋ + .seller(판매자_3_5점) + .subCategory(기타_서브_기타_카테고리) .build(); addAuctioneerCount(경매10, 6); 경매11 = Auction.builder() @@ -243,6 +255,7 @@ void commonFixtureSetUp() { .startPrice(new Price(1_000)) .closingTime(현재시간.plusDays(4)) .seller(판매자_2_1점) + .subCategory(기타_서브_기타_카테고리) .build(); addAuctioneerCount(경매11, 6); 경매12 = Auction.builder() @@ -251,7 +264,8 @@ void commonFixtureSetUp() { .bidUnit(new BidUnit(1_000)) .startPrice(new Price(1_000)) .closingTime(현재시간.plusDays(4)) - .seller(판매자_3_5점) // ㅇㅋ + .seller(판매자_3_5점) + .subCategory(기타_서브_기타_카테고리) .build(); addAuctioneerCount(경매12, 6); 경매14 = Auction.builder() @@ -260,7 +274,8 @@ void commonFixtureSetUp() { .bidUnit(new BidUnit(1_000)) .startPrice(new Price(1_000)) .closingTime(현재시간.plusDays(4)) - .seller(판매자_3_5점) // ㅇㅋ + .seller(판매자_3_5점) + .subCategory(기타_서브_기타_카테고리) .build(); addAuctioneerCount(경매14, 6); 경매15 = Auction.builder() @@ -270,6 +285,7 @@ void commonFixtureSetUp() { .startPrice(new Price(1_000)) .closingTime(현재시간.plusDays(4)) .seller(판매자_2_1점) + .subCategory(기타_서브_기타_카테고리) .build(); addAuctioneerCount(경매15, 6); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java index 215c975fa..905ba6c8a 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java @@ -4,6 +4,8 @@ import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.category.domain.Category; +import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.qna.application.dto.CreateQuestionDto; import com.ddang.ddang.qna.application.dto.ReadAnswerDto; @@ -13,6 +15,8 @@ import com.ddang.ddang.qna.domain.Question; import com.ddang.ddang.qna.infrastructure.JpaAnswerRepository; import com.ddang.ddang.qna.infrastructure.JpaQuestionRepository; +import com.ddang.ddang.region.domain.Region; +import com.ddang.ddang.region.infrastructure.persistence.JpaRegionRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; @@ -37,6 +41,12 @@ public class QuestionServiceFixture { @Autowired private JpaAnswerRepository answerRepository; + @Autowired + private JpaRegionRepository regionRepository; + + @Autowired + private JpaCategoryRepository categoryRepository; + protected Long 질문_3개_답변_2개가_존재하는_경매_아이디; protected Long 존재하지_않는_경매_아이디 = -999L; protected Long 존재하지_않는_질문_아이디 = -999L; @@ -58,6 +68,22 @@ public class QuestionServiceFixture { @BeforeEach void setUp() { + final Region 서울특별시 = new Region("서울특별시"); + final Region 강남구 = new Region("강남구"); + final Region 역삼동 = new Region("역삼동"); + + 서울특별시.addSecondRegion(강남구); + 강남구.addThirdRegion(역삼동); + + regionRepository.save(서울특별시); + + final Category 가구_카테고리 = new Category("가구"); + final Category 가구_서브_의자_카테고리 = new Category("의자"); + + 가구_카테고리.addSubCategory(가구_서브_의자_카테고리); + + categoryRepository.save(가구_카테고리); + final ProfileImage 프로필_이미지 = new ProfileImage("프로필.jpg", "프로필.jpg"); final User 판매자 = User.builder() .name("판매자") @@ -72,6 +98,7 @@ void setUp() { .bidUnit(new BidUnit(1_000)) .startPrice(new Price(1_000)) .closingTime(LocalDateTime.now().plusDays(7)) + .subCategory(가구_서브_의자_카테고리) .build(); final Auction 질문과_답변이_존재하는_경매 = Auction.builder() .seller(판매자) @@ -80,6 +107,7 @@ void setUp() { .bidUnit(new BidUnit(1_000)) .startPrice(new Price(1_000)) .closingTime(LocalDateTime.now().plusDays(7)) + .subCategory(가구_서브_의자_카테고리) .build(); final Auction 종료된_경매 = Auction.builder() .seller(판매자) @@ -88,6 +116,7 @@ void setUp() { .bidUnit(new BidUnit(1_000)) .startPrice(new Price(1_000)) .closingTime(LocalDateTime.now().minusDays(7)) + .subCategory(가구_서브_의자_카테고리) .build(); final Auction 삭제된_경매 = Auction.builder() .seller(판매자) @@ -96,6 +125,7 @@ void setUp() { .bidUnit(new BidUnit(1_000)) .startPrice(new Price(1_000)) .closingTime(LocalDateTime.now().plusDays(7)) + .subCategory(가구_서브_의자_카테고리) .build(); 삭제된_경매.delete(); 질문자 = User.builder() From 874913ea031ed1a08f4ac67cbedc221e28126af7 Mon Sep 17 00:00:00 2001 From: apptie <57691173+apptie@users.noreply.github.com> Date: Fri, 13 Oct 2023 10:14:02 +0900 Subject: [PATCH 08/37] =?UTF-8?q?refactor:=20#613=20=EA=B2=BD=EB=A7=A4=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D=20=EC=8B=9C=20=EA=B2=BD=EB=A7=A4=20=EB=A7=88?= =?UTF-8?q?=EA=B0=90=20=EC=8B=9C=EA=B0=84=20=EC=A0=9C=ED=95=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20(#620)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 마감 시간을 미래만 적용할 수 있도록 제약조건 변경 * feat: 마감 시간 Custom Validator 추가 * refactor: 경매 등록 요청 시 마감 시간 검증을 Custom Validator으로 하도록 변경 --- .../validator/ClosingTimeLimit.java | 19 ++++++++++++++++ .../validator/ClosingTimeValidator.java | 22 +++++++++++++++++++ .../dto/request/CreateAuctionRequest.java | 7 +++--- 3 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/auction/configuration/validator/ClosingTimeLimit.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/auction/configuration/validator/ClosingTimeValidator.java diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/configuration/validator/ClosingTimeLimit.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/configuration/validator/ClosingTimeLimit.java new file mode 100644 index 000000000..ad4b7e7b2 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/configuration/validator/ClosingTimeLimit.java @@ -0,0 +1,19 @@ +package com.ddang.ddang.auction.configuration.validator; + +import jakarta.validation.Constraint; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = ClosingTimeValidator.class) +public @interface ClosingTimeLimit { + + String message() default "마감 시간은 현재 일자로부터 최대 30일까지 설정할 수 있습니다."; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/configuration/validator/ClosingTimeValidator.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/configuration/validator/ClosingTimeValidator.java new file mode 100644 index 000000000..f7dae24c7 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/configuration/validator/ClosingTimeValidator.java @@ -0,0 +1,22 @@ +package com.ddang.ddang.auction.configuration.validator; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; + +public class ClosingTimeValidator implements ConstraintValidator { + + private static final int MAXIMUM_CLOSING_TIME_DAYS = 30; + + @Override + public boolean isValid(final LocalDateTime target, final ConstraintValidatorContext context) { + if (target == null) { + return false; + } + + final long days = ChronoUnit.DAYS.between(LocalDateTime.now(), target); + + return days <= MAXIMUM_CLOSING_TIME_DAYS; + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/request/CreateAuctionRequest.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/request/CreateAuctionRequest.java index 753fff9b5..09c891242 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/request/CreateAuctionRequest.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/request/CreateAuctionRequest.java @@ -1,10 +1,10 @@ package com.ddang.ddang.auction.presentation.dto.request; -import jakarta.validation.constraints.FutureOrPresent; +import com.ddang.ddang.auction.configuration.validator.ClosingTimeLimit; +import jakarta.validation.constraints.Future; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Positive; - import java.time.LocalDateTime; import java.util.List; @@ -24,7 +24,8 @@ public record CreateAuctionRequest( Integer startPrice, @NotNull(message = "마감 시간이 입력되지 않았습니다.") - @FutureOrPresent(message = "마감 시간은 과거를 입력할 수 없습니다.") + @Future(message = "마감 시간은 과거를 입력할 수 없습니다.") + @ClosingTimeLimit LocalDateTime closingTime, @NotNull(message = "하위 카테고리가 입력되지 않았습니다.") From 2958fe9e9ea0f5e225b5fc21ee5d7e76459c5615 Mon Sep 17 00:00:00 2001 From: apptie <57691173+apptie@users.noreply.github.com> Date: Fri, 13 Oct 2023 10:21:59 +0900 Subject: [PATCH 09/37] =?UTF-8?q?refactor:=20#609=20=EC=86=8C=EC=85=9C=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=8B=9C=20=EC=B5=9C=EC=B4=88=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8(=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85)=ED=95=9C=20=ED=9A=8C=EC=9B=90=EC=9D=B8=EC=A7=80=20?= =?UTF-8?q?=EC=97=AC=EB=B6=80=20=EB=B0=98=ED=99=98=20(#612)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 소셜 로그인 시 사용자가 최초 로그인을 하는지 여부를 의미하는 필드 추가 * docs: 문서 최신화 * refactor: 신규 회원가입을 했는지에 대한 네이밍을 명확하게 변경 * test: 실패하는 테스트 케이스 수정 * style: 개행 및 누락된 final 키워드 추가 --- .../application/AuthenticationService.java | 66 ++++++++++++------- .../application/dto/LoginInformationDto.java | 11 ++++ .../dto/LoginUserInformationDto.java | 6 ++ .../AuthenticationController.java | 11 ++-- .../response/LoginInformationResponse.java | 14 ++++ .../src/main/resources/static/docs/docs.html | 62 +++++++++-------- .../AuthenticationServiceTest.java | 26 ++++---- .../AuthenticationControllerTest.java | 9 ++- .../AuthenticationControllerFixture.java | 2 + 9 files changed, 136 insertions(+), 71 deletions(-) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/authentication/application/dto/LoginInformationDto.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/authentication/application/dto/LoginUserInformationDto.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/authentication/presentation/dto/response/LoginInformationResponse.java diff --git a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java index 58add0567..69aa2414f 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java @@ -1,5 +1,9 @@ package com.ddang.ddang.authentication.application; +import static com.ddang.ddang.image.domain.ProfileImage.DEFAULT_PROFILE_IMAGE_STORE_NAME; + +import com.ddang.ddang.authentication.application.dto.LoginInformationDto; +import com.ddang.ddang.authentication.application.dto.LoginUserInformationDto; import com.ddang.ddang.authentication.application.dto.TokenDto; import com.ddang.ddang.authentication.application.exception.InvalidWithdrawalException; import com.ddang.ddang.authentication.application.util.RandomNameGenerator; @@ -21,15 +25,13 @@ import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import java.time.LocalDateTime; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.time.LocalDateTime; -import java.util.Map; - -import static com.ddang.ddang.image.domain.ProfileImage.DEFAULT_PROFILE_IMAGE_STORE_NAME; - @Service @Transactional(readOnly = true) @RequiredArgsConstructor @@ -47,33 +49,47 @@ public class AuthenticationService { private final JpaDeviceTokenRepository deviceTokenRepository; @Transactional - public TokenDto login(final Oauth2Type oauth2Type, final String oauth2AccessToken, final String deviceToken) { + public LoginInformationDto login( + final Oauth2Type oauth2Type, + final String oauth2AccessToken, + final String deviceToken + ) { final OAuth2UserInformationProvider provider = providerComposite.findProvider(oauth2Type); final UserInformationDto userInformationDto = provider.findUserInformation(oauth2AccessToken); - final User persistUser = findOrPersistUser(oauth2Type, userInformationDto); + final LoginUserInformationDto loginUserInfo = findOrPersistUser(oauth2Type, userInformationDto); - updateOrPersistDeviceToken(deviceToken, persistUser); + updateOrPersistDeviceToken(deviceToken, loginUserInfo.user()); - return convertTokenDto(persistUser); + return LoginInformationDto.of(convertTokenDto(loginUserInfo), loginUserInfo); } private void updateOrPersistDeviceToken(final String deviceToken, final User persistUser) { final PersistDeviceTokenDto persistDeviceTokenDto = new PersistDeviceTokenDto(deviceToken); + deviceTokenService.persist(persistUser.getId(), persistDeviceTokenDto); } - private User findOrPersistUser(final Oauth2Type oauth2Type, final UserInformationDto userInformationDto) { - return userRepository.findByOauthIdAndDeletedIsFalse(userInformationDto.findUserId()) - .orElseGet(() -> { - final User user = User.builder() - .name(oauth2Type.calculateNickname(calculateRandomNumber())) - .profileImage(findDefaultProfileImage()) - .reliability(new Reliability(0.0d)) - .oauthId(userInformationDto.findUserId()) - .build(); - - return userRepository.save(user); - }); + private LoginUserInformationDto findOrPersistUser( + final Oauth2Type oauth2Type, + final UserInformationDto userInformationDto + ) { + final AtomicBoolean isSignUpUser = new AtomicBoolean(false); + + final User signInUser = userRepository.findByOauthIdAndDeletedIsFalse(userInformationDto.findUserId()) + .orElseGet(() -> { + final User user = User.builder() + .name(oauth2Type.calculateNickname( + calculateRandomNumber())) + .profileImage(findDefaultProfileImage()) + .reliability(new Reliability(0.0d)) + .oauthId(userInformationDto.findUserId()) + .build(); + + isSignUpUser.set(true); + return userRepository.save(user); + }); + + return new LoginUserInformationDto(signInUser, isSignUpUser.get()); } private ProfileImage findDefaultProfileImage() { @@ -95,16 +111,18 @@ private boolean isAlreadyExist(final String name) { return userRepository.existsByNameEndingWith(name); } - private TokenDto convertTokenDto(final User persistUser) { + private TokenDto convertTokenDto(final LoginUserInformationDto signInUserInfo) { + final User loginUser = signInUserInfo.user(); + final String accessToken = tokenEncoder.encode( LocalDateTime.now(), TokenType.ACCESS, - Map.of(PRIVATE_CLAIMS_KEY, persistUser.getId()) + Map.of(PRIVATE_CLAIMS_KEY, loginUser.getId()) ); final String refreshToken = tokenEncoder.encode( LocalDateTime.now(), TokenType.REFRESH, - Map.of(PRIVATE_CLAIMS_KEY, persistUser.getId()) + Map.of(PRIVATE_CLAIMS_KEY, loginUser.getId()) ); return new TokenDto(accessToken, refreshToken); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/dto/LoginInformationDto.java b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/dto/LoginInformationDto.java new file mode 100644 index 000000000..0972837f3 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/dto/LoginInformationDto.java @@ -0,0 +1,11 @@ +package com.ddang.ddang.authentication.application.dto; + +public record LoginInformationDto(TokenDto tokenDto, boolean isSignUpUser) { + + public static LoginInformationDto of( + final TokenDto tokenDto, + final LoginUserInformationDto loginUserInformationDto + ) { + return new LoginInformationDto(tokenDto, loginUserInformationDto.persisted()); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/dto/LoginUserInformationDto.java b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/dto/LoginUserInformationDto.java new file mode 100644 index 000000000..d3cfef0c5 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/dto/LoginUserInformationDto.java @@ -0,0 +1,6 @@ +package com.ddang.ddang.authentication.application.dto; + +import com.ddang.ddang.user.domain.User; + +public record LoginUserInformationDto(User user, boolean persisted) { +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/authentication/presentation/AuthenticationController.java b/backend/ddang/src/main/java/com/ddang/ddang/authentication/presentation/AuthenticationController.java index 0e2b0eed7..b8e5aeaa2 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/authentication/presentation/AuthenticationController.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/authentication/presentation/AuthenticationController.java @@ -2,12 +2,14 @@ import com.ddang.ddang.authentication.application.AuthenticationService; import com.ddang.ddang.authentication.application.BlackListTokenService; +import com.ddang.ddang.authentication.application.dto.LoginInformationDto; import com.ddang.ddang.authentication.application.dto.TokenDto; import com.ddang.ddang.authentication.infrastructure.oauth2.Oauth2Type; import com.ddang.ddang.authentication.presentation.dto.request.LoginTokenRequest; import com.ddang.ddang.authentication.presentation.dto.request.LogoutRequest; import com.ddang.ddang.authentication.presentation.dto.request.RefreshTokenRequest; import com.ddang.ddang.authentication.presentation.dto.request.WithdrawalRequest; +import com.ddang.ddang.authentication.presentation.dto.response.LoginInformationResponse; import com.ddang.ddang.authentication.presentation.dto.response.TokenResponse; import com.ddang.ddang.authentication.presentation.dto.response.ValidatedTokenResponse; import jakarta.validation.Valid; @@ -31,17 +33,18 @@ public class AuthenticationController { private final BlackListTokenService blackListTokenService; @PostMapping("/login/{oauth2Type}") - public ResponseEntity login( + public ResponseEntity login( @PathVariable final Oauth2Type oauth2Type, @RequestBody final LoginTokenRequest request ) { - final TokenDto tokenDto = authenticationService.login(oauth2Type, request.accessToken(), request.deviceToken()); + final LoginInformationDto loginInformationDto = + authenticationService.login(oauth2Type, request.accessToken(), request.deviceToken()); - return ResponseEntity.ok(TokenResponse.from(tokenDto)); + return ResponseEntity.ok(LoginInformationResponse.from(loginInformationDto)); } @PostMapping("/refresh-token") - public ResponseEntity refreshToken(@RequestBody final RefreshTokenRequest request) { + public ResponseEntity refreshToken(@RequestBody final RefreshTokenRequest request) { final TokenDto tokenDto = authenticationService.refreshToken(request.refreshToken()); return ResponseEntity.ok(TokenResponse.from(tokenDto)); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/authentication/presentation/dto/response/LoginInformationResponse.java b/backend/ddang/src/main/java/com/ddang/ddang/authentication/presentation/dto/response/LoginInformationResponse.java new file mode 100644 index 000000000..14ff3a2a3 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/authentication/presentation/dto/response/LoginInformationResponse.java @@ -0,0 +1,14 @@ +package com.ddang.ddang.authentication.presentation.dto.response; + +import com.ddang.ddang.authentication.application.dto.LoginInformationDto; + +public record LoginInformationResponse(String accessToken, String refreshToken, boolean isSignUpUser) { + + public static LoginInformationResponse from(final LoginInformationDto dto) { + return new LoginInformationResponse( + dto.tokenDto().accessToken(), + dto.tokenDto().refreshToken(), + dto.isSignUpUser() + ); + } +} diff --git a/backend/ddang/src/main/resources/static/docs/docs.html b/backend/ddang/src/main/resources/static/docs/docs.html index ecfe045b1..0054f2344 100644 --- a/backend/ddang/src/main/resources/static/docs/docs.html +++ b/backend/ddang/src/main/resources/static/docs/docs.html @@ -654,7 +654,8 @@

응답

{ "accessToken" : "Bearer accessToken", - "refreshToken" : "Bearer refreshToken" + "refreshToken" : "Bearer refreshToken", + "persisted" : false } @@ -682,6 +683,11 @@

응답

String

Refresh Token

+ +

persisted

+

Boolean

+

최초 로그인 여부(회원가입)

+ @@ -1463,7 +1469,7 @@

요청

Content-Disposition: form-data; name=request; filename=request Content-Type: application/json -{"title":"제목","description":"내용","bidUnit":1000,"startPrice":1000,"closingTime":"2023-10-12T11:02:42.5505268","subCategoryId":2,"thirdRegionIds":[3]} +{"title":"제목","description":"내용","bidUnit":1000,"startPrice":1000,"closingTime":"2023-10-14T14:17:47.075705","subCategoryId":2,"thirdRegionIds":[3]} --6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm-- @@ -2070,8 +2076,8 @@

응답

"lastBidPrice" : null, "status" : "UNBIDDEN", "bidUnit" : 1000, - "registerTime" : "2023-10-09T11:02:42", - "closingTime" : "2023-10-09T11:02:42", + "registerTime" : "2023-10-11T14:17:47", + "closingTime" : "2023-10-11T14:17:47", "directRegions" : [ { "first" : "서울특별시", "second" : "강서구", @@ -2593,7 +2599,7 @@

응답

"name" : "질문자", "image" : "http://localhost:8080/users/images/1" }, - "createdTime" : "2023-10-09T11:02:42", + "createdTime" : "2023-10-11T14:17:47", "content" : "질문1" }, "answer" : { @@ -2603,7 +2609,7 @@

응답

"name" : "판매자", "image" : "http://localhost:8080/users/images/2" }, - "createdTime" : "2023-10-09T11:02:42", + "createdTime" : "2023-10-11T14:17:47", "content" : "답변1" } }, { @@ -2614,7 +2620,7 @@

응답

"name" : "질문자", "image" : "http://localhost:8080/users/images/1" }, - "createdTime" : "2023-10-09T11:02:42", + "createdTime" : "2023-10-11T14:17:47", "content" : "질문2" }, "answer" : { @@ -2624,7 +2630,7 @@

응답

"name" : "판매자", "image" : "http://localhost:8080/users/images/2" }, - "createdTime" : "2023-10-09T11:02:42", + "createdTime" : "2023-10-11T14:17:47", "content" : "답변1" } } ] @@ -2833,12 +2839,12 @@

응답

"name" : "사용자1", "profileImage" : "http://localhost:8080/users/images/1", "price" : 10000, - "bidTime" : "2023-10-09T11:02:50" + "bidTime" : "2023-10-11T14:17:53" }, { "name" : "사용자2", "profileImage" : "http://localhost:8080/users/images/2", "price" : 12000, - "bidTime" : "2023-10-09T11:02:50" + "bidTime" : "2023-10-11T14:17:53" } ] } @@ -3033,7 +3039,7 @@

응답

"price" : 10000 }, "lastMessage" : { - "createdAt" : "2023-10-09T11:02:52", + "createdAt" : "2023-10-11T14:17:54", "contents" : "메시지1" }, "isChatAvailable" : true @@ -3051,7 +3057,7 @@

응답

"price" : 20000 }, "lastMessage" : { - "createdAt" : "2023-10-09T11:02:52", + "createdAt" : "2023-10-11T14:17:54", "contents" : "메시지2" }, "isChatAvailable" : true @@ -3489,7 +3495,7 @@

응답

[ { "id" : 1, - "createdAt" : "2023-10-09T11:02:52", + "createdAt" : "2023-10-11T14:17:54", "isMyMessage" : true, "contents" : "메시지내용" } ] @@ -3639,7 +3645,7 @@

응답

"id" : 2, "name" : "회원1" }, - "createdTime" : "2023-10-09T11:03:02", + "createdTime" : "2023-10-11T14:18:01", "auction" : { "id" : 1, "title" : "제목" @@ -3651,7 +3657,7 @@

응답

"id" : 3, "name" : "회원2" }, - "createdTime" : "2023-10-09T11:03:02", + "createdTime" : "2023-10-11T14:18:01", "auction" : { "id" : 1, "title" : "제목" @@ -3663,7 +3669,7 @@

응답

"id" : 4, "name" : "회원3" }, - "createdTime" : "2023-10-09T11:03:02", + "createdTime" : "2023-10-11T14:18:01", "auction" : { "id" : 1, "title" : "제목" @@ -3827,7 +3833,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-09T11:03:02", + "createdTime" : "2023-10-11T14:18:01", "chatRoom" : { "id" : 1 }, @@ -3838,7 +3844,7 @@

응답

"id" : 3, "name" : "구매자2" }, - "createdTime" : "2023-10-09T11:03:02", + "createdTime" : "2023-10-11T14:18:01", "chatRoom" : { "id" : 1 }, @@ -3849,7 +3855,7 @@

응답

"id" : 3, "name" : "구매자2" }, - "createdTime" : "2023-10-09T11:03:02", + "createdTime" : "2023-10-11T14:18:01", "chatRoom" : { "id" : 1 }, @@ -4013,7 +4019,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-09T11:03:02", + "createdTime" : "2023-10-11T14:18:01", "question" : { "id" : 1 }, @@ -4024,7 +4030,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-09T11:03:02", + "createdTime" : "2023-10-11T14:18:01", "question" : { "id" : 2 }, @@ -4035,7 +4041,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-09T11:03:02", + "createdTime" : "2023-10-11T14:18:01", "question" : { "id" : 3 }, @@ -4199,7 +4205,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-09T11:03:02", + "createdTime" : "2023-10-11T14:18:01", "answer" : { "id" : 1 }, @@ -4210,7 +4216,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-09T11:03:02", + "createdTime" : "2023-10-11T14:18:01", "answer" : { "id" : 2 }, @@ -4221,7 +4227,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-09T11:03:02", + "createdTime" : "2023-10-11T14:18:01", "answer" : { "id" : 3 }, @@ -4557,7 +4563,7 @@

응답

}, "content" : "친절하다.", "score" : 5.0, - "createdTime" : "2023-10-09T11:03:03" + "createdTime" : "2023-10-11T14:18:02" }, { "id" : 2, "writer" : { @@ -4567,7 +4573,7 @@

응답

}, "content" : "친절하다.", "score" : 5.0, - "createdTime" : "2023-10-09T11:03:03" + "createdTime" : "2023-10-11T14:18:02" } ] @@ -4725,7 +4731,7 @@

응답

diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java index 6238cad68..9ed6beeb2 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java @@ -5,6 +5,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; +import com.ddang.ddang.authentication.application.dto.LoginInformationDto; import com.ddang.ddang.authentication.application.dto.TokenDto; import com.ddang.ddang.authentication.application.exception.InvalidWithdrawalException; import com.ddang.ddang.authentication.application.fixture.AuthenticationServiceFixture; @@ -122,12 +123,13 @@ void setUp() { given(userInfoProvider.findUserInformation(anyString())).willReturn(사용자_회원_정보); // when - final TokenDto actual = authenticationService.login(지원하는_소셜_로그인_타입, 유효한_소셜_로그인_토큰, 디바이스_토큰); + final LoginInformationDto actual = authenticationService.login(지원하는_소셜_로그인_타입, 유효한_소셜_로그인_토큰, 디바이스_토큰); // then SoftAssertions.assertSoftly(softAssertions -> { - softAssertions.assertThat(actual.accessToken()).isNotEmpty().contains("Bearer "); - softAssertions.assertThat(actual.refreshToken()).isNotEmpty().contains("Bearer "); + softAssertions.assertThat(actual.tokenDto().accessToken()).isNotEmpty().contains("Bearer "); + softAssertions.assertThat(actual.tokenDto().refreshToken()).isNotEmpty().contains("Bearer "); + softAssertions.assertThat(actual.isSignUpUser()).isFalse(); }); } @@ -150,12 +152,12 @@ void setUp() { given(userInfoProvider.findUserInformation(anyString())).willReturn(사용자_회원_정보); // when - final TokenDto actual = authenticationService.login(지원하는_소셜_로그인_타입, 유효한_소셜_로그인_토큰, 디바이스_토큰); + final LoginInformationDto actual = authenticationService.login(지원하는_소셜_로그인_타입, 유효한_소셜_로그인_토큰, 디바이스_토큰); // then SoftAssertions.assertSoftly(softAssertions -> { - softAssertions.assertThat(actual.accessToken()).isNotEmpty(); - softAssertions.assertThat(actual.refreshToken()).isNotEmpty(); + softAssertions.assertThat(actual.tokenDto().accessToken()).isNotEmpty(); + softAssertions.assertThat(actual.tokenDto().refreshToken()).isNotEmpty(); }); } @@ -166,12 +168,12 @@ void setUp() { given(userInfoProvider.findUserInformation(anyString())).willReturn(사용자_회원_정보); // when - final TokenDto actual = authenticationService.login(지원하는_소셜_로그인_타입, 유효한_소셜_로그인_토큰, 디바이스_토큰); + final LoginInformationDto actual = authenticationService.login(지원하는_소셜_로그인_타입, 유효한_소셜_로그인_토큰, 디바이스_토큰); // then SoftAssertions.assertSoftly(softAssertions -> { - softAssertions.assertThat(actual.accessToken()).isNotEmpty(); - softAssertions.assertThat(actual.refreshToken()).isNotEmpty(); + softAssertions.assertThat(actual.tokenDto().accessToken()).isNotEmpty(); + softAssertions.assertThat(actual.tokenDto().refreshToken()).isNotEmpty(); }); } @@ -273,13 +275,13 @@ void setUp() { given(userInfoProvider.findUserInformation(anyString())).willReturn(가입하지_않은_사용자_회원_정보); // when - final TokenDto actual = authenticationService.login(지원하는_소셜_로그인_타입, 유효한_소셜_로그인_토큰, 디바이스_토큰); + final LoginInformationDto actual = authenticationService.login(지원하는_소셜_로그인_타입, 유효한_소셜_로그인_토큰, 디바이스_토큰); // then SoftAssertions.assertSoftly(softAssertions -> { - softAssertions.assertThat(actual.accessToken()).isNotEmpty().contains("Bearer "); - softAssertions.assertThat(actual.refreshToken()).isNotEmpty().contains("Bearer "); + softAssertions.assertThat(actual.tokenDto().accessToken()).isNotEmpty().contains("Bearer "); + softAssertions.assertThat(actual.tokenDto().refreshToken()).isNotEmpty().contains("Bearer "); }); } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/presentation/AuthenticationControllerTest.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/presentation/AuthenticationControllerTest.java index 13a707c9f..757269135 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/presentation/AuthenticationControllerTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/presentation/AuthenticationControllerTest.java @@ -59,7 +59,7 @@ void setUp() { @Test void 소셜_로그인을_지원하는_타입과_소셜_로그인_토큰을_전달하면_accessToken과_refreshToken을_반환한다() throws Exception { // given - given(authenticationService.login(eq(지원하는_소셜_로그인_타입), anyString(), anyString())).willReturn(발급된_토큰); + given(authenticationService.login(eq(지원하는_소셜_로그인_타입), anyString(), anyString())).willReturn(로그인한_사용자_정보); // when & then final ResultActions resultActions = @@ -70,7 +70,8 @@ void setUp() { .andExpectAll( status().isOk(), jsonPath("$.accessToken").exists(), - jsonPath("$.refreshToken").exists() + jsonPath("$.refreshToken").exists(), + jsonPath("$.isSignUpUser").exists() ); login_문서화(resultActions); @@ -249,7 +250,9 @@ void setUp() { fieldWithPath("accessToken").type(JsonFieldType.STRING) .description("Access Token"), fieldWithPath("refreshToken").type(JsonFieldType.STRING) - .description("Refresh Token") + .description("Refresh Token"), + fieldWithPath("isSignUpUser").type(JsonFieldType.BOOLEAN) + .description("최초 로그인 여부(회원가입)") ) ) ); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/presentation/fixture/AuthenticationControllerFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/presentation/fixture/AuthenticationControllerFixture.java index ee3145fee..a09ec833e 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/presentation/fixture/AuthenticationControllerFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/presentation/fixture/AuthenticationControllerFixture.java @@ -1,5 +1,6 @@ package com.ddang.ddang.authentication.presentation.fixture; +import com.ddang.ddang.authentication.application.dto.LoginInformationDto; import com.ddang.ddang.authentication.application.dto.TokenDto; import com.ddang.ddang.authentication.infrastructure.oauth2.Oauth2Type; import com.ddang.ddang.authentication.presentation.dto.request.LoginTokenRequest; @@ -17,6 +18,7 @@ public class AuthenticationControllerFixture extends CommonControllerSliceTest { protected String 유효한_액세스_토큰_내용 = "Bearer accessToken"; protected String 만료된_액세스_토큰_내용 = "Bearer accessToken"; protected TokenDto 발급된_토큰 = new TokenDto(유효한_액세스_토큰_내용, "Bearer refreshToken"); + protected LoginInformationDto 로그인한_사용자_정보 = new LoginInformationDto(발급된_토큰, false); protected LoginTokenRequest 유효한_로그인_요청 = new LoginTokenRequest("kakaoAccessToken", "deviceToken"); protected LoginTokenRequest 유효하지_않은_로그인_요청 = new LoginTokenRequest("kakaoAccessToken", "deviceToken"); protected RefreshTokenRequest 유효한_토큰_재발급_요청 = new RefreshTokenRequest("Bearer refreshToken"); From 0d7809510432faa15837bdcbb3952a690a4a6ee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=EC=98=88=EC=A7=84?= <96688810+kwonyj1022@users.noreply.github.com> Date: Fri, 13 Oct 2023 17:14:00 +0900 Subject: [PATCH 10/37] =?UTF-8?q?feat:=20#585=20=EC=83=81=ED=98=B8=20?= =?UTF-8?q?=ED=8F=89=EA=B0=80=20=EB=B0=98=EC=98=81=20=EC=8A=A4=EC=BC=80?= =?UTF-8?q?=EC=A4=84=EB=A7=81=20(#602)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 신뢰도 점수 타입을 Double -> double로 변경 * feat: 평가 저장 시 신뢰도를 갱신하지 않고 저장만 하도록 변경 * feat: 신뢰도 업데이트에 필요한 비즈니스 로직 추가 * feat: 신뢰도 업데이트 서비스 구현에 필요한 비즈니스 로직 보완 및 레포지토리 추가 * feat: 신뢰도 업데이트 서비스 추가 * feat: 스케줄링 설정 추가 * feat: flyway 스크립트 추가 * style: 개행 수정 * feat: 신뢰도 업데이트 이력을 관리하는 엔티티의 toString 대상 항목 추가 * refactor: 평가 관련 일급컬렉션에서 EqualsAndHashCode 재정의 제거 * test: 테스트코드에서 선언과 assertion 분리 * comment: 주석 제거 --- .../SchedulingConfiguration.java | 9 + .../review/application/ReviewService.java | 15 +- .../ddang/ddang/review/domain/Reviews.java | 52 +++ .../persistence/JpaReviewRepository.java | 6 +- .../ReliabilityUpdateSchedulingService.java | 65 ++++ .../ddang/ddang/user/domain/Reliability.java | 23 +- .../user/domain/ReliabilityUpdateHistory.java | 29 ++ .../com/ddang/ddang/user/domain/User.java | 7 +- .../ddang/user/domain/UserReliability.java | 72 ++++ ...JpaReliabilityUpdateHistoryRepository.java | 11 + .../JpaUserReliabilityRepository.java | 11 + .../V17__create_reliability_tables.sql | 18 + .../review/application/ReviewServiceTest.java | 8 +- .../fixture/ReviewServiceFixture.java | 8 +- .../ddang/review/domain/ReviewsTest.java | 103 ++++++ .../review/domain/fixture/ReviewsFixture.java | 61 ++++ .../persistence/JpaReviewRepositoryTest.java | 12 + ...eliabilityUpdateSchedulingServiceTest.java | 81 +++++ ...abilityUpdateSchedulingServiceFixture.java | 333 ++++++++++++++++++ .../ddang/user/domain/ReliabilityTest.java | 28 +- .../domain/ReliabilityUpdateHistoryTest.java | 32 ++ .../user/domain/UserReliabilityTest.java | 44 +++ .../com/ddang/ddang/user/domain/UserTest.java | 20 +- .../domain/fixture/ReliabilityFixture.java | 50 --- .../user/domain/fixture/UserFixture.java | 52 +-- .../fixture/UserReliabilityFixture.java | 75 ++++ ...eliabilityUpdateHistoryRepositoryTest.java | 59 ++++ .../JpaUserReliabilityRepositoryTest.java | 35 ++ .../JpaUserReliabilityRepositoryFixture.java | 45 +++ 29 files changed, 1203 insertions(+), 161 deletions(-) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/configuration/SchedulingConfiguration.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/review/domain/Reviews.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/user/application/schedule/ReliabilityUpdateSchedulingService.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/user/domain/ReliabilityUpdateHistory.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/user/domain/UserReliability.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaReliabilityUpdateHistoryRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserReliabilityRepository.java create mode 100644 backend/ddang/src/main/resources/db/migration/V17__create_reliability_tables.sql create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/review/domain/ReviewsTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/review/domain/fixture/ReviewsFixture.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/ReliabilityUpdateSchedulingServiceTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/fixture/ReliabilityUpdateSchedulingServiceFixture.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/user/domain/ReliabilityUpdateHistoryTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/user/domain/UserReliabilityTest.java delete mode 100644 backend/ddang/src/test/java/com/ddang/ddang/user/domain/fixture/ReliabilityFixture.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/user/domain/fixture/UserReliabilityFixture.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaReliabilityUpdateHistoryRepositoryTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserReliabilityRepositoryTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/JpaUserReliabilityRepositoryFixture.java diff --git a/backend/ddang/src/main/java/com/ddang/ddang/configuration/SchedulingConfiguration.java b/backend/ddang/src/main/java/com/ddang/ddang/configuration/SchedulingConfiguration.java new file mode 100644 index 000000000..e8141a7ca --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/configuration/SchedulingConfiguration.java @@ -0,0 +1,9 @@ +package com.ddang.ddang.configuration; + +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; + +@Configuration +@EnableScheduling +public class SchedulingConfiguration { +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/review/application/ReviewService.java b/backend/ddang/src/main/java/com/ddang/ddang/review/application/ReviewService.java index fad0e2a06..7922b15e5 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/review/application/ReviewService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/review/application/ReviewService.java @@ -44,9 +44,9 @@ public Long create(final CreateReviewDto reviewDto) { validateWriterCanReview(findAuction, writer); final Review review = reviewDto.toEntity(findAuction, writer, target); - final Review persistReview = saveReviewAndUpdateReliability(review, target); - return persistReview.getId(); + return reviewRepository.save(review) + .getId(); } private void validateWriterCanReview(final Auction auction, final User writer) { @@ -63,18 +63,9 @@ private void validateAlreadyReviewed(final Auction auction, final User writer) { } } - private Review saveReviewAndUpdateReliability(final Review review, final User target) { - final Review persistReview = reviewRepository.save(review); - - final List targetReviews = reviewRepository.findAllByTargetId(target.getId()); - target.updateReliability(targetReviews); - - return persistReview; - } - public ReadReviewDetailDto readByReviewId(final Long reviewId) { final Review findReview = reviewRepository.findById(reviewId) - .orElseThrow(() -> new ReviewNotFoundException("해당 평가를 찾을 수 없습니다.")); + .orElseThrow(() -> new ReviewNotFoundException("해당 평가를 찾을 수 없습니다.")); return ReadReviewDetailDto.from(findReview); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/review/domain/Reviews.java b/backend/ddang/src/main/java/com/ddang/ddang/review/domain/Reviews.java new file mode 100644 index 000000000..87d5ad746 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/review/domain/Reviews.java @@ -0,0 +1,52 @@ +package com.ddang.ddang.review.domain; + +import com.ddang.ddang.user.domain.User; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +import java.util.List; +import java.util.Set; + +import static java.util.stream.Collectors.toSet; + +@RequiredArgsConstructor +@Getter +@ToString +public class Reviews { + + private final List reviews; + + public double addAllReviewScore() { + return reviews.stream() + .mapToDouble(review -> review.getScore().getValue()) + .sum(); + } + + public int size() { + return reviews.size(); + } + + public boolean isEmpty() { + return reviews.isEmpty(); + } + + public Set findReviewTargets() { + return reviews.stream() + .map(Review::getTarget) + .collect(toSet()); + } + + public List findReviewsByTarget(final User targetUser) { + return reviews.stream() + .filter(review -> review.getTarget().equals(targetUser)) + .toList(); + } + + public Long findLastReviewId() { + final int lastIndex = reviews.size() - 1; + + return reviews.get(lastIndex) + .getId(); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/review/infrastructure/persistence/JpaReviewRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/review/infrastructure/persistence/JpaReviewRepository.java index 0d6e71e6a..5462534d6 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/review/infrastructure/persistence/JpaReviewRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/review/infrastructure/persistence/JpaReviewRepository.java @@ -12,11 +12,15 @@ public interface JpaReviewRepository extends JpaRepository { boolean existsByAuctionIdAndWriterId(final Long auctionId, final Long writerId); @Query(""" - SELECT r FROM Review r JOIN FETCH r.writer w JOIN FETCH r.target t + SELECT r FROM Review r + JOIN FETCH r.writer w + JOIN FETCH r.target t WHERE t.id = :targetId ORDER BY r.id DESC """) List findAllByTargetId(final Long targetId); Optional findByAuctionIdAndWriterId(final Long auctionId, final Long writerId); + + List findAllByIdGreaterThan(final Long id); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/application/schedule/ReliabilityUpdateSchedulingService.java b/backend/ddang/src/main/java/com/ddang/ddang/user/application/schedule/ReliabilityUpdateSchedulingService.java new file mode 100644 index 000000000..9b244d0c4 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/application/schedule/ReliabilityUpdateSchedulingService.java @@ -0,0 +1,65 @@ +package com.ddang.ddang.user.application.schedule; + +import com.ddang.ddang.review.domain.Review; +import com.ddang.ddang.review.domain.Reviews; +import com.ddang.ddang.review.infrastructure.persistence.JpaReviewRepository; +import com.ddang.ddang.user.domain.ReliabilityUpdateHistory; +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.UserReliability; +import com.ddang.ddang.user.infrastructure.persistence.JpaReliabilityUpdateHistoryRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserReliabilityRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Set; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class ReliabilityUpdateSchedulingService { + + private final JpaReliabilityUpdateHistoryRepository updateHistoryRepository; + private final JpaReviewRepository reviewRepository; + private final JpaUserReliabilityRepository userReliabilityRepository; + + @Transactional + @Scheduled(cron = "0 0 4 ? * MON") + public void updateAllUserReliability() { + final ReliabilityUpdateHistory updateHistory = updateHistoryRepository.findFirstByOrderByIdDesc() + .orElse(new ReliabilityUpdateHistory()); + final Long lastAppliedReviewId = updateHistory.getLastAppliedReviewId(); + final List findNewReviews = reviewRepository.findAllByIdGreaterThan(lastAppliedReviewId); + final Reviews newReviews = new Reviews(findNewReviews); + + if (newReviews.isEmpty()) { + return; + } + + update(newReviews); + } + + private void update(final Reviews newReviews) { + final Set targetUsers = newReviews.findReviewTargets(); + for (final User targetUser : targetUsers) { + final UserReliability userReliability = userReliabilityRepository.findByUserId(targetUser.getId()) + .orElseGet(() -> createUserReliability(targetUser)); + + final List targetReviews = newReviews.findReviewsByTarget(targetUser); + + userReliability.updateReliability(new Reviews(targetReviews)); + } + + final ReliabilityUpdateHistory newHistory = new ReliabilityUpdateHistory(newReviews.findLastReviewId()); + + updateHistoryRepository.save(newHistory); + } + + private UserReliability createUserReliability(final User user) { + final UserReliability userReliability = new UserReliability(user); + + return userReliabilityRepository.save(userReliability); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/Reliability.java b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/Reliability.java index cda3996cf..22fe3e67f 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/Reliability.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/Reliability.java @@ -1,6 +1,5 @@ package com.ddang.ddang.user.domain; -import com.ddang.ddang.review.domain.Review; import jakarta.persistence.Embeddable; import lombok.AccessLevel; import lombok.EqualsAndHashCode; @@ -8,8 +7,6 @@ import lombok.NoArgsConstructor; import lombok.ToString; -import java.util.List; - @Embeddable @NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter @@ -17,24 +14,16 @@ @ToString public class Reliability { - public static final Reliability INITIAL_RELIABILITY = new Reliability(null); + private static final double INITIAL_RELIABILITY_VALUE = Double.MIN_VALUE; + public static final Reliability INITIAL_RELIABILITY = new Reliability(INITIAL_RELIABILITY_VALUE); - private Double value; + private double value; - public Reliability(final Double value) { + public Reliability(final double value) { this.value = value; } - public void updateReliability(final List reviews) { - if (reviews.isEmpty()) { - this.value = null; - - return; - } - - this.value = reviews.stream() - .mapToDouble(review -> review.getScore().getValue()) - .average() - .orElseGet(null); + public double calculateReviewScoreSum(final int appliedReviewCount) { + return value * appliedReviewCount; } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/ReliabilityUpdateHistory.java b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/ReliabilityUpdateHistory.java new file mode 100644 index 000000000..31d670c54 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/ReliabilityUpdateHistory.java @@ -0,0 +1,29 @@ +package com.ddang.ddang.user.domain; + +import com.ddang.ddang.common.entity.BaseCreateTimeEntity; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@Entity +@NoArgsConstructor +@Getter +@EqualsAndHashCode(of = "id", callSuper = false) +@ToString(of = {"id", "lastAppliedReviewId"}) +public class ReliabilityUpdateHistory extends BaseCreateTimeEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private Long lastAppliedReviewId = 0L; + + public ReliabilityUpdateHistory(final Long lastAppliedReviewId) { + this.lastAppliedReviewId = lastAppliedReviewId; + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/User.java b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/User.java index 2bee553ec..85c464520 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/User.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/User.java @@ -2,7 +2,6 @@ import com.ddang.ddang.common.entity.BaseTimeEntity; import com.ddang.ddang.image.domain.ProfileImage; -import com.ddang.ddang.review.domain.Review; import jakarta.persistence.AttributeOverride; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; @@ -23,8 +22,6 @@ import lombok.NoArgsConstructor; import lombok.ToString; -import java.util.List; - @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter @@ -90,7 +87,7 @@ public void withdrawal() { this.deleted = DELETED_STATUS; } - public void updateReliability(final List reviews) { - reliability.updateReliability(reviews); + public void updateReliability(final Reliability reliability) { + this.reliability = reliability; } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/UserReliability.java b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/UserReliability.java new file mode 100644 index 000000000..c89639d07 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/UserReliability.java @@ -0,0 +1,72 @@ +package com.ddang.ddang.user.domain; + +import com.ddang.ddang.review.domain.Reviews; +import jakarta.persistence.AttributeOverride; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.ForeignKey; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToOne; +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter +@EqualsAndHashCode(of = "id", callSuper = false) +@ToString(of = {"id", "reliability", "appliedReviewCount"}) +public class UserReliability { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.REMOVE}) + @JoinColumn(name = "user_id", foreignKey = @ForeignKey(name = "fk_user_reliability_user"), nullable = false) + private User user; + + @Embedded + @AttributeOverride(name = "value", column = @Column(name = "reliability")) + private Reliability reliability; + + private int appliedReviewCount = 0; + + public UserReliability(final User user) { + this.user = user; + this.reliability = user.getReliability(); + } + + public void updateReliability(final Reviews newReviews) { + if (newReviews.isEmpty()) { + return; + } + final Reliability newReliability = calculateNewReliability(newReviews); + + this.reliability = newReliability; + addAppliedReviewCount(newReviews.size()); + user.updateReliability(newReliability); + } + + private Reliability calculateNewReliability(final Reviews newReviews) { + final double currentReviewScoreSum = reliability.calculateReviewScoreSum(appliedReviewCount); + final double newReviewScoreSum = newReviews.addAllReviewScore(); + final int allReviewCount = appliedReviewCount + newReviews.size(); + + final double newReliabilityValue = (currentReviewScoreSum + newReviewScoreSum) / allReviewCount; + + return new Reliability(newReliabilityValue); + } + + private void addAppliedReviewCount(final int newReviewCount) { + this.appliedReviewCount += newReviewCount; + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaReliabilityUpdateHistoryRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaReliabilityUpdateHistoryRepository.java new file mode 100644 index 000000000..c08d74b8f --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaReliabilityUpdateHistoryRepository.java @@ -0,0 +1,11 @@ +package com.ddang.ddang.user.infrastructure.persistence; + +import com.ddang.ddang.user.domain.ReliabilityUpdateHistory; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface JpaReliabilityUpdateHistoryRepository extends JpaRepository { + + Optional findFirstByOrderByIdDesc(); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserReliabilityRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserReliabilityRepository.java new file mode 100644 index 000000000..5362ee465 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserReliabilityRepository.java @@ -0,0 +1,11 @@ +package com.ddang.ddang.user.infrastructure.persistence; + +import com.ddang.ddang.user.domain.UserReliability; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface JpaUserReliabilityRepository extends JpaRepository { + + Optional findByUserId(final Long userId); +} diff --git a/backend/ddang/src/main/resources/db/migration/V17__create_reliability_tables.sql b/backend/ddang/src/main/resources/db/migration/V17__create_reliability_tables.sql new file mode 100644 index 000000000..91ce85f37 --- /dev/null +++ b/backend/ddang/src/main/resources/db/migration/V17__create_reliability_tables.sql @@ -0,0 +1,18 @@ +create table reliability_update_history +( + id bigint not null auto_increment, + created_time datetime(6) not null, + last_applied_review_id bigint, + primary key (id) +); + +create table user_reliability +( + id bigint not null auto_increment, + applied_review_count integer not null, + reliability float(53), + user_id bigint not null, + primary key (id) +); + +alter table user_reliability add constraint fk_user_reliability_user foreign key (user_id) references users (id); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/review/application/ReviewServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/review/application/ReviewServiceTest.java index 65307b708..72e5bc32a 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/review/application/ReviewServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/review/application/ReviewServiceTest.java @@ -17,6 +17,7 @@ import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; @IsolateDatabase @@ -28,15 +29,12 @@ class ReviewServiceTest extends ReviewServiceFixture { ReviewService reviewService; @Test - void 평가를_등록한고_평가_상대의_신뢰도를_갱신한다() { + void 평가를_등록한다() { // when final Long actual = reviewService.create(구매자에_대한_평가_등록을_위한_DTO); // then - SoftAssertions.assertSoftly(softAssertions -> { - softAssertions.assertThat(actual).isPositive(); - softAssertions.assertThat(구매자.getReliability().getValue()).isEqualTo(구매자가_새로운_평가_점수를_받고난_후의_신뢰도_점수); - }); + assertThat(actual).isPositive(); } @Test diff --git a/backend/ddang/src/test/java/com/ddang/ddang/review/application/fixture/ReviewServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/review/application/fixture/ReviewServiceFixture.java index 510d1ea42..3cab1c14f 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/review/application/fixture/ReviewServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/review/application/fixture/ReviewServiceFixture.java @@ -36,11 +36,11 @@ public class ReviewServiceFixture { @Autowired private JpaReviewRepository reviewRepository; - private Double 구매자가_판매자1에게_받은_평가_점수 = 5.0d; - private Double 구매자가_판매자2에게_받은_평가_점수 = 1.0d; - private Double 구매자가_받을_새로운_평가_점수 = 4.5d; + private double 구매자가_판매자1에게_받은_평가_점수 = 5.0d; + private double 구매자가_판매자2에게_받은_평가_점수 = 1.0d; + private double 구매자가_받을_새로운_평가_점수 = 4.5d; - protected Double 구매자가_새로운_평가_점수를_받고난_후의_신뢰도_점수 = + protected double 구매자가_새로운_평가_점수를_받고난_후의_신뢰도_점수 = (구매자가_판매자1에게_받은_평가_점수 + 구매자가_판매자2에게_받은_평가_점수 + 구매자가_받을_새로운_평가_점수) / 3; protected Long 존재하지_않는_사용자 = -999L; protected User 판매자1; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/review/domain/ReviewsTest.java b/backend/ddang/src/test/java/com/ddang/ddang/review/domain/ReviewsTest.java new file mode 100644 index 000000000..034f69eef --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/review/domain/ReviewsTest.java @@ -0,0 +1,103 @@ +package com.ddang.ddang.review.domain; + +import com.ddang.ddang.review.domain.fixture.ReviewsFixture; +import com.ddang.ddang.user.domain.User; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +class ReviewsTest extends ReviewsFixture { + + @Test + void 리뷰들의_점수를_모두_더해서_반환한다() { + // given + final Reviews reviews = new Reviews(List.of(사용자1의_평가1, 사용자1의_평가2)); + + // when + final double actual = reviews.addAllReviewScore(); + + // then + assertThat(actual).isEqualTo(평가1_점수 + 평가2_점수); + } + + @Test + void 리뷰들의_개수를_반환한다() { + // given + final Reviews reviews = new Reviews(List.of(사용자1의_평가1, 사용자1의_평가2)); + + // when + final int actual = reviews.size(); + + // then + assertThat(actual).isEqualTo(2); + } + + @Test + void 리뷰가_없다면_참을_반환한다() { + // given + final Reviews reviews = new Reviews(Collections.emptyList()); + + // when + final boolean actual = reviews.isEmpty(); + + // then + assertThat(actual).isTrue(); + } + + @Test + void 리뷰가_존재한다면_거짓을_반환한다() { + // given + final Reviews reviews = new Reviews(List.of(사용자1의_평가1, 사용자1의_평가2)); + + // when + final boolean actual = reviews.isEmpty(); + + // then + assertThat(actual).isFalse(); + } + + @Test + void 평가_대상자_목록을_중복_없이_반환한다() { + // given + final Reviews reviews = new Reviews(List.of(사용자1의_평가1, 사용자1의_평가2, 사용자2의_평가1, 사용자2의_평가2)); + + // when + final Set actual = reviews.findReviewTargets(); + + // then + assertThat(actual).containsExactlyInAnyOrder(사용자1, 사용자2); + } + + @Test + void 평가_대상_사용자가_받은_평가_목록을_반환한다() { + // given + final Reviews reviews = new Reviews(List.of(사용자1의_평가1, 사용자1의_평가2, 사용자2의_평가1, 사용자2의_평가2)); + + // when + final List actual = reviews.findReviewsByTarget(사용자1); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).hasSize(2); + softAssertions.assertThat(actual.get(0)).isEqualTo(사용자1의_평가1); + softAssertions.assertThat(actual.get(1)).isEqualTo(사용자1의_평가2); + }); + } + + @Test + void 평가_목록_중_가장_마지막_평가의_아이디를_반환한다() { + // given + final Reviews reviews = new Reviews(List.of(사용자1의_평가1, 사용자1의_평가2, 사용자2의_평가1, 사용자2의_평가2)); + + // when + final Long actual = reviews.findLastReviewId(); + + // then + assertThat(actual).isEqualTo(사용자2의_평가2.getId()); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/review/domain/fixture/ReviewsFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/review/domain/fixture/ReviewsFixture.java new file mode 100644 index 000000000..15cf0673b --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/review/domain/fixture/ReviewsFixture.java @@ -0,0 +1,61 @@ +package com.ddang.ddang.review.domain.fixture; + +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.review.domain.Review; +import com.ddang.ddang.review.domain.Score; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.test.util.ReflectionTestUtils; + +@SuppressWarnings("NonAsciiCharacters") +public class ReviewsFixture { + + protected double 평가1_점수 = 1.5d; + protected double 평가2_점수 = 2.5d; + protected User 사용자1; + protected User 사용자2; + protected Review 사용자1의_평가1; + protected Review 사용자1의_평가2; + protected Review 사용자2의_평가1; + protected Review 사용자2의_평가2; + + @BeforeEach + void setUp() { + 사용자1 = User.builder() + .name("사용자1") + .profileImage(new ProfileImage("uplad.png", "store.png")) + .reliability(Reliability.INITIAL_RELIABILITY) + .oauthId("12345") + .build(); + 사용자2 = User.builder() + .name("사용자2") + .profileImage(new ProfileImage("uplad.png", "store.png")) + .reliability(Reliability.INITIAL_RELIABILITY) + .oauthId("12346") + .build(); + ReflectionTestUtils.setField(사용자1, "id", 1L); + ReflectionTestUtils.setField(사용자2, "id", 2L); + + 사용자1의_평가1 = Review.builder() + .target(사용자1) + .score(new Score(평가1_점수)) + .build(); + ReflectionTestUtils.setField(사용자1의_평가1, "id", 1L); + 사용자1의_평가2 = Review.builder() + .target(사용자1) + .score(new Score(평가2_점수)) + .build(); + ReflectionTestUtils.setField(사용자1의_평가1, "id", 2L); + 사용자2의_평가1 = Review.builder() + .target(사용자2) + .score(new Score(평가1_점수)) + .build(); + ReflectionTestUtils.setField(사용자2의_평가1, "id", 3L); + 사용자2의_평가2 = Review.builder() + .target(사용자2) + .score(new Score(평가2_점수)) + .build(); + ReflectionTestUtils.setField(사용자2의_평가2, "id", 4L); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/review/infrastructure/persistence/JpaReviewRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/review/infrastructure/persistence/JpaReviewRepositoryTest.java index 1a491874c..d48cd257d 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/review/infrastructure/persistence/JpaReviewRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/review/infrastructure/persistence/JpaReviewRepositoryTest.java @@ -93,4 +93,16 @@ class JpaReviewRepositoryTest extends JpaReviewRepositoryFixture { // then assertThat(actual).isEmpty(); } + + @Test + void 지정한_평가_아이디보다_아이디가_큰_평가_목록을_조회한다() { + // when + final List actual = reviewRepository.findAllByIdGreaterThan(구매자가_판매자1에게_받은_평가.getId()); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).hasSize(1); + softAssertions.assertThat(actual.get(0)).isEqualTo(구매자가_판매자2에게_받은_평가); + }); + } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/ReliabilityUpdateSchedulingServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/ReliabilityUpdateSchedulingServiceTest.java new file mode 100644 index 000000000..557ca3529 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/ReliabilityUpdateSchedulingServiceTest.java @@ -0,0 +1,81 @@ +package com.ddang.ddang.user.application.schedule; + +import com.ddang.ddang.configuration.IsolateDatabase; +import com.ddang.ddang.user.application.schedule.fixture.ReliabilityUpdateSchedulingServiceFixture; +import com.ddang.ddang.user.domain.ReliabilityUpdateHistory; +import com.ddang.ddang.user.domain.UserReliability; +import com.ddang.ddang.user.infrastructure.persistence.JpaReliabilityUpdateHistoryRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserReliabilityRepository; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@IsolateDatabase +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class ReliabilityUpdateSchedulingServiceTest extends ReliabilityUpdateSchedulingServiceFixture { + + @Autowired + ReliabilityUpdateSchedulingService reliabilityUpdateSchedulingService; + + @Autowired + JpaReliabilityUpdateHistoryRepository reliabilityUpdateHistoryRepository; + + @Autowired + JpaUserReliabilityRepository userReliabilityRepository; + + @Test + void 사용자의_신뢰도를_갱신한다() { + // when + reliabilityUpdateSchedulingService.updateAllUserReliability(); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(구매자1_기존_평가_2개_새로운_평가_1개.getReliability()).isEqualTo(구매자1_최종_신뢰도); + softAssertions.assertThat(구매자2_기존_평가_3개_새로운_평가_2개.getReliability()).isEqualTo(구매자2_최종_신뢰도); + softAssertions.assertThat(구매자3_기존_평가_5개_새로운_평가_1개.getReliability()).isEqualTo(구매자3_최종_신뢰도); + softAssertions.assertThat(구매자4_기존_평가_없고_새로운_평가_1개.getReliability()).isEqualTo(구매자4_최종_신뢰도); + softAssertions.assertThat(구매자5_기존_평가_없고_새로운_평가_3개.getReliability()).isEqualTo(구매자5_최종_신뢰도); + }); + } + + @Test + void 사용자의_신뢰도를_갱신하면_사용자_신뢰도_반영_정보도_갱신된다() { + // when + reliabilityUpdateSchedulingService.updateAllUserReliability(); + + // then + final Optional actual1 = userReliabilityRepository.findByUserId(구매자1_기존_평가_2개_새로운_평가_1개.getId()); + final Optional actual2 = userReliabilityRepository.findByUserId(구매자2_기존_평가_3개_새로운_평가_2개.getId()); + final Optional actual3 = userReliabilityRepository.findByUserId(구매자3_기존_평가_5개_새로운_평가_1개.getId()); + final Optional actual4 = userReliabilityRepository.findByUserId(구매자4_기존_평가_없고_새로운_평가_1개.getId()); + final Optional actual5 = userReliabilityRepository.findByUserId(구매자5_기존_평가_없고_새로운_평가_3개.getId()); + final Optional actual6 = userReliabilityRepository.findByUserId(구매자6_기존_평가_없고_새로운_평가_없음.getId()); + + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual1.get().getAppliedReviewCount()).isEqualTo(구매자1_최종_신뢰도_반영_개수); + softAssertions.assertThat(actual2.get().getAppliedReviewCount()).isEqualTo(구매자2_최종_신뢰도_반영_개수); + softAssertions.assertThat(actual3.get().getAppliedReviewCount()).isEqualTo(구매자3_최종_신뢰도_반영_개수); + softAssertions.assertThat(actual4.get().getAppliedReviewCount()).isEqualTo(구매자4_최종_신뢰도_반영_개수); + softAssertions.assertThat(actual5.get().getAppliedReviewCount()).isEqualTo(구매자5_최종_신뢰도_반영_개수); + softAssertions.assertThat(actual6).isEmpty(); + }); + } + + @Test + void 사용자_신뢰도_갱신_후에_마지막으로_적용된_평가의_아이디를_디비에_저장한다() { + // when + reliabilityUpdateSchedulingService.updateAllUserReliability(); + + // then + final Optional actual = reliabilityUpdateHistoryRepository.findFirstByOrderByIdDesc(); + + assertThat(actual.get().getLastAppliedReviewId()).isEqualTo(새로운_평가를_업데이트한_후의_마지막으로_적용된_평가의_아이디); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/fixture/ReliabilityUpdateSchedulingServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/fixture/ReliabilityUpdateSchedulingServiceFixture.java new file mode 100644 index 000000000..25e0adaca --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/fixture/ReliabilityUpdateSchedulingServiceFixture.java @@ -0,0 +1,333 @@ +package com.ddang.ddang.user.application.schedule.fixture; + +import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.review.domain.Review; +import com.ddang.ddang.review.domain.Reviews; +import com.ddang.ddang.review.domain.Score; +import com.ddang.ddang.review.infrastructure.persistence.JpaReviewRepository; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.ReliabilityUpdateHistory; +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.UserReliability; +import com.ddang.ddang.user.infrastructure.persistence.JpaReliabilityUpdateHistoryRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserReliabilityRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.List; + +@SuppressWarnings("NonAsciiCharacters") +public class ReliabilityUpdateSchedulingServiceFixture { + + @Autowired + private JpaUserRepository userRepository; + + @Autowired + private JpaAuctionRepository auctionRepository; + + @Autowired + private JpaReviewRepository reviewRepository; + + @Autowired + private JpaUserReliabilityRepository userReliabilityRepository; + + @Autowired + private JpaReliabilityUpdateHistoryRepository reliabilityUpdateHistoryRepository; + + private double 구매자1_기존_신뢰도_점수 = 3.5d; + private double 구매자2_기존_신뢰도_점수 = 4.0d; + private double 구매자3_기존_신뢰도_점수 = 4.5d; + private double 구매자1_새로운_평가1_점수 = 5.0d; + private double 구매자2_새로운_평가1_점수 = 4.5d; + private double 구매자2_새로운_평가2_점수 = 5.0d; + private double 구매자3_새로운_평가1_점수 = 3.0d; + private double 구매자4_새로운_평가1_점수 = 3.5d; + private double 구매자5_새로운_평가1_점수 = 1.0d; + private double 구매자5_새로운_평가2_점수 = 2.0d; + private double 구매자5_새로운_평가3_점수 = 3.0d; + protected Long 기존에_적용된_평가_중_마지막_평가의_아이디 = 10L; + protected Reliability 구매자1_최종_신뢰도 = new Reliability(4.0d); + protected Reliability 구매자2_최종_신뢰도 = new Reliability(4.3d); + protected Reliability 구매자3_최종_신뢰도 = new Reliability(4.25d); + protected Reliability 구매자4_최종_신뢰도 = new Reliability(3.5d); + protected Reliability 구매자5_최종_신뢰도 = new Reliability(2.0d); + protected User 구매자1_기존_평가_2개_새로운_평가_1개; + protected User 구매자2_기존_평가_3개_새로운_평가_2개; + protected User 구매자3_기존_평가_5개_새로운_평가_1개; + protected User 구매자4_기존_평가_없고_새로운_평가_1개; + protected User 구매자5_기존_평가_없고_새로운_평가_3개; + protected User 구매자6_기존_평가_없고_새로운_평가_없음; + + protected int 구매자1_최종_신뢰도_반영_개수 = 3; + protected int 구매자2_최종_신뢰도_반영_개수 = 5; + protected int 구매자3_최종_신뢰도_반영_개수 = 6; + protected int 구매자4_최종_신뢰도_반영_개수 = 1; + protected int 구매자5_최종_신뢰도_반영_개수 = 3; + protected Review 구매자1_새로운_평가1; + protected Review 구매자2_새로운_평가1; + protected Review 구매자2_새로운_평가2; + protected Review 구매자3_새로운_평가1; + protected Review 구매자4_새로운_평가1; + protected Review 구매자5_새로운_평가1; + protected Review 구매자5_새로운_평가2; + protected Review 구매자5_새로운_평가3; + protected Long 새로운_평가를_업데이트한_후의_마지막으로_적용된_평가의_아이디 = 18L; + + + @BeforeEach + void setUp() { + final User 판매자 = User.builder() + .name("판매자") + .profileImage(new ProfileImage("upload.png", "updateImage.png")) + .reliability(Reliability.INITIAL_RELIABILITY) + .oauthId("1000") + .build(); + 구매자1_기존_평가_2개_새로운_평가_1개 = User.builder() + .name("구매자1") + .profileImage(new ProfileImage("upload.png", "updateImage.png")) + .reliability(Reliability.INITIAL_RELIABILITY) + .oauthId("1001") + .build(); + 구매자2_기존_평가_3개_새로운_평가_2개 = User.builder() + .name("구매자2") + .profileImage(new ProfileImage("upload.png", "updateImage.png")) + .reliability(Reliability.INITIAL_RELIABILITY) + .oauthId("1002") + .build(); + 구매자3_기존_평가_5개_새로운_평가_1개 = User.builder() + .name("구매자3") + .profileImage(new ProfileImage("upload.png", "updateImage.png")) + .reliability(Reliability.INITIAL_RELIABILITY) + .oauthId("1003") + .build(); + 구매자4_기존_평가_없고_새로운_평가_1개 = User.builder() + .name("구매자4") + .profileImage(new ProfileImage("upload.png", "updateImage.png")) + .reliability(Reliability.INITIAL_RELIABILITY) + .oauthId("1004") + .build(); + 구매자5_기존_평가_없고_새로운_평가_3개 = User.builder() + .name("구매자5") + .profileImage(new ProfileImage("upload.png", "updateImage.png")) + .reliability(Reliability.INITIAL_RELIABILITY) + .oauthId("1005") + .build(); + 구매자6_기존_평가_없고_새로운_평가_없음 = User.builder() + .name("구매자6") + .profileImage(new ProfileImage("upload.png", "updateImage.png")) + .reliability(Reliability.INITIAL_RELIABILITY) + .oauthId("1006") + .build(); + userRepository.saveAll(List.of(판매자, + 구매자1_기존_평가_2개_새로운_평가_1개, + 구매자2_기존_평가_3개_새로운_평가_2개, + 구매자3_기존_평가_5개_새로운_평가_1개, + 구매자4_기존_평가_없고_새로운_평가_1개, + 구매자5_기존_평가_없고_새로운_평가_3개, + 구매자6_기존_평가_없고_새로운_평가_없음 + )); + final Auction 경매1 = Auction.builder() + .title("경매1") + .seller(판매자) + .build(); + final Auction 경매2 = Auction.builder() + .title("경매2") + .seller(판매자) + .build(); + final Auction 경매3 = Auction.builder() + .title("경매3") + .seller(판매자) + .build(); + final Auction 경매4 = Auction.builder() + .title("경매4") + .seller(판매자) + .build(); + final Auction 경매5 = Auction.builder() + .title("경매5") + .seller(판매자) + .build(); + final Auction 경매6 = Auction.builder() + .title("경매7") + .seller(판매자) + .build(); + final Auction 경매7 = Auction.builder() + .title("경매7") + .seller(판매자) + .build(); + final Auction 경매8 = Auction.builder() + .title("경매8") + .seller(판매자) + .build(); + final Auction 경매9 = Auction.builder() + .title("경매9") + .seller(판매자) + .build(); + final Auction 경매10 = Auction.builder() + .title("경매10") + .seller(판매자) + .build(); + final Auction 경매11 = Auction.builder() + .title("경매11") + .seller(판매자) + .build(); + final Auction 경매12 = Auction.builder() + .title("경매12") + .seller(판매자) + .build(); + final Auction 경매13 = Auction.builder() + .title("경매13") + .seller(판매자) + .build(); + final Auction 경매14 = Auction.builder() + .title("경매14") + .seller(판매자) + .build(); + final Auction 경매15 = Auction.builder() + .title("경매15") + .seller(판매자) + .build(); + final Auction 경매16 = Auction.builder() + .title("경매16") + .seller(판매자) + .build(); + final Auction 경매17 = Auction.builder() + .title("경매17") + .seller(판매자) + .build(); + final Auction 경매18 = Auction.builder() + .title("경매18") + .seller(판매자) + .build(); + auctionRepository.saveAll(List.of(경매1, 경매2, 경매3, 경매4, 경매5, 경매6, 경매7, 경매8, 경매9, 경매10, 경매11, 경매12, 경매13, 경매14, 경매15, 경매16, 경매17, 경매18)); + + final Review 구매자1_기존_평가1 = Review.builder() + .auction(경매1) + .writer(판매자) + .target(구매자1_기존_평가_2개_새로운_평가_1개) + .score(new Score(구매자1_기존_신뢰도_점수)) + .build(); + final Review 구매자1_기존_평가2 = Review.builder() + .auction(경매2) + .writer(판매자) + .target(구매자1_기존_평가_2개_새로운_평가_1개) + .score(new Score(구매자1_기존_신뢰도_점수)) + .build(); + final Review 구매자2_기존_평가1 = Review.builder() + .auction(경매3) + .writer(판매자) + .target(구매자2_기존_평가_3개_새로운_평가_2개) + .score(new Score(구매자2_기존_신뢰도_점수)) + .build(); + final Review 구매자2_기존_평가2 = Review.builder() + .auction(경매4) + .writer(판매자) + .target(구매자2_기존_평가_3개_새로운_평가_2개) + .score(new Score(구매자2_기존_신뢰도_점수)) + .build(); + final Review 구매자2_기존_평가3 = Review.builder() + .auction(경매5) + .writer(판매자) + .target(구매자2_기존_평가_3개_새로운_평가_2개) + .score(new Score(구매자2_기존_신뢰도_점수)) + .build(); + final Review 구매자3_기존_평가1 = Review.builder() + .auction(경매6) + .writer(판매자) + .target(구매자3_기존_평가_5개_새로운_평가_1개) + .score(new Score(구매자3_기존_신뢰도_점수)) + .build(); + final Review 구매자3_기존_평가2 = Review.builder() + .auction(경매7) + .writer(판매자) + .target(구매자3_기존_평가_5개_새로운_평가_1개) + .score(new Score(구매자3_기존_신뢰도_점수)) + .build(); + final Review 구매자3_기존_평가3 = Review.builder() + .auction(경매8) + .writer(판매자) + .target(구매자3_기존_평가_5개_새로운_평가_1개) + .score(new Score(구매자3_기존_신뢰도_점수)) + .build(); + final Review 구매자3_기존_평가4 = Review.builder() + .auction(경매9) + .writer(판매자) + .target(구매자3_기존_평가_5개_새로운_평가_1개) + .score(new Score(구매자3_기존_신뢰도_점수)) + .build(); + final Review 구매자3_기존_평가5 = Review.builder() + .auction(경매10) + .writer(판매자) + .target(구매자3_기존_평가_5개_새로운_평가_1개) + .score(new Score(구매자3_기존_신뢰도_점수)) + .build(); + reviewRepository.saveAll(List.of(구매자1_기존_평가1, 구매자1_기존_평가2, 구매자2_기존_평가1, 구매자2_기존_평가2, 구매자2_기존_평가3, 구매자3_기존_평가1, 구매자3_기존_평가2, 구매자3_기존_평가3, 구매자3_기존_평가4, 구매자3_기존_평가5 + )); + + final UserReliability 구매자1_기존_신뢰도_반영_정보 = new UserReliability(구매자1_기존_평가_2개_새로운_평가_1개); + 구매자1_기존_신뢰도_반영_정보.updateReliability(new Reviews(List.of(구매자1_기존_평가1, 구매자1_기존_평가2))); + + final UserReliability 구매자2_기존_신뢰도_반영_정보 = new UserReliability(구매자2_기존_평가_3개_새로운_평가_2개); + 구매자2_기존_신뢰도_반영_정보.updateReliability(new Reviews(List.of(구매자2_기존_평가1, 구매자2_기존_평가2, 구매자2_기존_평가3))); + + final UserReliability 구매자3_기존_신뢰도_반영_정보 = new UserReliability(구매자3_기존_평가_5개_새로운_평가_1개); + 구매자3_기존_신뢰도_반영_정보.updateReliability(new Reviews(List.of(구매자3_기존_평가1, 구매자3_기존_평가2, 구매자3_기존_평가3, 구매자3_기존_평가4, 구매자3_기존_평가5))); + + userReliabilityRepository.saveAll(List.of(구매자1_기존_신뢰도_반영_정보, 구매자2_기존_신뢰도_반영_정보, 구매자3_기존_신뢰도_반영_정보)); + + reliabilityUpdateHistoryRepository.save(new ReliabilityUpdateHistory(기존에_적용된_평가_중_마지막_평가의_아이디)); + + 구매자1_새로운_평가1 = Review.builder() + .auction(경매11) + .writer(판매자) + .target(구매자1_기존_평가_2개_새로운_평가_1개) + .score(new Score(구매자1_새로운_평가1_점수)) + .build(); + 구매자2_새로운_평가1 = Review.builder() + .auction(경매12) + .writer(판매자) + .target(구매자2_기존_평가_3개_새로운_평가_2개) + .score(new Score(구매자2_새로운_평가1_점수)) + .build(); + 구매자2_새로운_평가2 = Review.builder() + .auction(경매13) + .writer(판매자) + .target(구매자2_기존_평가_3개_새로운_평가_2개) + .score(new Score(구매자2_새로운_평가2_점수)) + .build(); + 구매자3_새로운_평가1 = Review.builder() + .auction(경매14) + .writer(판매자) + .target(구매자3_기존_평가_5개_새로운_평가_1개) + .score(new Score(구매자3_새로운_평가1_점수)) + .build(); + 구매자4_새로운_평가1 = Review.builder() + .auction(경매15) + .writer(판매자) + .target(구매자4_기존_평가_없고_새로운_평가_1개) + .score(new Score(구매자4_새로운_평가1_점수)) + .build(); + 구매자5_새로운_평가1 = Review.builder() + .auction(경매16) + .writer(판매자) + .target(구매자5_기존_평가_없고_새로운_평가_3개) + .score(new Score(구매자5_새로운_평가1_점수)) + .build(); + 구매자5_새로운_평가2 = Review.builder() + .auction(경매17) + .writer(판매자) + .target(구매자5_기존_평가_없고_새로운_평가_3개) + .score(new Score(구매자5_새로운_평가2_점수)) + .build(); + 구매자5_새로운_평가3 = Review.builder() + .auction(경매18) + .writer(판매자) + .target(구매자5_기존_평가_없고_새로운_평가_3개) + .score(new Score(구매자5_새로운_평가3_점수)) + .build(); + reviewRepository.saveAll(List.of(구매자1_새로운_평가1, 구매자2_새로운_평가1, 구매자2_새로운_평가2, 구매자3_새로운_평가1, 구매자4_새로운_평가1, 구매자5_새로운_평가1, 구매자5_새로운_평가2, 구매자5_새로운_평가3 + )); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/domain/ReliabilityTest.java b/backend/ddang/src/test/java/com/ddang/ddang/user/domain/ReliabilityTest.java index 9aec3fc19..0fd14c11f 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/domain/ReliabilityTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/domain/ReliabilityTest.java @@ -1,38 +1,28 @@ package com.ddang.ddang.user.domain; -import com.ddang.ddang.review.domain.Review; -import com.ddang.ddang.user.domain.fixture.ReliabilityFixture; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; -import java.util.Collections; -import java.util.List; - import static org.assertj.core.api.Assertions.assertThat; @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @SuppressWarnings("NonAsciiCharacters") -class ReliabilityTest extends ReliabilityFixture { - - @Test - void 신뢰도_점수_평균을_계산한다() { - // when - 평가_대상.updateReliability(평가_대상이_받은_평가_목록); - - // then - assertThat(평가_대상.getReliability().getValue()).isEqualTo(평가_대상의_신뢰도_점수); - } +class ReliabilityTest { @Test - void 신뢰도_기록이_없다면_신뢰도_점수는_null이다() { + void 신뢰도에_반영된_평가의_개수가_주어지면_신뢰도에_반영된_평가_점수들의_합을_반환한다() { // given - final List targetReviews = Collections.emptyList(); + final double reliabilityValue = 4.0d; + final Reliability reliability = new Reliability(reliabilityValue); + final int appliedReviewCount = 3; + + final double expect = reliabilityValue * appliedReviewCount; // when - 평가_대상.updateReliability(targetReviews); + final double actual = reliability.calculateReviewScoreSum(appliedReviewCount); // then - assertThat(평가_대상.getReliability().getValue()).isNull(); + assertThat(actual).isEqualTo(expect); } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/domain/ReliabilityUpdateHistoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/user/domain/ReliabilityUpdateHistoryTest.java new file mode 100644 index 000000000..563981a7c --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/domain/ReliabilityUpdateHistoryTest.java @@ -0,0 +1,32 @@ +package com.ddang.ddang.user.domain; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class ReliabilityUpdateHistoryTest { + + @Test + void 빈_생성자로_생성하면_마지막으로_적용된_평가_아이디가_0이다() { + // given + final Long expect = 0L; + + // when + final ReliabilityUpdateHistory actual = new ReliabilityUpdateHistory(); + + // then + assertThat(actual.getLastAppliedReviewId()).isEqualTo(expect); + } + + @Test + void 생성자에_마직막으로_적용된_평가_아이디를_지정할_수_있다() { + // given + final Long lastAppliedReviewId = 2L; + + // when + final ReliabilityUpdateHistory actual = new ReliabilityUpdateHistory(2L); + + // then + assertThat(actual.getLastAppliedReviewId()).isEqualTo(lastAppliedReviewId); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/domain/UserReliabilityTest.java b/backend/ddang/src/test/java/com/ddang/ddang/user/domain/UserReliabilityTest.java new file mode 100644 index 000000000..c2f274dd8 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/domain/UserReliabilityTest.java @@ -0,0 +1,44 @@ +package com.ddang.ddang.user.domain; + +import com.ddang.ddang.user.domain.fixture.UserReliabilityFixture; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.Test; +import org.springframework.test.util.ReflectionTestUtils; + +class UserReliabilityTest extends UserReliabilityFixture { + + @Test + void 새로운_평가가_주어지면_사용자의_신뢰도_관련_정보들을_갱신한다() { + // given + final UserReliability userReliability = new UserReliability(기존에_평가_3개_받은_평가_대상); + ReflectionTestUtils.setField(userReliability, "appliedReviewCount", 3); + + // when + userReliability.updateReliability(평가_대상이_받은_새로운_평가_목록); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(userReliability.getReliability()).isEqualTo(새로운_평가가_반영된_신뢰도); + softAssertions.assertThat(userReliability.getAppliedReviewCount()).isEqualTo(새로운_평가_반영_이후의_평가_대상의_신뢰도에_반영된_평가_개수); + softAssertions.assertThat(기존에_평가_3개_받은_평가_대상.getReliability()).isEqualTo(새로운_평가가_반영된_신뢰도); + }); + } + + @Test + void 신뢰도_기록이_없다면_신뢰도_점수는_그대로이다() { + // given + final UserReliability userReliability = new UserReliability(기존에_평가_3개_받은_평가_대상); + ReflectionTestUtils.setField(userReliability, "appliedReviewCount", 3); + + // when + userReliability.updateReliability(비어있는_평가_목록); + + // then + + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(userReliability.getReliability()).isEqualTo(기존에_평가3개가_적용되어있는_신뢰도); + softAssertions.assertThat(userReliability.getAppliedReviewCount()).isEqualTo(새로운_평가_반영_전의_평가_대상의_신뢰도에_반영된_평가_개수); + softAssertions.assertThat(기존에_평가_3개_받은_평가_대상.getReliability()).isEqualTo(기존에_평가3개가_적용되어있는_신뢰도); + }); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/domain/UserTest.java b/backend/ddang/src/test/java/com/ddang/ddang/user/domain/UserTest.java index 9946a3d3b..6d47960c8 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/domain/UserTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/domain/UserTest.java @@ -14,18 +14,18 @@ class UserTest extends UserFixture { @Test - void 회원_생성시_신뢰도가_null이면_신뢰도_점수가_null인_신뢰도로_회원을_생성한다() { + void 회원_생성시_신뢰도가_null이면_신뢰도_점수가_double의_최솟값인_신뢰도로_회원을_생성한다() { // given final Reliability nullReliability = null; - final Reliability expect = new Reliability(null); + final Reliability expect = new Reliability(Double.MIN_VALUE); // when final User user = User.builder() - .name("kakao12345") - .profileImage(new ProfileImage("uplad.png", "store.png")) - .reliability(nullReliability) - .oauthId("12345") - .build(); + .name("kakao12345") + .profileImage(new ProfileImage("uplad.png", "store.png")) + .reliability(nullReliability) + .oauthId("12345") + .build(); // then assertThat(user.getReliability()).isEqualTo(expect); @@ -108,11 +108,11 @@ class UserTest extends UserFixture { } @Test - void 신뢰도_평균을_계산한다() { + void 새로운_신뢰도로_변경한다() { // when - 평가_대상.updateReliability(평가_대상이_받은_평가_목록); + 평가_대상.updateReliability(새로운_신뢰도); // then - assertThat(평가_대상.getReliability().getValue()).isEqualTo(평가_대상의_신뢰도_점수); + assertThat(평가_대상.getReliability().getValue()).isEqualTo(새로운_신뢰도_점수); } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/domain/fixture/ReliabilityFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/user/domain/fixture/ReliabilityFixture.java deleted file mode 100644 index bd0ff2e2d..000000000 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/domain/fixture/ReliabilityFixture.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.ddang.ddang.user.domain.fixture; - -import com.ddang.ddang.image.domain.ProfileImage; -import com.ddang.ddang.review.domain.Review; -import com.ddang.ddang.review.domain.Score; -import com.ddang.ddang.user.domain.Reliability; -import com.ddang.ddang.user.domain.User; - -import java.util.List; - -@SuppressWarnings("NonAsciiCharacters") -public class ReliabilityFixture { - - private double 평가1_점수 = 5.0d; - private double 평가2_점수 = 1.0d; - private User 평가_작성자1 = User.builder() - .name("평가 작성자1") - .profileImage(new ProfileImage("profile.png", "profile.png")) - .reliability(new Reliability(4.7d)) - .oauthId("12346") - .build(); - private User 평가_작성자2 = User.builder() - .name("평가 작성자2") - .profileImage(new ProfileImage("profile.png", "profile.png")) - .reliability(new Reliability(4.7d)) - .oauthId("12347") - .build(); - - protected User 평가_대상 = User.builder() - .name("평가 대상") - .profileImage(new ProfileImage("profile.png", "profile.png")) - .reliability(new Reliability(null)) - .oauthId("12345") - .build(); - private Review 평가1 = Review.builder() - .writer(평가_작성자1) - .target(평가_대상) - .content("친절하다") - .score(new Score(평가1_점수)) - .build(); - private Review 평가2 = Review.builder() - .writer(평가_작성자2) - .target(평가_대상) - .content("별로다") - .score(new Score(평가2_점수)) - .build(); - - protected List 평가_대상이_받은_평가_목록 = List.of(평가1, 평가2); - protected Double 평가_대상의_신뢰도_점수 = (평가1_점수 + 평가2_점수) / 2; -} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/domain/fixture/UserFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/user/domain/fixture/UserFixture.java index 44c558433..71c9f2949 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/domain/fixture/UserFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/domain/fixture/UserFixture.java @@ -1,50 +1,26 @@ package com.ddang.ddang.user.domain.fixture; import com.ddang.ddang.image.domain.ProfileImage; -import com.ddang.ddang.review.domain.Review; -import com.ddang.ddang.review.domain.Score; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; - -import java.util.List; +import org.junit.jupiter.api.BeforeEach; @SuppressWarnings("NonAsciiCharacters") public class UserFixture { - private double 평가1_점수 = 5.0d; - private double 평가2_점수 = 1.0d; - private User 평가_작성자1 = User.builder() - .name("평가 작성자1") - .profileImage(new ProfileImage("profile.png", "profile.png")) - .reliability(new Reliability(4.7d)) - .oauthId("12346") - .build(); - private User 평가_작성자2 = User.builder() - .name("평가 작성자2") - .profileImage(new ProfileImage("profile.png", "profile.png")) - .reliability(new Reliability(4.7d)) - .oauthId("12347") - .build(); + protected double 새로운_신뢰도_점수 = 3.0d; + protected User 평가_대상; + protected Reliability 새로운_신뢰도; - protected User 평가_대상 = User.builder() - .name("평가 대상") - .profileImage(new ProfileImage("profile.png", "profile.png")) - .reliability(new Reliability(null)) - .oauthId("12345") - .build(); - private Review 평가1 = Review.builder() - .writer(평가_작성자1) - .target(평가_대상) - .content("친절하다") - .score(new Score(평가1_점수)) - .build(); - private Review 평가2 = Review.builder() - .writer(평가_작성자2) - .target(평가_대상) - .content("별로다") - .score(new Score(평가2_점수)) - .build(); + @BeforeEach + void setUp() { + 평가_대상 = User.builder() + .name("평가 대상") + .profileImage(new ProfileImage("profile.png", "profile.png")) + .reliability(new Reliability(0.0d)) + .oauthId("12345") + .build(); - protected List 평가_대상이_받은_평가_목록 = List.of(평가1, 평가2); - protected Double 평가_대상의_신뢰도_점수 = (평가1_점수 + 평가2_점수) / 2; + 새로운_신뢰도 = new Reliability(새로운_신뢰도_점수); + } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/domain/fixture/UserReliabilityFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/user/domain/fixture/UserReliabilityFixture.java new file mode 100644 index 000000000..8b244dd68 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/domain/fixture/UserReliabilityFixture.java @@ -0,0 +1,75 @@ +package com.ddang.ddang.user.domain.fixture; + +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.review.domain.Review; +import com.ddang.ddang.review.domain.Reviews; +import com.ddang.ddang.review.domain.Score; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import org.junit.jupiter.api.BeforeEach; + +import java.util.Collections; +import java.util.List; + +@SuppressWarnings("NonAsciiCharacters") +public class UserReliabilityFixture { + + private double 새로운_평가1_점수 = 5.0d; + private double 새로운_평가2_점수 = 1.0d; + private double 새로운_평가_반영_전의_평가_대상의_신뢰도_점수 = 4.0d; + protected int 새로운_평가_반영_전의_평가_대상의_신뢰도에_반영된_평가_개수 = 3; + protected int 새로운_평가_반영_이후의_평가_대상의_신뢰도에_반영된_평가_개수 = 새로운_평가_반영_전의_평가_대상의_신뢰도에_반영된_평가_개수 + 2; + protected double 새로운_평가_반영_이후의_평가_대상의_신뢰도_점수 = + (새로운_평가_반영_전의_평가_대상의_신뢰도_점수 * 새로운_평가_반영_전의_평가_대상의_신뢰도에_반영된_평가_개수 + + 새로운_평가1_점수 + 새로운_평가2_점수) / 새로운_평가_반영_이후의_평가_대상의_신뢰도에_반영된_평가_개수; + protected User 기존에_평가_3개_받은_평가_대상; + protected Reviews 평가_대상이_받은_새로운_평가_목록; + protected Reviews 비어있는_평가_목록; + protected Reliability 기존에_평가3개가_적용되어있는_신뢰도; + protected Reliability 새로운_평가가_반영된_신뢰도; + + @BeforeEach + void setUp() { + final User 평가_작성자1 = User.builder() + .name("평가 작성자1") + .profileImage(new ProfileImage("profile.png", "profile.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12346") + .build(); + final User 평가_작성자2 = User.builder() + .name("평가 작성자2") + .profileImage(new ProfileImage("profile.png", "profile.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12347") + .build(); + + + 기존에_평가3개가_적용되어있는_신뢰도 = new Reliability(새로운_평가_반영_전의_평가_대상의_신뢰도_점수); + + 기존에_평가_3개_받은_평가_대상 = User.builder() + .name("평가 대상") + .profileImage(new ProfileImage("profile.png", "profile.png")) + .reliability(기존에_평가3개가_적용되어있는_신뢰도) + .oauthId("12345") + .build(); + + final Review 새로운_평가1 = Review.builder() + .writer(평가_작성자1) + .target(기존에_평가_3개_받은_평가_대상) + .content("친절하다") + .score(new Score(새로운_평가1_점수)) + .build(); + final Review 새로운_평가2 = Review.builder() + .writer(평가_작성자2) + .target(기존에_평가_3개_받은_평가_대상) + .content("별로다") + .score(new Score(새로운_평가2_점수)) + .build(); + + 평가_대상이_받은_새로운_평가_목록 = new Reviews(List.of(새로운_평가1, 새로운_평가2)); + + 비어있는_평가_목록 = new Reviews(Collections.emptyList()); + + 새로운_평가가_반영된_신뢰도 = new Reliability(새로운_평가_반영_이후의_평가_대상의_신뢰도_점수); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaReliabilityUpdateHistoryRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaReliabilityUpdateHistoryRepositoryTest.java new file mode 100644 index 000000000..39e392e2c --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaReliabilityUpdateHistoryRepositoryTest.java @@ -0,0 +1,59 @@ +package com.ddang.ddang.user.infrastructure.persistence; + +import com.ddang.ddang.configuration.JpaConfiguration; +import com.ddang.ddang.configuration.QuerydslConfiguration; +import com.ddang.ddang.user.domain.ReliabilityUpdateHistory; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@Import({JpaConfiguration.class, QuerydslConfiguration.class}) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class JpaReliabilityUpdateHistoryRepositoryTest { + + @PersistenceContext + EntityManager em; + + @Autowired + JpaReliabilityUpdateHistoryRepository reliabilityUpdateHistoryRepository; + + @Test + void 신뢰도_업데이트_기록이_없으면_빈_Optional을_반환한다() { + // when + final Optional actual = reliabilityUpdateHistoryRepository.findFirstByOrderByIdDesc(); + + // then + assertThat(actual).isEmpty(); + } + + @Test + void 신뢰도_업데이트_기록의_아이디가_가장_큰_것을_조회한다() { + // given + final ReliabilityUpdateHistory history1 = new ReliabilityUpdateHistory(); + final ReliabilityUpdateHistory history2 = new ReliabilityUpdateHistory(); + final ReliabilityUpdateHistory history3 = new ReliabilityUpdateHistory(); + + reliabilityUpdateHistoryRepository.saveAll(List.of(history1, history2, history3)); + + em.flush(); + em.clear(); + + // when + final Optional actual = reliabilityUpdateHistoryRepository.findFirstByOrderByIdDesc(); + + // then + assertThat(actual).contains(history3); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserReliabilityRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserReliabilityRepositoryTest.java new file mode 100644 index 000000000..ff9eba8ec --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserReliabilityRepositoryTest.java @@ -0,0 +1,35 @@ +package com.ddang.ddang.user.infrastructure.persistence; + +import com.ddang.ddang.configuration.JpaConfiguration; +import com.ddang.ddang.configuration.QuerydslConfiguration; +import com.ddang.ddang.user.domain.UserReliability; +import com.ddang.ddang.user.infrastructure.persistence.fixture.JpaUserReliabilityRepositoryFixture; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@Import({JpaConfiguration.class, QuerydslConfiguration.class}) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class JpaUserReliabilityRepositoryTest extends JpaUserReliabilityRepositoryFixture { + + @Autowired + JpaUserReliabilityRepository userReliabilityRepository; + + @Test + void 주어진_사용자_아이디에_해당하는_사용자_신뢰도_정보를_반환한다() { + // when + final Optional actual = userReliabilityRepository.findByUserId(사용자.getId()); + + // then + assertThat(actual).contains(사용자_신뢰도_정보); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/JpaUserReliabilityRepositoryFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/JpaUserReliabilityRepositoryFixture.java new file mode 100644 index 000000000..c7df2ce66 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/JpaUserReliabilityRepositoryFixture.java @@ -0,0 +1,45 @@ +package com.ddang.ddang.user.infrastructure.persistence.fixture; + +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.UserReliability; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserReliabilityRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +@SuppressWarnings("NonAsciiCharacters") +public class JpaUserReliabilityRepositoryFixture { + + @PersistenceContext + private EntityManager em; + + @Autowired + private JpaUserRepository userRepository; + + @Autowired + private JpaUserReliabilityRepository userReliabilityRepository; + + protected User 사용자; + protected UserReliability 사용자_신뢰도_정보; + + @BeforeEach + void setUp() { + 사용자 = User.builder() + .name("사용자") + .profileImage(new ProfileImage("uplad.png", "store.png")) + .reliability(Reliability.INITIAL_RELIABILITY) + .oauthId("12345") + .build(); + userRepository.save(사용자); + + 사용자_신뢰도_정보 = new UserReliability(사용자); + userReliabilityRepository.save(사용자_신뢰도_정보); + + em.flush(); + em.clear(); + } +} From 7143025bb27eda55a7b9349b0df5d7365a42ce5e Mon Sep 17 00:00:00 2001 From: apptie <57691173+apptie@users.noreply.github.com> Date: Fri, 13 Oct 2023 17:45:14 +0900 Subject: [PATCH 11/37] =?UTF-8?q?refactor:=20#625=20=ED=9A=8C=EC=9B=90=20?= =?UTF-8?q?=ED=83=88=ED=87=B4=20=EC=8B=9C=20=EC=86=8C=EC=85=9C=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EB=B0=A9=EC=8B=9D=EC=9D=84=20DB=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=A1=B0=ED=9A=8C=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20(#626)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: flyway 버전 17 추가 * feat: User 도메인에 사용한 소셜 로그인 방식 필드 추가 * refactor: 회원 탈퇴 시 소셜 로그인 방식을 DB에서 조회하도록 변경 * refactor: Oauth2와 관련된 필드를 별도의 클래스로 분리 * chore: flyway 스크립트 버전 변경 * test: 의미 없는 테스트 mocking 삭제 * refactor: access token 재발급 시 refresh token도 재발급되도록 변경 --- .../application/AuthenticationService.java | 42 +++++++++++-------- .../AuthenticationController.java | 5 +-- .../qna/application/dto/ReadUserInQnaDto.java | 2 +- .../application/dto/ReadUserInReportDto.java | 2 +- .../application/dto/ReadUserInReviewDto.java | 2 +- .../user/application/dto/ReadUserDto.java | 2 +- .../ddang/user/domain/OauthInformation.java | 31 ++++++++++++++ .../com/ddang/ddang/user/domain/User.java | 13 +++--- .../persistence/JpaUserRepository.java | 8 +++- .../V18__alter_user_oauth_type_tables.sql | 3 ++ .../AuthenticationServiceTest.java | 12 +++--- .../fixture/AuthenticationServiceFixture.java | 7 +++- .../AuthenticationControllerTest.java | 12 ++---- .../persistence/JpaUserRepositoryTest.java | 11 +++-- 14 files changed, 100 insertions(+), 52 deletions(-) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/user/domain/OauthInformation.java create mode 100644 backend/ddang/src/main/resources/db/migration/V18__alter_user_oauth_type_tables.sql diff --git a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java index 69aa2414f..ec0ee41f9 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java @@ -75,19 +75,19 @@ private LoginUserInformationDto findOrPersistUser( ) { final AtomicBoolean isSignUpUser = new AtomicBoolean(false); - final User signInUser = userRepository.findByOauthIdAndDeletedIsFalse(userInformationDto.findUserId()) - .orElseGet(() -> { - final User user = User.builder() - .name(oauth2Type.calculateNickname( - calculateRandomNumber())) - .profileImage(findDefaultProfileImage()) - .reliability(new Reliability(0.0d)) - .oauthId(userInformationDto.findUserId()) - .build(); - - isSignUpUser.set(true); - return userRepository.save(user); - }); + final User signInUser = userRepository.findByOauthId(userInformationDto.findUserId()) + .orElseGet(() -> { + final User user = User.builder() + .name(oauth2Type.calculateNickname( + calculateRandomNumber())) + .profileImage(findDefaultProfileImage()) + .reliability(new Reliability(0.0d)) + .oauthId(userInformationDto.findUserId()) + .build(); + + isSignUpUser.set(true); + return userRepository.save(user); + }); return new LoginUserInformationDto(signInUser, isSignUpUser.get()); } @@ -139,7 +139,13 @@ public TokenDto refreshToken(final String refreshToken) { Map.of(PRIVATE_CLAIMS_KEY, privateClaims.userId()) ); - return new TokenDto(accessToken, refreshToken); + final String newRefreshToken = tokenEncoder.encode( + LocalDateTime.now(), + TokenType.REFRESH, + Map.of(PRIVATE_CLAIMS_KEY, privateClaims.userId()) + ); + + return new TokenDto(accessToken, newRefreshToken); } public boolean validateToken(final String accessToken) { @@ -149,21 +155,21 @@ public boolean validateToken(final String accessToken) { @Transactional public void withdrawal( - final Oauth2Type oauth2Type, final String accessToken, final String refreshToken ) throws InvalidWithdrawalException { - final OAuth2UserInformationProvider provider = providerComposite.findProvider(oauth2Type); final PrivateClaims privateClaims = tokenDecoder.decode(TokenType.ACCESS, accessToken) .orElseThrow(() -> new InvalidTokenException("유효한 토큰이 아닙니다.") ); final User user = userRepository.findByIdAndDeletedIsFalse(privateClaims.userId()) - .orElseThrow(() -> new InvalidWithdrawalException("탈퇴에 대한 권한 없습니다.")); + .orElseThrow(() -> new InvalidWithdrawalException("탈퇴에 대한 권한이 없습니다.")); + final OAuth2UserInformationProvider provider = providerComposite.findProvider(user.getOauthInformation() + .getOauth2Type()); user.withdrawal(); blackListTokenService.registerBlackListToken(accessToken, refreshToken); deviceTokenRepository.deleteByUserId(user.getId()); - provider.unlinkUserBy(user.getOauthId()); + provider.unlinkUserBy(user.getOauthInformation().getOauthId()); } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/authentication/presentation/AuthenticationController.java b/backend/ddang/src/main/java/com/ddang/ddang/authentication/presentation/AuthenticationController.java index b8e5aeaa2..52f02a9f0 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/authentication/presentation/AuthenticationController.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/authentication/presentation/AuthenticationController.java @@ -70,13 +70,12 @@ public ResponseEntity logout( .build(); } - @PostMapping("/withdrawal/{oauth2Type}") + @PostMapping("/withdrawal") public ResponseEntity withdrawal( - @PathVariable final Oauth2Type oauth2Type, @RequestHeader(HttpHeaders.AUTHORIZATION) final String accessToken, @RequestBody @Valid final WithdrawalRequest request ) { - authenticationService.withdrawal(oauth2Type, accessToken, request.refreshToken()); + authenticationService.withdrawal(accessToken, request.refreshToken()); return ResponseEntity.noContent() .build(); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadUserInQnaDto.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadUserInQnaDto.java index d0a6b2812..a75d44558 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadUserInQnaDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadUserInQnaDto.java @@ -16,7 +16,7 @@ public static ReadUserInQnaDto from(final User writer) { writer.getName(), writer.getProfileImage().getId(), writer.getReliability().getValue(), - writer.getOauthId(), + writer.getOauthInformation().getOauthId(), writer.isDeleted() ); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/application/dto/ReadUserInReportDto.java b/backend/ddang/src/main/java/com/ddang/ddang/report/application/dto/ReadUserInReportDto.java index dbc8db994..cd4fbd220 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/report/application/dto/ReadUserInReportDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/application/dto/ReadUserInReportDto.java @@ -18,7 +18,7 @@ public static ReadUserInReportDto from(final User user) { user.getName(), ImageIdProcessor.process(user.getProfileImage()), user.getReliability().getValue(), - user.getOauthId(), + user.getOauthInformation().getOauthId(), user.isDeleted() ); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/review/application/dto/ReadUserInReviewDto.java b/backend/ddang/src/main/java/com/ddang/ddang/review/application/dto/ReadUserInReviewDto.java index ecbf938e8..bb0fa0927 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/review/application/dto/ReadUserInReviewDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/review/application/dto/ReadUserInReviewDto.java @@ -10,7 +10,7 @@ public static ReadUserInReviewDto from(final User user) { user.getName(), user.getProfileImage().getId(), user.getReliability().getValue(), - user.getOauthId() + user.getOauthInformation().getOauthId() ); } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/application/dto/ReadUserDto.java b/backend/ddang/src/main/java/com/ddang/ddang/user/application/dto/ReadUserDto.java index 15ca854b6..015310258 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/user/application/dto/ReadUserDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/application/dto/ReadUserDto.java @@ -18,7 +18,7 @@ public static ReadUserDto from(final User user) { user.getName(), ImageIdProcessor.process(user.getProfileImage()), user.getReliability().getValue(), - user.getOauthId(), + user.getOauthInformation().getOauthId(), user.isDeleted() ); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/OauthInformation.java b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/OauthInformation.java new file mode 100644 index 000000000..7e069b7fa --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/OauthInformation.java @@ -0,0 +1,31 @@ +package com.ddang.ddang.user.domain; + +import com.ddang.ddang.authentication.infrastructure.oauth2.Oauth2Type; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@Embeddable +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter +@EqualsAndHashCode +@ToString +public class OauthInformation { + + private String oauthId; + + @Column(name = "oauth2_type") + @Enumerated(EnumType.STRING) + private Oauth2Type oauth2Type; + + public OauthInformation(final String oauthId, final Oauth2Type oauth2Type) { + this.oauthId = oauthId; + this.oauth2Type = oauth2Type; + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/User.java b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/User.java index 85c464520..629a87a69 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/User.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/User.java @@ -1,5 +1,6 @@ package com.ddang.ddang.user.domain; +import com.ddang.ddang.authentication.infrastructure.oauth2.Oauth2Type; import com.ddang.ddang.common.entity.BaseTimeEntity; import com.ddang.ddang.image.domain.ProfileImage; import jakarta.persistence.AttributeOverride; @@ -26,13 +27,13 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter @EqualsAndHashCode(of = "id", callSuper = false) -@ToString(of = {"id", "name", "reliability", "oauthId", "deleted"}) +@ToString(of = {"id", "name", "reliability", "oauthId", "deleted", "oauthInformation"}) @Table(name = "users") public class User extends BaseTimeEntity { public static final User EMPTY_USER = null; private static final boolean DELETED_STATUS = true; - private static final String UNKOWN_NAME = "알 수 없음"; + private static final String UNKNOWN_NAME = "알 수 없음"; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -49,7 +50,8 @@ public class User extends BaseTimeEntity { @AttributeOverride(name = "value", column = @Column(name = "reliability")) private Reliability reliability; - private String oauthId; + @Embedded + private OauthInformation oauthInformation; @Column(name = "is_deleted") private boolean deleted = false; @@ -59,12 +61,13 @@ private User( final String name, final ProfileImage profileImage, final Reliability reliability, - final String oauthId + final String oauthId, + final Oauth2Type oauth2Type ) { this.name = name; this.profileImage = profileImage; this.reliability = processReliability(reliability); - this.oauthId = oauthId; + this.oauthInformation = new OauthInformation(oauthId, oauth2Type); } private Reliability processReliability(final Reliability reliability) { diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepository.java index 390768b88..81e78042d 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepository.java @@ -4,10 +4,16 @@ import org.springframework.data.jpa.repository.JpaRepository; import java.util.Optional; +import org.springframework.data.jpa.repository.Query; public interface JpaUserRepository extends JpaRepository { - Optional findByOauthIdAndDeletedIsFalse(final String oauthId); + @Query(""" + SELECT u + FROM User u + WHERE u.deleted = false AND u.oauthInformation.oauthId = :oauthId + """) + Optional findByOauthId(final String oauthId); Optional findByIdAndDeletedIsFalse(final Long id); diff --git a/backend/ddang/src/main/resources/db/migration/V18__alter_user_oauth_type_tables.sql b/backend/ddang/src/main/resources/db/migration/V18__alter_user_oauth_type_tables.sql new file mode 100644 index 000000000..1a614bb22 --- /dev/null +++ b/backend/ddang/src/main/resources/db/migration/V18__alter_user_oauth_type_tables.sql @@ -0,0 +1,3 @@ +ALTER TABLE users ADD oauth2_type VARCHAR(10); +UPDATE users SET oauth2_type = 'KAKAO' WHERE oauth2_type is null; +ALTER TABLE users MODIFY oauth2_type VARCHAR(10) NOT NULL; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java index 9ed6beeb2..00c27f910 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java @@ -230,7 +230,7 @@ void setUp() { given(userInfoProvider.findUserInformation(anyString())).willReturn(사용자_회원_정보); // when - authenticationService.withdrawal(지원하는_소셜_로그인_타입, 유효한_액세스_토큰, 유효한_리프레시_토큰); + authenticationService.withdrawal(유효한_액세스_토큰, 유효한_리프레시_토큰); // then assertThat(사용자.isDeleted()).isTrue(); @@ -243,9 +243,9 @@ void setUp() { given(userInfoProvider.unlinkUserBy(anyString())).willReturn(탈퇴한_사용자_회원_정보); // when && then - assertThatThrownBy(() -> authenticationService.withdrawal(지원하는_소셜_로그인_타입, 탈퇴한_사용자_액세스_토큰, 유효한_리프레시_토큰)) + assertThatThrownBy(() -> authenticationService.withdrawal(탈퇴한_사용자_액세스_토큰, 유효한_리프레시_토큰)) .isInstanceOf(InvalidWithdrawalException.class) - .hasMessage("탈퇴에 대한 권한 없습니다."); + .hasMessage("탈퇴에 대한 권한이 없습니다."); } @Test @@ -255,15 +255,15 @@ void setUp() { given(userInfoProvider.findUserInformation(anyString())).willThrow(new InvalidTokenException("401 Unauthorized")); // when & then - assertThatThrownBy(() -> authenticationService.withdrawal(지원하는_소셜_로그인_타입, 존재하지_않는_사용자_액세스_토큰, 유효한_리프레시_토큰)) + assertThatThrownBy(() -> authenticationService.withdrawal(존재하지_않는_사용자_액세스_토큰, 유효한_리프레시_토큰)) .isInstanceOf(InvalidWithdrawalException.class) - .hasMessage("탈퇴에 대한 권한 없습니다."); + .hasMessage("탈퇴에 대한 권한이 없습니다."); } @Test void 탈퇴할_때_유효한_토큰이_아닌_경우_예외가_발생한다() { // when & then - assertThatThrownBy(() -> authenticationService.withdrawal(지원하는_소셜_로그인_타입, 유효하지_않은_액세스_토큰, 유효한_리프레시_토큰)) + assertThatThrownBy(() -> authenticationService.withdrawal(유효하지_않은_액세스_토큰, 유효한_리프레시_토큰)) .isInstanceOf(InvalidTokenException.class) .hasMessage("유효한 토큰이 아닙니다."); } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java index 19ef0f791..7b1b827dd 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java @@ -3,6 +3,7 @@ import com.ddang.ddang.authentication.domain.TokenEncoder; import com.ddang.ddang.authentication.domain.TokenType; import com.ddang.ddang.authentication.domain.dto.UserInformationDto; +import com.ddang.ddang.authentication.infrastructure.jwt.PrivateClaims; import com.ddang.ddang.authentication.infrastructure.oauth2.Oauth2Type; import com.ddang.ddang.device.domain.DeviceToken; import com.ddang.ddang.device.infrastructure.persistence.JpaDeviceTokenRepository; @@ -33,6 +34,8 @@ public class AuthenticationServiceFixture { protected User 사용자; protected User 탈퇴한_사용자; + protected PrivateClaims 사용자_id_클레임 = new PrivateClaims(1L); + protected UserInformationDto 사용자_회원_정보 = new UserInformationDto(12345L); protected UserInformationDto 탈퇴한_사용자_회원_정보 = new UserInformationDto(54321L); protected UserInformationDto 가입하지_않은_사용자_회원_정보 = new UserInformationDto(-99999L); @@ -67,6 +70,7 @@ void fixtureSetUp() { .profileImage(new ProfileImage("upload.png", "store.png")) .reliability(new Reliability(0.0d)) .oauthId("12345") + .oauth2Type(Oauth2Type.KAKAO) .build(); 탈퇴한_사용자 = User.builder() @@ -74,6 +78,7 @@ void fixtureSetUp() { .profileImage(new ProfileImage("upload.png", "store.png")) .reliability(new Reliability(0.0d)) .oauthId("12346") + .oauth2Type(Oauth2Type.KAKAO) .build(); userRepository.save(사용자); @@ -90,7 +95,7 @@ void fixtureSetUp() { ); 만료된_리프레시_토큰 = tokenEncoder.encode( - LocalDateTime.ofInstant(Instant.parse("2023-01-01T22:21:20Z"), ZoneId.of("UTC")), + LocalDateTime.ofInstant(Instant.parse("2023-01-01T22:21:20Z"), ZoneId.of("UTC")), TokenType.REFRESH, Map.of("userId", 1L) ); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/presentation/AuthenticationControllerTest.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/presentation/AuthenticationControllerTest.java index 757269135..48aea2bae 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/presentation/AuthenticationControllerTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/presentation/AuthenticationControllerTest.java @@ -1,6 +1,5 @@ package com.ddang.ddang.authentication.presentation; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; @@ -202,11 +201,11 @@ void setUp() { @Test void ouath2Type과_accessToken과_refreshToken을_전달하면_탈퇴한다() throws Exception { // given - willDoNothing().given(authenticationService).withdrawal(any(), anyString(), anyString()); + willDoNothing().given(authenticationService).withdrawal(anyString(), anyString()); // when & then final ResultActions resultActions = - mockMvc.perform(RestDocumentationRequestBuilders.post("/oauth2/withdrawal/{oauth2Type}", 소셜_로그인_타입) + mockMvc.perform(RestDocumentationRequestBuilders.post("/oauth2/withdrawal") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(유효한_회원탈퇴_요청)) .header(HttpHeaders.AUTHORIZATION, 유효한_액세스_토큰_내용) @@ -222,10 +221,10 @@ void setUp() { void ouath2Type과_accessToken과_refreshToken을_전달시_이미_탈퇴_혹은_존재하지_않아_권한이_없는_회원인_경우_403을_반환한다() throws Exception { // given willThrow(new InvalidWithdrawalException("탈퇴에 대한 권한 없습니다.")).given(authenticationService) - .withdrawal(any(), anyString(), anyString()); + .withdrawal(anyString(), anyString()); // when & then - mockMvc.perform(RestDocumentationRequestBuilders.post("/oauth2/withdrawal/{oauth2Type}", 소셜_로그인_타입) + mockMvc.perform(RestDocumentationRequestBuilders.post("/oauth2/withdrawal") .header(HttpHeaders.AUTHORIZATION, 유효한_액세스_토큰_내용) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(유효하지_않은_회원탈퇴_요청)) @@ -304,9 +303,6 @@ void setUp() { private void withdrawal_문서화(final ResultActions resultActions) throws Exception { resultActions.andDo( restDocs.document( - pathParameters( - parameterWithName("oauth2Type").description("소셜 로그인을 할 서비스 선택(kakao로 고정)") - ), requestHeaders( headerWithName("Authorization").description("회원 Bearer 인증 정보") ), diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepositoryTest.java index c6564ec79..c86733036 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepositoryTest.java @@ -1,5 +1,7 @@ package com.ddang.ddang.user.infrastructure.persistence; +import static org.assertj.core.api.Assertions.assertThat; + import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; import com.ddang.ddang.user.domain.Reliability; @@ -7,6 +9,7 @@ import com.ddang.ddang.user.infrastructure.persistence.fixture.JpaUserRepositoryFixture; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; +import java.util.Optional; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; @@ -14,10 +17,6 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.context.annotation.Import; -import java.util.Optional; - -import static org.assertj.core.api.Assertions.assertThat; - @DataJpaTest @Import({JpaConfiguration.class, QuerydslConfiguration.class}) @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @@ -53,7 +52,7 @@ class JpaUserRepositoryTest extends JpaUserRepositoryFixture { @Test void 존재하는_oauthId를_전달하면_해당_회원을_Optional로_감싸_반환한다() { // when - final Optional actual = userRepository.findByOauthIdAndDeletedIsFalse(사용자.getOauthId()); + final Optional actual = userRepository.findByOauthId(사용자.getOauthInformation().getOauthId()); // then assertThat(actual).contains(사용자); @@ -62,7 +61,7 @@ class JpaUserRepositoryTest extends JpaUserRepositoryFixture { @Test void 존재하지_않는_oauthId를_전달하면_해당_회원을_빈_Optional로_반환한다() { // when - final Optional actual = userRepository.findByOauthIdAndDeletedIsFalse(존재하지_않는_oauth_아이디); + final Optional actual = userRepository.findByOauthId(존재하지_않는_oauth_아이디); // then assertThat(actual).isEmpty(); From 3ff04a443c130e9b5bb71c32301759cb22aa9a86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=8A=B9=EC=9B=90=20Merry?= Date: Fri, 13 Oct 2023 22:46:30 +0900 Subject: [PATCH 12/37] =?UTF-8?q?feat:=20#587=20Q&A=20=EC=95=8C=EB=A6=BC?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20(#614)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 답변 서비스에서 알림 이벤트 발행 * feat: 질문 서비스에서 알림 이벤트 발행 * feat: 질문, 답변 이벤트 리스너 추가 * chore: 수정 필요한 부분 주석 추가 * refactor: 이미지 절대 경로 컨트롤러에서 전송하도록 수정 * refactor: 이벤트 발행 시 별도의 DTO가 아닌 도메인 전달하도록 수정 * fix: 잘못 복제한 커밋 내역 복구 * refactor: 레포지토리 저장 엔티티를 이벤트 dto에 전달하도록 수정 --- .../chat/application/MessageService.java | 4 +- .../event/MessageNotificationEvent.java | 4 +- .../NotificationEventListener.java | 66 ++++++++++++++++--- .../notification/domain/NotificationType.java | 4 +- .../ddang/qna/application/AnswerService.java | 12 +++- .../qna/application/QuestionService.java | 12 +++- .../qna/application/dto/QuestionDto.java | 20 ++++++ .../event/AnswerNotificationEvent.java | 6 ++ .../event/QuestionNotificationEvent.java | 6 ++ .../ddang/qna/presentation/QnaController.java | 9 +-- .../NotificationEventListenerTest.java | 24 +++++++ .../NotificationEventListenerFixture.java | 54 +++++++++------ .../qna/application/AnswerServiceTest.java | 27 ++++++-- .../qna/application/QuestionServiceTest.java | 29 ++++++-- .../fixture/AnswerServiceFixture.java | 2 + .../fixture/QuestionServiceFixture.java | 2 + .../qna/presentation/QnaControllerTest.java | 22 +++---- .../fixture/QnaControllerFixture.java | 1 + 18 files changed, 237 insertions(+), 67 deletions(-) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/QuestionDto.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/qna/application/event/AnswerNotificationEvent.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/qna/application/event/QuestionNotificationEvent.java diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java index 7b26fc486..3654953eb 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java @@ -1,7 +1,6 @@ package com.ddang.ddang.chat.application; import com.ddang.ddang.chat.application.dto.CreateMessageDto; -import com.ddang.ddang.chat.application.dto.MessageDto; import com.ddang.ddang.chat.application.dto.ReadMessageDto; import com.ddang.ddang.chat.application.event.MessageNotificationEvent; import com.ddang.ddang.chat.application.exception.ChatRoomNotFoundException; @@ -54,8 +53,7 @@ public Long create(final CreateMessageDto dto, final String profileImageAbsolute final Message persistMessage = messageRepository.save(message); - final MessageDto messageDto = MessageDto.of(persistMessage, chatRoom, writer, receiver, profileImageAbsoluteUrl); - messageEventPublisher.publishEvent(new MessageNotificationEvent(messageDto)); + messageEventPublisher.publishEvent(new MessageNotificationEvent(persistMessage, profileImageAbsoluteUrl)); return persistMessage.getId(); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/event/MessageNotificationEvent.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/event/MessageNotificationEvent.java index 56bf90d60..9597cafc9 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/event/MessageNotificationEvent.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/event/MessageNotificationEvent.java @@ -1,6 +1,6 @@ package com.ddang.ddang.chat.application.event; -import com.ddang.ddang.chat.application.dto.MessageDto; +import com.ddang.ddang.chat.domain.Message; -public record MessageNotificationEvent(MessageDto messageDto) { +public record MessageNotificationEvent(Message message, String profileImageAbsoluteUrl) { } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/notification/application/NotificationEventListener.java b/backend/ddang/src/main/java/com/ddang/ddang/notification/application/NotificationEventListener.java index 345db4213..1a06f1125 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/notification/application/NotificationEventListener.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/notification/application/NotificationEventListener.java @@ -3,13 +3,17 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.bid.application.dto.BidDto; import com.ddang.ddang.bid.application.event.BidNotificationEvent; -import com.ddang.ddang.chat.application.dto.MessageDto; import com.ddang.ddang.chat.application.event.MessageNotificationEvent; +import com.ddang.ddang.chat.domain.Message; import com.ddang.ddang.image.domain.AuctionImage; import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.image.presentation.util.ImageUrlCalculator; import com.ddang.ddang.notification.application.dto.CreateNotificationDto; import com.ddang.ddang.notification.domain.NotificationType; +import com.ddang.ddang.qna.application.event.AnswerNotificationEvent; +import com.ddang.ddang.qna.application.event.QuestionNotificationEvent; +import com.ddang.ddang.qna.domain.Answer; +import com.ddang.ddang.qna.domain.Question; import com.google.firebase.messaging.FirebaseMessagingException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -23,23 +27,24 @@ public class NotificationEventListener { private static final String URI_DELIMITER = "/"; private static final String MESSAGE_NOTIFICATION_REDIRECT_URI = "/chattings"; - private static final String BID_NOTIFICATION_REDIRECT_URI = "/auctions"; + private static final String AUCTION_DETAIL_URI = "/auctions"; private static final String BID_NOTIFICATION_MESSAGE_FORMAT = "상위 입찰자가 나타났습니다. 구매를 원하신다면 더 높은 가격을 제시해 주세요."; + private static final int FIRST_IMAGE_INDEX = 0; private final NotificationService notificationService; @TransactionalEventListener public void sendMessageNotification(final MessageNotificationEvent messageNotificationEvent) { try { - final MessageDto messageDto = messageNotificationEvent.messageDto(); - final ProfileImage profileImage = messageDto.writer().getProfileImage(); + final Message message = messageNotificationEvent.message(); + final ProfileImage profileImage = message.getWriter().getProfileImage(); final CreateNotificationDto createNotificationDto = new CreateNotificationDto( NotificationType.MESSAGE, - messageDto.receiver().getId(), - messageDto.writer().getName(), - messageDto.contents(), - calculateRedirectUrl(MESSAGE_NOTIFICATION_REDIRECT_URI, messageDto.chatRoom().getId()), - ImageUrlCalculator.calculateBy(messageDto.profileImageAbsoluteUrl(), profileImage.getId()) + message.getReceiver().getId(), + message.getWriter().getName(), + message.getContents(), + calculateRedirectUrl(MESSAGE_NOTIFICATION_REDIRECT_URI, message.getChatRoom().getId()), + ImageUrlCalculator.calculateBy(messageNotificationEvent.profileImageAbsoluteUrl(), profileImage.getId()) ); notificationService.send(createNotificationDto); } catch (final FirebaseMessagingException ex) { @@ -58,7 +63,7 @@ public void sendBidNotification(final BidNotificationEvent bidNotificationEvent) bidDto.previousBidderId(), auction.getTitle(), BID_NOTIFICATION_MESSAGE_FORMAT, - calculateRedirectUrl(BID_NOTIFICATION_REDIRECT_URI, auction.getId()), + calculateRedirectUrl(AUCTION_DETAIL_URI, auction.getId()), ImageUrlCalculator.calculateBy(bidDto.auctionImageAbsoluteUrl(), auctionImage.getId()) ); notificationService.send(createNotificationDto); @@ -67,6 +72,47 @@ public void sendBidNotification(final BidNotificationEvent bidNotificationEvent) } } + @TransactionalEventListener + public void sendQuestionNotification(final QuestionNotificationEvent questionNotificationEvent) { + try { + final Question question = questionNotificationEvent.question(); + final Auction auction = question.getAuction(); + final AuctionImage auctionImage = auction.getAuctionImages().get(FIRST_IMAGE_INDEX); + final CreateNotificationDto createNotificationDto = new CreateNotificationDto( + NotificationType.QUESTION, + auction.getSeller().getId(), + auction.getTitle(), + question.getContent(), + calculateRedirectUrl(AUCTION_DETAIL_URI, auction.getId()), + ImageUrlCalculator.calculateBy(questionNotificationEvent.absoluteImageUrl(), auctionImage.getId()) + ); + notificationService.send(createNotificationDto); + } catch (final FirebaseMessagingException ex) { + log.error("exception type : {}, ", ex.getClass().getSimpleName(), ex); + } + } + + @TransactionalEventListener + public void sendAnswerNotification(final AnswerNotificationEvent answerNotificationEvent) { + try { + final Answer answer = answerNotificationEvent.answer(); + final Auction auction = answer.getQuestion().getAuction(); + final Question question = answer.getQuestion(); + final AuctionImage auctionImage = auction.getAuctionImages().get(FIRST_IMAGE_INDEX); + final CreateNotificationDto createNotificationDto = new CreateNotificationDto( + NotificationType.ANSWER, + question.getWriter().getId(), + question.getContent(), + answer.getContent(), + calculateRedirectUrl(AUCTION_DETAIL_URI, auction.getId()), + ImageUrlCalculator.calculateBy(answerNotificationEvent.absoluteImageUrl(), auctionImage.getId()) + ); + notificationService.send(createNotificationDto); + } catch (final FirebaseMessagingException ex) { + log.error("exception type : {}, ", ex.getClass().getSimpleName(), ex); + } + } + private String calculateRedirectUrl(final String uri, final Long id) { return uri + URI_DELIMITER + id; } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/notification/domain/NotificationType.java b/backend/ddang/src/main/java/com/ddang/ddang/notification/domain/NotificationType.java index ba0e6ae1e..c40995b37 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/notification/domain/NotificationType.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/notification/domain/NotificationType.java @@ -6,7 +6,9 @@ public enum NotificationType { MESSAGE("message"), - BID("bid"); + BID("bid"), + QUESTION("question"), + ANSWER("answer"); private final String value; diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/AnswerService.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/AnswerService.java index cf1055b8a..df662f456 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/AnswerService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/AnswerService.java @@ -2,6 +2,7 @@ import com.ddang.ddang.auction.application.exception.UserForbiddenException; import com.ddang.ddang.qna.application.dto.CreateAnswerDto; +import com.ddang.ddang.qna.application.event.AnswerNotificationEvent; import com.ddang.ddang.qna.application.exception.AlreadyAnsweredException; import com.ddang.ddang.qna.application.exception.AnswerNotFoundException; import com.ddang.ddang.qna.application.exception.InvalidAnswererException; @@ -14,6 +15,7 @@ import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -22,12 +24,13 @@ @RequiredArgsConstructor public class AnswerService { + private final ApplicationEventPublisher answerEventPublisher; private final JpaUserRepository userRepository; private final JpaQuestionRepository questionRepository; private final JpaAnswerRepository answerRepository; @Transactional - public Long create(final CreateAnswerDto answerDto) { + public Long create(final CreateAnswerDto answerDto, final String absoluteImageUrl) { final User writer = userRepository.findById(answerDto.userId()) .orElseThrow(() -> new UserNotFoundException("해당 사용자를 찾을 수 없습니다.")); final Question question = questionRepository.findById(answerDto.questionId()) @@ -41,8 +44,11 @@ public Long create(final CreateAnswerDto answerDto) { final Answer answer = answerDto.toEntity(); question.addAnswer(answer); - return answerRepository.save(answer) - .getId(); + final Answer persistAnswer = answerRepository.save(answer); + + answerEventPublisher.publishEvent(new AnswerNotificationEvent(persistAnswer, absoluteImageUrl)); + + return persistAnswer.getId(); } private void checkInvalidAnswerer(final Question question, final User writer) { diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java index 50f9dd2a5..40a0fd656 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java @@ -6,6 +6,7 @@ import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; import com.ddang.ddang.qna.application.dto.CreateQuestionDto; import com.ddang.ddang.qna.application.dto.ReadQnasDto; +import com.ddang.ddang.qna.application.event.QuestionNotificationEvent; import com.ddang.ddang.qna.application.exception.InvalidAuctionToAskQuestionException; import com.ddang.ddang.qna.application.exception.InvalidQuestionerException; import com.ddang.ddang.qna.application.exception.QuestionNotFoundException; @@ -15,6 +16,7 @@ import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -26,12 +28,13 @@ @RequiredArgsConstructor public class QuestionService { + private final ApplicationEventPublisher questionEventPublisher; private final JpaAuctionRepository auctionRepository; private final JpaUserRepository userRepository; private final JpaQuestionRepository questionRepository; @Transactional - public Long create(final CreateQuestionDto questionDto) { + public Long create(final CreateQuestionDto questionDto, final String absoluteImageUrl) { final User questioner = userRepository.findByIdAndDeletedIsFalse(questionDto.userId()) .orElseThrow(() -> new UserNotFoundException("해당 사용자를 찾을 수 없습니다.")); final Auction auction = auctionRepository.findPureAuctionById(questionDto.auctionId()) @@ -42,8 +45,11 @@ public Long create(final CreateQuestionDto questionDto) { final Question question = questionDto.toEntity(auction, questioner); - return questionRepository.save(question) - .getId(); + final Question persistQuestion = questionRepository.save(question); + + questionEventPublisher.publishEvent(new QuestionNotificationEvent(persistQuestion, absoluteImageUrl)); + + return persistQuestion.getId(); } private void checkInvalidAuction(final Auction auction) { diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/QuestionDto.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/QuestionDto.java new file mode 100644 index 000000000..6e5eb7224 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/QuestionDto.java @@ -0,0 +1,20 @@ +package com.ddang.ddang.qna.application.dto; + +import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.qna.domain.Answer; +import com.ddang.ddang.qna.domain.Question; +import com.ddang.ddang.user.domain.User; + +public record QuestionDto(Auction auction, User writer, String content, Answer answer, boolean deleted, String auctionImageAbsoluteUrl){ + + public static QuestionDto from(final Question question, String auctionImageAbsoluteUrl) { + return new QuestionDto( + question.getAuction(), + question.getWriter(), + question.getContent(), + question.getAnswer(), + question.isDeleted(), + auctionImageAbsoluteUrl + ); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/event/AnswerNotificationEvent.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/event/AnswerNotificationEvent.java new file mode 100644 index 000000000..b960cc420 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/event/AnswerNotificationEvent.java @@ -0,0 +1,6 @@ +package com.ddang.ddang.qna.application.event; + +import com.ddang.ddang.qna.domain.Answer; + +public record AnswerNotificationEvent(Answer answer, String absoluteImageUrl) { +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/event/QuestionNotificationEvent.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/event/QuestionNotificationEvent.java new file mode 100644 index 000000000..544e1b0cc --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/event/QuestionNotificationEvent.java @@ -0,0 +1,6 @@ +package com.ddang.ddang.qna.application.event; + +import com.ddang.ddang.qna.domain.Question; + +public record QuestionNotificationEvent(Question question, String absoluteImageUrl) { +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/presentation/QnaController.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/presentation/QnaController.java index 184017777..5641fa81b 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/presentation/QnaController.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/presentation/QnaController.java @@ -2,12 +2,13 @@ import com.ddang.ddang.authentication.configuration.AuthenticateUser; import com.ddang.ddang.authentication.domain.dto.AuthenticationUserInfo; +import com.ddang.ddang.image.presentation.util.ImageRelativeUrl; import com.ddang.ddang.qna.application.AnswerService; import com.ddang.ddang.qna.application.QuestionService; -import com.ddang.ddang.qna.presentation.dto.request.CreateAnswerRequest; -import com.ddang.ddang.qna.presentation.dto.request.CreateQuestionRequest; import com.ddang.ddang.qna.application.dto.CreateAnswerDto; import com.ddang.ddang.qna.application.dto.CreateQuestionDto; +import com.ddang.ddang.qna.presentation.dto.request.CreateAnswerRequest; +import com.ddang.ddang.qna.presentation.dto.request.CreateQuestionRequest; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; @@ -33,7 +34,7 @@ public ResponseEntity createQuestion( @AuthenticateUser AuthenticationUserInfo userInfo, @RequestBody @Valid final CreateQuestionRequest questionRequest ) { - questionService.create(CreateQuestionDto.of(questionRequest, userInfo.userId())); + questionService.create(CreateQuestionDto.of(questionRequest, userInfo.userId()), ImageRelativeUrl.AUCTION.calculateAbsoluteUrl()); return ResponseEntity.created(URI.create("/auctions/" + questionRequest.auctionId())) .build(); @@ -45,7 +46,7 @@ public ResponseEntity createAnswer( @PathVariable final Long questionId, @RequestBody @Valid final CreateAnswerRequest answerRequest ) { - answerService.create(CreateAnswerDto.of(questionId, answerRequest, userInfo.userId())); + answerService.create(CreateAnswerDto.of(questionId, answerRequest, userInfo.userId()), ImageRelativeUrl.AUCTION.calculateAbsoluteUrl()); return ResponseEntity.created(URI.create("/auctions/" + answerRequest.auctionId())) .build(); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/NotificationEventListenerTest.java b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/NotificationEventListenerTest.java index 3cce5b25a..a7f2d15ab 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/NotificationEventListenerTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/NotificationEventListenerTest.java @@ -128,4 +128,28 @@ class NotificationEventListenerTest extends NotificationEventListenerFixture { // then verify(notificationService).send(any()); } + + @Test + void 이벤트가_호출되면_질문_알림을_전송한다() throws FirebaseMessagingException { + // given + given(notificationService.send(any())).willReturn(NotificationStatus.SUCCESS); + + // when + notificationEventListener.sendQuestionNotification(질문_알림_이벤트); + + // then + verify(notificationService).send(any()); + } + + @Test + void 이벤트가_호출되면_답변_알림을_전송한다() throws FirebaseMessagingException { + // given + given(notificationService.send(any())).willReturn(NotificationStatus.SUCCESS); + + // when + notificationEventListener.sendAnswerNotification(답변_알림_이벤트); + + // then + verify(notificationService).send(any()); + } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java index 72f007c9a..a8baa456a 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java @@ -12,7 +12,6 @@ import com.ddang.ddang.bid.domain.BidPrice; import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; import com.ddang.ddang.chat.application.dto.CreateMessageDto; -import com.ddang.ddang.chat.application.dto.MessageDto; import com.ddang.ddang.chat.application.event.MessageNotificationEvent; import com.ddang.ddang.chat.domain.ChatRoom; import com.ddang.ddang.chat.domain.Message; @@ -21,6 +20,10 @@ import com.ddang.ddang.image.domain.AuctionImage; import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.image.infrastructure.persistence.JpaAuctionImageRepository; +import com.ddang.ddang.qna.application.event.AnswerNotificationEvent; +import com.ddang.ddang.qna.application.event.QuestionNotificationEvent; +import com.ddang.ddang.qna.domain.Answer; +import com.ddang.ddang.qna.domain.Question; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; @@ -55,6 +58,8 @@ public class NotificationEventListenerFixture { protected CreateBidDto 입찰_생성_DTO; protected MessageNotificationEvent 메시지_알림_이벤트; protected BidNotificationEvent 입찰_알림_이벤트; + protected QuestionNotificationEvent 질문_알림_이벤트; + protected AnswerNotificationEvent 답변_알림_이벤트; protected String 이미지_절대_경로 = "/imageUrl"; @@ -78,9 +83,16 @@ void setUp() { .reliability(new Reliability(4.7d)) .oauthId("13579") .build(); + final User 질문자 = User.builder() + .name("질문자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12038") + .build(); userRepository.save(발신자_겸_판매자); userRepository.save(수신자_겸_기존_입찰자); userRepository.save(새로운_입찰자); + userRepository.save(질문자); final Auction 경매 = Auction.builder() .seller(발신자_겸_판매자) @@ -93,33 +105,37 @@ void setUp() { auctionRepository.save(경매); final AuctionImage 경매_이미지 = new AuctionImage("upload.jpg", "store.jpg"); - auctionImageRepository.save(경매_이미지); 경매.addAuctionImages(List.of(경매_이미지)); - final ChatRoom 채팅방 = new ChatRoom(경매, 발신자_겸_판매자); - chatRoomRepository.save(채팅방); - - final Message 메시지 = Message.builder() - .chatRoom(채팅방) - .writer(발신자_겸_판매자) - .receiver(수신자_겸_기존_입찰자) - .contents("메시지 내용") - .build(); - final Message 저장된_메시지 = messageRepository.save(메시지); - - 메시지_생성_DTO = new CreateMessageDto(채팅방.getId(), 발신자_겸_판매자.getId(), 수신자_겸_기존_입찰자.getId(), "메시지 내용"); - final Bid bid = new Bid(경매, 수신자_겸_기존_입찰자, new BidPrice(200)); - bidRepository.save(bid); 경매.updateLastBid(bid); - 입찰_생성_DTO = new CreateBidDto(경매.getId(), 1000, 새로운_입찰자.getId()); + auctionImageRepository.save(경매_이미지); + chatRoomRepository.save(채팅방); + bidRepository.save(bid); - final MessageDto 메시지_DTO = MessageDto.of(저장된_메시지, 채팅방, 발신자_겸_판매자, 수신자_겸_기존_입찰자, 이미지_절대_경로); - 메시지_알림_이벤트 = new MessageNotificationEvent(메시지_DTO); + 메시지_생성_DTO = new CreateMessageDto(채팅방.getId(), 발신자_겸_판매자.getId(), 수신자_겸_기존_입찰자.getId(), "메시지 내용"); + 입찰_생성_DTO = new CreateBidDto(경매.getId(), 1000, 새로운_입찰자.getId()); + final Message 저장된_메시지 = messageRepository.save( + Message.builder() + .chatRoom(채팅방) + .writer(발신자_겸_판매자) + .receiver(수신자_겸_기존_입찰자) + .contents("메시지 내용") + .build() + ); final AuctionAndImageDto auctionAndImageDto = new AuctionAndImageDto(경매, 경매_이미지); final BidDto 입찰_DTO = new BidDto(수신자_겸_기존_입찰자.getId(), auctionAndImageDto, 이미지_절대_경로); + + 메시지_알림_이벤트 = new MessageNotificationEvent(저장된_메시지, 이미지_절대_경로); 입찰_알림_이벤트 = new BidNotificationEvent(입찰_DTO); + + final Question 질문 = new Question(경매, 질문자, "질문 내용"); + final Answer 답변 = new Answer("응답 내용"); + 질문.addAnswer(답변); + + 질문_알림_이벤트 = new QuestionNotificationEvent(질문, 이미지_절대_경로); + 답변_알림_이벤트 = new AnswerNotificationEvent(답변, 이미지_절대_경로); } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/AnswerServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/AnswerServiceTest.java index f1f7a37d4..feac87d7a 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/AnswerServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/AnswerServiceTest.java @@ -2,6 +2,7 @@ import com.ddang.ddang.auction.application.exception.UserForbiddenException; import com.ddang.ddang.configuration.IsolateDatabase; +import com.ddang.ddang.qna.application.event.AnswerNotificationEvent; import com.ddang.ddang.qna.application.exception.AlreadyAnsweredException; import com.ddang.ddang.qna.application.exception.AnswerNotFoundException; import com.ddang.ddang.qna.application.exception.InvalidAnswererException; @@ -12,11 +13,14 @@ import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.event.ApplicationEvents; +import org.springframework.test.context.event.RecordApplicationEvents; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @IsolateDatabase +@RecordApplicationEvents @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @SuppressWarnings("NonAsciiCharacters") class AnswerServiceTest extends AnswerServiceFixture { @@ -24,10 +28,13 @@ class AnswerServiceTest extends AnswerServiceFixture { @Autowired AnswerService answerService; + @Autowired + ApplicationEvents events; + @Test void 답변을_등록한다() { // when - final Long actual = answerService.create(답변_등록_요청_dto); + final Long actual = answerService.create(답변_등록_요청_dto, 이미지_절대_경로); // then assertThat(actual).isPositive(); @@ -36,7 +43,7 @@ class AnswerServiceTest extends AnswerServiceFixture { @Test void 존재하지_않는_사용자가_질문에_답하는_경우_예외가_발생한다() { // when & then - assertThatThrownBy(() -> answerService.create(존재하지_않는_사용자의_답변_등록_요청_dto)) + assertThatThrownBy(() -> answerService.create(존재하지_않는_사용자의_답변_등록_요청_dto, 이미지_절대_경로)) .isInstanceOf(UserNotFoundException.class) .hasMessage("해당 사용자를 찾을 수 없습니다."); } @@ -44,7 +51,7 @@ class AnswerServiceTest extends AnswerServiceFixture { @Test void 존재하지_않는_질문에_답하는_경우_예외가_발생한다() { // when & then - assertThatThrownBy(() -> answerService.create(존재하지_않는_질문에_답변_등록_요청_dto)) + assertThatThrownBy(() -> answerService.create(존재하지_않는_질문에_답변_등록_요청_dto, 이미지_절대_경로)) .isInstanceOf(QuestionNotFoundException.class) .hasMessage("해당 질문을 찾을 수 없습니다."); } @@ -52,7 +59,7 @@ class AnswerServiceTest extends AnswerServiceFixture { @Test void 판매자가_아닌_다른_사용자가_질문에_답하는_경우_예외가_발생한다() { // when & then - assertThatThrownBy(() -> answerService.create(판매자가_아닌_사용자가_질문에_답변_등록_요청_dto)) + assertThatThrownBy(() -> answerService.create(판매자가_아닌_사용자가_질문에_답변_등록_요청_dto, 이미지_절대_경로)) .isInstanceOf(InvalidAnswererException.class) .hasMessage("판매자만 답변할 수 있습니다."); } @@ -60,7 +67,7 @@ class AnswerServiceTest extends AnswerServiceFixture { @Test void 이미_답변한_질문에_답하는_경우_예외가_발생한다() { // when & then - assertThatThrownBy(() -> answerService.create(이미_답변한_질문에_답변_등록_요청_dto)) + assertThatThrownBy(() -> answerService.create(이미_답변한_질문에_답변_등록_요청_dto, 이미지_절대_경로)) .isInstanceOf(AlreadyAnsweredException.class) .hasMessage("이미 답변한 질문입니다."); } @@ -97,4 +104,14 @@ class AnswerServiceTest extends AnswerServiceFixture { .isInstanceOf(UserForbiddenException.class) .hasMessage("삭제할 권한이 없습니다."); } + + @Test + void 질문에_대한_답변이_생성되면_질문자에게_알림을_보낸다() { + // when + answerService.create(답변_등록_요청_dto, 이미지_절대_경로); + final long actual = events.stream(AnswerNotificationEvent.class).count(); + + // then + assertThat(actual).isEqualTo(1); + } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/QuestionServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/QuestionServiceTest.java index c994b7f55..1801e8490 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/QuestionServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/QuestionServiceTest.java @@ -5,6 +5,7 @@ import com.ddang.ddang.configuration.IsolateDatabase; import com.ddang.ddang.qna.application.dto.ReadQnaDto; import com.ddang.ddang.qna.application.dto.ReadQnasDto; +import com.ddang.ddang.qna.application.event.QuestionNotificationEvent; import com.ddang.ddang.qna.application.exception.InvalidAuctionToAskQuestionException; import com.ddang.ddang.qna.application.exception.InvalidQuestionerException; import com.ddang.ddang.qna.application.exception.QuestionNotFoundException; @@ -15,6 +16,8 @@ import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.event.ApplicationEvents; +import org.springframework.test.context.event.RecordApplicationEvents; import java.util.List; @@ -22,6 +25,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; @IsolateDatabase +@RecordApplicationEvents @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @SuppressWarnings("NonAsciiCharacters") class QuestionServiceTest extends QuestionServiceFixture { @@ -29,10 +33,13 @@ class QuestionServiceTest extends QuestionServiceFixture { @Autowired QuestionService questionService; + @Autowired + ApplicationEvents events; + @Test void 질문을_등록한다() { // when - final Long actual = questionService.create(경매_질문_등록_요청_dto); + final Long actual = questionService.create(경매_질문_등록_요청_dto, 이미지_절대_경로); // then assertThat(actual).isPositive(); @@ -41,7 +48,7 @@ class QuestionServiceTest extends QuestionServiceFixture { @Test void 존재하지_않는_사용자가_경매에_질문하는_경우_예외가_발생한다() { // when & then - assertThatThrownBy(() -> questionService.create(존재하지_않는_사용자가_경매_질문_등록_요청_dto)) + assertThatThrownBy(() -> questionService.create(존재하지_않는_사용자가_경매_질문_등록_요청_dto, 이미지_절대_경로)) .isInstanceOf(UserNotFoundException.class) .hasMessage("해당 사용자를 찾을 수 없습니다."); } @@ -49,7 +56,7 @@ class QuestionServiceTest extends QuestionServiceFixture { @Test void 존재하지_않는_경매에_질문하는_경우_예외가_발생한다() { // when & then - assertThatThrownBy(() -> questionService.create(존재하지_않는_경매_질문_등록_요청_dto)) + assertThatThrownBy(() -> questionService.create(존재하지_않는_경매_질문_등록_요청_dto, 이미지_절대_경로)) .isInstanceOf(AuctionNotFoundException.class) .hasMessage("해당 경매를 찾을 수 없습니다."); } @@ -57,7 +64,7 @@ class QuestionServiceTest extends QuestionServiceFixture { @Test void 이미_종료된_경매에_질문하는_경우_예외가_발생한다() { // when & then - assertThatThrownBy(() -> questionService.create(종료된_경매_질문_등록_요청_dto)) + assertThatThrownBy(() -> questionService.create(종료된_경매_질문_등록_요청_dto, 이미지_절대_경로)) .isInstanceOf(InvalidAuctionToAskQuestionException.class) .hasMessage("이미 종료된 경매입니다."); } @@ -65,7 +72,7 @@ class QuestionServiceTest extends QuestionServiceFixture { @Test void 삭제된_경매에_질문하는_경우_예외가_발생한다() { // when & then - assertThatThrownBy(() -> questionService.create(삭제된_경매_질문_등록_요청_dto)) + assertThatThrownBy(() -> questionService.create(삭제된_경매_질문_등록_요청_dto, 이미지_절대_경로)) .isInstanceOf(AuctionNotFoundException.class) .hasMessage("해당 경매를 찾을 수 없습니다."); } @@ -73,7 +80,7 @@ class QuestionServiceTest extends QuestionServiceFixture { @Test void 판매자가_본인_경매에_질문하는_경우_예외가_발생한다() { // when & then - assertThatThrownBy(() -> questionService.create(판매자가_본인_경매_질문_등록_요청_dto)) + assertThatThrownBy(() -> questionService.create(판매자가_본인_경매_질문_등록_요청_dto, 이미지_절대_경로)) .isInstanceOf(InvalidQuestionerException.class) .hasMessage("경매 등록자는 질문할 수 없습니다."); } @@ -142,4 +149,14 @@ class QuestionServiceTest extends QuestionServiceFixture { .isInstanceOf(UserForbiddenException.class) .hasMessage("삭제할 권한이 없습니다."); } + + @Test + void 질문이_생성되면_판매자에게_알림을_보낸다() { + // when + questionService.create(경매_질문_등록_요청_dto, 이미지_절대_경로); + final long actual = events.stream(QuestionNotificationEvent.class).count(); + + // then + assertThat(actual).isEqualTo(1); + } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/AnswerServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/AnswerServiceFixture.java index 28afd100c..1ffabd63b 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/AnswerServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/AnswerServiceFixture.java @@ -36,6 +36,8 @@ public class AnswerServiceFixture { protected Long 존재하지_않는_답변_아이디 = -999L; protected Long 존재하지_않는_사용자_아이디 = -999L; + protected String 이미지_절대_경로 = "/imageUrl"; + protected Answer 답변; protected User 판매자; protected User 판매자가_아닌_사용자; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java index 905ba6c8a..3f37fcfb7 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java @@ -66,6 +66,8 @@ public class QuestionServiceFixture { protected ReadAnswerDto 답변_정보_dto1; protected ReadAnswerDto 답변_정보_dto2; + protected String 이미지_절대_경로 = "/imageUrl"; + @BeforeEach void setUp() { final Region 서울특별시 = new Region("서울특별시"); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/presentation/QnaControllerTest.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/presentation/QnaControllerTest.java index df9614eff..fef77aefc 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/presentation/QnaControllerTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/presentation/QnaControllerTest.java @@ -92,7 +92,7 @@ void setUp() { void 질문을_등록한다() throws Exception { // given given(tokenDecoder.decode(eq(TokenType.ACCESS), anyString())).willReturn(Optional.of(사용자_ID_클레임)); - given(questionService.create(any(CreateQuestionDto.class))).willReturn(생성된_질문_아이디); + given(questionService.create(any(CreateQuestionDto.class), anyString())).willReturn(생성된_질문_아이디); // when & then final ResultActions resultActions = mockMvc.perform(post("/questions") @@ -168,7 +168,7 @@ private static Stream provideQuestionRequestWithEmptyCont void 존재하지_않은_사용자가_질문시_404를_반환한다() throws Exception { // given given(tokenDecoder.decode(eq(TokenType.ACCESS), anyString())).willReturn(Optional.of(존재하지_않는_사용자_ID_클레임)); - given(questionService.create(any(CreateQuestionDto.class))) + given(questionService.create(any(CreateQuestionDto.class), anyString())) .willThrow(new UserNotFoundException("해당 사용자를 찾을 수 없습니다.")); // when & then @@ -187,7 +187,7 @@ private static Stream provideQuestionRequestWithEmptyCont void 존재하지_않은_경매에_질문시_404를_반환한다() throws Exception { // given given(tokenDecoder.decode(eq(TokenType.ACCESS), anyString())).willReturn(Optional.of(사용자_ID_클레임)); - given(questionService.create(any(CreateQuestionDto.class))) + given(questionService.create(any(CreateQuestionDto.class), anyString())) .willThrow(new AuctionNotFoundException("해당 경매를 찾을 수 없습니다.")); // when & then @@ -206,7 +206,7 @@ private static Stream provideQuestionRequestWithEmptyCont void 이미_종료된_경매에_질문시_400을_반환한다() throws Exception { // given given(tokenDecoder.decode(eq(TokenType.ACCESS), anyString())).willReturn(Optional.of(사용자_ID_클레임)); - given(questionService.create(any(CreateQuestionDto.class))) + given(questionService.create(any(CreateQuestionDto.class), anyString())) .willThrow(new InvalidAuctionToAskQuestionException("이미 종료된 경매입니다")); // when & then @@ -225,7 +225,7 @@ private static Stream provideQuestionRequestWithEmptyCont void 삭제된_경매에_질문시_400을_반환한다() throws Exception { // given given(tokenDecoder.decode(eq(TokenType.ACCESS), anyString())).willReturn(Optional.of(사용자_ID_클레임)); - given(questionService.create(any(CreateQuestionDto.class))) + given(questionService.create(any(CreateQuestionDto.class), anyString())) .willThrow(new InvalidAuctionToAskQuestionException("삭제된 경매입니다")); // when & then @@ -244,7 +244,7 @@ private static Stream provideQuestionRequestWithEmptyCont void 경매자가_본인이_등록한_경매에_질문시_400을_반환한다() throws Exception { // given given(tokenDecoder.decode(eq(TokenType.ACCESS), anyString())).willReturn(Optional.of(사용자_ID_클레임)); - given(questionService.create(any(CreateQuestionDto.class))) + given(questionService.create(any(CreateQuestionDto.class), anyString())) .willThrow(new InvalidQuestionerException("경매 등록자는 질문할 수 없습니다")); // when & then @@ -263,7 +263,7 @@ private static Stream provideQuestionRequestWithEmptyCont void 답변을_등록한다() throws Exception { // given given(tokenDecoder.decode(eq(TokenType.ACCESS), anyString())).willReturn(Optional.of(사용자_ID_클레임)); - given(answerService.create(any(CreateAnswerDto.class))).willReturn(생성된_답변_아이디); + given(answerService.create(any(CreateAnswerDto.class), anyString())).willReturn(생성된_답변_아이디); // when & then final ResultActions resultActions = @@ -340,7 +340,7 @@ private static Stream provideAnswerRequestWithEmptyContent( void 존재하지_않은_사용자가_답변시_404을_반환한다() throws Exception { // given given(tokenDecoder.decode(eq(TokenType.ACCESS), anyString())).willReturn(Optional.of(존재하지_않는_사용자_ID_클레임)); - given(answerService.create(any(CreateAnswerDto.class))) + given(answerService.create(any(CreateAnswerDto.class), anyString())) .willThrow(new UserNotFoundException("해당 사용자를 찾을 수 없습니다.")); // when & then @@ -359,7 +359,7 @@ private static Stream provideAnswerRequestWithEmptyContent( void 존재하지_않은_질문에_답변시_404을_반환한다() throws Exception { // given given(tokenDecoder.decode(eq(TokenType.ACCESS), anyString())).willReturn(Optional.of(사용자_ID_클레임)); - given(answerService.create(any(CreateAnswerDto.class))) + given(answerService.create(any(CreateAnswerDto.class), anyString())) .willThrow(new QuestionNotFoundException("해당 질문을 찾을 수 없습니다.")); // when & then @@ -378,7 +378,7 @@ private static Stream provideAnswerRequestWithEmptyContent( void 판매자가_아닌_사용자가_질문에_답변시_400을_반환한다() throws Exception { // given given(tokenDecoder.decode(eq(TokenType.ACCESS), anyString())).willReturn(Optional.of(사용자_ID_클레임)); - given(answerService.create(any(CreateAnswerDto.class))) + given(answerService.create(any(CreateAnswerDto.class), anyString())) .willThrow(new InvalidAnswererException("판매자만 답변할 수 있습니다.")); // when & then @@ -397,7 +397,7 @@ private static Stream provideAnswerRequestWithEmptyContent( void 이미_답변한_질문에_답변시_400을_반환한다() throws Exception { // given given(tokenDecoder.decode(eq(TokenType.ACCESS), anyString())).willReturn(Optional.of(사용자_ID_클레임)); - given(answerService.create(any(CreateAnswerDto.class))) + given(answerService.create(any(CreateAnswerDto.class), anyString())) .willThrow(new AlreadyAnsweredException("이미 답변한 질문입니다.")); // when & then diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/presentation/fixture/QnaControllerFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/presentation/fixture/QnaControllerFixture.java index 51e7dd519..5d80b44b1 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/presentation/fixture/QnaControllerFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/presentation/fixture/QnaControllerFixture.java @@ -17,6 +17,7 @@ public class QnaControllerFixture extends CommonControllerSliceTest { protected Long 존재하지_않는_질문_아이디 = 999L; protected Long 존재하지_않는_답변_아이디 = 999L; protected String 액세스_토큰_값 = "Bearer accessToken"; + protected String 이미지_절대_경로 = "/imageUrl"; protected CreateQuestionRequest 질문_등록_request = new CreateQuestionRequest(1L, "궁금한 점이 있습니다."); protected CreateQuestionRequest 경매_아이디가_없는_질문_등록_request = new CreateQuestionRequest(null, "궁금한 점이 있습니다."); From 149a646d2e04f1934c227cac06d9bda1f15307c0 Mon Sep 17 00:00:00 2001 From: apptie <57691173+apptie@users.noreply.github.com> Date: Sat, 14 Oct 2023 15:02:07 +0900 Subject: [PATCH 13/37] =?UTF-8?q?refactor:=20#649=20Auction=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=9D=B8=ED=94=84=EB=9D=BC=20=EB=A6=AC=ED=8E=99?= =?UTF-8?q?=ED=86=A0=EB=A7=81=20(#651)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: Querydsl 기반의 Auction 인터페이스 제거 및 구현체에서 일반 클래스로 변환 * refactor: Querydsl 기반의 Auction 조회 인터페이스를 domain 패키지로 이동 * refactor: 경매 목록 조회 메서드 파라미터 순서 변경 * feat: 도메인 영역의 Repository 추가 * feat: 도메인 영역의 Repository 구현체 추가 * test: 누락된 테스트 케이스 추가 * feat: 경매 id가 존재하는지 여부를 반환하는 기능 추가 * refactor: Service에서 도메인 영역의 Repository를 사용하도록 변경 * refactor: Service에서 도메인 영역의 Repository를 사용하도록 변경 * rename: 경매 목록 조회 관련 테스트 패키지 분리 * remove: 사용하지 않는 경매 더미 데이터 초기화 로직 삭제 * test: fixture에서 구체적인 DB 구현 기술에 의존적이지 않도록 변경 --- .../auction/application/AuctionService.java | 8 +- .../dto/AuctionAndImageDto.java | 2 +- .../repository/AuctionAndImageRepository.java | 9 + .../domain/repository/AuctionRepository.java | 27 +++ .../persistence/AuctionRepositoryImpl.java | 56 +++++ .../persistence/JpaAuctionRepository.java | 2 +- .../QuerydslAuctionAndImageRepository.java | 42 +++- ...QuerydslAuctionAndImageRepositoryImpl.java | 46 ----- .../QuerydslAuctionRepository.java | 186 ++++++++++++++++- .../QuerydslAuctionRepositoryImpl.java | 193 ------------------ .../AuctionAndImageQueryProjectionDto.java | 1 + .../ddang/bid/application/BidService.java | 21 +- .../ddang/bid/application/dto/BidDto.java | 2 +- .../chat/application/ChatRoomService.java | 9 +- .../InitializationAuctionConfiguration.java | 73 ------- .../qna/application/QuestionService.java | 9 +- .../application/AuctionReportService.java | 13 +- .../review/application/ReviewService.java | 11 +- .../fixture/AuctionServiceFixture.java | 15 +- .../AuctionRepositoryImplTest.java | 172 ++++++++++++++++ .../persistence/JpaAuctionRepositoryTest.java | 18 ++ ...uerydslAuctionAndImageRepositoryTest.java} | 18 +- .../fixture/AuctionRepositoryImplFixture.java | 157 ++++++++++++++ .../fixture/JpaAuctionRepositoryFixture.java | 1 + ...ydslAuctionAndImageRepositoryFixture.java} | 20 +- ...rydslAuctionRepositoryForListFixture.java} | 56 ++--- ...dslAuctionRepositoryForObjectFixture.java} | 32 ++- .../AuctionForListByBidderIdFixture.java | 5 +- .../AuctionForListByUserIdFixture.java | 5 +- ...yTitleAndSortByAuctioneerCountFixture.java | 6 +- ...rchByTitleAndSortByClosingTimeFixture.java | 5 +- ...orListSearchByTitleAndSortByIdFixture.java | 5 +- ...rchByTitleAndSortByReliabilityFixture.java | 5 +- .../AuctionForListSearchByTitleFixture.java | 5 +- ...onForListSortByAuctioneerCountFixture.java | 5 +- ...uctionForListSortByClosingTimeFixture.java | 5 +- .../AuctionForListSortByIdFixture.java | 5 +- ...uctionForListSortByReliabilityFixture.java | 5 +- .../AuctionForListByBidderIdTest.java | 7 +- .../AuctionForListByUserIdTest.java | 7 +- ...chByTitleAndSortByAuctioneerCountTest.java | 31 +-- ...SearchByTitleAndSortByClosingTimeTest.java | 31 +-- ...onForListSearchByTitleAndSortByIdTest.java | 31 +-- ...SearchByTitleAndSortByReliabilityTest.java | 31 +-- .../AuctionForListSearchByTitleTest.java | 35 ++-- ...ctionForListSortByAuctioneerCountTest.java | 35 ++-- .../AuctionForListSortByClosingTimeTest.java | 35 ++-- .../AuctionForListSortByIdTest.java | 35 ++-- .../AuctionForListSortByReliabilityTest.java | 35 ++-- .../fixture/BidServiceFixture.java | 17 +- .../fixture/ChatRoomServiceFixture.java | 22 +- .../fixture/MessageServiceFixture.java | 11 +- ...ChatRoomAndImageRepositoryImplFixture.java | 25 ++- ...dMessageAndImageRepositoryImplFixture.java | 28 ++- ...QuerydslChatRoomRepositoryImplFixture.java | 24 ++- .../QuerydslMessageRepositoryImplFixture.java | 21 +- .../FcmNotificationServiceFixture.java | 9 +- .../NotificationEventListenerFixture.java | 11 +- .../fixture/AnswerServiceFixture.java | 9 +- .../fixture/QuestionServiceFixture.java | 14 +- .../application/AuctionReportServiceTest.java | 14 +- .../fixture/AnswerReportServiceFixture.java | 9 +- .../fixture/AuctionReportServiceFixture.java | 13 +- .../fixture/ChatRoomReportServiceFixture.java | 13 +- .../fixture/QuestionReportServiceFixture.java | 9 +- .../fixture/ReviewServiceFixture.java | 11 +- ...abilityUpdateSchedulingServiceFixture.java | 27 ++- 67 files changed, 1156 insertions(+), 699 deletions(-) rename backend/ddang/src/main/java/com/ddang/ddang/auction/{infrastructure/persistence => domain}/dto/AuctionAndImageDto.java (73%) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/auction/domain/repository/AuctionAndImageRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/auction/domain/repository/AuctionRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionRepositoryImpl.java delete mode 100644 backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionAndImageRepositoryImpl.java delete mode 100644 backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepositoryImpl.java delete mode 100644 backend/ddang/src/main/java/com/ddang/ddang/configuration/initialization/InitializationAuctionConfiguration.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionRepositoryImplTest.java rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/{QuerydslAuctionAndImageRepositoryImplTest.java => QuerydslAuctionAndImageRepositoryTest.java} (65%) create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/{QuerydslAuctionAndImageRepositoryImplFixture.java => QuerydslAuctionAndImageRepositoryFixture.java} (77%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/{QuerydslAuctionRepositoryImplForListFixture.java => QuerydslAuctionRepositoryForListFixture.java} (91%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/{QuerydslAuctionRepositoryImplForObjectFixture.java => QuerydslAuctionRepositoryForObjectFixture.java} (77%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/{ => list}/AuctionForListByBidderIdFixture.java (90%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/{ => list}/AuctionForListByUserIdFixture.java (88%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/{ => list}/AuctionForListSearchByTitleAndSortByAuctioneerCountFixture.java (94%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/{ => list}/AuctionForListSearchByTitleAndSortByClosingTimeFixture.java (94%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/{ => list}/AuctionForListSearchByTitleAndSortByIdFixture.java (94%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/{ => list}/AuctionForListSearchByTitleAndSortByReliabilityFixture.java (94%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/{ => list}/AuctionForListSearchByTitleFixture.java (95%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/{ => list}/AuctionForListSortByAuctioneerCountFixture.java (95%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/{ => list}/AuctionForListSortByClosingTimeFixture.java (95%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/{ => list}/AuctionForListSortByIdFixture.java (95%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/{ => list}/AuctionForListSortByReliabilityFixture.java (95%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/{ => list}/AuctionForListByBidderIdTest.java (96%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/{ => list}/AuctionForListByUserIdTest.java (95%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/{ => list}/AuctionForListSearchByTitleAndSortByAuctioneerCountTest.java (92%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/{ => list}/AuctionForListSearchByTitleAndSortByClosingTimeTest.java (91%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/{ => list}/AuctionForListSearchByTitleAndSortByIdTest.java (93%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/{ => list}/AuctionForListSearchByTitleAndSortByReliabilityTest.java (92%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/{ => list}/AuctionForListSearchByTitleTest.java (88%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/{ => list}/AuctionForListSortByAuctioneerCountTest.java (92%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/{ => list}/AuctionForListSortByClosingTimeTest.java (92%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/{ => list}/AuctionForListSortByIdTest.java (93%) rename backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/{ => list}/AuctionForListSortByReliabilityTest.java (92%) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/application/AuctionService.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/application/AuctionService.java index 1131ec206..197c45d5f 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/application/AuctionService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/application/AuctionService.java @@ -7,7 +7,7 @@ import com.ddang.ddang.auction.application.exception.AuctionNotFoundException; import com.ddang.ddang.auction.application.exception.UserForbiddenException; import com.ddang.ddang.auction.domain.Auction; -import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.auction.presentation.dto.request.ReadAuctionSearchCondition; import com.ddang.ddang.category.application.exception.CategoryNotFoundException; import com.ddang.ddang.category.domain.Category; @@ -36,7 +36,7 @@ public class AuctionService { private final JpaUserRepository userRepository; - private final JpaAuctionRepository auctionRepository; + private final AuctionRepository auctionRepository; private final JpaRegionRepository regionRepository; private final JpaCategoryRepository categoryRepository; private final StoreImageProcessor imageProcessor; @@ -91,8 +91,8 @@ public ReadAuctionsDto readAllByCondition( final Pageable pageable, final ReadAuctionSearchCondition readAuctionSearchCondition) { final Slice auctions = auctionRepository.findAuctionsAllByCondition( - pageable, - readAuctionSearchCondition + readAuctionSearchCondition, + pageable ); return ReadAuctionsDto.of(auctions, LocalDateTime.now()); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/dto/AuctionAndImageDto.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/domain/dto/AuctionAndImageDto.java similarity index 73% rename from backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/dto/AuctionAndImageDto.java rename to backend/ddang/src/main/java/com/ddang/ddang/auction/domain/dto/AuctionAndImageDto.java index 2615a219e..06fba43b8 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/dto/AuctionAndImageDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/domain/dto/AuctionAndImageDto.java @@ -1,4 +1,4 @@ -package com.ddang.ddang.auction.infrastructure.persistence.dto; +package com.ddang.ddang.auction.domain.dto; import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.image.domain.AuctionImage; diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/domain/repository/AuctionAndImageRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/domain/repository/AuctionAndImageRepository.java new file mode 100644 index 000000000..5ec07ba19 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/domain/repository/AuctionAndImageRepository.java @@ -0,0 +1,9 @@ +package com.ddang.ddang.auction.domain.repository; + +import com.ddang.ddang.auction.domain.dto.AuctionAndImageDto; +import java.util.Optional; + +public interface AuctionAndImageRepository { + + Optional findDtoByAuctionId(final Long auctionId); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/domain/repository/AuctionRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/domain/repository/AuctionRepository.java new file mode 100644 index 000000000..a175eac29 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/domain/repository/AuctionRepository.java @@ -0,0 +1,27 @@ +package com.ddang.ddang.auction.domain.repository; + +import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.presentation.dto.request.ReadAuctionSearchCondition; +import java.util.Optional; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; + +public interface AuctionRepository { + + Auction save(final Auction auction); + + boolean existsById(final Long id); + + Optional findTotalAuctionById(final Long id); + + Optional findPureAuctionById(final Long id); + + Slice findAuctionsAllByCondition( + final ReadAuctionSearchCondition readAuctionSearchCondition, + final Pageable pageable + ); + + Slice findAuctionsAllByUserId(final Long userId, final Pageable pageable); + + Slice findAuctionsAllByBidderId(final Long bidderId, final Pageable pageable); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionRepositoryImpl.java new file mode 100644 index 000000000..1f67b0ac1 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionRepositoryImpl.java @@ -0,0 +1,56 @@ +package com.ddang.ddang.auction.infrastructure.persistence; + +import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.presentation.dto.request.ReadAuctionSearchCondition; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class AuctionRepositoryImpl implements AuctionRepository { + + private final JpaAuctionRepository jpaAuctionRepository; + private final QuerydslAuctionRepository querydslAuctionRepository; + + @Override + public Auction save(final Auction auction) { + return jpaAuctionRepository.save(auction); + } + + @Override + public boolean existsById(final Long id) { + return jpaAuctionRepository.existsById(id); + } + + @Override + public Optional findTotalAuctionById(final Long id) { + return jpaAuctionRepository.findTotalAuctionById(id); + } + + @Override + public Optional findPureAuctionById(final Long id) { + return jpaAuctionRepository.findPureAuctionById(id); + } + + @Override + public Slice findAuctionsAllByCondition( + final ReadAuctionSearchCondition readAuctionSearchCondition, + final Pageable pageable + ) { + return querydslAuctionRepository.findAuctionsAllByCondition(readAuctionSearchCondition, pageable); + } + + @Override + public Slice findAuctionsAllByUserId(final Long userId, final Pageable pageable) { + return querydslAuctionRepository.findAuctionsAllByUserId(userId, pageable); + } + + @Override + public Slice findAuctionsAllByBidderId(final Long bidderId, final Pageable pageable) { + return querydslAuctionRepository.findAuctionsAllByBidderId(bidderId, pageable); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepository.java index 184a21853..9e37a0e75 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepository.java @@ -6,7 +6,7 @@ import java.util.Optional; import org.springframework.data.jpa.repository.Query; -public interface JpaAuctionRepository extends JpaRepository, QuerydslAuctionRepository, QuerydslAuctionAndImageRepository { +public interface JpaAuctionRepository extends JpaRepository { @Query(""" SELECT a diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionAndImageRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionAndImageRepository.java index 8c7c4fe4a..1b8915afc 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionAndImageRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionAndImageRepository.java @@ -1,10 +1,46 @@ package com.ddang.ddang.auction.infrastructure.persistence; -import com.ddang.ddang.auction.infrastructure.persistence.dto.AuctionAndImageDto; +import static com.ddang.ddang.auction.domain.QAuction.auction; +import static com.ddang.ddang.bid.domain.QBid.bid; +import static com.ddang.ddang.image.domain.QAuctionImage.auctionImage; +import com.ddang.ddang.auction.domain.dto.AuctionAndImageDto; +import com.ddang.ddang.auction.domain.repository.AuctionAndImageRepository; +import com.ddang.ddang.auction.infrastructure.persistence.dto.AuctionAndImageQueryProjectionDto; +import com.ddang.ddang.auction.infrastructure.persistence.dto.QAuctionAndImageQueryProjectionDto; +import com.querydsl.jpa.JPAExpressions; +import com.querydsl.jpa.impl.JPAQueryFactory; import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; -public interface QuerydslAuctionAndImageRepository { +@Repository +@RequiredArgsConstructor +public class QuerydslAuctionAndImageRepository implements AuctionAndImageRepository { - Optional findDtoByAuctionId(final Long auctionId); + private final JPAQueryFactory queryFactory; + + @Override + public Optional findDtoByAuctionId(final Long auctionId) { + final AuctionAndImageQueryProjectionDto auctionAndImageQueryProjectionDto = + queryFactory.select(new QAuctionAndImageQueryProjectionDto(auction, auctionImage)) + .from(auction) + .leftJoin(auction.lastBid, bid).fetchJoin() + .leftJoin(bid.bidder).fetchJoin() + .leftJoin(auctionImage).on(auctionImage.id.eq( + JPAExpressions + .select(auctionImage.id.min()) + .from(auctionImage) + .where(auctionImage.auction.id.eq(auction.id)) + .groupBy(auctionImage.auction.id) + )).fetchJoin() + .where(auction.id.eq(auctionId)) + .fetchOne(); + + if (auctionAndImageQueryProjectionDto == null) { + return Optional.empty(); + } + + return Optional.of(auctionAndImageQueryProjectionDto.toDto()); + } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionAndImageRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionAndImageRepositoryImpl.java deleted file mode 100644 index e1a1e79df..000000000 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionAndImageRepositoryImpl.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.ddang.ddang.auction.infrastructure.persistence; - -import com.ddang.ddang.auction.infrastructure.persistence.dto.AuctionAndImageDto; -import com.ddang.ddang.auction.infrastructure.persistence.dto.AuctionAndImageQueryProjectionDto; -import com.ddang.ddang.auction.infrastructure.persistence.dto.QAuctionAndImageQueryProjectionDto; -import com.querydsl.jpa.JPAExpressions; -import com.querydsl.jpa.impl.JPAQueryFactory; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Repository; - -import java.util.Optional; - -import static com.ddang.ddang.auction.domain.QAuction.auction; -import static com.ddang.ddang.bid.domain.QBid.bid; -import static com.ddang.ddang.image.domain.QAuctionImage.auctionImage; - -@Repository -@RequiredArgsConstructor -public class QuerydslAuctionAndImageRepositoryImpl implements QuerydslAuctionAndImageRepository { - - private final JPAQueryFactory queryFactory; - - @Override - public Optional findDtoByAuctionId(final Long auctionId) { - final AuctionAndImageQueryProjectionDto auctionAndImageQueryProjectionDto = - queryFactory.select(new QAuctionAndImageQueryProjectionDto(auction, auctionImage)) - .from(auction) - .leftJoin(auction.lastBid, bid).fetchJoin() - .leftJoin(bid.bidder).fetchJoin() - .leftJoin(auctionImage).on(auctionImage.id.eq( - JPAExpressions - .select(auctionImage.id.min()) - .from(auctionImage) - .where(auctionImage.auction.id.eq(auction.id)) - .groupBy(auctionImage.auction.id) - )).fetchJoin() - .where(auction.id.eq(auctionId)) - .fetchOne(); - - if (auctionAndImageQueryProjectionDto == null) { - return Optional.empty(); - } - - return Optional.of(auctionAndImageQueryProjectionDto.toDto()); - } -} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepository.java index 53bf948c2..306aa2603 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepository.java @@ -1,18 +1,190 @@ package com.ddang.ddang.auction.infrastructure.persistence; +import static com.ddang.ddang.auction.domain.QAuction.auction; +import static com.ddang.ddang.bid.domain.QBid.bid; +import static com.ddang.ddang.category.domain.QCategory.category; +import static com.ddang.ddang.region.domain.QAuctionRegion.auctionRegion; +import static com.ddang.ddang.region.domain.QRegion.region; + +import com.ddang.ddang.auction.configuration.util.AuctionSortConditionConsts; import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.infrastructure.persistence.exception.UnsupportedSortConditionException; import com.ddang.ddang.auction.presentation.dto.request.ReadAuctionSearchCondition; +import com.ddang.ddang.common.helper.QuerydslSliceHelper; +import com.querydsl.core.types.OrderSpecifier; +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.core.types.dsl.CaseBuilder; +import com.querydsl.jpa.impl.JPAQueryFactory; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; +import org.springframework.data.domain.Sort; +import org.springframework.data.domain.Sort.Order; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class QuerydslAuctionRepository { + + private static final long SLICE_OFFSET = 1L; + private static final int HIGH_PRIORITY = 2; + private static final int LOW_PRIORITY = 1; + + private final JPAQueryFactory queryFactory; + + public Slice findAuctionsAllByCondition( + final ReadAuctionSearchCondition readAuctionSearchCondition, + final Pageable pageable + ) { + final List> orderSpecifiers = calculateOrderSpecifiers(pageable); + final List booleanExpressions = calculateBooleanExpressions(readAuctionSearchCondition); + final List findAuctionIds = findAuctionIds(booleanExpressions, orderSpecifiers, pageable); + final List findAuctions = findAuctionsByIdsAndOrderSpecifiers(findAuctionIds, orderSpecifiers); + + return QuerydslSliceHelper.toSlice(findAuctions, pageable); + } + + private List> calculateOrderSpecifiers(final Pageable pageable) { + final List> orderSpecifiers = new ArrayList<>(); + + orderSpecifiers.add(closingTimeOrderSpecifier()); + orderSpecifiers.addAll(processOrderSpecifiers(pageable)); + orderSpecifiers.add(auction.id.desc()); + + return orderSpecifiers; + } + + private List> processOrderSpecifiers(final Pageable pageable) { + final List> orderSpecifiers = new ArrayList<>(); + final Sort sort = pageable.getSort(); + + for (final Order order : sort) { + if (AuctionSortConditionConsts.ID.equals(order.getProperty())) { + return Collections.emptyList(); + } + + orderSpecifiers.add(processOrderSpecifierByCondition(order)); + } + + return orderSpecifiers; + } + + private OrderSpecifier processOrderSpecifierByCondition(final Order order) { + if (AuctionSortConditionConsts.RELIABILITY.equals(order.getProperty())) { + return auction.seller.reliability.value.desc(); + } + if (AuctionSortConditionConsts.AUCTIONEER_COUNT.equals(order.getProperty())) { + return auction.auctioneerCount.desc(); + } + if (AuctionSortConditionConsts.CLOSING_TINE.equals(order.getProperty())) { + return auction.closingTime.asc(); + } + + throw new UnsupportedSortConditionException("지원하지 않는 정렬 방식입니다."); + } + + private OrderSpecifier closingTimeOrderSpecifier() { + final LocalDateTime now = LocalDateTime.now(); + + return new CaseBuilder() + .when(auction.closingTime.after(now)).then(LOW_PRIORITY) + .otherwise(HIGH_PRIORITY) + .asc(); + } + + private List calculateBooleanExpressions(final ReadAuctionSearchCondition searchCondition) { + final List booleanExpressions = new ArrayList<>(); + + booleanExpressions.add(auction.deleted.isFalse()); + + final BooleanExpression titleBooleanExpression = convertTitleSearchCondition(searchCondition); + + if (titleBooleanExpression != null) { + booleanExpressions.add(titleBooleanExpression); + } + + return booleanExpressions; + } + + private List findAuctionIds( + final List booleanExpressions, + final List> orderSpecifiers, + final Pageable pageable + ) { + return queryFactory.select(auction.id) + .from(auction) + .where(booleanExpressions.toArray(BooleanExpression[]::new)) + .orderBy(orderSpecifiers.toArray(OrderSpecifier[]::new)) + .limit(pageable.getPageSize() + SLICE_OFFSET) + .offset(pageable.getOffset()) + .fetch(); + } + + private BooleanExpression convertTitleSearchCondition(final ReadAuctionSearchCondition readAuctionSearchCondition) { + final String titleSearchCondition = readAuctionSearchCondition.title(); + + if (titleSearchCondition == null) { + return null; + } + + return auction.title.like("%" + titleSearchCondition + "%"); + } + + private List findAuctionsByIdsAndOrderSpecifiers( + final List targetIds, + final List> orderSpecifiers + ) { + return queryFactory.selectFrom(auction) + .leftJoin(auction.auctionRegions, auctionRegion).fetchJoin() + .leftJoin(auctionRegion.thirdRegion, region).fetchJoin() + .leftJoin(region.firstRegion).fetchJoin() + .leftJoin(region.secondRegion).fetchJoin() + .leftJoin(auction.lastBid).fetchJoin() + .join(auction.subCategory, category).fetchJoin() + .join(category.mainCategory).fetchJoin() + .join(auction.seller).fetchJoin() + .where(auction.id.in(targetIds.toArray(Long[]::new))) + .orderBy(orderSpecifiers.toArray(OrderSpecifier[]::new)) + .fetch(); + } + + public Slice findAuctionsAllByUserId(final Long userId, final Pageable pageable) { + final List booleanExpressions = List.of( + auction.seller.id.eq(userId), + auction.deleted.isFalse() + ); + final List> orderSpecifiers = List.of(auction.id.desc()); + final List findAuctionIds = findAuctionIds(booleanExpressions, orderSpecifiers, pageable); + final List findAuctions = findAuctionsByIdsAndOrderSpecifiers( + findAuctionIds, + List.of(auction.id.desc()) + ); + + return QuerydslSliceHelper.toSlice(findAuctions, pageable); + } -public interface QuerydslAuctionRepository { + public Slice findAuctionsAllByBidderId(final Long bidderId, final Pageable pageable) { + final List findAuctionIds = queryFactory.select(bid.auction.id) + .from(bid) + .where(bid.bidder.id.eq(bidderId)) + .groupBy(bid.auction.id) + .orderBy(bid.id.max().desc()) + .limit(pageable.getPageSize() + SLICE_OFFSET) + .offset(pageable.getOffset()) + .fetch(); + final List findAuctions = findAuctionsByIdsAndOrderSpecifiers(findAuctionIds, Collections.emptyList()); - Slice findAuctionsAllByCondition( - final Pageable pageable, - final ReadAuctionSearchCondition readAuctionSearchCondition - ); + findAuctions.sort((firstAuction, secondAuction) -> { + int firstAuctionIndex = findAuctionIds.indexOf(firstAuction.getId()); + int secondAuctionIndex = findAuctionIds.indexOf(secondAuction.getId()); - Slice findAuctionsAllByUserId(final Long userId, final Pageable pageable); + return Integer.compare(firstAuctionIndex, secondAuctionIndex); + }); - Slice findAuctionsAllByBidderId(final Long bidderId, final Pageable pageable); + return QuerydslSliceHelper.toSlice(findAuctions, pageable); + } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepositoryImpl.java deleted file mode 100644 index b859bdc0e..000000000 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepositoryImpl.java +++ /dev/null @@ -1,193 +0,0 @@ -package com.ddang.ddang.auction.infrastructure.persistence; - -import static com.ddang.ddang.auction.domain.QAuction.auction; -import static com.ddang.ddang.bid.domain.QBid.bid; -import static com.ddang.ddang.category.domain.QCategory.category; -import static com.ddang.ddang.region.domain.QAuctionRegion.auctionRegion; -import static com.ddang.ddang.region.domain.QRegion.region; - -import com.ddang.ddang.auction.configuration.util.AuctionSortConditionConsts; -import com.ddang.ddang.auction.domain.Auction; -import com.ddang.ddang.auction.infrastructure.persistence.exception.UnsupportedSortConditionException; -import com.ddang.ddang.auction.presentation.dto.request.ReadAuctionSearchCondition; -import com.ddang.ddang.common.helper.QuerydslSliceHelper; -import com.querydsl.core.types.OrderSpecifier; -import com.querydsl.core.types.dsl.BooleanExpression; -import com.querydsl.core.types.dsl.CaseBuilder; -import com.querydsl.jpa.impl.JPAQueryFactory; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Slice; -import org.springframework.data.domain.Sort; -import org.springframework.data.domain.Sort.Order; -import org.springframework.stereotype.Repository; - -@Repository -@RequiredArgsConstructor -public class QuerydslAuctionRepositoryImpl implements QuerydslAuctionRepository { - - private static final long SLICE_OFFSET = 1L; - private static final int HIGH_PRIORITY = 2; - private static final int LOW_PRIORITY = 1; - - private final JPAQueryFactory queryFactory; - - @Override - public Slice findAuctionsAllByCondition( - final Pageable pageable, - final ReadAuctionSearchCondition readAuctionSearchCondition - ) { - final List> orderSpecifiers = calculateOrderSpecifiers(pageable); - final List booleanExpressions = calculateBooleanExpressions(readAuctionSearchCondition); - final List findAuctionIds = findAuctionIds(booleanExpressions, orderSpecifiers, pageable); - final List findAuctions = findAuctionsByIdsAndOrderSpecifiers(findAuctionIds, orderSpecifiers); - - return QuerydslSliceHelper.toSlice(findAuctions, pageable); - } - - private List> calculateOrderSpecifiers(final Pageable pageable) { - final List> orderSpecifiers = new ArrayList<>(); - - orderSpecifiers.add(closingTimeOrderSpecifier()); - orderSpecifiers.addAll(processOrderSpecifiers(pageable)); - orderSpecifiers.add(auction.id.desc()); - - return orderSpecifiers; - } - - private List> processOrderSpecifiers(final Pageable pageable) { - final List> orderSpecifiers = new ArrayList<>(); - final Sort sort = pageable.getSort(); - - for (final Order order : sort) { - if (AuctionSortConditionConsts.ID.equals(order.getProperty())) { - return Collections.emptyList(); - } - - orderSpecifiers.add(processOrderSpecifierByCondition(order)); - } - - return orderSpecifiers; - } - - private OrderSpecifier processOrderSpecifierByCondition(final Order order) { - if (AuctionSortConditionConsts.RELIABILITY.equals(order.getProperty())) { - return auction.seller.reliability.value.desc(); - } - if (AuctionSortConditionConsts.AUCTIONEER_COUNT.equals(order.getProperty())) { - return auction.auctioneerCount.desc(); - } - if (AuctionSortConditionConsts.CLOSING_TINE.equals(order.getProperty())) { - return auction.closingTime.asc(); - } - - throw new UnsupportedSortConditionException("지원하지 않는 정렬 방식입니다."); - } - - private OrderSpecifier closingTimeOrderSpecifier() { - final LocalDateTime now = LocalDateTime.now(); - - return new CaseBuilder() - .when(auction.closingTime.after(now)).then(LOW_PRIORITY) - .otherwise(HIGH_PRIORITY) - .asc(); - } - - private List calculateBooleanExpressions(final ReadAuctionSearchCondition searchCondition) { - final List booleanExpressions = new ArrayList<>(); - - booleanExpressions.add(auction.deleted.isFalse()); - - final BooleanExpression titleBooleanExpression = convertTitleSearchCondition(searchCondition); - - if (titleBooleanExpression != null) { - booleanExpressions.add(titleBooleanExpression); - } - - return booleanExpressions; - } - - private List findAuctionIds( - final List booleanExpressions, - final List> orderSpecifiers, - final Pageable pageable - ) { - return queryFactory.select(auction.id) - .from(auction) - .where(booleanExpressions.toArray(BooleanExpression[]::new)) - .orderBy(orderSpecifiers.toArray(OrderSpecifier[]::new)) - .limit(pageable.getPageSize() + SLICE_OFFSET) - .offset(pageable.getOffset()) - .fetch(); - } - - private BooleanExpression convertTitleSearchCondition(final ReadAuctionSearchCondition readAuctionSearchCondition) { - final String titleSearchCondition = readAuctionSearchCondition.title(); - - if (titleSearchCondition == null) { - return null; - } - - return auction.title.like("%" + titleSearchCondition + "%"); - } - - private List findAuctionsByIdsAndOrderSpecifiers( - final List targetIds, - final List> orderSpecifiers - ) { - return queryFactory.selectFrom(auction) - .leftJoin(auction.auctionRegions, auctionRegion).fetchJoin() - .leftJoin(auctionRegion.thirdRegion, region).fetchJoin() - .leftJoin(region.firstRegion).fetchJoin() - .leftJoin(region.secondRegion).fetchJoin() - .leftJoin(auction.lastBid).fetchJoin() - .join(auction.subCategory, category).fetchJoin() - .join(category.mainCategory).fetchJoin() - .join(auction.seller).fetchJoin() - .where(auction.id.in(targetIds.toArray(Long[]::new))) - .orderBy(orderSpecifiers.toArray(OrderSpecifier[]::new)) - .fetch(); - } - - @Override - public Slice findAuctionsAllByUserId(final Long userId, final Pageable pageable) { - final List booleanExpressions = List.of( - auction.seller.id.eq(userId), - auction.deleted.isFalse() - ); - final List> orderSpecifiers = List.of(auction.id.desc()); - final List findAuctionIds = findAuctionIds(booleanExpressions, orderSpecifiers, pageable); - final List findAuctions = findAuctionsByIdsAndOrderSpecifiers( - findAuctionIds, - List.of(auction.id.desc()) - ); - - return QuerydslSliceHelper.toSlice(findAuctions, pageable); - } - - @Override - public Slice findAuctionsAllByBidderId(final Long bidderId, final Pageable pageable) { - final List findAuctionIds = queryFactory.select(bid.auction.id) - .from(bid) - .where(bid.bidder.id.eq(bidderId)) - .groupBy(bid.auction.id) - .orderBy(bid.id.max().desc()) - .limit(pageable.getPageSize() + SLICE_OFFSET) - .offset(pageable.getOffset()) - .fetch(); - final List findAuctions = findAuctionsByIdsAndOrderSpecifiers(findAuctionIds, Collections.emptyList()); - - findAuctions.sort((firstAuction, secondAuction) -> { - int firstAuctionIndex = findAuctionIds.indexOf(firstAuction.getId()); - int secondAuctionIndex = findAuctionIds.indexOf(secondAuction.getId()); - - return Integer.compare(firstAuctionIndex, secondAuctionIndex); - }); - - return QuerydslSliceHelper.toSlice(findAuctions, pageable); - } -} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/dto/AuctionAndImageQueryProjectionDto.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/dto/AuctionAndImageQueryProjectionDto.java index 80b2e77e1..909372950 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/dto/AuctionAndImageQueryProjectionDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/dto/AuctionAndImageQueryProjectionDto.java @@ -1,6 +1,7 @@ package com.ddang.ddang.auction.infrastructure.persistence.dto; import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.domain.dto.AuctionAndImageDto; import com.ddang.ddang.image.domain.AuctionImage; import com.querydsl.core.annotations.QueryProjection; diff --git a/backend/ddang/src/main/java/com/ddang/ddang/bid/application/BidService.java b/backend/ddang/src/main/java/com/ddang/ddang/bid/application/BidService.java index 49e6375b5..10a4c5f61 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/bid/application/BidService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/bid/application/BidService.java @@ -2,8 +2,9 @@ import com.ddang.ddang.auction.application.exception.AuctionNotFoundException; import com.ddang.ddang.auction.domain.Auction; -import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; -import com.ddang.ddang.auction.infrastructure.persistence.dto.AuctionAndImageDto; +import com.ddang.ddang.auction.domain.dto.AuctionAndImageDto; +import com.ddang.ddang.auction.domain.repository.AuctionAndImageRepository; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.bid.application.dto.BidDto; import com.ddang.ddang.bid.application.dto.CreateBidDto; import com.ddang.ddang.bid.application.dto.ReadBidDto; @@ -17,24 +18,22 @@ import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.time.LocalDateTime; -import java.util.List; -import java.util.Optional; - @Service @Transactional(readOnly = true) @RequiredArgsConstructor -@Slf4j public class BidService { private final ApplicationEventPublisher bidEventPublisher; - private final JpaAuctionRepository auctionRepository; + private final AuctionRepository auctionRepository; + private final AuctionAndImageRepository auctionAndImageRepository; private final JpaUserRepository userRepository; private final JpaBidRepository bidRepository; @@ -43,8 +42,8 @@ public Long create(final CreateBidDto bidDto, final String auctionImageAbsoluteU final User bidder = userRepository.findById(bidDto.userId()) .orElseThrow(() -> new UserNotFoundException("해당 사용자를 찾을 수 없습니다.")); final AuctionAndImageDto auctionAndImageDto = - auctionRepository.findDtoByAuctionId(bidDto.auctionId()) - .orElseThrow(() -> new AuctionNotFoundException("해당 경매를 찾을 수 없습니다.")); + auctionAndImageRepository.findDtoByAuctionId(bidDto.auctionId()) + .orElseThrow(() -> new AuctionNotFoundException("해당 경매를 찾을 수 없습니다.")); final Auction auction = auctionAndImageDto.auction(); checkInvalidAuction(auction); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/bid/application/dto/BidDto.java b/backend/ddang/src/main/java/com/ddang/ddang/bid/application/dto/BidDto.java index 8787a5cf4..6be141e5a 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/bid/application/dto/BidDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/bid/application/dto/BidDto.java @@ -1,6 +1,6 @@ package com.ddang.ddang.bid.application.dto; -import com.ddang.ddang.auction.infrastructure.persistence.dto.AuctionAndImageDto; +import com.ddang.ddang.auction.domain.dto.AuctionAndImageDto; public record BidDto( Long previousBidderId, diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java index 168736232..db764208d 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java @@ -4,7 +4,7 @@ import com.ddang.ddang.auction.application.exception.AuctionNotFoundException; import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.domain.exception.WinnerNotFoundException; -import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.authentication.domain.dto.AuthenticationUserInfo; import com.ddang.ddang.chat.application.dto.CreateChatRoomDto; import com.ddang.ddang.chat.application.dto.ReadChatRoomWithLastMessageDto; @@ -21,13 +21,12 @@ import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import java.time.LocalDateTime; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.time.LocalDateTime; -import java.util.List; - @Service @Transactional(readOnly = true) @RequiredArgsConstructor @@ -39,7 +38,7 @@ public class ChatRoomService { private final QuerydslChatRoomAndImageRepositoryImpl querydslChatRoomAndImageRepository; private final QuerydslChatRoomAndMessageAndImageRepository querydslChatRoomAndMessageAndImageRepository; private final JpaUserRepository userRepository; - private final JpaAuctionRepository auctionRepository; + private final AuctionRepository auctionRepository; @Transactional public Long create(final Long userId, final CreateChatRoomDto chatRoomDto) { diff --git a/backend/ddang/src/main/java/com/ddang/ddang/configuration/initialization/InitializationAuctionConfiguration.java b/backend/ddang/src/main/java/com/ddang/ddang/configuration/initialization/InitializationAuctionConfiguration.java deleted file mode 100644 index bb741693e..000000000 --- a/backend/ddang/src/main/java/com/ddang/ddang/configuration/initialization/InitializationAuctionConfiguration.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.ddang.ddang.configuration.initialization; - -import com.ddang.ddang.auction.domain.Auction; -import com.ddang.ddang.auction.domain.BidUnit; -import com.ddang.ddang.auction.domain.Price; -import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; -import com.ddang.ddang.category.domain.Category; -import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; -import com.ddang.ddang.region.domain.AuctionRegion; -import com.ddang.ddang.region.domain.Region; -import com.ddang.ddang.region.infrastructure.persistence.JpaRegionRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.boot.ApplicationArguments; -import org.springframework.boot.ApplicationRunner; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Configuration; -import org.springframework.transaction.annotation.Transactional; - -import java.time.LocalDateTime; -import java.util.List; - -@Configuration -@ConditionalOnProperty(name = "data.init.auction.enabled", havingValue = "true") -@RequiredArgsConstructor -public class InitializationAuctionConfiguration implements ApplicationRunner { - - private final JpaAuctionRepository auctionRepository; - private final JpaRegionRepository regionRepository; - private final JpaCategoryRepository categoryRepository; - - @Override - @Transactional - public void run(final ApplicationArguments args) { - final Region firstRegion = regionRepository.findById(1L).get(); - final Region secondRegion = regionRepository.findById(2L).get(); - final Region thirdRegion = regionRepository.findById(3L).get(); - - secondRegion.addThirdRegion(thirdRegion); - firstRegion.addSecondRegion(secondRegion); - - final AuctionRegion auctionRegion1 = new AuctionRegion(thirdRegion); - final AuctionRegion auctionRegion2 = new AuctionRegion(thirdRegion); - - final Category main = new Category("전자기기"); - final Category sub = new Category("노트북"); - - main.addSubCategory(sub); - - categoryRepository.save(main); - - final Auction auction1 = Auction.builder() - .title("맥북 2021 13인치") - .description("맥북 2021 13인치 팝니다. 애플 감성 안 맞아요.") - .bidUnit(new BidUnit(1_000)) - .startPrice(new Price(1_000_000)) - .closingTime(LocalDateTime.now()) - .build(); - auction1.addAuctionRegions(List.of(auctionRegion1)); - - final Auction auction2 = Auction.builder() - .title("맥북 16인치") - .description("맥북 2019 16인치 팝니다. 급전이 필요해요...") - .bidUnit(new BidUnit(3_000)) - .startPrice(new Price(900_000)) - .closingTime(LocalDateTime.now() - .plusDays(5L)) - .build(); - auction2.addAuctionRegions(List.of(auctionRegion2)); - - auctionRepository.save(auction1); - auctionRepository.save(auction2); - } -} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java index 40a0fd656..611047750 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java @@ -3,7 +3,7 @@ import com.ddang.ddang.auction.application.exception.AuctionNotFoundException; import com.ddang.ddang.auction.application.exception.UserForbiddenException; import com.ddang.ddang.auction.domain.Auction; -import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.qna.application.dto.CreateQuestionDto; import com.ddang.ddang.qna.application.dto.ReadQnasDto; import com.ddang.ddang.qna.application.event.QuestionNotificationEvent; @@ -15,21 +15,20 @@ import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import java.time.LocalDateTime; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.time.LocalDateTime; -import java.util.List; - @Service @Transactional(readOnly = true) @RequiredArgsConstructor public class QuestionService { private final ApplicationEventPublisher questionEventPublisher; - private final JpaAuctionRepository auctionRepository; + private final AuctionRepository auctionRepository; private final JpaUserRepository userRepository; private final JpaQuestionRepository questionRepository; diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/application/AuctionReportService.java b/backend/ddang/src/main/java/com/ddang/ddang/report/application/AuctionReportService.java index d38c222f1..2c459c74d 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/report/application/AuctionReportService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/application/AuctionReportService.java @@ -2,29 +2,27 @@ import com.ddang.ddang.auction.application.exception.AuctionNotFoundException; import com.ddang.ddang.auction.domain.Auction; -import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.report.application.dto.CreateAuctionReportDto; import com.ddang.ddang.report.application.dto.ReadAuctionReportDto; import com.ddang.ddang.report.application.exception.AlreadyReportAuctionException; -import com.ddang.ddang.report.application.exception.InvalidReportAuctionException; import com.ddang.ddang.report.application.exception.InvalidReporterToAuctionException; import com.ddang.ddang.report.domain.AuctionReport; import com.ddang.ddang.report.infrastructure.persistence.JpaAuctionReportRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; - @Service @Transactional(readOnly = true) @RequiredArgsConstructor public class AuctionReportService { - private final JpaAuctionRepository auctionRepository; + private final AuctionRepository auctionRepository; private final JpaUserRepository userRepository; private final JpaAuctionReportRepository auctionReportRepository; @@ -32,7 +30,7 @@ public class AuctionReportService { public Long create(final CreateAuctionReportDto auctionReportDto) { final User reporter = userRepository.findById(auctionReportDto.reporterId()) .orElseThrow(() -> new UserNotFoundException("해당 사용자를 찾을 수 없습니다.")); - final Auction auction = auctionRepository.findById(auctionReportDto.auctionId()) + final Auction auction = auctionRepository.findTotalAuctionById(auctionReportDto.auctionId()) .orElseThrow(() -> new AuctionNotFoundException("해당 경매를 찾을 수 없습니다.")); checkInvalidAuctionReport(reporter, auction); @@ -46,9 +44,6 @@ private void checkInvalidAuctionReport(final User reporter, final Auction auctio if (auction.isOwner(reporter)) { throw new InvalidReporterToAuctionException("본인 경매글입니다."); } - if (auction.isDeleted()) { - throw new InvalidReportAuctionException("이미 삭제된 경매입니다."); - } if (auctionReportRepository.existsByAuctionIdAndReporterId(auction.getId(), reporter.getId())) { throw new AlreadyReportAuctionException("이미 신고한 경매입니다."); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/review/application/ReviewService.java b/backend/ddang/src/main/java/com/ddang/ddang/review/application/ReviewService.java index 7922b15e5..73a686dd9 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/review/application/ReviewService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/review/application/ReviewService.java @@ -2,7 +2,7 @@ import com.ddang.ddang.auction.application.exception.AuctionNotFoundException; import com.ddang.ddang.auction.domain.Auction; -import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.review.application.dto.CreateReviewDto; import com.ddang.ddang.review.application.dto.ReadReviewDetailDto; import com.ddang.ddang.review.application.dto.ReadReviewDto; @@ -14,25 +14,24 @@ import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import java.time.LocalDateTime; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.time.LocalDateTime; -import java.util.List; - @Service @Transactional(readOnly = true) @RequiredArgsConstructor public class ReviewService { private final JpaReviewRepository reviewRepository; - private final JpaAuctionRepository auctionRepository; + private final AuctionRepository auctionRepository; private final JpaUserRepository userRepository; @Transactional public Long create(final CreateReviewDto reviewDto) { - final Auction findAuction = auctionRepository.findById(reviewDto.auctionId()) + final Auction findAuction = auctionRepository.findTotalAuctionById(reviewDto.auctionId()) .orElseThrow(() -> new AuctionNotFoundException("해당 경매를 찾을 수 없습니다.") ); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/application/fixture/AuctionServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/application/fixture/AuctionServiceFixture.java index d0324cc7a..997f4fd45 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/application/fixture/AuctionServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/application/fixture/AuctionServiceFixture.java @@ -2,7 +2,7 @@ import com.ddang.ddang.auction.application.dto.CreateAuctionDto; import com.ddang.ddang.auction.domain.Auction; -import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.bid.domain.Bid; import com.ddang.ddang.bid.domain.BidPrice; import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; @@ -16,19 +16,18 @@ import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import java.time.LocalDateTime; +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.mock.web.MockMultipartFile; -import java.time.LocalDateTime; -import java.util.List; - @SuppressWarnings("NonAsciiCharacters") public class AuctionServiceFixture { @Autowired - private JpaAuctionRepository auctionRepository; + private AuctionRepository auctionRepository; @Autowired private JpaRegionRepository regionRepository; @@ -222,6 +221,10 @@ void setUp() { 구매자가_입찰한_경매2.addAuctionRegions(List.of(new AuctionRegion(역삼동))); 종료되는_날이_3일_뒤인_경매.addAuctionRegions(List.of(new AuctionRegion(역삼동))); 종료된_경매.addAuctionRegions(List.of(new AuctionRegion(역삼동))); - auctionRepository.saveAll(List.of(구매자가_입찰한_경매1, 구매자가_입찰한_경매2, 종료되는_날이_3일_뒤인_경매, 종료된_경매)); + + auctionRepository.save(구매자가_입찰한_경매1); + auctionRepository.save(구매자가_입찰한_경매2); + auctionRepository.save(종료되는_날이_3일_뒤인_경매); + auctionRepository.save(종료된_경매); } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionRepositoryImplTest.java new file mode 100644 index 000000000..0486386bd --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionRepositoryImplTest.java @@ -0,0 +1,172 @@ +package com.ddang.ddang.auction.infrastructure.persistence; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.AuctionRepositoryImplFixture; +import com.ddang.ddang.configuration.JpaConfiguration; +import com.ddang.ddang.configuration.QuerydslConfiguration; +import com.querydsl.jpa.impl.JPAQueryFactory; +import java.util.Optional; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Slice; + +@DataJpaTest +@Import({JpaConfiguration.class, QuerydslConfiguration.class}) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class AuctionRepositoryImplTest extends AuctionRepositoryImplFixture { + + @Autowired + JpaAuctionRepository jpaAuctionRepository; + + @Autowired + JPAQueryFactory queryFactory; + + AuctionRepository auctionRepository; + + @BeforeEach + void setUp() { + auctionRepository = new AuctionRepositoryImpl( + jpaAuctionRepository, + new QuerydslAuctionRepository(queryFactory) + ); + } + + @Test + void 경매를_저장한다() { + // when + final Auction actual = auctionRepository.save(저장하기_전_경매_엔티티); + + // then + assertThat(actual.getId()).isPositive(); + } + + @Test + void 지정한_id의_경매가_존재하는_경우_true를_반환한다() { + // when + final boolean actual = auctionRepository.existsById(저장된_경매_엔티티.getId()); + + // then + assertThat(actual).isTrue(); + } + + @Test + void 지정한_id의_경매가_존재하지_않는_경우_false를_반환한다() { + // when + final boolean actual = auctionRepository.existsById(존재하지_않는_경매_id); + + // then + assertThat(actual).isFalse(); + } + + @Test + void 지정한_아이디에_대한_경매와_관련된_데이터를_모두_조회한다() { + // when + final Optional actual = auctionRepository.findTotalAuctionById(저장된_경매_엔티티.getId()); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).isPresent(); + softAssertions.assertThat(actual.get().getId()).isEqualTo(저장된_경매_엔티티.getId()); + softAssertions.assertThat(actual.get().getTitle()).isEqualTo(저장된_경매_엔티티.getTitle()); + softAssertions.assertThat(actual.get().getDescription()).isEqualTo(저장된_경매_엔티티.getDescription()); + softAssertions.assertThat(actual.get().getBidUnit()).isEqualTo(저장된_경매_엔티티.getBidUnit()); + softAssertions.assertThat(actual.get().getStartPrice()).isEqualTo(저장된_경매_엔티티.getStartPrice()); + softAssertions.assertThat(actual.get().getClosingTime()).isEqualTo(저장된_경매_엔티티.getClosingTime()); + softAssertions.assertThat(actual.get().getAuctionRegions()).isNotNull(); + softAssertions.assertThat(actual.get().getAuctionRegions().get(0)).isNotNull(); + softAssertions.assertThat(actual.get().getAuctionRegions().get(0).getThirdRegion()).isNotNull(); + softAssertions.assertThat(actual.get().getAuctionRegions().get(0).getThirdRegion().getFirstRegion()) + .isNotNull(); + softAssertions.assertThat(actual.get().getAuctionRegions().get(0).getThirdRegion().getSecondRegion()) + .isNotNull(); + softAssertions.assertThat(actual.get().getSubCategory()).isNotNull(); + softAssertions.assertThat(actual.get().getSubCategory().getMainCategory()).isNotNull(); + softAssertions.assertThat(actual.get().getSeller()).isNotNull(); + }); + } + + @Test + void 지정한_아이디에_대한_경매를_조회한다() { + // when + final Optional actual = auctionRepository.findPureAuctionById(저장된_경매_엔티티.getId()); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).isPresent(); + softAssertions.assertThat(actual.get().getId()).isEqualTo(저장된_경매_엔티티.getId()); + softAssertions.assertThat(actual.get().getTitle()).isEqualTo(저장된_경매_엔티티.getTitle()); + softAssertions.assertThat(actual.get().getDescription()).isEqualTo(저장된_경매_엔티티.getDescription()); + softAssertions.assertThat(actual.get().getBidUnit()).isEqualTo(저장된_경매_엔티티.getBidUnit()); + softAssertions.assertThat(actual.get().getStartPrice()).isEqualTo(저장된_경매_엔티티.getStartPrice()); + softAssertions.assertThat(actual.get().getClosingTime()).isEqualTo(저장된_경매_엔티티.getClosingTime()); + }); + } + + @Test + void 삭제된_아이디에_대한_경매_조회시_빈_optional을_반환한다() { + // when + final Optional actual = auctionRepository.findTotalAuctionById(삭제된_경매_엔티티.getId()); + + // then + assertThat(actual).isEmpty(); + } + + @Test + void 경매_목록을_조회한다() { + // when + final Slice actual = auctionRepository.findAuctionsAllByCondition( + 검색어_없음, + PageRequest.of(페이지_1, 페이지_크기) + ); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + assertThat(actual).hasSize(1); + assertThat(actual.getContent().get(0)).isEqualTo(저장된_경매_엔티티); + assertThat(actual.hasNext()).isFalse(); + }); + } + + @Test + void 사용자가_등록한_경매_목록을_조회한다() { + // when + final Slice actual = auctionRepository.findAuctionsAllByUserId( + 판매자.getId(), + PageRequest.of(페이지_1, 페이지_크기) + ); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + assertThat(actual).hasSize(1); + assertThat(actual.getContent().get(0)).isEqualTo(저장된_경매_엔티티); + assertThat(actual.hasNext()).isFalse(); + }); + } + + @Test + void 사용자가_입찰한_경매_목록을_조회한다() { + // when + final Slice actual = auctionRepository.findAuctionsAllByBidderId( + 구매자.getId(), + PageRequest.of(페이지_1, 페이지_크기) + ); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + assertThat(actual).hasSize(1); + assertThat(actual.getContent().get(0)).isEqualTo(저장된_경매_엔티티); + assertThat(actual.hasNext()).isFalse(); + }); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepositoryTest.java index b2909978a..d8b992ae6 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepositoryTest.java @@ -32,6 +32,24 @@ class JpaAuctionRepositoryTest extends JpaAuctionRepositoryFixture { assertThat(actual.getId()).isPositive(); } + @Test + void 지정한_id의_경매가_존재하는_경우_true를_반환한다() { + // when + final boolean actual = auctionRepository.existsById(저장된_경매_엔티티.getId()); + + // then + assertThat(actual).isTrue(); + } + + @Test + void 지정한_id의_경매가_존재하지_않는_경우_false를_반환한다() { + // when + final boolean actual = auctionRepository.existsById(존재하지_않는_경매_id); + + // then + assertThat(actual).isFalse(); + } + @Test void 지정한_아이디에_대한_경매와_관련된_데이터를_모두_조회한다() { // when diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionAndImageRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionAndImageRepositoryTest.java similarity index 65% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionAndImageRepositoryImplTest.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionAndImageRepositoryTest.java index 43d57c08e..7ac95a9b1 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionAndImageRepositoryImplTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionAndImageRepositoryTest.java @@ -1,11 +1,13 @@ package com.ddang.ddang.auction.infrastructure.persistence; -import com.ddang.ddang.auction.infrastructure.persistence.dto.AuctionAndImageDto; -import com.ddang.ddang.auction.infrastructure.persistence.fixture.QuerydslAuctionAndImageRepositoryImplFixture; +import com.ddang.ddang.auction.domain.dto.AuctionAndImageDto; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.QuerydslAuctionAndImageRepositoryFixture; import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; +import com.querydsl.jpa.impl.JPAQueryFactory; import java.util.Optional; import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; @@ -17,15 +19,19 @@ @Import({JpaConfiguration.class, QuerydslConfiguration.class}) @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @SuppressWarnings("NonAsciiCharacters") -class QuerydslAuctionAndImageRepositoryImplTest extends QuerydslAuctionAndImageRepositoryImplFixture { +class QuerydslAuctionAndImageRepositoryTest extends QuerydslAuctionAndImageRepositoryFixture { - @Autowired - JpaAuctionRepository auctionRepository; + QuerydslAuctionAndImageRepository querydslAuctionAndImageRepository; + + @BeforeEach + void setUp(@Autowired JPAQueryFactory queryFactory) { + querydslAuctionAndImageRepository = new QuerydslAuctionAndImageRepository(queryFactory); + } @Test void 경매와_경매_대표이미지를_조회한다() { // when - final Optional actual = auctionRepository.findDtoByAuctionId(경매.getId()); + final Optional actual = querydslAuctionAndImageRepository.findDtoByAuctionId(경매.getId()); // then SoftAssertions.assertSoftly(softAssertions -> { diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java new file mode 100644 index 000000000..786add227 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java @@ -0,0 +1,157 @@ +package com.ddang.ddang.auction.infrastructure.persistence.fixture; + +import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.domain.BidUnit; +import com.ddang.ddang.auction.domain.Price; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.AuctionRepositoryImpl; +import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.auction.presentation.dto.request.ReadAuctionSearchCondition; +import com.ddang.ddang.bid.domain.Bid; +import com.ddang.ddang.bid.domain.BidPrice; +import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; +import com.ddang.ddang.category.domain.Category; +import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.region.domain.AuctionRegion; +import com.ddang.ddang.region.domain.Region; +import com.ddang.ddang.region.infrastructure.persistence.JpaRegionRepository; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.querydsl.jpa.impl.JPAQueryFactory; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +@SuppressWarnings("NonAsciiCharacters") +public class AuctionRepositoryImplFixture { + + @Autowired + private JpaAuctionRepository jpaAuctionRepository; + + @Autowired + private JPAQueryFactory queryFactory; + + @Autowired + private JpaUserRepository userRepository; + + @Autowired + private JpaRegionRepository regionRepository; + + @Autowired + private JpaCategoryRepository categoryRepository; + + @Autowired + private JpaBidRepository bidRepository; + + private Instant 시간 = Instant.parse("2023-07-08T22:21:20Z"); + private ZoneId 위치 = ZoneId.of("UTC"); + + protected Long 존재하지_않는_경매_id = -999L; + protected ReadAuctionSearchCondition 검색어_없음 = new ReadAuctionSearchCondition(null); + protected int 페이지_1 = 0; + protected int 페이지_크기 = 3; + protected Auction 저장하기_전_경매_엔티티 = Auction.builder() + .title("제목") + .description("내용") + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(LocalDateTime.now()) + .build(); + protected Auction 저장된_경매_엔티티; + protected Auction 삭제된_경매_엔티티; + protected User 판매자; + protected User 구매자; + + @BeforeEach + void fixtureSetUp() { + final Region 서울특별시 = new Region("서울특별시"); + final Region 강남구 = new Region("강남구"); + final Region 역삼동 = new Region("역삼동"); + + 서울특별시.addSecondRegion(강남구); + 강남구.addThirdRegion(역삼동); + + regionRepository.save(서울특별시); + + final Category 가구_카테고리 = new Category("가구"); + final Category 가구_서브_의자_카테고리 = new Category("의자"); + + 가구_카테고리.addSubCategory(가구_서브_의자_카테고리); + + categoryRepository.save(가구_카테고리); + + 판매자 = User.builder() + .name("판매자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); + + 구매자 = User.builder() + .name("구매자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(2.7d)) + .oauthId("54321") + .build(); + + userRepository.save(판매자); + userRepository.save(구매자); + + 저장된_경매_엔티티 = Auction.builder() + .title("경매 상품 1") + .description("이것은 경매 상품 1 입니다.") + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(시간.atZone(위치).toLocalDateTime()) + .subCategory(가구_서브_의자_카테고리) + .seller(판매자) + .build(); + 삭제된_경매_엔티티 = Auction.builder() + .title("경매 상품 1") + .description("이것은 경매 상품 1 입니다.") + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(시간.atZone(위치).toLocalDateTime()) + .subCategory(가구_서브_의자_카테고리) + .seller(판매자) + .build(); + + 삭제된_경매_엔티티.addAuctionRegions(List.of(new AuctionRegion(역삼동))); + 저장된_경매_엔티티.addAuctionRegions(List.of(new AuctionRegion(역삼동))); + 삭제된_경매_엔티티.delete(); + bidding(저장된_경매_엔티티, 구매자); + addAuctioneerCount(저장된_경매_엔티티, 1); + + final AuctionRepository auctionRepository = new AuctionRepositoryImpl( + jpaAuctionRepository, + new QuerydslAuctionRepository(queryFactory) + ); + + auctionRepository.save(삭제된_경매_엔티티); + auctionRepository.save(저장된_경매_엔티티); + } + + private void bidding(final Auction targetAuction, final User bidder) { + final Bid lastBid = new Bid(targetAuction, bidder, new BidPrice(1)); + + bidRepository.save(lastBid); + + targetAuction.updateLastBid(lastBid); + } + + private void addAuctioneerCount(final Auction targetAuction, final int count) { + final Bid lastBid = new Bid(targetAuction, targetAuction.getSeller(), new BidPrice(1)); + + bidRepository.save(lastBid); + + for (int i = 0; i < count; i++) { + targetAuction.updateLastBid(lastBid); + } + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/JpaAuctionRepositoryFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/JpaAuctionRepositoryFixture.java index 2dacef8da..5505f822e 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/JpaAuctionRepositoryFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/JpaAuctionRepositoryFixture.java @@ -44,6 +44,7 @@ public class JpaAuctionRepositoryFixture { private Instant 시간 = Instant.parse("2023-07-08T22:21:20Z"); private ZoneId 위치 = ZoneId.of("UTC"); + protected Long 존재하지_않는_경매_id = -999L; protected Auction 저장하기_전_경매_엔티티 = Auction.builder() .title("제목") .description("내용") diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionAndImageRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionAndImageRepositoryFixture.java similarity index 77% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionAndImageRepositoryImplFixture.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionAndImageRepositoryFixture.java index 485cbfeaa..170011312 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionAndImageRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionAndImageRepositoryFixture.java @@ -3,29 +3,35 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.AuctionRepositoryImpl; import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; import com.ddang.ddang.image.domain.AuctionImage; import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.image.infrastructure.persistence.JpaAuctionImageRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; - import java.time.LocalDateTime; import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; @SuppressWarnings("NonAsciiCharacters") -public class QuerydslAuctionAndImageRepositoryImplFixture { +public class QuerydslAuctionAndImageRepositoryFixture { @PersistenceContext private EntityManager em; @Autowired - private JpaAuctionRepository auctionRepository; + private JPAQueryFactory queryFactory; + + @Autowired + private JpaAuctionRepository jpaAuctionRepository; @Autowired private JpaAuctionImageRepository auctionImageRepository; @@ -57,6 +63,10 @@ void setUp() { .oauthId("12345") .build(); + final AuctionRepository auctionRepository = new AuctionRepositoryImpl( + jpaAuctionRepository, + new QuerydslAuctionRepository(queryFactory) + ); auctionRepository.save(경매); userRepository.save(사용자); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionRepositoryImplForListFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionRepositoryForListFixture.java similarity index 91% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionRepositoryImplForListFixture.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionRepositoryForListFixture.java index 2ec2f0507..05333d2a1 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionRepositoryImplForListFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionRepositoryForListFixture.java @@ -3,7 +3,10 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.AuctionRepositoryImpl; import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; import com.ddang.ddang.bid.domain.Bid; import com.ddang.ddang.bid.domain.BidPrice; import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; @@ -13,25 +16,28 @@ import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; - import java.time.LocalDateTime; import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; @SuppressWarnings("NonAsciiCharacters") -public class QuerydslAuctionRepositoryImplForListFixture { +public class QuerydslAuctionRepositoryForListFixture { @PersistenceContext private EntityManager em; @Autowired - private JpaUserRepository userRepository; + private JPAQueryFactory queryFactory; @Autowired - private JpaAuctionRepository auctionRepository; + private JpaAuctionRepository jpaAuctionRepository; + + @Autowired + private JpaUserRepository userRepository; @Autowired private JpaCategoryRepository categoryRepository; @@ -289,25 +295,27 @@ void commonFixtureSetUp() { .build(); addAuctioneerCount(경매15, 6); - final List 경매들 = List.of( - 경매1, - 경매2, - 경매3, - 경매4, - 경매5, - 경매6, - 경매7, - 경매8, - 경매9, - 경매10, - 경매11, - 경매12, - 경매13, - 경매14, - 경매15, - 경매16 + final AuctionRepository auctionRepository = new AuctionRepositoryImpl( + jpaAuctionRepository, + new QuerydslAuctionRepository(queryFactory) ); - auctionRepository.saveAll(경매들); + + auctionRepository.save(경매1); + auctionRepository.save(경매2); + auctionRepository.save(경매3); + auctionRepository.save(경매4); + auctionRepository.save(경매5); + auctionRepository.save(경매6); + auctionRepository.save(경매7); + auctionRepository.save(경매8); + auctionRepository.save(경매9); + auctionRepository.save(경매10); + auctionRepository.save(경매11); + auctionRepository.save(경매12); + auctionRepository.save(경매13); + auctionRepository.save(경매14); + auctionRepository.save(경매15); + auctionRepository.save(경매16); em.flush(); em.clear(); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionRepositoryImplForObjectFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionRepositoryForObjectFixture.java similarity index 77% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionRepositoryImplForObjectFixture.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionRepositoryForObjectFixture.java index 617113574..0869c08c7 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionRepositoryImplForObjectFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionRepositoryForObjectFixture.java @@ -3,7 +3,10 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.AuctionRepositoryImpl; import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; import com.ddang.ddang.category.domain.Category; import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; import com.ddang.ddang.image.domain.ProfileImage; @@ -13,33 +16,35 @@ import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; - import java.time.LocalDateTime; import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; @SuppressWarnings("NonAsciiCharacters") -public class QuerydslAuctionRepositoryImplForObjectFixture { +public class QuerydslAuctionRepositoryForObjectFixture { @PersistenceContext - EntityManager em; + private EntityManager em; + + @Autowired + private JPAQueryFactory queryFactory; @Autowired - JpaUserRepository userRepository; + private JpaAuctionRepository jpaAuctionRepository; @Autowired - JpaAuctionRepository auctionRepository; + private JpaUserRepository userRepository; @Autowired - JpaRegionRepository regionRepository; + private JpaRegionRepository regionRepository; @Autowired - JpaCategoryRepository categoryRepository; + private JpaCategoryRepository categoryRepository; - protected Long 존재하지_않는_경매 = -999L; protected Auction 경매; protected Region 서울특별시; protected Region 강남구; @@ -87,6 +92,13 @@ void totalFixtureSetUp() { 경매.addAuctionRegions(List.of(직거래_지역)); + final AuctionRepository auctionRepository = new AuctionRepositoryImpl( + jpaAuctionRepository, + new QuerydslAuctionRepository(queryFactory) + ); auctionRepository.save(경매); + + em.flush(); + em.clear(); } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListByBidderIdFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListByBidderIdFixture.java similarity index 90% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListByBidderIdFixture.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListByBidderIdFixture.java index 4d0b1f940..6cf82c487 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListByBidderIdFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListByBidderIdFixture.java @@ -1,11 +1,12 @@ -package com.ddang.ddang.auction.infrastructure.persistence.fixture; +package com.ddang.ddang.auction.infrastructure.persistence.fixture.list; import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.QuerydslAuctionRepositoryForListFixture; import com.ddang.ddang.user.domain.User; import org.junit.jupiter.api.BeforeEach; @SuppressWarnings("NonAsciiCharacters") -public class AuctionForListByBidderIdFixture extends QuerydslAuctionRepositoryImplForListFixture { +public class AuctionForListByBidderIdFixture extends QuerydslAuctionRepositoryForListFixture { protected User 참여한_경매가_7개인_사용자; protected Auction 첫번째_페이지_인덱스_0; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListByUserIdFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListByUserIdFixture.java similarity index 88% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListByUserIdFixture.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListByUserIdFixture.java index 57cef12fa..3db8a307c 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListByUserIdFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListByUserIdFixture.java @@ -1,11 +1,12 @@ -package com.ddang.ddang.auction.infrastructure.persistence.fixture; +package com.ddang.ddang.auction.infrastructure.persistence.fixture.list; import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.QuerydslAuctionRepositoryForListFixture; import com.ddang.ddang.user.domain.User; import org.junit.jupiter.api.BeforeEach; @SuppressWarnings("NonAsciiCharacters") -public class AuctionForListByUserIdFixture extends QuerydslAuctionRepositoryImplForListFixture { +public class AuctionForListByUserIdFixture extends QuerydslAuctionRepositoryForListFixture { protected User 등록한_경매가_5개인_사용자; protected Auction 첫번째_페이지_인덱스_0; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleAndSortByAuctioneerCountFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSearchByTitleAndSortByAuctioneerCountFixture.java similarity index 94% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleAndSortByAuctioneerCountFixture.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSearchByTitleAndSortByAuctioneerCountFixture.java index 8d5a0f148..98982d5f4 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleAndSortByAuctioneerCountFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSearchByTitleAndSortByAuctioneerCountFixture.java @@ -1,13 +1,15 @@ -package com.ddang.ddang.auction.infrastructure.persistence.fixture; +package com.ddang.ddang.auction.infrastructure.persistence.fixture.list; import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.QuerydslAuctionRepositoryForListFixture; import com.ddang.ddang.auction.presentation.dto.request.ReadAuctionSearchCondition; import org.junit.jupiter.api.BeforeEach; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Order; @SuppressWarnings("NonAsciiCharacters") -public class AuctionForListSearchByTitleAndSortByAuctioneerCountFixture extends QuerydslAuctionRepositoryImplForListFixture { +public class AuctionForListSearchByTitleAndSortByAuctioneerCountFixture extends + QuerydslAuctionRepositoryForListFixture { protected Sort 참여_인원순_정렬 = Sort.by(Order.asc("auctioneerCount")); protected ReadAuctionSearchCondition 검색어_맥북 = new ReadAuctionSearchCondition("맥북"); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleAndSortByClosingTimeFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSearchByTitleAndSortByClosingTimeFixture.java similarity index 94% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleAndSortByClosingTimeFixture.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSearchByTitleAndSortByClosingTimeFixture.java index b11603ab9..56df73783 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleAndSortByClosingTimeFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSearchByTitleAndSortByClosingTimeFixture.java @@ -1,13 +1,14 @@ -package com.ddang.ddang.auction.infrastructure.persistence.fixture; +package com.ddang.ddang.auction.infrastructure.persistence.fixture.list; import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.QuerydslAuctionRepositoryForListFixture; import com.ddang.ddang.auction.presentation.dto.request.ReadAuctionSearchCondition; import org.junit.jupiter.api.BeforeEach; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Order; @SuppressWarnings("NonAsciiCharacters") -public class AuctionForListSearchByTitleAndSortByClosingTimeFixture extends QuerydslAuctionRepositoryImplForListFixture { +public class AuctionForListSearchByTitleAndSortByClosingTimeFixture extends QuerydslAuctionRepositoryForListFixture { protected Sort 마감_임박순_정렬 = Sort.by(Order.asc("closingTime")); protected ReadAuctionSearchCondition 검색어_맥북 = new ReadAuctionSearchCondition("맥북"); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleAndSortByIdFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSearchByTitleAndSortByIdFixture.java similarity index 94% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleAndSortByIdFixture.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSearchByTitleAndSortByIdFixture.java index e673e5016..6c7050bf6 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleAndSortByIdFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSearchByTitleAndSortByIdFixture.java @@ -1,13 +1,14 @@ -package com.ddang.ddang.auction.infrastructure.persistence.fixture; +package com.ddang.ddang.auction.infrastructure.persistence.fixture.list; import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.QuerydslAuctionRepositoryForListFixture; import com.ddang.ddang.auction.presentation.dto.request.ReadAuctionSearchCondition; import org.junit.jupiter.api.BeforeEach; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Order; @SuppressWarnings("NonAsciiCharacters") -public class AuctionForListSearchByTitleAndSortByIdFixture extends QuerydslAuctionRepositoryImplForListFixture { +public class AuctionForListSearchByTitleAndSortByIdFixture extends QuerydslAuctionRepositoryForListFixture { protected Sort id순_정렬 = Sort.by(Order.asc("id")); protected ReadAuctionSearchCondition 검색어_맥북 = new ReadAuctionSearchCondition("맥북"); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleAndSortByReliabilityFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSearchByTitleAndSortByReliabilityFixture.java similarity index 94% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleAndSortByReliabilityFixture.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSearchByTitleAndSortByReliabilityFixture.java index dfa71bef5..bf025b749 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleAndSortByReliabilityFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSearchByTitleAndSortByReliabilityFixture.java @@ -1,13 +1,14 @@ -package com.ddang.ddang.auction.infrastructure.persistence.fixture; +package com.ddang.ddang.auction.infrastructure.persistence.fixture.list; import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.QuerydslAuctionRepositoryForListFixture; import com.ddang.ddang.auction.presentation.dto.request.ReadAuctionSearchCondition; import org.junit.jupiter.api.BeforeEach; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Order; @SuppressWarnings("NonAsciiCharacters") -public class AuctionForListSearchByTitleAndSortByReliabilityFixture extends QuerydslAuctionRepositoryImplForListFixture { +public class AuctionForListSearchByTitleAndSortByReliabilityFixture extends QuerydslAuctionRepositoryForListFixture { protected Sort 신뢰도순_정렬 = Sort.by(Order.asc("reliability")); protected ReadAuctionSearchCondition 검색어_맥북 = new ReadAuctionSearchCondition("맥북"); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSearchByTitleFixture.java similarity index 95% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleFixture.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSearchByTitleFixture.java index 34a97da5b..ab03d1149 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSearchByTitleFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSearchByTitleFixture.java @@ -1,11 +1,12 @@ -package com.ddang.ddang.auction.infrastructure.persistence.fixture; +package com.ddang.ddang.auction.infrastructure.persistence.fixture.list; import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.QuerydslAuctionRepositoryForListFixture; import com.ddang.ddang.auction.presentation.dto.request.ReadAuctionSearchCondition; import org.junit.jupiter.api.BeforeEach; @SuppressWarnings("NonAsciiCharacters") -public class AuctionForListSearchByTitleFixture extends QuerydslAuctionRepositoryImplForListFixture { +public class AuctionForListSearchByTitleFixture extends QuerydslAuctionRepositoryForListFixture { protected ReadAuctionSearchCondition 검색어_맥북 = new ReadAuctionSearchCondition("맥북"); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSortByAuctioneerCountFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSortByAuctioneerCountFixture.java similarity index 95% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSortByAuctioneerCountFixture.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSortByAuctioneerCountFixture.java index 7d836df44..9a27dab2a 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSortByAuctioneerCountFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSortByAuctioneerCountFixture.java @@ -1,13 +1,14 @@ -package com.ddang.ddang.auction.infrastructure.persistence.fixture; +package com.ddang.ddang.auction.infrastructure.persistence.fixture.list; import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.QuerydslAuctionRepositoryForListFixture; import com.ddang.ddang.auction.presentation.dto.request.ReadAuctionSearchCondition; import org.junit.jupiter.api.BeforeEach; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Order; @SuppressWarnings("NonAsciiCharacters") -public class AuctionForListSortByAuctioneerCountFixture extends QuerydslAuctionRepositoryImplForListFixture { +public class AuctionForListSortByAuctioneerCountFixture extends QuerydslAuctionRepositoryForListFixture { protected Sort 참여_인원순_정렬 = Sort.by(Order.asc("auctioneerCount")); protected ReadAuctionSearchCondition 검색어_없음 = new ReadAuctionSearchCondition(null); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSortByClosingTimeFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSortByClosingTimeFixture.java similarity index 95% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSortByClosingTimeFixture.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSortByClosingTimeFixture.java index e7cb94697..09f4ed722 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSortByClosingTimeFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSortByClosingTimeFixture.java @@ -1,13 +1,14 @@ -package com.ddang.ddang.auction.infrastructure.persistence.fixture; +package com.ddang.ddang.auction.infrastructure.persistence.fixture.list; import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.QuerydslAuctionRepositoryForListFixture; import com.ddang.ddang.auction.presentation.dto.request.ReadAuctionSearchCondition; import org.junit.jupiter.api.BeforeEach; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Order; @SuppressWarnings("NonAsciiCharacters") -public class AuctionForListSortByClosingTimeFixture extends QuerydslAuctionRepositoryImplForListFixture { +public class AuctionForListSortByClosingTimeFixture extends QuerydslAuctionRepositoryForListFixture { protected Sort 마감_임박순_정렬 = Sort.by(Order.asc("closingTime")); protected ReadAuctionSearchCondition 검색어_없음 = new ReadAuctionSearchCondition(null); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSortByIdFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSortByIdFixture.java similarity index 95% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSortByIdFixture.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSortByIdFixture.java index 93c8137d0..289cc035d 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSortByIdFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSortByIdFixture.java @@ -1,13 +1,14 @@ -package com.ddang.ddang.auction.infrastructure.persistence.fixture; +package com.ddang.ddang.auction.infrastructure.persistence.fixture.list; import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.QuerydslAuctionRepositoryForListFixture; import com.ddang.ddang.auction.presentation.dto.request.ReadAuctionSearchCondition; import org.junit.jupiter.api.BeforeEach; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Order; @SuppressWarnings("NonAsciiCharacters") -public class AuctionForListSortByIdFixture extends QuerydslAuctionRepositoryImplForListFixture { +public class AuctionForListSortByIdFixture extends QuerydslAuctionRepositoryForListFixture { protected Sort id순_정렬 = Sort.by(Order.asc("id")); protected ReadAuctionSearchCondition 검색어_없음 = new ReadAuctionSearchCondition(null); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSortByReliabilityFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSortByReliabilityFixture.java similarity index 95% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSortByReliabilityFixture.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSortByReliabilityFixture.java index 45f0a9b7a..1e5678b6a 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionForListSortByReliabilityFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/list/AuctionForListSortByReliabilityFixture.java @@ -1,13 +1,14 @@ -package com.ddang.ddang.auction.infrastructure.persistence.fixture; +package com.ddang.ddang.auction.infrastructure.persistence.fixture.list; import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.QuerydslAuctionRepositoryForListFixture; import com.ddang.ddang.auction.presentation.dto.request.ReadAuctionSearchCondition; import org.junit.jupiter.api.BeforeEach; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Order; @SuppressWarnings("NonAsciiCharacters") -public class AuctionForListSortByReliabilityFixture extends QuerydslAuctionRepositoryImplForListFixture { +public class AuctionForListSortByReliabilityFixture extends QuerydslAuctionRepositoryForListFixture { protected Sort 신뢰도순_정렬 = Sort.by(Order.asc("reliability")); protected ReadAuctionSearchCondition 검색어_없음 = new ReadAuctionSearchCondition(null); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListByBidderIdTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListByBidderIdTest.java similarity index 96% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListByBidderIdTest.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListByBidderIdTest.java index 9ef4bdf99..90edc7aa5 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListByBidderIdTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListByBidderIdTest.java @@ -1,7 +1,8 @@ -package com.ddang.ddang.auction.infrastructure.persistence; +package com.ddang.ddang.auction.infrastructure.persistence.list; import com.ddang.ddang.auction.domain.Auction; -import com.ddang.ddang.auction.infrastructure.persistence.fixture.AuctionForListByBidderIdFixture; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.list.AuctionForListByBidderIdFixture; import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; import com.querydsl.jpa.impl.JPAQueryFactory; @@ -27,7 +28,7 @@ class AuctionForListByBidderIdTest extends AuctionForListByBidderIdFixture { @BeforeEach void setUp(@Autowired final JPAQueryFactory queryFactory) { - querydslAuctionRepository = new QuerydslAuctionRepositoryImpl(queryFactory); + querydslAuctionRepository = new QuerydslAuctionRepository(queryFactory); } @Nested diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListByUserIdTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListByUserIdTest.java similarity index 95% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListByUserIdTest.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListByUserIdTest.java index 5c200dc28..7d81822f7 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListByUserIdTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListByUserIdTest.java @@ -1,7 +1,8 @@ -package com.ddang.ddang.auction.infrastructure.persistence; +package com.ddang.ddang.auction.infrastructure.persistence.list; import com.ddang.ddang.auction.domain.Auction; -import com.ddang.ddang.auction.infrastructure.persistence.fixture.AuctionForListByUserIdFixture; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.list.AuctionForListByUserIdFixture; import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; import com.querydsl.jpa.impl.JPAQueryFactory; @@ -27,7 +28,7 @@ class AuctionForListByUserIdTest extends AuctionForListByUserIdFixture { @BeforeEach void setUp(@Autowired final JPAQueryFactory queryFactory) { - querydslAuctionRepository = new QuerydslAuctionRepositoryImpl(queryFactory); + querydslAuctionRepository = new QuerydslAuctionRepository(queryFactory); } @Nested diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleAndSortByAuctioneerCountTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSearchByTitleAndSortByAuctioneerCountTest.java similarity index 92% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleAndSortByAuctioneerCountTest.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSearchByTitleAndSortByAuctioneerCountTest.java index ebf8de098..17ea95c66 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleAndSortByAuctioneerCountTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSearchByTitleAndSortByAuctioneerCountTest.java @@ -1,7 +1,8 @@ -package com.ddang.ddang.auction.infrastructure.persistence; +package com.ddang.ddang.auction.infrastructure.persistence.list; import com.ddang.ddang.auction.domain.Auction; -import com.ddang.ddang.auction.infrastructure.persistence.fixture.AuctionForListSearchByTitleAndSortByAuctioneerCountFixture; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.list.AuctionForListSearchByTitleAndSortByAuctioneerCountFixture; import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; import com.querydsl.jpa.impl.JPAQueryFactory; @@ -26,15 +27,15 @@ class AuctionForListSearchByTitleAndSortByAuctioneerCountTest extends AuctionFor @BeforeEach void setUp(@Autowired final JPAQueryFactory queryFactory) { - querydslAuctionRepository = new QuerydslAuctionRepositoryImpl(queryFactory); + querydslAuctionRepository = new QuerydslAuctionRepository(queryFactory); } @Test void 첫번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(0, 페이지_크기_3, 참여_인원순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(0, 페이지_크기_3, 참여_인원순_정렬) ); // then @@ -51,8 +52,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 두번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(1, 페이지_크기_3, 참여_인원순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(1, 페이지_크기_3, 참여_인원순_정렬) ); // then @@ -69,8 +70,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 세번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(2, 페이지_크기_3, 참여_인원순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(2, 페이지_크기_3, 참여_인원순_정렬) ); // then @@ -87,8 +88,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 네번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(3, 페이지_크기_3, 참여_인원순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(3, 페이지_크기_3, 참여_인원순_정렬) ); // then @@ -105,8 +106,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 다섯번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(4, 페이지_크기_3, 참여_인원순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(4, 페이지_크기_3, 참여_인원순_정렬) ); SoftAssertions.assertSoftly(softAssertions -> { @@ -121,8 +122,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_여섯번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(5, 페이지_크기_3, 참여_인원순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(5, 페이지_크기_3, 참여_인원순_정렬) ); // then diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleAndSortByClosingTimeTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSearchByTitleAndSortByClosingTimeTest.java similarity index 91% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleAndSortByClosingTimeTest.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSearchByTitleAndSortByClosingTimeTest.java index 5c89f96a4..50380aff3 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleAndSortByClosingTimeTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSearchByTitleAndSortByClosingTimeTest.java @@ -1,7 +1,8 @@ -package com.ddang.ddang.auction.infrastructure.persistence; +package com.ddang.ddang.auction.infrastructure.persistence.list; import com.ddang.ddang.auction.domain.Auction; -import com.ddang.ddang.auction.infrastructure.persistence.fixture.AuctionForListSearchByTitleAndSortByClosingTimeFixture; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.list.AuctionForListSearchByTitleAndSortByClosingTimeFixture; import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; import com.querydsl.jpa.impl.JPAQueryFactory; @@ -26,15 +27,15 @@ class AuctionForListSearchByTitleAndSortByClosingTimeTest extends AuctionForList @BeforeEach void setUp(@Autowired final JPAQueryFactory queryFactory) { - querydslAuctionRepository = new QuerydslAuctionRepositoryImpl(queryFactory); + querydslAuctionRepository = new QuerydslAuctionRepository(queryFactory); } @Test void 첫번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(0, 페이지_크기_3, 마감_임박순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(0, 페이지_크기_3, 마감_임박순_정렬) ); // then @@ -51,8 +52,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 두번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(1, 페이지_크기_3, 마감_임박순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(1, 페이지_크기_3, 마감_임박순_정렬) ); // then @@ -69,8 +70,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 세번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(2, 페이지_크기_3, 마감_임박순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(2, 페이지_크기_3, 마감_임박순_정렬) ); // then @@ -87,8 +88,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 네번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(3, 페이지_크기_3, 마감_임박순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(3, 페이지_크기_3, 마감_임박순_정렬) ); // then @@ -105,8 +106,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 다섯번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(4, 페이지_크기_3, 마감_임박순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(4, 페이지_크기_3, 마감_임박순_정렬) ); SoftAssertions.assertSoftly(softAssertions -> { @@ -121,8 +122,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_여섯번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(5, 페이지_크기_3, 마감_임박순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(5, 페이지_크기_3, 마감_임박순_정렬) ); // then diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleAndSortByIdTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSearchByTitleAndSortByIdTest.java similarity index 93% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleAndSortByIdTest.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSearchByTitleAndSortByIdTest.java index da1762e59..24129045d 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleAndSortByIdTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSearchByTitleAndSortByIdTest.java @@ -1,7 +1,8 @@ -package com.ddang.ddang.auction.infrastructure.persistence; +package com.ddang.ddang.auction.infrastructure.persistence.list; import com.ddang.ddang.auction.domain.Auction; -import com.ddang.ddang.auction.infrastructure.persistence.fixture.AuctionForListSearchByTitleAndSortByIdFixture; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.list.AuctionForListSearchByTitleAndSortByIdFixture; import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; import com.querydsl.jpa.impl.JPAQueryFactory; @@ -26,15 +27,15 @@ class AuctionForListSearchByTitleAndSortByIdTest extends AuctionForListSearchByT @BeforeEach void setUp(@Autowired final JPAQueryFactory queryFactory) { - querydslAuctionRepository = new QuerydslAuctionRepositoryImpl(queryFactory); + querydslAuctionRepository = new QuerydslAuctionRepository(queryFactory); } @Test void 첫번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(0, 페이지_크기_3, id순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(0, 페이지_크기_3, id순_정렬) ); // then @@ -51,8 +52,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 두번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(1, 페이지_크기_3, id순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(1, 페이지_크기_3, id순_정렬) ); // then @@ -69,8 +70,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 세번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(2, 페이지_크기_3, id순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(2, 페이지_크기_3, id순_정렬) ); // then @@ -87,8 +88,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 네번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(3, 페이지_크기_3, id순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(3, 페이지_크기_3, id순_정렬) ); // then @@ -105,8 +106,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 다섯번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(4, 페이지_크기_3, id순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(4, 페이지_크기_3, id순_정렬) ); SoftAssertions.assertSoftly(softAssertions -> { @@ -121,8 +122,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_여섯번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(5, 페이지_크기_3, id순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(5, 페이지_크기_3, id순_정렬) ); // then diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleAndSortByReliabilityTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSearchByTitleAndSortByReliabilityTest.java similarity index 92% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleAndSortByReliabilityTest.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSearchByTitleAndSortByReliabilityTest.java index 573a53bd4..b3a8503cb 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleAndSortByReliabilityTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSearchByTitleAndSortByReliabilityTest.java @@ -1,7 +1,8 @@ -package com.ddang.ddang.auction.infrastructure.persistence; +package com.ddang.ddang.auction.infrastructure.persistence.list; import com.ddang.ddang.auction.domain.Auction; -import com.ddang.ddang.auction.infrastructure.persistence.fixture.AuctionForListSearchByTitleAndSortByReliabilityFixture; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.list.AuctionForListSearchByTitleAndSortByReliabilityFixture; import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; import com.querydsl.jpa.impl.JPAQueryFactory; @@ -26,15 +27,15 @@ class AuctionForListSearchByTitleAndSortByReliabilityTest extends AuctionForList @BeforeEach void setUp(@Autowired final JPAQueryFactory queryFactory) { - querydslAuctionRepository = new QuerydslAuctionRepositoryImpl(queryFactory); + querydslAuctionRepository = new QuerydslAuctionRepository(queryFactory); } @Test void 페이지_크기_3_첫번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(0, 페이지_크기_3, 신뢰도순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(0, 페이지_크기_3, 신뢰도순_정렬) ); // then @@ -51,8 +52,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_두번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(1, 페이지_크기_3, 신뢰도순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(1, 페이지_크기_3, 신뢰도순_정렬) ); // then @@ -69,8 +70,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_세번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(2, 페이지_크기_3, 신뢰도순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(2, 페이지_크기_3, 신뢰도순_정렬) ); // then @@ -87,8 +88,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_네번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(3, 페이지_크기_3, 신뢰도순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(3, 페이지_크기_3, 신뢰도순_정렬) ); // then @@ -105,8 +106,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_다섯번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(4, 페이지_크기_3, 신뢰도순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(4, 페이지_크기_3, 신뢰도순_정렬) ); SoftAssertions.assertSoftly(softAssertions -> { @@ -121,8 +122,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_여섯번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(5, 페이지_크기_3, 신뢰도순_정렬), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(5, 페이지_크기_3, 신뢰도순_정렬) ); // then diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSearchByTitleTest.java similarity index 88% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleTest.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSearchByTitleTest.java index 443353f7f..fb36cb88b 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSearchByTitleTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSearchByTitleTest.java @@ -1,7 +1,8 @@ -package com.ddang.ddang.auction.infrastructure.persistence; +package com.ddang.ddang.auction.infrastructure.persistence.list; import com.ddang.ddang.auction.domain.Auction; -import com.ddang.ddang.auction.infrastructure.persistence.fixture.AuctionForListSearchByTitleFixture; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.list.AuctionForListSearchByTitleFixture; import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; import com.querydsl.jpa.impl.JPAQueryFactory; @@ -27,7 +28,7 @@ class AuctionForListSearchByTitleTest extends AuctionForListSearchByTitleFixture @BeforeEach void setUp(@Autowired final JPAQueryFactory queryFactory) { - querydslAuctionRepository = new QuerydslAuctionRepositoryImpl(queryFactory); + querydslAuctionRepository = new QuerydslAuctionRepository(queryFactory); } @Nested @@ -37,8 +38,8 @@ class 검색_결과가_14개인_검색어_테스트 { void 페이지_크기_3_첫번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(0, 페이지_크기_3), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(0, 페이지_크기_3) ); // then @@ -55,8 +56,8 @@ class 검색_결과가_14개인_검색어_테스트 { void 페이지_크기_3_두번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(1, 페이지_크기_3), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(1, 페이지_크기_3) ); // then @@ -73,8 +74,8 @@ class 검색_결과가_14개인_검색어_테스트 { void 페이지_크기_3_세번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(2, 페이지_크기_3), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(2, 페이지_크기_3) ); // then @@ -91,8 +92,8 @@ class 검색_결과가_14개인_검색어_테스트 { void 페이지_크기_3_네번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(3, 페이지_크기_3), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(3, 페이지_크기_3) ); // then @@ -109,8 +110,8 @@ class 검색_결과가_14개인_검색어_테스트 { void 페이지_크기_3_다섯번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(4, 페이지_크기_3), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(4, 페이지_크기_3) ); // then @@ -126,8 +127,8 @@ class 검색_결과가_14개인_검색어_테스트 { void 페이지_크기_3_여섯번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(5, 페이지_크기_3), - 검색어_맥북 + 검색어_맥북, + PageRequest.of(5, 페이지_크기_3) ); // then @@ -146,8 +147,8 @@ class 검색_결과가_존재하지_않는_검색어_테스트 { void 페이지_크기_3_첫번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(0, 페이지_크기_3), - 검색어_캐비어 + 검색어_캐비어, + PageRequest.of(0, 페이지_크기_3) ); // then diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSortByAuctioneerCountTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSortByAuctioneerCountTest.java similarity index 92% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSortByAuctioneerCountTest.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSortByAuctioneerCountTest.java index 5faf1e672..5750e4fac 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSortByAuctioneerCountTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSortByAuctioneerCountTest.java @@ -1,7 +1,8 @@ -package com.ddang.ddang.auction.infrastructure.persistence; +package com.ddang.ddang.auction.infrastructure.persistence.list; import com.ddang.ddang.auction.domain.Auction; -import com.ddang.ddang.auction.infrastructure.persistence.fixture.AuctionForListSortByAuctioneerCountFixture; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.list.AuctionForListSortByAuctioneerCountFixture; import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; import com.querydsl.jpa.impl.JPAQueryFactory; @@ -26,15 +27,15 @@ class AuctionForListSortByAuctioneerCountTest extends AuctionForListSortByAuctio @BeforeEach void setUp(@Autowired final JPAQueryFactory queryFactory) { - querydslAuctionRepository = new QuerydslAuctionRepositoryImpl(queryFactory); + querydslAuctionRepository = new QuerydslAuctionRepository(queryFactory); } @Test void 페이지_크기_3_첫번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(0, 페이지_크기_3, 참여_인원순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(0, 페이지_크기_3, 참여_인원순_정렬) ); // then @@ -51,8 +52,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_두번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(1, 페이지_크기_3, 참여_인원순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(1, 페이지_크기_3, 참여_인원순_정렬) ); // then @@ -69,8 +70,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_세번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(2, 페이지_크기_3, 참여_인원순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(2, 페이지_크기_3, 참여_인원순_정렬) ); // then @@ -87,8 +88,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_네번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(3, 페이지_크기_3, 참여_인원순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(3, 페이지_크기_3, 참여_인원순_정렬) ); // then @@ -105,8 +106,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_다섯번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(4, 페이지_크기_3, 참여_인원순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(4, 페이지_크기_3, 참여_인원순_정렬) ); SoftAssertions.assertSoftly(softAssertions -> { @@ -122,8 +123,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_여섯번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(5, 페이지_크기_3, 참여_인원순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(5, 페이지_크기_3, 참여_인원순_정렬) ); SoftAssertions.assertSoftly(softAssertions -> { @@ -137,8 +138,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_일곱번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(6, 페이지_크기_3, 참여_인원순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(6, 페이지_크기_3, 참여_인원순_정렬) ); // then diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSortByClosingTimeTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSortByClosingTimeTest.java similarity index 92% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSortByClosingTimeTest.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSortByClosingTimeTest.java index b94cac4b7..7f56c4d92 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSortByClosingTimeTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSortByClosingTimeTest.java @@ -1,7 +1,8 @@ -package com.ddang.ddang.auction.infrastructure.persistence; +package com.ddang.ddang.auction.infrastructure.persistence.list; import com.ddang.ddang.auction.domain.Auction; -import com.ddang.ddang.auction.infrastructure.persistence.fixture.AuctionForListSortByClosingTimeFixture; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.list.AuctionForListSortByClosingTimeFixture; import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; import com.querydsl.jpa.impl.JPAQueryFactory; @@ -26,15 +27,15 @@ class AuctionForListSortByClosingTimeTest extends AuctionForListSortByClosingTim @BeforeEach void setUp(@Autowired final JPAQueryFactory queryFactory) { - querydslAuctionRepository = new QuerydslAuctionRepositoryImpl(queryFactory); + querydslAuctionRepository = new QuerydslAuctionRepository(queryFactory); } @Test void 페이지_크기_3_첫번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(0, 페이지_크기_3, 마감_임박순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(0, 페이지_크기_3, 마감_임박순_정렬) ); // then @@ -51,8 +52,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_두번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(1, 페이지_크기_3, 마감_임박순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(1, 페이지_크기_3, 마감_임박순_정렬) ); // then @@ -69,8 +70,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_세번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(2, 페이지_크기_3, 마감_임박순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(2, 페이지_크기_3, 마감_임박순_정렬) ); // then @@ -87,8 +88,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_네번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(3, 페이지_크기_3, 마감_임박순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(3, 페이지_크기_3, 마감_임박순_정렬) ); // then @@ -105,8 +106,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_다섯번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(4, 페이지_크기_3, 마감_임박순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(4, 페이지_크기_3, 마감_임박순_정렬) ); SoftAssertions.assertSoftly(softAssertions -> { @@ -122,8 +123,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_여섯번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(5, 페이지_크기_3, 마감_임박순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(5, 페이지_크기_3, 마감_임박순_정렬) ); SoftAssertions.assertSoftly(softAssertions -> { @@ -137,8 +138,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_일곱번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(6, 페이지_크기_3, 마감_임박순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(6, 페이지_크기_3, 마감_임박순_정렬) ); // then diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSortByIdTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSortByIdTest.java similarity index 93% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSortByIdTest.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSortByIdTest.java index f759c099d..8024185e2 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSortByIdTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSortByIdTest.java @@ -1,7 +1,8 @@ -package com.ddang.ddang.auction.infrastructure.persistence; +package com.ddang.ddang.auction.infrastructure.persistence.list; import com.ddang.ddang.auction.domain.Auction; -import com.ddang.ddang.auction.infrastructure.persistence.fixture.AuctionForListSortByIdFixture; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.list.AuctionForListSortByIdFixture; import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; import com.querydsl.jpa.impl.JPAQueryFactory; @@ -26,15 +27,15 @@ class AuctionForListSortByIdTest extends AuctionForListSortByIdFixture { @BeforeEach void setUp(@Autowired final JPAQueryFactory queryFactory) { - querydslAuctionRepository = new QuerydslAuctionRepositoryImpl(queryFactory); + querydslAuctionRepository = new QuerydslAuctionRepository(queryFactory); } @Test void 페이지_크기_3_첫번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(0, 페이지_크기_3, id순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(0, 페이지_크기_3, id순_정렬) ); // then @@ -51,8 +52,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_두번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(1, 페이지_크기_3, id순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(1, 페이지_크기_3, id순_정렬) ); // then @@ -69,8 +70,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_세번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(2, 페이지_크기_3, id순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(2, 페이지_크기_3, id순_정렬) ); // then @@ -87,8 +88,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_네번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(3, 페이지_크기_3, id순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(3, 페이지_크기_3, id순_정렬) ); // then @@ -105,8 +106,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_다섯번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(4, 페이지_크기_3, id순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(4, 페이지_크기_3, id순_정렬) ); SoftAssertions.assertSoftly(softAssertions -> { @@ -122,8 +123,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_여섯번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(5, 페이지_크기_3, id순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(5, 페이지_크기_3, id순_정렬) ); SoftAssertions.assertSoftly(softAssertions -> { @@ -137,8 +138,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_일곱번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(6, 페이지_크기_3, id순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(6, 페이지_크기_3, id순_정렬) ); // then diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSortByReliabilityTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSortByReliabilityTest.java similarity index 92% rename from backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSortByReliabilityTest.java rename to backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSortByReliabilityTest.java index c296e536d..f711e4f77 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionForListSortByReliabilityTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/list/AuctionForListSortByReliabilityTest.java @@ -1,7 +1,8 @@ -package com.ddang.ddang.auction.infrastructure.persistence; +package com.ddang.ddang.auction.infrastructure.persistence.list; import com.ddang.ddang.auction.domain.Auction; -import com.ddang.ddang.auction.infrastructure.persistence.fixture.AuctionForListSortByReliabilityFixture; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.fixture.list.AuctionForListSortByReliabilityFixture; import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; import com.querydsl.jpa.impl.JPAQueryFactory; @@ -26,15 +27,15 @@ class AuctionForListSortByReliabilityTest extends AuctionForListSortByReliabilit @BeforeEach void setUp(@Autowired final JPAQueryFactory queryFactory) { - querydslAuctionRepository = new QuerydslAuctionRepositoryImpl(queryFactory); + querydslAuctionRepository = new QuerydslAuctionRepository(queryFactory); } @Test void 페이지_크기_3_첫번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(0, 페이지_크기_3, 신뢰도순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(0, 페이지_크기_3, 신뢰도순_정렬) ); // then @@ -51,8 +52,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_두번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(1, 페이지_크기_3, 신뢰도순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(1, 페이지_크기_3, 신뢰도순_정렬) ); // then @@ -69,8 +70,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_세번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(2, 페이지_크기_3, 신뢰도순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(2, 페이지_크기_3, 신뢰도순_정렬) ); // then @@ -87,8 +88,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_네번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(3, 페이지_크기_3, 신뢰도순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(3, 페이지_크기_3, 신뢰도순_정렬) ); // then @@ -105,8 +106,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_다섯번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(4, 페이지_크기_3, 신뢰도순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(4, 페이지_크기_3, 신뢰도순_정렬) ); SoftAssertions.assertSoftly(softAssertions -> { @@ -122,8 +123,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_여섯번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(5, 페이지_크기_3, 신뢰도순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(5, 페이지_크기_3, 신뢰도순_정렬) ); SoftAssertions.assertSoftly(softAssertions -> { @@ -137,8 +138,8 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { void 페이지_크기_3_일곱번째_페이지_요청_테스트() { // when final Slice actual = querydslAuctionRepository.findAuctionsAllByCondition( - PageRequest.of(6, 페이지_크기_3, 신뢰도순_정렬), - 검색어_없음 + 검색어_없음, + PageRequest.of(6, 페이지_크기_3, 신뢰도순_정렬) ); // then diff --git a/backend/ddang/src/test/java/com/ddang/ddang/bid/application/fixture/BidServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/bid/application/fixture/BidServiceFixture.java index 022acf6e8..12a35aee0 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/bid/application/fixture/BidServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/bid/application/fixture/BidServiceFixture.java @@ -3,7 +3,7 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; -import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.bid.application.dto.CreateBidDto; import com.ddang.ddang.bid.domain.Bid; import com.ddang.ddang.bid.domain.BidPrice; @@ -14,11 +14,10 @@ import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; - import java.time.LocalDateTime; import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; @SuppressWarnings("NonAsciiCharacters") public class BidServiceFixture { @@ -27,7 +26,7 @@ public class BidServiceFixture { private JpaUserRepository userRepository; @Autowired - private JpaAuctionRepository auctionRepository; + private AuctionRepository auctionRepository; @Autowired private JpaBidRepository bidRepository; @@ -130,7 +129,13 @@ void setUp() { 경매1.addAuctionImages(List.of(경매_이미지1)); 경매2.addAuctionImages(List.of(경매_이미지2)); 경매3.addAuctionImages(List.of(경매_이미지3)); - auctionRepository.saveAll(List.of(경매1, 경매2, 경매3, 입찰_내역이_하나_있던_경매, 종료된_경매, 삭제된_경매)); + + auctionRepository.save(경매1); + auctionRepository.save(경매2); + auctionRepository.save(경매3); + auctionRepository.save(입찰_내역이_하나_있던_경매); + auctionRepository.save(종료된_경매); + auctionRepository.save(삭제된_경매); final Bid bid1 = new Bid(경매1, 입찰자1, new BidPrice(1_000)); final Bid bid2 = new Bid(경매2, 입찰자1, new BidPrice(1_000)); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java index 1ec29707a..27b3518df 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java @@ -4,7 +4,7 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; -import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.authentication.domain.dto.AuthenticationUserInfo; import com.ddang.ddang.bid.domain.Bid; import com.ddang.ddang.bid.domain.BidPrice; @@ -27,23 +27,22 @@ import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; - import java.time.LocalDateTime; import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; @SuppressWarnings("NonAsciiCharacters") public class ChatRoomServiceFixture { @Autowired - private JpaCategoryRepository categoryRepository; + private AuctionRepository auctionRepository; @Autowired - private JpaUserRepository userRepository; + private JpaCategoryRepository categoryRepository; @Autowired - private JpaAuctionRepository auctionRepository; + private JpaUserRepository userRepository; @Autowired private JpaBidRepository bidRepository; @@ -190,9 +189,12 @@ void setUp() { 채팅방이_없는_경매.addAuctionImages(List.of(경매_대표_이미지, 대표_이미지가_아닌_경매_이미지)); 판매자_엔초_구매자_지토_경매.addAuctionImages(List.of(엔초의_경매_대표_이미지, 엔초의_대표_이미지가_아닌_경매_이미지)); 판매자_제이미_구매자_엔초_경매.addAuctionImages(List.of(제이미의_경매_대표_이미지, 제이미의_대표_이미지가_아닌_경매_이미지)); - auctionRepository.saveAll( - List.of(채팅방이_없는_경매, 종료되지_않은_경매, 낙찰자가_없는_경매, 판매자_엔초_구매자_지토_경매, 판매자_제이미_구매자_엔초_경매) - ); + + auctionRepository.save(채팅방이_없는_경매); + auctionRepository.save(종료되지_않은_경매); + auctionRepository.save(낙찰자가_없는_경매); + auctionRepository.save(판매자_엔초_구매자_지토_경매); + auctionRepository.save(판매자_제이미_구매자_엔초_경매); final Bid 채팅방_없는_경매_입찰 = new Bid(채팅방이_없는_경매, 구매자, new BidPrice(15_000)); final Bid 지토가_엔초_경매에_입찰 = new Bid(판매자_엔초_구매자_지토_경매, 지토, new BidPrice(15_000)); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java index 05e417e85..b34e7e247 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java @@ -3,7 +3,7 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; -import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.category.domain.Category; import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; import com.ddang.ddang.chat.application.dto.CreateMessageDto; @@ -16,21 +16,20 @@ import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; - import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; @SuppressWarnings("NonAsciiCharacters") public class MessageServiceFixture { @Autowired - private JpaMessageRepository messageRepository; + private AuctionRepository auctionRepository; @Autowired - private JpaAuctionRepository auctionRepository; + private JpaMessageRepository messageRepository; @Autowired private JpaUserRepository userRepository; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndImageRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndImageRepositoryImplFixture.java index 15c437d93..4d3898633 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndImageRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndImageRepositoryImplFixture.java @@ -3,7 +3,10 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.AuctionRepositoryImpl; import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; import com.ddang.ddang.bid.domain.Bid; import com.ddang.ddang.bid.domain.BidPrice; import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; @@ -16,13 +19,13 @@ import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; - import java.time.LocalDateTime; import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; @SuppressWarnings("NonAsciiCharacters") public class QuerydslChatRoomAndImageRepositoryImplFixture { @@ -31,13 +34,16 @@ public class QuerydslChatRoomAndImageRepositoryImplFixture { private EntityManager em; @Autowired - private JpaCategoryRepository categoryRepository; + private JPAQueryFactory queryFactory; @Autowired - private JpaUserRepository userRepository; + private JpaAuctionRepository jpaAuctionRepository; @Autowired - private JpaAuctionRepository auctionRepository; + private JpaCategoryRepository categoryRepository; + + @Autowired + private JpaUserRepository userRepository; @Autowired private JpaBidRepository bidRepository; @@ -81,11 +87,16 @@ void setUp() { 경매_대표_이미지 = new AuctionImage("경매_대표_이미지.png", "경매_대표_이미지.png"); 채팅방 = new ChatRoom(경매, 구매자); + final AuctionRepository auctionRepository = new AuctionRepositoryImpl( + jpaAuctionRepository, + new QuerydslAuctionRepository(queryFactory) + ); + auctionRepository.save(경매); + 전자기기_카테고리.addSubCategory(전자기기_서브_노트북_카테고리); categoryRepository.save(전자기기_카테고리); userRepository.saveAll(List.of(판매자, 구매자)); 경매.addAuctionImages(List.of(경매_대표_이미지, 대표_이미지가_아닌_경매_이미지)); - auctionRepository.save(경매); bidRepository.save(입찰); 경매.updateLastBid(입찰); chatRoomRepository.save(채팅방); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndMessageAndImageRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndMessageAndImageRepositoryImplFixture.java index e404c5de1..e82911db1 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndMessageAndImageRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndMessageAndImageRepositoryImplFixture.java @@ -3,7 +3,10 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.AuctionRepositoryImpl; import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; import com.ddang.ddang.bid.domain.Bid; import com.ddang.ddang.bid.domain.BidPrice; import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; @@ -18,13 +21,13 @@ import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; - import java.time.LocalDateTime; import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; @SuppressWarnings("NonAsciiCharacters") public class QuerydslChatRoomAndMessageAndImageRepositoryImplFixture { @@ -33,13 +36,16 @@ public class QuerydslChatRoomAndMessageAndImageRepositoryImplFixture { private EntityManager em; @Autowired - private JpaCategoryRepository categoryRepository; + private JPAQueryFactory queryFactory; @Autowired - private JpaUserRepository userRepository; + private JpaAuctionRepository jpaAuctionRepository; @Autowired - private JpaAuctionRepository auctionRepository; + private JpaCategoryRepository categoryRepository; + + @Autowired + private JpaUserRepository userRepository; @Autowired private JpaBidRepository bidRepository; @@ -178,7 +184,15 @@ void setUp() { 메리의_경매.addAuctionImages(List.of(메리의_경매_대표_이미지, 메리의_대표_이미지가_아닌_경매_이미지)); 엔초의_경매.addAuctionImages(List.of(엔초의_경매_대표_이미지, 엔초의_대표_이미지가_아닌_경매_이미지)); 제이미의_경매.addAuctionImages(List.of(제이미의_경매_대표_이미지, 제이미의_대표_이미지가_아닌_경매_이미지)); - auctionRepository.saveAll(List.of(메리의_경매, 엔초의_경매, 제이미의_경매)); + + final AuctionRepository auctionRepository = new AuctionRepositoryImpl( + jpaAuctionRepository, + new QuerydslAuctionRepository(queryFactory) + ); + + auctionRepository.save(메리의_경매); + auctionRepository.save(엔초의_경매); + auctionRepository.save(제이미의_경매); bidRepository.saveAll(List.of(엔초가_메리_경매에_입찰, 지토가_엔초_경매에_입찰, 엔초가_제이미_경매에_입찰)); 메리의_경매.updateLastBid(엔초가_메리_경매에_입찰); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomRepositoryImplFixture.java index bef8380e9..36ddea388 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomRepositoryImplFixture.java @@ -3,7 +3,10 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.AuctionRepositoryImpl; import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; import com.ddang.ddang.bid.domain.Bid; import com.ddang.ddang.bid.domain.BidPrice; import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; @@ -16,13 +19,13 @@ import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; - import java.time.LocalDateTime; import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; @SuppressWarnings("NonAsciiCharacters") public class QuerydslChatRoomRepositoryImplFixture { @@ -31,13 +34,16 @@ public class QuerydslChatRoomRepositoryImplFixture { private EntityManager em; @Autowired - private JpaCategoryRepository categoryRepository; + private JPAQueryFactory queryFactory; @Autowired - private JpaUserRepository userRepository; + private JpaAuctionRepository jpaAuctionRepository; @Autowired - private JpaAuctionRepository auctionRepository; + private JpaCategoryRepository categoryRepository; + + @Autowired + private JpaUserRepository userRepository; @Autowired private JpaBidRepository bidRepository; @@ -90,6 +96,12 @@ void setUp() { userRepository.saveAll(List.of(판매자, 구매자)); 경매.addAuctionImages(List.of(경매_대표_이미지, 대표_이미지가_아닌_경매_이미지)); + + final AuctionRepository auctionRepository = new AuctionRepositoryImpl( + jpaAuctionRepository, + new QuerydslAuctionRepository(queryFactory) + ); + auctionRepository.save(경매); bidRepository.save(입찰); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslMessageRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslMessageRepositoryImplFixture.java index fa02b5fb4..ca6a05285 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslMessageRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslMessageRepositoryImplFixture.java @@ -1,7 +1,10 @@ package com.ddang.ddang.chat.infrastructure.persistence.fixture; import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.AuctionRepositoryImpl; import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; import com.ddang.ddang.chat.domain.ChatRoom; import com.ddang.ddang.chat.domain.Message; import com.ddang.ddang.chat.infrastructure.persistence.JpaChatRoomRepository; @@ -10,13 +13,13 @@ import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; - import java.util.ArrayList; import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; @SuppressWarnings("NonAsciiCharacters") public class QuerydslMessageRepositoryImplFixture { @@ -25,10 +28,13 @@ public class QuerydslMessageRepositoryImplFixture { private EntityManager em; @Autowired - private JpaUserRepository userRepository; + private JPAQueryFactory queryFactory; @Autowired - private JpaAuctionRepository auctionRepository; + private JpaAuctionRepository jpaAuctionRepository; + + @Autowired + private JpaUserRepository userRepository; @Autowired private JpaChatRoomRepository chatRoomRepository; @@ -73,6 +79,11 @@ void setUp() { .title("title") .build(); + final AuctionRepository auctionRepository = new AuctionRepositoryImpl( + jpaAuctionRepository, + new QuerydslAuctionRepository(queryFactory) + ); + auctionRepository.save(경매); 채팅방 = new ChatRoom(경매, 구매자); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java index 2fc19c520..d5b91d5d4 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java @@ -3,7 +3,7 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; -import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.bid.domain.Bid; import com.ddang.ddang.bid.domain.BidPrice; import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; @@ -21,11 +21,10 @@ import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; - import java.time.LocalDateTime; import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; @SuppressWarnings("NonAsciiCharacters") public class FcmNotificationServiceFixture { @@ -43,7 +42,7 @@ public class FcmNotificationServiceFixture { private JpaDeviceTokenRepository deviceTokenRepository; @Autowired - private JpaAuctionRepository auctionRepository; + private AuctionRepository auctionRepository; @Autowired private JpaBidRepository bidRepository; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java index a8baa456a..997c4f7cd 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java @@ -3,8 +3,8 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; -import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; -import com.ddang.ddang.auction.infrastructure.persistence.dto.AuctionAndImageDto; +import com.ddang.ddang.auction.domain.dto.AuctionAndImageDto; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.bid.application.dto.BidDto; import com.ddang.ddang.bid.application.dto.CreateBidDto; import com.ddang.ddang.bid.application.event.BidNotificationEvent; @@ -27,11 +27,10 @@ import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; - import java.time.LocalDateTime; import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; @SuppressWarnings("NonAsciiCharacters") public class NotificationEventListenerFixture { @@ -43,7 +42,7 @@ public class NotificationEventListenerFixture { private JpaChatRoomRepository chatRoomRepository; @Autowired - private JpaAuctionRepository auctionRepository; + private AuctionRepository auctionRepository; @Autowired private JpaAuctionImageRepository auctionImageRepository; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/AnswerServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/AnswerServiceFixture.java index 1ffabd63b..987b82e7f 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/AnswerServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/AnswerServiceFixture.java @@ -3,7 +3,7 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; -import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.qna.application.dto.CreateAnswerDto; import com.ddang.ddang.qna.domain.Answer; @@ -13,17 +13,16 @@ import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; - import java.time.LocalDateTime; import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; @SuppressWarnings("NonAsciiCharacters") public class AnswerServiceFixture { @Autowired - private JpaAuctionRepository auctionRepository; + private AuctionRepository auctionRepository; @Autowired private JpaUserRepository userRepository; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java index 3f37fcfb7..ae97d5d1b 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java @@ -3,7 +3,7 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; -import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.category.domain.Category; import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; import com.ddang.ddang.image.domain.ProfileImage; @@ -20,11 +20,10 @@ import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; - import java.time.LocalDateTime; import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; @SuppressWarnings("NonAsciiCharacters") public class QuestionServiceFixture { @@ -33,7 +32,7 @@ public class QuestionServiceFixture { private JpaUserRepository userRepository; @Autowired - private JpaAuctionRepository auctionRepository; + private AuctionRepository auctionRepository; @Autowired private JpaQuestionRepository questionRepository; @@ -151,7 +150,10 @@ void setUp() { 질문2.addAnswer(답변2); userRepository.saveAll(List.of(판매자, 질문자, 질문하지_않은_사용자)); - auctionRepository.saveAll(List.of(경매, 질문과_답변이_존재하는_경매, 종료된_경매, 삭제된_경매)); + auctionRepository.save(경매); + auctionRepository.save(질문과_답변이_존재하는_경매); + auctionRepository.save(종료된_경매); + auctionRepository.save(삭제된_경매); questionRepository.saveAll(List.of(질문, 질문2, 질문3)); answerRepository.saveAll(List.of(답변1, 답변2)); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/application/AuctionReportServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/report/application/AuctionReportServiceTest.java index e754fa7a6..9a133a9af 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/application/AuctionReportServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/application/AuctionReportServiceTest.java @@ -1,24 +1,22 @@ package com.ddang.ddang.report.application; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + import com.ddang.ddang.auction.application.exception.AuctionNotFoundException; import com.ddang.ddang.configuration.IsolateDatabase; import com.ddang.ddang.report.application.dto.ReadAuctionReportDto; import com.ddang.ddang.report.application.exception.AlreadyReportAuctionException; -import com.ddang.ddang.report.application.exception.InvalidReportAuctionException; import com.ddang.ddang.report.application.exception.InvalidReporterToAuctionException; import com.ddang.ddang.report.application.fixture.AuctionReportServiceFixture; import com.ddang.ddang.user.application.exception.UserNotFoundException; +import java.util.List; import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - @IsolateDatabase @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @SuppressWarnings("NonAsciiCharacters") @@ -64,8 +62,8 @@ class AuctionReportServiceTest extends AuctionReportServiceFixture { void 삭제한_경매를_신고하는_경우_예외가_발생한다() { // when & then assertThatThrownBy(() -> auctionReportService.create(삭제된_경매_신고_요청_dto)) - .isInstanceOf(InvalidReportAuctionException.class) - .hasMessage("이미 삭제된 경매입니다."); + .isInstanceOf(AuctionNotFoundException.class) + .hasMessage("해당 경매를 찾을 수 없습니다."); } @Test diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AnswerReportServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AnswerReportServiceFixture.java index 82a5494b0..1c775c4b1 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AnswerReportServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AnswerReportServiceFixture.java @@ -3,7 +3,7 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; -import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.category.domain.Category; import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; import com.ddang.ddang.image.domain.AuctionImage; @@ -18,11 +18,10 @@ import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; - import java.time.LocalDateTime; import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; @SuppressWarnings("NonAsciiCharacters") public class AnswerReportServiceFixture { @@ -34,7 +33,7 @@ public class AnswerReportServiceFixture { private JpaUserRepository userRepository; @Autowired - private JpaAuctionRepository auctionRepository; + private AuctionRepository auctionRepository; @Autowired private JpaQuestionRepository questionRepository; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AuctionReportServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AuctionReportServiceFixture.java index eac55d091..b0e811f46 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AuctionReportServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AuctionReportServiceFixture.java @@ -3,7 +3,7 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; -import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.category.domain.Category; import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; import com.ddang.ddang.image.domain.AuctionImage; @@ -16,11 +16,10 @@ import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; - import java.time.LocalDateTime; import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; @SuppressWarnings("NonAsciiCharacters") public class AuctionReportServiceFixture { @@ -38,7 +37,7 @@ public class AuctionReportServiceFixture { private JpaAuctionImageRepository auctionImageRepository; @Autowired - private JpaAuctionRepository auctionRepository; + private AuctionRepository auctionRepository; @Autowired private JpaAuctionReportRepository auctionReportRepository; @@ -128,7 +127,9 @@ void setUp() { categoryRepository.saveAll(List.of(전자기기_카테고리, 전자기기_서브_노트북_카테고리)); auctionImageRepository.save(경매_이미지); - auctionRepository.saveAll(List.of(경매, 삭제된_경매)); + auctionRepository.save(경매); + auctionRepository.save(삭제된_경매); + auctionReportRepository.saveAll(List.of(경매_신고1, 경매_신고2, 경매_신고3)); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/ChatRoomReportServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/ChatRoomReportServiceFixture.java index 0f2ac6fda..6aa94e0b8 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/ChatRoomReportServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/ChatRoomReportServiceFixture.java @@ -3,7 +3,7 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; -import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.category.domain.Category; import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; import com.ddang.ddang.chat.domain.ChatRoom; @@ -18,11 +18,10 @@ import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; - import java.time.LocalDateTime; import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; @SuppressWarnings("NonAsciiCharacters") public class ChatRoomReportServiceFixture { @@ -40,7 +39,7 @@ public class ChatRoomReportServiceFixture { private JpaAuctionImageRepository auctionImageRepository; @Autowired - private JpaAuctionRepository auctionRepository; + private AuctionRepository auctionRepository; @Autowired private JpaChatRoomReportRepository chatRoomReportRepository; @@ -147,7 +146,9 @@ void setUp() { categoryRepository.saveAll(List.of(전자기기_카테고리, 전자기기_서브_노트북_카테고리)); auctionImageRepository.save(경매_이미지); - auctionRepository.saveAll(List.of(경매1, 경매2, 경매3)); + auctionRepository.save(경매1); + auctionRepository.save(경매2); + auctionRepository.save(경매3); chatRoomRepository.saveAll(List.of(채팅방1, 채팅방2, 채팅방3)); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/QuestionReportServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/QuestionReportServiceFixture.java index 88832351d..99873eb97 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/QuestionReportServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/QuestionReportServiceFixture.java @@ -3,7 +3,7 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; -import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.category.domain.Category; import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; import com.ddang.ddang.image.domain.AuctionImage; @@ -16,11 +16,10 @@ import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; - import java.time.LocalDateTime; import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; @SuppressWarnings("NonAsciiCharacters") public class QuestionReportServiceFixture { @@ -32,7 +31,7 @@ public class QuestionReportServiceFixture { private JpaUserRepository userRepository; @Autowired - private JpaAuctionRepository auctionRepository; + private AuctionRepository auctionRepository; @Autowired private JpaQuestionRepository questionRepository; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/review/application/fixture/ReviewServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/review/application/fixture/ReviewServiceFixture.java index 3cab1c14f..57babacdf 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/review/application/fixture/ReviewServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/review/application/fixture/ReviewServiceFixture.java @@ -3,7 +3,7 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; -import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.category.domain.Category; import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; import com.ddang.ddang.image.domain.AuctionImage; @@ -31,7 +31,7 @@ public class ReviewServiceFixture { private JpaUserRepository userRepository; @Autowired - private JpaAuctionRepository auctionRepository; + private AuctionRepository auctionRepository; @Autowired private JpaReviewRepository reviewRepository; @@ -39,9 +39,6 @@ public class ReviewServiceFixture { private double 구매자가_판매자1에게_받은_평가_점수 = 5.0d; private double 구매자가_판매자2에게_받은_평가_점수 = 1.0d; private double 구매자가_받을_새로운_평가_점수 = 4.5d; - - protected double 구매자가_새로운_평가_점수를_받고난_후의_신뢰도_점수 = - (구매자가_판매자1에게_받은_평가_점수 + 구매자가_판매자2에게_받은_평가_점수 + 구매자가_받을_새로운_평가_점수) / 3; protected Long 존재하지_않는_사용자 = -999L; protected User 판매자1; protected User 판매자2; @@ -140,7 +137,9 @@ void setUp() { 판매자1이_평가한_경매.addAuctionImages(List.of(경매1_대표_이미지)); 판매자2가_평가한_경매.addAuctionImages(List.of(경매2_대표_이미지)); 평가_안한_경매.addAuctionImages(List.of(평가_안한_경매_대표_이미지)); - auctionRepository.saveAll(List.of(판매자1이_평가한_경매, 판매자2가_평가한_경매, 평가_안한_경매)); + auctionRepository.save(판매자1이_평가한_경매); + auctionRepository.save(판매자2가_평가한_경매); + auctionRepository.save(평가_안한_경매); 구매자가_판매자1에게_받은_평가 = Review.builder() .auction(판매자1이_평가한_경매) diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/fixture/ReliabilityUpdateSchedulingServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/fixture/ReliabilityUpdateSchedulingServiceFixture.java index 25e0adaca..612ba76f6 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/fixture/ReliabilityUpdateSchedulingServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/fixture/ReliabilityUpdateSchedulingServiceFixture.java @@ -1,7 +1,7 @@ package com.ddang.ddang.user.application.schedule.fixture; import com.ddang.ddang.auction.domain.Auction; -import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.review.domain.Review; import com.ddang.ddang.review.domain.Reviews; @@ -14,11 +14,10 @@ import com.ddang.ddang.user.infrastructure.persistence.JpaReliabilityUpdateHistoryRepository; import com.ddang.ddang.user.infrastructure.persistence.JpaUserReliabilityRepository; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; -import java.util.List; - @SuppressWarnings("NonAsciiCharacters") public class ReliabilityUpdateSchedulingServiceFixture { @@ -26,7 +25,7 @@ public class ReliabilityUpdateSchedulingServiceFixture { private JpaUserRepository userRepository; @Autowired - private JpaAuctionRepository auctionRepository; + private AuctionRepository auctionRepository; @Autowired private JpaReviewRepository reviewRepository; @@ -201,7 +200,25 @@ void setUp() { .title("경매18") .seller(판매자) .build(); - auctionRepository.saveAll(List.of(경매1, 경매2, 경매3, 경매4, 경매5, 경매6, 경매7, 경매8, 경매9, 경매10, 경매11, 경매12, 경매13, 경매14, 경매15, 경매16, 경매17, 경매18)); + + auctionRepository.save(경매1); + auctionRepository.save(경매2); + auctionRepository.save(경매3); + auctionRepository.save(경매4); + auctionRepository.save(경매5); + auctionRepository.save(경매6); + auctionRepository.save(경매7); + auctionRepository.save(경매8); + auctionRepository.save(경매9); + auctionRepository.save(경매10); + auctionRepository.save(경매11); + auctionRepository.save(경매12); + auctionRepository.save(경매13); + auctionRepository.save(경매14); + auctionRepository.save(경매15); + auctionRepository.save(경매16); + auctionRepository.save(경매17); + auctionRepository.save(경매18); final Review 구매자1_기존_평가1 = Review.builder() .auction(경매1) From d0ce0d505855097a11f9c2430afcc09c55ef2580 Mon Sep 17 00:00:00 2001 From: apptie <57691173+apptie@users.noreply.github.com> Date: Sat, 14 Oct 2023 15:05:19 +0900 Subject: [PATCH 14/37] =?UTF-8?q?refactor:=20#648=20Category=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=9D=B8=ED=94=84=EB=9D=BC=20=EB=A6=AC=ED=8E=99?= =?UTF-8?q?=ED=86=A0=EB=A7=81=20(#650)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 도메인 영역의 Repository 추가 * feat: 도메인 영역의 Repository 구현체 추가 * refactor: Service에서 도메인 영역의 Repository를 사용하도록 변경 * refactor: Service에서 도메인 영역의 Repository를 사용하도록 변경 --- .../auction/application/AuctionService.java | 4 +- .../category/application/CategoryService.java | 7 +- .../domain/repository/CategoryRepository.java | 14 ++++ .../persistence/CategoryRepositoryImpl.java | 30 ++++++++ .../CategoryRepositoryImplTest.java | 76 +++++++++++++++++++ .../fixture/CategoryRepositoryFixture.java | 40 ++++++++++ 6 files changed, 165 insertions(+), 6 deletions(-) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/category/domain/repository/CategoryRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/category/infrastructure/persistence/CategoryRepositoryImpl.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/category/infrastructure/persistence/CategoryRepositoryImplTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/category/infrastructure/persistence/fixture/CategoryRepositoryFixture.java diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/application/AuctionService.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/application/AuctionService.java index 197c45d5f..b0167416c 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/application/AuctionService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/application/AuctionService.java @@ -11,7 +11,7 @@ import com.ddang.ddang.auction.presentation.dto.request.ReadAuctionSearchCondition; import com.ddang.ddang.category.application.exception.CategoryNotFoundException; import com.ddang.ddang.category.domain.Category; -import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; +import com.ddang.ddang.category.domain.repository.CategoryRepository; import com.ddang.ddang.image.domain.AuctionImage; import com.ddang.ddang.image.domain.StoreImageProcessor; import com.ddang.ddang.image.domain.dto.StoreImageDto; @@ -38,7 +38,7 @@ public class AuctionService { private final JpaUserRepository userRepository; private final AuctionRepository auctionRepository; private final JpaRegionRepository regionRepository; - private final JpaCategoryRepository categoryRepository; + private final CategoryRepository categoryRepository; private final StoreImageProcessor imageProcessor; @Transactional diff --git a/backend/ddang/src/main/java/com/ddang/ddang/category/application/CategoryService.java b/backend/ddang/src/main/java/com/ddang/ddang/category/application/CategoryService.java index 48df85d4a..e47ea0a66 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/category/application/CategoryService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/category/application/CategoryService.java @@ -3,19 +3,18 @@ import com.ddang.ddang.category.application.dto.ReadCategoryDto; import com.ddang.ddang.category.application.exception.CategoryNotFoundException; import com.ddang.ddang.category.domain.Category; -import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; +import com.ddang.ddang.category.domain.repository.CategoryRepository; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; - @Service @Transactional(readOnly = true) @RequiredArgsConstructor public class CategoryService { - private final JpaCategoryRepository categoryRepository; + private final CategoryRepository categoryRepository; public List readAllMain() { final List mainCategories = categoryRepository.findMainAllByMainCategoryIsNull(); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/category/domain/repository/CategoryRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/category/domain/repository/CategoryRepository.java new file mode 100644 index 000000000..5b10afdd4 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/category/domain/repository/CategoryRepository.java @@ -0,0 +1,14 @@ +package com.ddang.ddang.category.domain.repository; + +import com.ddang.ddang.category.domain.Category; +import java.util.List; +import java.util.Optional; + +public interface CategoryRepository { + + List findMainAllByMainCategoryIsNull(); + + List findSubAllByMainCategoryId(final Long mainCategoryId); + + Optional findSubCategoryById(final Long subCategoryId); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/category/infrastructure/persistence/CategoryRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/category/infrastructure/persistence/CategoryRepositoryImpl.java new file mode 100644 index 000000000..58e3faed0 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/category/infrastructure/persistence/CategoryRepositoryImpl.java @@ -0,0 +1,30 @@ +package com.ddang.ddang.category.infrastructure.persistence; + +import com.ddang.ddang.category.domain.Category; +import com.ddang.ddang.category.domain.repository.CategoryRepository; +import java.util.List; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class CategoryRepositoryImpl implements CategoryRepository { + + private final JpaCategoryRepository jpaCategoryRepository; + + @Override + public List findMainAllByMainCategoryIsNull() { + return jpaCategoryRepository.findMainAllByMainCategoryIsNull(); + } + + @Override + public List findSubAllByMainCategoryId(final Long mainCategoryId) { + return jpaCategoryRepository.findSubAllByMainCategoryId(mainCategoryId); + } + + @Override + public Optional findSubCategoryById(final Long subCategoryId) { + return jpaCategoryRepository.findSubCategoryById(subCategoryId); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/category/infrastructure/persistence/CategoryRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/category/infrastructure/persistence/CategoryRepositoryImplTest.java new file mode 100644 index 000000000..19feb7c34 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/category/infrastructure/persistence/CategoryRepositoryImplTest.java @@ -0,0 +1,76 @@ +package com.ddang.ddang.category.infrastructure.persistence; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ddang.ddang.category.domain.Category; +import com.ddang.ddang.category.domain.repository.CategoryRepository; +import com.ddang.ddang.category.infrastructure.persistence.fixture.CategoryRepositoryFixture; +import com.ddang.ddang.configuration.QuerydslConfiguration; +import java.util.List; +import java.util.Optional; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +@DataJpaTest +@Import(QuerydslConfiguration.class) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class CategoryRepositoryImplTest extends CategoryRepositoryFixture { + + CategoryRepository categoryRepository; + + @BeforeEach + void setUp(@Autowired JpaCategoryRepository jpaCategoryRepository) { + categoryRepository = new CategoryRepositoryImpl(jpaCategoryRepository); + } + + @Test + void 모든_메인_카테고리를_조회한다() { + // when + final List actual = categoryRepository.findMainAllByMainCategoryIsNull(); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).hasSize(2); + softAssertions.assertThat(actual.get(0)).isEqualTo(가구_카테고리); + softAssertions.assertThat(actual.get(1)).isEqualTo(전자기기_카테고리); + }); + } + + @Test + void 메인_카테고리에_해당하는_모든_서브_카테고리를_조회한다() { + // when + final List actual = categoryRepository.findSubAllByMainCategoryId(가구_카테고리.getId()); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).hasSize(2); + softAssertions.assertThat(actual.get(0)).isEqualTo(가구_서브_의자_카테고리); + softAssertions.assertThat(actual.get(1)).isEqualTo(가구_서브_책상_카테고리); + }); + } + + @Test + void 서브_카테고리를_조회한다() { + // when + final Optional actual = categoryRepository.findSubCategoryById(가구_서브_의자_카테고리.getId()); + + // then + assertThat(actual).contains(가구_서브_의자_카테고리); + } + + @Test + void 서브_카테고리가_아닌_카테고리의_아이디를_전달하면_빈_Optional을_반환한다() { + // when + final Optional actual = categoryRepository.findSubCategoryById(가구_카테고리.getId()); + + // then + assertThat(actual).isEmpty(); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/category/infrastructure/persistence/fixture/CategoryRepositoryFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/category/infrastructure/persistence/fixture/CategoryRepositoryFixture.java new file mode 100644 index 000000000..eb1ef4f78 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/category/infrastructure/persistence/fixture/CategoryRepositoryFixture.java @@ -0,0 +1,40 @@ +package com.ddang.ddang.category.infrastructure.persistence.fixture; + +import com.ddang.ddang.category.domain.Category; +import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +@SuppressWarnings("NonAsciiCharacters") +public class CategoryRepositoryFixture { + + @PersistenceContext + private EntityManager em; + + @Autowired + private JpaCategoryRepository categoryRepository; + + protected Category 가구_카테고리; + protected Category 전자기기_카테고리; + protected Category 가구_서브_의자_카테고리; + protected Category 가구_서브_책상_카테고리; + + @BeforeEach + void setUp() { + 가구_카테고리 = new Category("가구"); + 전자기기_카테고리 = new Category("전자기기"); + 가구_서브_의자_카테고리 = new Category("의자"); + 가구_서브_책상_카테고리 = new Category("책상"); + + 가구_카테고리.addSubCategory(가구_서브_의자_카테고리); + 가구_카테고리.addSubCategory(가구_서브_책상_카테고리); + + categoryRepository.save(가구_카테고리); + categoryRepository.save(전자기기_카테고리); + + em.flush(); + em.clear(); + } +} From 3160e7d2bc3a6bafff0f10bbfecd3b7d0737597e Mon Sep 17 00:00:00 2001 From: apptie <57691173+apptie@users.noreply.github.com> Date: Sat, 14 Oct 2023 15:16:00 +0900 Subject: [PATCH 15/37] =?UTF-8?q?refactor:=20#645=20Authentication=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EC=9D=B8=ED=94=84=EB=9D=BC=20=EB=A6=AC?= =?UTF-8?q?=ED=8E=99=ED=86=A0=EB=A7=81=20(#647)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test: 누락된 테스트 케이스 추가 * feat: 도메인 영역의 Repository 추가 * feat: 도메인 영역의 Repository 구현체 추가 * refactor: Service에서 도메인 영역의 Repository를 사용하도록 변경 * test: when & then 주석 추가 * test: BlackListToken의 도메인 인터페이스 Fixture에서 구체적인 인프라 구현 방식을 알지 못하도록 변경 * test: fixture 메서드 네이밍 변경 --- .../application/BlackListTokenService.java | 4 +- .../repository/BlackListTokenRepository.java | 14 ++++ .../BlackListTokenRepositoryImpl.java | 30 ++++++++ .../fixture/BlackListTokenServiceFixture.java | 4 +- .../domain/BlackListTokenTest.java | 1 + .../BlackListTokenRepositoryImplTest.java | 70 +++++++++++++++++++ .../JpaBlackListTokenRepositoryTest.java | 12 +++- .../BlackListTokenRepositoryFixture.java | 30 ++++++++ .../JpaBlackListTokenRepositoryFixture.java | 3 +- 9 files changed, 162 insertions(+), 6 deletions(-) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/authentication/domain/repository/BlackListTokenRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/authentication/infrastructure/persistence/BlackListTokenRepositoryImpl.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/authentication/infrastructure/persistence/BlackListTokenRepositoryImplTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/authentication/infrastructure/persistence/fixture/BlackListTokenRepositoryFixture.java diff --git a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/BlackListTokenService.java b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/BlackListTokenService.java index ac271a1a5..30c6c0386 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/BlackListTokenService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/BlackListTokenService.java @@ -4,7 +4,7 @@ import com.ddang.ddang.authentication.domain.TokenDecoder; import com.ddang.ddang.authentication.domain.TokenType; import com.ddang.ddang.authentication.domain.exception.EmptyTokenException; -import com.ddang.ddang.authentication.infrastructure.persistence.JpaBlackListTokenRepository; +import com.ddang.ddang.authentication.domain.repository.BlackListTokenRepository; import java.util.ArrayList; import java.util.List; import lombok.RequiredArgsConstructor; @@ -16,7 +16,7 @@ @Transactional(readOnly = true) public class BlackListTokenService { - private final JpaBlackListTokenRepository blackListTokenRepository; + private final BlackListTokenRepository blackListTokenRepository; private final TokenDecoder tokenDecoder; @Transactional diff --git a/backend/ddang/src/main/java/com/ddang/ddang/authentication/domain/repository/BlackListTokenRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/authentication/domain/repository/BlackListTokenRepository.java new file mode 100644 index 000000000..1c7039fff --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/authentication/domain/repository/BlackListTokenRepository.java @@ -0,0 +1,14 @@ +package com.ddang.ddang.authentication.domain.repository; + +import com.ddang.ddang.authentication.domain.BlackListToken; +import com.ddang.ddang.authentication.domain.TokenType; +import java.util.List; + +public interface BlackListTokenRepository { + + BlackListToken save(final BlackListToken blackListToken); + + List saveAll(final List blackListTokens); + + boolean existsByTokenTypeAndToken(final TokenType tokenType, final String accessToken); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/authentication/infrastructure/persistence/BlackListTokenRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/authentication/infrastructure/persistence/BlackListTokenRepositoryImpl.java new file mode 100644 index 000000000..8e8d5c88a --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/authentication/infrastructure/persistence/BlackListTokenRepositoryImpl.java @@ -0,0 +1,30 @@ +package com.ddang.ddang.authentication.infrastructure.persistence; + +import com.ddang.ddang.authentication.domain.BlackListToken; +import com.ddang.ddang.authentication.domain.TokenType; +import com.ddang.ddang.authentication.domain.repository.BlackListTokenRepository; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class BlackListTokenRepositoryImpl implements BlackListTokenRepository { + + private final JpaBlackListTokenRepository jpaBlackListTokenRepository; + + @Override + public BlackListToken save(final BlackListToken blackListToken) { + return jpaBlackListTokenRepository.save(blackListToken); + } + + @Override + public List saveAll(final List blackListTokens) { + return jpaBlackListTokenRepository.saveAll(blackListTokens); + } + + @Override + public boolean existsByTokenTypeAndToken(final TokenType tokenType, final String accessToken) { + return jpaBlackListTokenRepository.existsByTokenTypeAndToken(tokenType, accessToken); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/BlackListTokenServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/BlackListTokenServiceFixture.java index 1e9b09bbf..9ee03c94c 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/BlackListTokenServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/BlackListTokenServiceFixture.java @@ -3,7 +3,7 @@ import com.ddang.ddang.authentication.domain.BlackListToken; import com.ddang.ddang.authentication.domain.TokenEncoder; import com.ddang.ddang.authentication.domain.TokenType; -import com.ddang.ddang.authentication.infrastructure.persistence.JpaBlackListTokenRepository; +import com.ddang.ddang.authentication.domain.repository.BlackListTokenRepository; import java.time.LocalDateTime; import java.util.Map; import org.junit.jupiter.api.BeforeEach; @@ -13,7 +13,7 @@ public class BlackListTokenServiceFixture { @Autowired - private JpaBlackListTokenRepository blackListTokenRepository; + private BlackListTokenRepository blackListTokenRepository; @Autowired private TokenEncoder tokenEncoder; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/domain/BlackListTokenTest.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/domain/BlackListTokenTest.java index 6ce7563b7..7ffb5b945 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/domain/BlackListTokenTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/domain/BlackListTokenTest.java @@ -16,6 +16,7 @@ class BlackListTokenTest { @Test void 생성자에_유효한_토큰을_전달하면_BlackListToken을_반환한다() { + // when & then assertDoesNotThrow(() -> new BlackListToken(TokenType.ACCESS, "accessToken")); } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/infrastructure/persistence/BlackListTokenRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/infrastructure/persistence/BlackListTokenRepositoryImplTest.java new file mode 100644 index 000000000..2fb557928 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/infrastructure/persistence/BlackListTokenRepositoryImplTest.java @@ -0,0 +1,70 @@ +package com.ddang.ddang.authentication.infrastructure.persistence; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ddang.ddang.authentication.domain.BlackListToken; +import com.ddang.ddang.authentication.domain.TokenType; +import com.ddang.ddang.authentication.domain.repository.BlackListTokenRepository; +import com.ddang.ddang.authentication.infrastructure.persistence.fixture.BlackListTokenRepositoryFixture; +import com.ddang.ddang.configuration.JpaConfiguration; +import com.ddang.ddang.configuration.QuerydslConfiguration; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +@DataJpaTest +@Import({JpaConfiguration.class, QuerydslConfiguration.class}) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class BlackListTokenRepositoryImplTest extends BlackListTokenRepositoryFixture { + + BlackListTokenRepository blackListTokenRepository; + + @BeforeEach + void setUp(@Autowired JpaBlackListTokenRepository jpaBlackListTokenRepository) { + blackListTokenRepository = new BlackListTokenRepositoryImpl(jpaBlackListTokenRepository); + } + + @Test + void BlackListToken_엔티티를_저장한다() { + // when + final BlackListToken actual = blackListTokenRepository.save(만료할_토큰1); + + // then + assertThat(actual.getId()).isPositive(); + } + + @Test + void BlackListToken_엔티티_여러개를_저장한다() { + // when + final List actual = blackListTokenRepository.saveAll(List.of(만료할_토큰1, 만료할_토큰2)); + + // then + assertThat(actual).hasSize(2); + } + + @Test + void 블랙리스트로_등록된_토큰인지_확인할때_이미_블랙리스트로_등록된_토큰을_전달하면_참을_반환한다() { + // when + final boolean actual = blackListTokenRepository + .existsByTokenTypeAndToken(TokenType.ACCESS, 만료_토큰_내용); + + // then + assertThat(actual).isTrue(); + } + + @Test + void 블랙리스트로_등록된_토큰인지_확인할때_블랙리스트로_등록되지_않은_토큰을_전달하면_거짓을_반환한다() { + // when + final boolean actual = blackListTokenRepository + .existsByTokenTypeAndToken(TokenType.ACCESS, 만료되지_않은_토큰_내용); + + // then + assertThat(actual).isFalse(); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/infrastructure/persistence/JpaBlackListTokenRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/infrastructure/persistence/JpaBlackListTokenRepositoryTest.java index 8633ce4a5..6e6e26145 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/infrastructure/persistence/JpaBlackListTokenRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/infrastructure/persistence/JpaBlackListTokenRepositoryTest.java @@ -7,6 +7,7 @@ import com.ddang.ddang.authentication.infrastructure.persistence.fixture.JpaBlackListTokenRepositoryFixture; import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; +import java.util.List; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; @@ -26,12 +27,21 @@ class JpaBlackListTokenRepositoryTest extends JpaBlackListTokenRepositoryFixture @Test void BlackListToken_엔티티를_저장한다() { // when - final BlackListToken actual = blackListTokenRepository.save(만료할_토큰); + final BlackListToken actual = blackListTokenRepository.save(만료할_토큰1); // then assertThat(actual.getId()).isPositive(); } + @Test + void BlackListToken_엔티티_여러개를_저장한다() { + // when + final List actual = blackListTokenRepository.saveAll(List.of(만료할_토큰1, 만료할_토큰2)); + + // then + assertThat(actual).hasSize(2); + } + @Test void 블랙리스트로_등록된_토큰인지_확인할때_이미_블랙리스트로_등록된_토큰을_전달하면_참을_반환한다() { // when diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/infrastructure/persistence/fixture/BlackListTokenRepositoryFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/infrastructure/persistence/fixture/BlackListTokenRepositoryFixture.java new file mode 100644 index 000000000..d59bebcd3 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/infrastructure/persistence/fixture/BlackListTokenRepositoryFixture.java @@ -0,0 +1,30 @@ +package com.ddang.ddang.authentication.infrastructure.persistence.fixture; + +import com.ddang.ddang.authentication.domain.BlackListToken; +import com.ddang.ddang.authentication.domain.TokenType; +import com.ddang.ddang.authentication.domain.repository.BlackListTokenRepository; +import com.ddang.ddang.authentication.infrastructure.persistence.BlackListTokenRepositoryImpl; +import com.ddang.ddang.authentication.infrastructure.persistence.JpaBlackListTokenRepository; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +@SuppressWarnings("NonAsciiCharacters") +public class BlackListTokenRepositoryFixture { + + @Autowired + private JpaBlackListTokenRepository jpaBlackListTokenRepository; + + protected String 만료_토큰_내용 = "expired token"; + protected String 만료되지_않은_토큰_내용 = "not expired token"; + protected BlackListToken 만료할_토큰1 = new BlackListToken(TokenType.ACCESS, 만료되지_않은_토큰_내용); + protected BlackListToken 만료할_토큰2 = new BlackListToken(TokenType.ACCESS, 만료되지_않은_토큰_내용); + protected BlackListToken 만료된_토큰 = new BlackListToken(TokenType.ACCESS, 만료_토큰_내용); + + @BeforeEach + void fixtureSetUp() { + final BlackListTokenRepository blackListTokenRepository = + new BlackListTokenRepositoryImpl(jpaBlackListTokenRepository); + + blackListTokenRepository.save(만료된_토큰); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/infrastructure/persistence/fixture/JpaBlackListTokenRepositoryFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/infrastructure/persistence/fixture/JpaBlackListTokenRepositoryFixture.java index 3ea72710a..99a6965df 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/infrastructure/persistence/fixture/JpaBlackListTokenRepositoryFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/infrastructure/persistence/fixture/JpaBlackListTokenRepositoryFixture.java @@ -19,7 +19,8 @@ public class JpaBlackListTokenRepositoryFixture { protected String 만료_토큰_내용 = "expired token"; protected String 만료되지_않은_토큰_내용 = "not expired token"; - protected BlackListToken 만료할_토큰 = new BlackListToken(TokenType.ACCESS, 만료되지_않은_토큰_내용); + protected BlackListToken 만료할_토큰1 = new BlackListToken(TokenType.ACCESS, 만료되지_않은_토큰_내용); + protected BlackListToken 만료할_토큰2 = new BlackListToken(TokenType.ACCESS, 만료되지_않은_토큰_내용); protected BlackListToken 만료된_토큰 = new BlackListToken(TokenType.ACCESS, 만료_토큰_내용); @BeforeEach From 455e3ab140b81a0e4fa83279614c28670b6d397e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=EC=98=88=EC=A7=84?= <96688810+kwonyj1022@users.noreply.github.com> Date: Sat, 14 Oct 2023 23:30:42 +0900 Subject: [PATCH 16/37] =?UTF-8?q?refactor:=20#655=20User=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=9D=B8=ED=94=84=EB=9D=BC=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81=20(#661)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 도메인 영역의 사용자 Repository 추가 * feat: 도메인 영역의 사용자 Repository 구현체 추가 * test: 누락된 테스트 케이스 추가 * refactor: Service에서 도메인 영역의 사용자 Repository를 사용하도록 변경 * refactor: id로 사용자 조회 시 삭제된 값은 조회하지 않도록 수정 * feat: 도메인 영역의 사용자 신뢰도 Repository 추가 * feat: 도메인 영역의 사용자 신뢰도 Repository 구현체 추가 * test: 누락된 테스트 케이스 추가 * refactor: Service에서 도메인 영역의 사용자 신뢰도 Repository를 사용하도록 변경 * refactor: 사용자 신뢰도 조회 시 사용자도 함께 조회되도록 수정 * fix: 사용자 레포지토리 구현체에서 잘못된 메서드를 호출해서 테스트를 실패하는 현상 해결 * test: 테스트 실패 해결 * refactor: 사용자 신뢰도 엔티티에서 cascade 옵션 수정 * feat: 도메인 영역의 신뢰도 업데이트 기록 Repository 추가 * feat: 도메인 영역의 신뢰도 업데이트 기록 Repository 구현체 추가 * test: 누락된 테스트 케이스 추가 * refactor: Service에서 도메인 영역의 신뢰도 업데이트 기록 Repository를 사용하도록 변경 * refactor: 픽스처에서 Jpa 사용자 Repository 의존 제거 * refactor: 픽스처에서 Jpa 사용자 신뢰도 Repository 의존 제거 * refactor: 픽스처에서 Jpa 신뢰도 업데이트 기록 Repository 의존 제거 * style: 개행 추가 * refactor: 누락된 final 추가 * test: jpa 저장 테스트 시 불필요한 엔티티 매니저 호출 제거 * refactor: 누락된 final 추가 * refactor: RepositoryImpl 테스트에서 Jpa 의존 제거 --- .../auction/application/AuctionService.java | 9 +- .../application/AuthenticationService.java | 17 +-- .../AuthenticationUserService.java | 4 +- .../ddang/bid/application/BidService.java | 11 +- .../chat/application/ChatRoomService.java | 9 +- .../chat/application/MessageService.java | 4 +- .../InitializationUserConfiguration.java | 4 +- .../application/DeviceTokenService.java | 4 +- .../ddang/qna/application/AnswerService.java | 6 +- .../qna/application/QuestionService.java | 13 +- .../application/AnswerReportService.java | 6 +- .../application/AuctionReportService.java | 7 +- .../application/ChatRoomReportService.java | 4 +- .../application/QuestionReportService.java | 10 +- .../review/application/ReviewService.java | 9 +- .../ddang/user/application/UserService.java | 6 +- .../ReliabilityUpdateSchedulingService.java | 8 +- .../ddang/user/domain/UserReliability.java | 3 +- .../ReliabilityUpdateHistoryRepository.java | 12 ++ .../repository/UserReliabilityRepository.java | 12 ++ .../domain/repository/UserRepository.java | 20 +++ .../JpaUserReliabilityRepository.java | 7 + .../persistence/JpaUserRepository.java | 11 +- ...eliabilityUpdateHistoryRepositoryImpl.java | 25 ++++ .../UserReliabilityRepositoryImpl.java | 25 ++++ .../persistence/UserRepositoryImpl.java | 45 ++++++ .../fixture/AuctionServiceFixture.java | 22 +-- .../fixture/AuctionRepositoryImplFixture.java | 27 ++-- .../AuthenticationServiceTest.java | 14 +- .../fixture/AuthenticationServiceFixture.java | 4 +- .../AuthenticationUserServiceFixture.java | 4 +- .../fixture/BidServiceFixture.java | 14 +- .../fixture/ChatRoomServiceFixture.java | 16 ++- .../fixture/MessageServiceFixture.java | 13 +- .../fixture/DeviceTokenServiceFixture.java | 31 +++-- .../FcmNotificationServiceFixture.java | 9 +- .../NotificationEventListenerFixture.java | 9 +- .../fixture/AnswerServiceFixture.java | 14 +- .../fixture/QuestionServiceFixture.java | 14 +- .../fixture/AnswerReportServiceFixture.java | 18 ++- .../fixture/AuctionReportServiceFixture.java | 32 +++-- .../fixture/ChatRoomReportServiceFixture.java | 16 ++- .../fixture/QuestionReportServiceFixture.java | 17 ++- .../fixture/ReviewServiceFixture.java | 10 +- .../fixture/UserServiceFixture.java | 4 +- ...eliabilityUpdateSchedulingServiceTest.java | 8 +- ...abilityUpdateSchedulingServiceFixture.java | 35 ++--- ...eliabilityUpdateHistoryRepositoryTest.java | 20 +-- .../JpaUserReliabilityRepositoryTest.java | 9 ++ .../persistence/JpaUserRepositoryTest.java | 43 +++--- ...bilityUpdateHistoryRepositoryImplTest.java | 70 ++++++++++ .../UserReliabilityRepositoryImplTest.java | 50 +++++++ .../persistence/UserRepositoryImplTest.java | 131 ++++++++++++++++++ .../JpaUserReliabilityRepositoryFixture.java | 3 + .../UserReliabilityRepositoryImplFixture.java | 47 +++++++ .../fixture/UserRepositoryImplFixture.java | 50 +++++++ 56 files changed, 811 insertions(+), 234 deletions(-) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/user/domain/repository/ReliabilityUpdateHistoryRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/user/domain/repository/UserReliabilityRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/user/domain/repository/UserRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/ReliabilityUpdateHistoryRepositoryImpl.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/UserReliabilityRepositoryImpl.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/UserRepositoryImpl.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/ReliabilityUpdateHistoryRepositoryImplTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/UserReliabilityRepositoryImplTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/UserRepositoryImplTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/UserReliabilityRepositoryImplFixture.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/UserRepositoryImplFixture.java diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/application/AuctionService.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/application/AuctionService.java index b0167416c..40d66f714 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/application/AuctionService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/application/AuctionService.java @@ -21,21 +21,22 @@ import com.ddang.ddang.region.infrastructure.persistence.JpaRegionRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import java.time.LocalDateTime; -import java.util.List; +import com.ddang.ddang.user.domain.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; +import java.util.List; + @Service @Transactional(readOnly = true) @RequiredArgsConstructor public class AuctionService { - private final JpaUserRepository userRepository; + private final UserRepository userRepository; private final AuctionRepository auctionRepository; private final JpaRegionRepository regionRepository; private final CategoryRepository categoryRepository; diff --git a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java index ec0ee41f9..9656de5e3 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java @@ -1,7 +1,5 @@ package com.ddang.ddang.authentication.application; -import static com.ddang.ddang.image.domain.ProfileImage.DEFAULT_PROFILE_IMAGE_STORE_NAME; - import com.ddang.ddang.authentication.application.dto.LoginInformationDto; import com.ddang.ddang.authentication.application.dto.LoginUserInformationDto; import com.ddang.ddang.authentication.application.dto.TokenDto; @@ -24,14 +22,17 @@ import com.ddang.ddang.image.infrastructure.persistence.JpaProfileImageRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import java.time.LocalDateTime; -import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; +import com.ddang.ddang.user.domain.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import static com.ddang.ddang.image.domain.ProfileImage.DEFAULT_PROFILE_IMAGE_STORE_NAME; + @Service @Transactional(readOnly = true) @RequiredArgsConstructor @@ -41,7 +42,7 @@ public class AuthenticationService { private final DeviceTokenService deviceTokenService; private final Oauth2UserInformationProviderComposite providerComposite; - private final JpaUserRepository userRepository; + private final UserRepository userRepository; private final JpaProfileImageRepository profileImageRepository; private final TokenEncoder tokenEncoder; private final TokenDecoder tokenDecoder; @@ -162,7 +163,7 @@ public void withdrawal( .orElseThrow(() -> new InvalidTokenException("유효한 토큰이 아닙니다.") ); - final User user = userRepository.findByIdAndDeletedIsFalse(privateClaims.userId()) + final User user = userRepository.findById(privateClaims.userId()) .orElseThrow(() -> new InvalidWithdrawalException("탈퇴에 대한 권한이 없습니다.")); final OAuth2UserInformationProvider provider = providerComposite.findProvider(user.getOauthInformation() .getOauth2Type()); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationUserService.java b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationUserService.java index 69486e4bd..0ffa6dd82 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationUserService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationUserService.java @@ -1,6 +1,6 @@ package com.ddang.ddang.authentication.application; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.domain.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -10,7 +10,7 @@ @Transactional(readOnly = true) public class AuthenticationUserService { - private final JpaUserRepository userRepository; + private final UserRepository userRepository; public boolean isWithdrawal(final Long userId) { return userRepository.existsByIdAndDeletedIsTrue(userId); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/bid/application/BidService.java b/backend/ddang/src/main/java/com/ddang/ddang/bid/application/BidService.java index 10a4c5f61..5920d13ac 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/bid/application/BidService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/bid/application/BidService.java @@ -17,15 +17,16 @@ import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import java.time.LocalDateTime; -import java.util.List; -import java.util.Optional; +import com.ddang.ddang.user.domain.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; + @Service @Transactional(readOnly = true) @RequiredArgsConstructor @@ -34,7 +35,7 @@ public class BidService { private final ApplicationEventPublisher bidEventPublisher; private final AuctionRepository auctionRepository; private final AuctionAndImageRepository auctionAndImageRepository; - private final JpaUserRepository userRepository; + private final UserRepository userRepository; private final JpaBidRepository bidRepository; @Transactional diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java index db764208d..14aa6f786 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java @@ -20,13 +20,14 @@ import com.ddang.ddang.chat.infrastructure.persistence.dto.ChatRoomAndMessageAndImageDto; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import java.time.LocalDateTime; -import java.util.List; +import com.ddang.ddang.user.domain.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; +import java.util.List; + @Service @Transactional(readOnly = true) @RequiredArgsConstructor @@ -37,7 +38,7 @@ public class ChatRoomService { private final JpaChatRoomRepository chatRoomRepository; private final QuerydslChatRoomAndImageRepositoryImpl querydslChatRoomAndImageRepository; private final QuerydslChatRoomAndMessageAndImageRepository querydslChatRoomAndMessageAndImageRepository; - private final JpaUserRepository userRepository; + private final UserRepository userRepository; private final AuctionRepository auctionRepository; @Transactional diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java index 3654953eb..280c93ece 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java @@ -13,7 +13,7 @@ import com.ddang.ddang.chat.presentation.dto.request.ReadMessageRequest; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.domain.repository.UserRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.context.ApplicationEventPublisher; @@ -31,7 +31,7 @@ public class MessageService { private final ApplicationEventPublisher messageEventPublisher; private final JpaMessageRepository messageRepository; private final JpaChatRoomRepository chatRoomRepository; - private final JpaUserRepository userRepository; + private final UserRepository userRepository; @Transactional public Long create(final CreateMessageDto dto, final String profileImageAbsoluteUrl) { diff --git a/backend/ddang/src/main/java/com/ddang/ddang/configuration/initialization/InitializationUserConfiguration.java b/backend/ddang/src/main/java/com/ddang/ddang/configuration/initialization/InitializationUserConfiguration.java index eca2b6d86..f89bfc8ce 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/configuration/initialization/InitializationUserConfiguration.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/configuration/initialization/InitializationUserConfiguration.java @@ -3,7 +3,7 @@ import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.domain.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; @@ -16,7 +16,7 @@ @RequiredArgsConstructor public class InitializationUserConfiguration implements ApplicationRunner { - private final JpaUserRepository userRepository; + private final UserRepository userRepository; @Override @Transactional diff --git a/backend/ddang/src/main/java/com/ddang/ddang/device/application/DeviceTokenService.java b/backend/ddang/src/main/java/com/ddang/ddang/device/application/DeviceTokenService.java index 47ca28e74..0733c5731 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/device/application/DeviceTokenService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/device/application/DeviceTokenService.java @@ -5,7 +5,7 @@ import com.ddang.ddang.device.infrastructure.persistence.JpaDeviceTokenRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.domain.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -16,7 +16,7 @@ public class DeviceTokenService { private final JpaDeviceTokenRepository deviceTokenRepository; - private final JpaUserRepository userRepository; + private final UserRepository userRepository; @Transactional public void persist(final Long userId, final PersistDeviceTokenDto deviceTokenDto) { diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/AnswerService.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/AnswerService.java index df662f456..2ef0967d4 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/AnswerService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/AnswerService.java @@ -13,7 +13,7 @@ import com.ddang.ddang.qna.infrastructure.JpaQuestionRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.domain.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; @@ -25,7 +25,7 @@ public class AnswerService { private final ApplicationEventPublisher answerEventPublisher; - private final JpaUserRepository userRepository; + private final UserRepository userRepository; private final JpaQuestionRepository questionRepository; private final JpaAnswerRepository answerRepository; @@ -67,7 +67,7 @@ private void checkAlreadyAnswered(final Question question) { public void deleteById(final Long answerId, final Long userId) { final Answer answer = answerRepository.findByIdAndDeletedIsFalse(answerId) .orElseThrow(() -> new AnswerNotFoundException("해당 답변을 찾을 수 없습니다.")); - final User user = userRepository.findByIdAndDeletedIsFalse(userId) + final User user = userRepository.findById(userId) .orElseThrow(() -> new UserNotFoundException("해당 사용자를 찾을 수 없습니다.")); if (!answer.isWriter(user)) { diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java index 611047750..3eedae7b3 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java @@ -14,14 +14,15 @@ import com.ddang.ddang.qna.infrastructure.JpaQuestionRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import java.time.LocalDateTime; -import java.util.List; +import com.ddang.ddang.user.domain.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; +import java.util.List; + @Service @Transactional(readOnly = true) @RequiredArgsConstructor @@ -29,12 +30,12 @@ public class QuestionService { private final ApplicationEventPublisher questionEventPublisher; private final AuctionRepository auctionRepository; - private final JpaUserRepository userRepository; + private final UserRepository userRepository; private final JpaQuestionRepository questionRepository; @Transactional public Long create(final CreateQuestionDto questionDto, final String absoluteImageUrl) { - final User questioner = userRepository.findByIdAndDeletedIsFalse(questionDto.userId()) + final User questioner = userRepository.findById(questionDto.userId()) .orElseThrow(() -> new UserNotFoundException("해당 사용자를 찾을 수 없습니다.")); final Auction auction = auctionRepository.findPureAuctionById(questionDto.auctionId()) .orElseThrow(() -> new AuctionNotFoundException("해당 경매를 찾을 수 없습니다.")); @@ -77,7 +78,7 @@ public ReadQnasDto readAllByAuctionId(final Long auctionId) { public void deleteById(final Long questionId, final Long userId) { final Question question = questionRepository.findById(questionId) .orElseThrow(() -> new QuestionNotFoundException("해당 질문을 찾을 수 없습니다.")); - final User user = userRepository.findByIdAndDeletedIsFalse(userId) + final User user = userRepository.findById(userId) .orElseThrow(() -> new UserNotFoundException("해당 사용자를 찾을 수 없습니다.")); if (!question.isWriter(user)) { diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/application/AnswerReportService.java b/backend/ddang/src/main/java/com/ddang/ddang/report/application/AnswerReportService.java index ff402f96b..c2151c209 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/report/application/AnswerReportService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/application/AnswerReportService.java @@ -10,7 +10,7 @@ import com.ddang.ddang.report.infrastructure.persistence.JpaAnswerReportRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.domain.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -23,7 +23,7 @@ public class AnswerReportService { private final JpaAnswerRepository answerRepository; - private final JpaUserRepository userRepository; + private final UserRepository userRepository; private final JpaAnswerReportRepository answerReportRepository; @Transactional @@ -32,7 +32,7 @@ public Long create(final CreateAnswerReportDto answerReportDto) { .orElseThrow(() -> new AnswerNotFoundException("해당 답변을 찾을 수 없습니다.") ); - final User reporter = userRepository.findByIdAndDeletedIsFalse(answerReportDto.reporterId()) + final User reporter = userRepository.findById(answerReportDto.reporterId()) .orElseThrow(() -> new UserNotFoundException("해당 사용자를 찾을 수 없습니다.")); checkInvalidAnswerReport(reporter, answer); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/application/AuctionReportService.java b/backend/ddang/src/main/java/com/ddang/ddang/report/application/AuctionReportService.java index 2c459c74d..4bd7bfffb 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/report/application/AuctionReportService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/application/AuctionReportService.java @@ -11,19 +11,20 @@ import com.ddang.ddang.report.infrastructure.persistence.JpaAuctionReportRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import java.util.List; +import com.ddang.ddang.user.domain.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.List; + @Service @Transactional(readOnly = true) @RequiredArgsConstructor public class AuctionReportService { private final AuctionRepository auctionRepository; - private final JpaUserRepository userRepository; + private final UserRepository userRepository; private final JpaAuctionReportRepository auctionReportRepository; @Transactional diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/application/ChatRoomReportService.java b/backend/ddang/src/main/java/com/ddang/ddang/report/application/ChatRoomReportService.java index 7a3613e79..a7a84acf0 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/report/application/ChatRoomReportService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/application/ChatRoomReportService.java @@ -11,7 +11,7 @@ import com.ddang.ddang.report.infrastructure.persistence.JpaChatRoomReportRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.domain.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -23,7 +23,7 @@ @RequiredArgsConstructor public class ChatRoomReportService { - private final JpaUserRepository userRepository; + private final UserRepository userRepository; private final JpaChatRoomRepository chatRoomRepository; private final JpaChatRoomReportRepository chatRoomReportRepository; diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/application/QuestionReportService.java b/backend/ddang/src/main/java/com/ddang/ddang/report/application/QuestionReportService.java index c99192aff..4c85f2b87 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/report/application/QuestionReportService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/application/QuestionReportService.java @@ -10,7 +10,7 @@ import com.ddang.ddang.report.infrastructure.persistence.JpaQuestionReportRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.domain.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -23,7 +23,7 @@ public class QuestionReportService { private final JpaQuestionRepository questionRepository; - private final JpaUserRepository userRepository; + private final UserRepository userRepository; private final JpaQuestionReportRepository questionReportRepository; @Transactional @@ -32,7 +32,7 @@ public Long create(final CreateQuestionReportDto questionReportDto) { .orElseThrow(() -> new QuestionNotFoundException("해당 질문을 찾을 수 없습니다.") ); - final User reporter = userRepository.findByIdAndDeletedIsFalse(questionReportDto.reporterId()) + final User reporter = userRepository.findById(questionReportDto.reporterId()) .orElseThrow(() -> new UserNotFoundException("해당 사용자를 찾을 수 없습니다.")); checkInvalidQuestionReport(reporter, question); @@ -55,7 +55,7 @@ public List readAll() { final List questionReports = questionReportRepository.findAllByOrderByIdAsc(); return questionReports.stream() - .map(ReadQuestionReportDto::from) - .toList(); + .map(ReadQuestionReportDto::from) + .toList(); } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/review/application/ReviewService.java b/backend/ddang/src/main/java/com/ddang/ddang/review/application/ReviewService.java index 73a686dd9..0b405c60f 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/review/application/ReviewService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/review/application/ReviewService.java @@ -13,13 +13,14 @@ import com.ddang.ddang.review.infrastructure.persistence.JpaReviewRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import java.time.LocalDateTime; -import java.util.List; +import com.ddang.ddang.user.domain.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; +import java.util.List; + @Service @Transactional(readOnly = true) @RequiredArgsConstructor @@ -27,7 +28,7 @@ public class ReviewService { private final JpaReviewRepository reviewRepository; private final AuctionRepository auctionRepository; - private final JpaUserRepository userRepository; + private final UserRepository userRepository; @Transactional public Long create(final CreateReviewDto reviewDto) { diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/application/UserService.java b/backend/ddang/src/main/java/com/ddang/ddang/user/application/UserService.java index 5dc1ca80c..be8daa106 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/user/application/UserService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/application/UserService.java @@ -6,7 +6,7 @@ import com.ddang.ddang.user.application.dto.UpdateUserDto; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.domain.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -16,7 +16,7 @@ @RequiredArgsConstructor public class UserService { - private final JpaUserRepository userRepository; + private final UserRepository userRepository; private final StoreImageProcessor imageProcessor; public ReadUserDto readById(final Long userId) { @@ -28,7 +28,7 @@ public ReadUserDto readById(final Long userId) { @Transactional public ReadUserDto updateById(final Long userId, final UpdateUserDto userDto) { - final User user = userRepository.findByIdAndDeletedIsFalse(userId) + final User user = userRepository.findById(userId) .orElseThrow(() -> new UserNotFoundException("사용자 정보를 사용할 수 없습니다.")); updateUserByRequest(userDto, user); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/application/schedule/ReliabilityUpdateSchedulingService.java b/backend/ddang/src/main/java/com/ddang/ddang/user/application/schedule/ReliabilityUpdateSchedulingService.java index 9b244d0c4..4ffb2d732 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/user/application/schedule/ReliabilityUpdateSchedulingService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/application/schedule/ReliabilityUpdateSchedulingService.java @@ -6,8 +6,8 @@ import com.ddang.ddang.user.domain.ReliabilityUpdateHistory; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.UserReliability; -import com.ddang.ddang.user.infrastructure.persistence.JpaReliabilityUpdateHistoryRepository; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserReliabilityRepository; +import com.ddang.ddang.user.domain.repository.ReliabilityUpdateHistoryRepository; +import com.ddang.ddang.user.domain.repository.UserReliabilityRepository; import lombok.RequiredArgsConstructor; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; @@ -21,9 +21,9 @@ @RequiredArgsConstructor public class ReliabilityUpdateSchedulingService { - private final JpaReliabilityUpdateHistoryRepository updateHistoryRepository; + private final ReliabilityUpdateHistoryRepository updateHistoryRepository; private final JpaReviewRepository reviewRepository; - private final JpaUserReliabilityRepository userReliabilityRepository; + private final UserReliabilityRepository userReliabilityRepository; @Transactional @Scheduled(cron = "0 0 4 ? * MON") diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/UserReliability.java b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/UserReliability.java index c89639d07..107697c4b 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/UserReliability.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/UserReliability.java @@ -2,7 +2,6 @@ import com.ddang.ddang.review.domain.Reviews; import jakarta.persistence.AttributeOverride; -import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Embedded; import jakarta.persistence.Entity; @@ -30,7 +29,7 @@ public class UserReliability { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OneToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.REMOVE}) + @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id", foreignKey = @ForeignKey(name = "fk_user_reliability_user"), nullable = false) private User user; diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/repository/ReliabilityUpdateHistoryRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/repository/ReliabilityUpdateHistoryRepository.java new file mode 100644 index 000000000..1f16b84d8 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/repository/ReliabilityUpdateHistoryRepository.java @@ -0,0 +1,12 @@ +package com.ddang.ddang.user.domain.repository; + +import com.ddang.ddang.user.domain.ReliabilityUpdateHistory; + +import java.util.Optional; + +public interface ReliabilityUpdateHistoryRepository { + + ReliabilityUpdateHistory save(final ReliabilityUpdateHistory reliabilityUpdateHistory); + + Optional findFirstByOrderByIdDesc(); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/repository/UserReliabilityRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/repository/UserReliabilityRepository.java new file mode 100644 index 000000000..03373f6a4 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/repository/UserReliabilityRepository.java @@ -0,0 +1,12 @@ +package com.ddang.ddang.user.domain.repository; + +import com.ddang.ddang.user.domain.UserReliability; + +import java.util.Optional; + +public interface UserReliabilityRepository { + + UserReliability save(final UserReliability userReliability); + + Optional findByUserId(final Long userId); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/repository/UserRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/repository/UserRepository.java new file mode 100644 index 000000000..6fac305ab --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/repository/UserRepository.java @@ -0,0 +1,20 @@ +package com.ddang.ddang.user.domain.repository; + +import com.ddang.ddang.user.domain.User; + +import java.util.Optional; + +public interface UserRepository { + + User save(final User user); + + Optional findById(final Long id); + + boolean existsById(final Long id); + + Optional findByOauthId(final String oauthId); + + boolean existsByIdAndDeletedIsTrue(final Long id); + + boolean existsByNameEndingWith(final String name); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserReliabilityRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserReliabilityRepository.java index 5362ee465..e85346b3a 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserReliabilityRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserReliabilityRepository.java @@ -2,10 +2,17 @@ import com.ddang.ddang.user.domain.UserReliability; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import java.util.Optional; public interface JpaUserReliabilityRepository extends JpaRepository { + @Query(""" + SELECT ur + FROM UserReliability ur + JOIN FETCH ur.user u + WHERE u.id = :userId + """) Optional findByUserId(final Long userId); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepository.java index 81e78042d..1d0b949c7 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepository.java @@ -2,12 +2,19 @@ import com.ddang.ddang.user.domain.User; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import java.util.Optional; -import org.springframework.data.jpa.repository.Query; public interface JpaUserRepository extends JpaRepository { + @Query(""" + SELECT u + FROM User u + WHERE u.deleted = false AND u.id = :id + """) + Optional findById(final Long id); + @Query(""" SELECT u FROM User u @@ -15,8 +22,6 @@ public interface JpaUserRepository extends JpaRepository { """) Optional findByOauthId(final String oauthId); - Optional findByIdAndDeletedIsFalse(final Long id); - boolean existsByIdAndDeletedIsTrue(final Long id); boolean existsByNameEndingWith(final String name); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/ReliabilityUpdateHistoryRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/ReliabilityUpdateHistoryRepositoryImpl.java new file mode 100644 index 000000000..c5427a852 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/ReliabilityUpdateHistoryRepositoryImpl.java @@ -0,0 +1,25 @@ +package com.ddang.ddang.user.infrastructure.persistence; + +import com.ddang.ddang.user.domain.ReliabilityUpdateHistory; +import com.ddang.ddang.user.domain.repository.ReliabilityUpdateHistoryRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +@RequiredArgsConstructor +public class ReliabilityUpdateHistoryRepositoryImpl implements ReliabilityUpdateHistoryRepository { + + private final JpaReliabilityUpdateHistoryRepository jpaReliabilityUpdateHistoryRepository; + + @Override + public ReliabilityUpdateHistory save(final ReliabilityUpdateHistory reliabilityUpdateHistory) { + return jpaReliabilityUpdateHistoryRepository.save(reliabilityUpdateHistory); + } + + @Override + public Optional findFirstByOrderByIdDesc() { + return jpaReliabilityUpdateHistoryRepository.findFirstByOrderByIdDesc(); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/UserReliabilityRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/UserReliabilityRepositoryImpl.java new file mode 100644 index 000000000..e2789739a --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/UserReliabilityRepositoryImpl.java @@ -0,0 +1,25 @@ +package com.ddang.ddang.user.infrastructure.persistence; + +import com.ddang.ddang.user.domain.UserReliability; +import com.ddang.ddang.user.domain.repository.UserReliabilityRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +@RequiredArgsConstructor +public class UserReliabilityRepositoryImpl implements UserReliabilityRepository { + + private final JpaUserReliabilityRepository jpaUserReliabilityRepository; + + @Override + public UserReliability save(final UserReliability userReliability) { + return jpaUserReliabilityRepository.save(userReliability); + } + + @Override + public Optional findByUserId(final Long userId) { + return jpaUserReliabilityRepository.findByUserId(userId); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/UserRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/UserRepositoryImpl.java new file mode 100644 index 000000000..4b0dc0d85 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/UserRepositoryImpl.java @@ -0,0 +1,45 @@ +package com.ddang.ddang.user.infrastructure.persistence; + +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +@RequiredArgsConstructor +public class UserRepositoryImpl implements UserRepository { + + private final JpaUserRepository jpaUserRepository; + + @Override + public User save(final User user) { + return jpaUserRepository.save(user); + } + + @Override + public Optional findById(final Long id) { + return jpaUserRepository.findById(id); + } + + @Override + public boolean existsById(final Long id) { + return jpaUserRepository.existsById(id); + } + + @Override + public Optional findByOauthId(final String oauthId) { + return jpaUserRepository.findByOauthId(oauthId); + } + + @Override + public boolean existsByIdAndDeletedIsTrue(final Long id) { + return jpaUserRepository.existsByIdAndDeletedIsTrue(id); + } + + @Override + public boolean existsByNameEndingWith(final String name) { + return jpaUserRepository.existsByNameEndingWith(name); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/application/fixture/AuctionServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/application/fixture/AuctionServiceFixture.java index 997f4fd45..69f0fb77f 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/application/fixture/AuctionServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/application/fixture/AuctionServiceFixture.java @@ -15,14 +15,15 @@ import com.ddang.ddang.region.infrastructure.persistence.JpaRegionRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import java.time.LocalDateTime; -import java.util.List; +import com.ddang.ddang.user.domain.repository.UserRepository; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.mock.web.MockMultipartFile; +import java.time.LocalDateTime; +import java.util.List; + @SuppressWarnings("NonAsciiCharacters") public class AuctionServiceFixture { @@ -36,7 +37,7 @@ public class AuctionServiceFixture { private JpaCategoryRepository categoryRepository; @Autowired - private JpaUserRepository userRepository; + private UserRepository userRepository; @Autowired private JpaBidRepository bidRepository; @@ -51,11 +52,11 @@ public class AuctionServiceFixture { .oauthId("12345") .build(); protected User 구매자 = User.builder() - .name("구매자") - .profileImage(new ProfileImage("upload.png", "store.png")) - .reliability(new Reliability(4.7d)) - .oauthId("54321") - .build(); + .name("구매자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("54321") + .build(); private MockMultipartFile 경매_이미지_파일 = new MockMultipartFile( "image.png", @@ -102,7 +103,8 @@ void setUp() { categoryRepository.save(가구_카테고리); - userRepository.saveAll(List.of(판매자, 구매자)); + userRepository.save(판매자); + userRepository.save(구매자); 유효한_경매_생성_dto = new CreateAuctionDto( "제목", diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java index 786add227..78ea8a4d7 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java @@ -19,26 +19,27 @@ import com.ddang.ddang.region.infrastructure.persistence.JpaRegionRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.repository.UserRepository; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.infrastructure.persistence.UserRepositoryImpl; import com.querydsl.jpa.impl.JPAQueryFactory; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.List; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; @SuppressWarnings("NonAsciiCharacters") public class AuctionRepositoryImplFixture { - @Autowired - private JpaAuctionRepository jpaAuctionRepository; + private AuctionRepository auctionRepository; @Autowired private JPAQueryFactory queryFactory; - @Autowired - private JpaUserRepository userRepository; + private UserRepository userRepository; @Autowired private JpaRegionRepository regionRepository; @@ -69,7 +70,14 @@ public class AuctionRepositoryImplFixture { protected User 구매자; @BeforeEach - void fixtureSetUp() { + void fixtureSetUp( + @Autowired final JPAQueryFactory jpaQueryFactory, + @Autowired final JpaAuctionRepository jpaAuctionRepository, + @Autowired final JpaUserRepository jpaUserRepository + ) { + auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(jpaQueryFactory)); + userRepository = new UserRepositoryImpl(jpaUserRepository); + final Region 서울특별시 = new Region("서울특별시"); final Region 강남구 = new Region("강남구"); final Region 역삼동 = new Region("역삼동"); @@ -128,11 +136,6 @@ void fixtureSetUp() { bidding(저장된_경매_엔티티, 구매자); addAuctioneerCount(저장된_경매_엔티티, 1); - final AuctionRepository auctionRepository = new AuctionRepositoryImpl( - jpaAuctionRepository, - new QuerydslAuctionRepository(queryFactory) - ); - auctionRepository.save(삭제된_경매_엔티티); auctionRepository.save(저장된_경매_엔티티); } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java index 00c27f910..60af9fddf 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java @@ -1,10 +1,5 @@ package com.ddang.ddang.authentication.application; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.BDDMockito.given; - import com.ddang.ddang.authentication.application.dto.LoginInformationDto; import com.ddang.ddang.authentication.application.dto.TokenDto; import com.ddang.ddang.authentication.application.exception.InvalidWithdrawalException; @@ -20,7 +15,7 @@ import com.ddang.ddang.device.infrastructure.persistence.JpaDeviceTokenRepository; import com.ddang.ddang.image.application.exception.ImageNotFoundException; import com.ddang.ddang.image.infrastructure.persistence.JpaProfileImageRepository; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.domain.repository.UserRepository; import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayNameGeneration; @@ -30,6 +25,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.MockBean; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; + @IsolateDatabase @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @SuppressWarnings("NonAsciiCharacters") @@ -48,7 +48,7 @@ class AuthenticationServiceTest extends AuthenticationServiceFixture { DeviceTokenService deviceTokenService; @Autowired - JpaUserRepository userRepository; + UserRepository userRepository; @Autowired JpaProfileImageRepository profileImageRepository; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java index 7b1b827dd..76e459ef7 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java @@ -11,7 +11,7 @@ import com.ddang.ddang.image.infrastructure.persistence.JpaProfileImageRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.domain.repository.UserRepository; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; @@ -50,7 +50,7 @@ public class AuthenticationServiceFixture { protected String 유효하지_않은_타입의_리프레시_토큰 = "invalidRefreshToken"; @Autowired - private JpaUserRepository userRepository; + private UserRepository userRepository; @Autowired private JpaProfileImageRepository profileImageRepository; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationUserServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationUserServiceFixture.java index b7281f200..ea790c774 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationUserServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationUserServiceFixture.java @@ -3,7 +3,7 @@ import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.domain.repository.UserRepository; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; @@ -11,7 +11,7 @@ public class AuthenticationUserServiceFixture { @Autowired - private JpaUserRepository userRepository; + private UserRepository userRepository; protected User 사용자; protected User 탈퇴한_사용자; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/bid/application/fixture/BidServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/bid/application/fixture/BidServiceFixture.java index 12a35aee0..d0b2d5564 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/bid/application/fixture/BidServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/bid/application/fixture/BidServiceFixture.java @@ -13,17 +13,18 @@ import com.ddang.ddang.notification.domain.NotificationStatus; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import java.time.LocalDateTime; -import java.util.List; +import com.ddang.ddang.user.domain.repository.UserRepository; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; +import java.time.LocalDateTime; +import java.util.List; + @SuppressWarnings("NonAsciiCharacters") public class BidServiceFixture { @Autowired - private JpaUserRepository userRepository; + private UserRepository userRepository; @Autowired private AuctionRepository auctionRepository; @@ -125,7 +126,10 @@ void setUp() { .build(); 삭제된_경매.delete(); - userRepository.saveAll(List.of(판매자, 입찰자1, 입찰자2)); + userRepository.save(판매자); + userRepository.save(입찰자1); + userRepository.save(입찰자2); + 경매1.addAuctionImages(List.of(경매_이미지1)); 경매2.addAuctionImages(List.of(경매_이미지2)); 경매3.addAuctionImages(List.of(경매_이미지3)); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java index 27b3518df..20d20ad91 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java @@ -26,12 +26,13 @@ import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import java.time.LocalDateTime; -import java.util.List; +import com.ddang.ddang.user.domain.repository.UserRepository; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; +import java.time.LocalDateTime; +import java.util.List; + @SuppressWarnings("NonAsciiCharacters") public class ChatRoomServiceFixture { @@ -42,7 +43,7 @@ public class ChatRoomServiceFixture { private JpaCategoryRepository categoryRepository; @Autowired - private JpaUserRepository userRepository; + private UserRepository userRepository; @Autowired private JpaBidRepository bidRepository; @@ -139,7 +140,12 @@ void setUp() { .reliability(new Reliability(4.7d)) .oauthId("12349") .build(); - userRepository.saveAll(List.of(판매자, 구매자, 엔초, 제이미, 지토, 경매에_참여한_적_없는_사용자)); + userRepository.save(판매자); + userRepository.save(구매자); + userRepository.save(엔초); + userRepository.save(제이미); + userRepository.save(지토); + userRepository.save(경매에_참여한_적_없는_사용자); 채팅방이_없는_경매 = Auction.builder() .seller(판매자) diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java index b34e7e247..16a2016ee 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java @@ -15,12 +15,13 @@ import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.domain.repository.UserRepository; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; @SuppressWarnings("NonAsciiCharacters") public class MessageServiceFixture { @@ -32,7 +33,7 @@ public class MessageServiceFixture { private JpaMessageRepository messageRepository; @Autowired - private JpaUserRepository userRepository; + private UserRepository userRepository; @Autowired private JpaChatRoomRepository chatRoomRepository; @@ -90,7 +91,9 @@ void setUp() { .oauthId("12347") .build(); 탈퇴한_사용자.withdrawal(); - userRepository.saveAll(List.of(발신자, 수신자, 탈퇴한_사용자)); + userRepository.save(발신자); + userRepository.save(수신자); + userRepository.save(탈퇴한_사용자); final ChatRoom 채팅방 = new ChatRoom(경매, 발신자); final ChatRoom 탈퇴한_사용자와의_채팅방 = new ChatRoom(경매, 탈퇴한_사용자); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/device/application/fixture/DeviceTokenServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/device/application/fixture/DeviceTokenServiceFixture.java index 0006789d2..243208fc7 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/device/application/fixture/DeviceTokenServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/device/application/fixture/DeviceTokenServiceFixture.java @@ -6,12 +6,10 @@ import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.domain.repository.UserRepository; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; -import java.util.List; - @SuppressWarnings("NonAsciiCharacters") public class DeviceTokenServiceFixture { @@ -19,7 +17,7 @@ public class DeviceTokenServiceFixture { private JpaDeviceTokenRepository deviceTokenRepository; @Autowired - private JpaUserRepository userRepository; + private UserRepository userRepository; private String 초기_디바이스_토큰_값 = "initialDeviceToken"; private DeviceToken 사용자의_디바이스_토큰; @@ -35,19 +33,22 @@ public class DeviceTokenServiceFixture { @BeforeEach void setUp() { 디바이스_토큰이_있는_사용자 = User.builder() - .name("디바이스 토큰이 있는 사용자") - .profileImage(new ProfileImage("upload.png", "store.png")) - .reliability(new Reliability(4.7d)) - .oauthId("12345") - .build(); + .name("디바이스 토큰이 있는 사용자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); 디바이스_토큰이_없는_사용자 = User.builder() - .name("디바이스 토큰이 없는 사용자") - .profileImage(new ProfileImage("upload.png", "store.png")) - .reliability(new Reliability(4.7d)) - .oauthId("12346") - .build(); + .name("디바이스 토큰이 없는 사용자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12346") + .build(); 사용자의_디바이스_토큰 = new DeviceToken(디바이스_토큰이_있는_사용자, 사용_중인_디바이스_토큰_값); - userRepository.saveAll(List.of(디바이스_토큰이_있는_사용자, 디바이스_토큰이_없는_사용자)); + + userRepository.save(디바이스_토큰이_있는_사용자); + userRepository.save(디바이스_토큰이_없는_사용자); + deviceTokenRepository.save(사용자의_디바이스_토큰); 디바이스_토큰_저장을_위한_DTO = new PersistDeviceTokenDto(초기_디바이스_토큰_값); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java index d5b91d5d4..1850fa822 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java @@ -20,17 +20,18 @@ import com.ddang.ddang.notification.domain.NotificationType; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import java.time.LocalDateTime; -import java.util.List; +import com.ddang.ddang.user.domain.repository.UserRepository; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; +import java.time.LocalDateTime; +import java.util.List; + @SuppressWarnings("NonAsciiCharacters") public class FcmNotificationServiceFixture { @Autowired - private JpaUserRepository userRepository; + private UserRepository userRepository; @Autowired private JpaMessageRepository messageRepository; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java index 997c4f7cd..b1a1db5d7 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java @@ -26,17 +26,18 @@ import com.ddang.ddang.qna.domain.Question; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import java.time.LocalDateTime; -import java.util.List; +import com.ddang.ddang.user.domain.repository.UserRepository; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; +import java.time.LocalDateTime; +import java.util.List; + @SuppressWarnings("NonAsciiCharacters") public class NotificationEventListenerFixture { @Autowired - private JpaUserRepository userRepository; + private UserRepository userRepository; @Autowired private JpaChatRoomRepository chatRoomRepository; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/AnswerServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/AnswerServiceFixture.java index 987b82e7f..0cb19e684 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/AnswerServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/AnswerServiceFixture.java @@ -12,12 +12,13 @@ import com.ddang.ddang.qna.infrastructure.JpaQuestionRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import java.time.LocalDateTime; -import java.util.List; +import com.ddang.ddang.user.domain.repository.UserRepository; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; +import java.time.LocalDateTime; +import java.util.List; + @SuppressWarnings("NonAsciiCharacters") public class AnswerServiceFixture { @@ -25,7 +26,7 @@ public class AnswerServiceFixture { private AuctionRepository auctionRepository; @Autowired - private JpaUserRepository userRepository; + private UserRepository userRepository; @Autowired private JpaQuestionRepository questionRepository; @@ -81,7 +82,10 @@ void setUp() { 답변 = new Answer("답변드립니다."); 답변한_질문.addAnswer(답변); - userRepository.saveAll(List.of(판매자, 질문자, 판매자가_아닌_사용자)); + userRepository.save(판매자); + userRepository.save(질문자); + userRepository.save(판매자가_아닌_사용자); + auctionRepository.save(경매); questionRepository.saveAll(List.of(질문, 답변한_질문)); answerRepository.save(답변); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java index ae97d5d1b..37e4d8019 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java @@ -19,17 +19,18 @@ import com.ddang.ddang.region.infrastructure.persistence.JpaRegionRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import java.time.LocalDateTime; -import java.util.List; +import com.ddang.ddang.user.domain.repository.UserRepository; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; +import java.time.LocalDateTime; +import java.util.List; + @SuppressWarnings("NonAsciiCharacters") public class QuestionServiceFixture { @Autowired - private JpaUserRepository userRepository; + private UserRepository userRepository; @Autowired private AuctionRepository auctionRepository; @@ -149,7 +150,10 @@ void setUp() { 질문.addAnswer(답변1); 질문2.addAnswer(답변2); - userRepository.saveAll(List.of(판매자, 질문자, 질문하지_않은_사용자)); + userRepository.save(판매자); + userRepository.save(질문자); + userRepository.save(질문하지_않은_사용자); + auctionRepository.save(경매); auctionRepository.save(질문과_답변이_존재하는_경매); auctionRepository.save(종료된_경매); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AnswerReportServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AnswerReportServiceFixture.java index 1c775c4b1..9e067fed2 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AnswerReportServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AnswerReportServiceFixture.java @@ -17,12 +17,13 @@ import com.ddang.ddang.report.infrastructure.persistence.JpaAnswerReportRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import java.time.LocalDateTime; -import java.util.List; +import com.ddang.ddang.user.domain.repository.UserRepository; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; +import java.time.LocalDateTime; +import java.util.List; + @SuppressWarnings("NonAsciiCharacters") public class AnswerReportServiceFixture { @@ -30,7 +31,7 @@ public class AnswerReportServiceFixture { private JpaCategoryRepository categoryRepository; @Autowired - private JpaUserRepository userRepository; + private UserRepository userRepository; @Autowired private AuctionRepository auctionRepository; @@ -124,7 +125,14 @@ void setUp() { 답변_신고2 = new AnswerReport(이미_신고한_신고자2, 답변, "신고합니다."); 답변_신고3 = new AnswerReport(이미_신고한_신고자3, 답변, "신고합니다."); - userRepository.saveAll(List.of(판매자, 질문자, 답변자, 신고자, 이미_신고한_신고자1, 이미_신고한_신고자2, 이미_신고한_신고자3)); + userRepository.save(판매자); + userRepository.save(질문자); + userRepository.save(답변자); + userRepository.save(신고자); + userRepository.save(이미_신고한_신고자1); + userRepository.save(이미_신고한_신고자2); + userRepository.save(이미_신고한_신고자3); + categoryRepository.saveAll(List.of(전자기기_카테고리, 전자기기_서브_노트북_카테고리)); auctionRepository.save(경매); questionRepository.save(질문); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AuctionReportServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AuctionReportServiceFixture.java index b0e811f46..162d68ba1 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AuctionReportServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AuctionReportServiceFixture.java @@ -15,12 +15,13 @@ import com.ddang.ddang.report.infrastructure.persistence.JpaAuctionReportRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import java.time.LocalDateTime; -import java.util.List; +import com.ddang.ddang.user.domain.repository.UserRepository; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; +import java.time.LocalDateTime; +import java.util.List; + @SuppressWarnings("NonAsciiCharacters") public class AuctionReportServiceFixture { @@ -31,7 +32,7 @@ public class AuctionReportServiceFixture { private JpaProfileImageRepository profileImageRepository; @Autowired - private JpaUserRepository userRepository; + private UserRepository userRepository; @Autowired private JpaAuctionImageRepository auctionImageRepository; @@ -107,14 +108,14 @@ void setUp() { 경매.addAuctionImages(List.of(경매_이미지)); final Auction 삭제된_경매 = Auction.builder() - .seller(판매자) - .title("삭제된 경매 상품") - .description("이것은 삭제된 경매 상품입니다.") - .subCategory(전자기기_서브_노트북_카테고리) - .bidUnit(new BidUnit(1_000)) - .startPrice(new Price(1_000)) - .closingTime(LocalDateTime.now()) - .build(); + .seller(판매자) + .title("삭제된 경매 상품") + .description("이것은 삭제된 경매 상품입니다.") + .subCategory(전자기기_서브_노트북_카테고리) + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(LocalDateTime.now()) + .build(); 삭제된_경매.addAuctionImages(List.of(경매_이미지)); 삭제된_경매.delete(); @@ -123,7 +124,12 @@ void setUp() { final AuctionReport 경매_신고3 = new AuctionReport(이미_신고한_신고자3, 경매, "신고합니다"); profileImageRepository.save(프로필_이미지); - userRepository.saveAll(List.of(판매자, 새로운_신고자, 이미_신고한_신고자1, 이미_신고한_신고자2, 이미_신고한_신고자3)); + + userRepository.save(판매자); + userRepository.save(새로운_신고자); + userRepository.save(이미_신고한_신고자1); + userRepository.save(이미_신고한_신고자2); + userRepository.save(이미_신고한_신고자3); categoryRepository.saveAll(List.of(전자기기_카테고리, 전자기기_서브_노트북_카테고리)); auctionImageRepository.save(경매_이미지); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/ChatRoomReportServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/ChatRoomReportServiceFixture.java index 6aa94e0b8..5667e7670 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/ChatRoomReportServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/ChatRoomReportServiceFixture.java @@ -17,12 +17,13 @@ import com.ddang.ddang.report.infrastructure.persistence.JpaChatRoomReportRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import java.time.LocalDateTime; -import java.util.List; +import com.ddang.ddang.user.domain.repository.UserRepository; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; +import java.time.LocalDateTime; +import java.util.List; + @SuppressWarnings("NonAsciiCharacters") public class ChatRoomReportServiceFixture { @@ -33,7 +34,7 @@ public class ChatRoomReportServiceFixture { private JpaProfileImageRepository profileImageRepository; @Autowired - private JpaUserRepository userRepository; + private UserRepository userRepository; @Autowired private JpaAuctionImageRepository auctionImageRepository; @@ -142,7 +143,12 @@ void setUp() { final ChatRoomReport 채팅방_신고3 = new ChatRoomReport(이미_신고한_구매자3, 채팅방3, "신고합니다."); profileImageRepository.save(프로필_이미지); - userRepository.saveAll(List.of(판매자겸_아직_신고하지_않은_신고자, 이미_신고한_구매자1, 이미_신고한_구매자2, 이미_신고한_구매자3, 채팅방_참여자가_아닌_사용자)); + + userRepository.save(판매자겸_아직_신고하지_않은_신고자); + userRepository.save(이미_신고한_구매자1); + userRepository.save(이미_신고한_구매자2); + userRepository.save(이미_신고한_구매자3); + userRepository.save(채팅방_참여자가_아닌_사용자); categoryRepository.saveAll(List.of(전자기기_카테고리, 전자기기_서브_노트북_카테고리)); auctionImageRepository.save(경매_이미지); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/QuestionReportServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/QuestionReportServiceFixture.java index 99873eb97..087656702 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/QuestionReportServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/QuestionReportServiceFixture.java @@ -15,12 +15,13 @@ import com.ddang.ddang.report.infrastructure.persistence.JpaQuestionReportRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import java.time.LocalDateTime; -import java.util.List; +import com.ddang.ddang.user.domain.repository.UserRepository; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; +import java.time.LocalDateTime; +import java.util.List; + @SuppressWarnings("NonAsciiCharacters") public class QuestionReportServiceFixture { @@ -28,7 +29,7 @@ public class QuestionReportServiceFixture { private JpaCategoryRepository categoryRepository; @Autowired - private JpaUserRepository userRepository; + private UserRepository userRepository; @Autowired private AuctionRepository auctionRepository; @@ -115,7 +116,13 @@ void setUp() { 질문_신고2 = new QuestionReport(이미_신고한_신고자2, 질문, "신고합니다."); 질문_신고3 = new QuestionReport(이미_신고한_신고자3, 질문, "신고합니다."); - userRepository.saveAll(List.of(판매자, 질문자, 신고자, 이미_신고한_신고자1, 이미_신고한_신고자2, 이미_신고한_신고자3)); + userRepository.save(판매자); + userRepository.save(질문자); + userRepository.save(신고자); + userRepository.save(이미_신고한_신고자1); + userRepository.save(이미_신고한_신고자2); + userRepository.save(이미_신고한_신고자3); + categoryRepository.saveAll(List.of(전자기기_카테고리, 전자기기_서브_노트북_카테고리)); auctionRepository.save(경매); questionRepository.save(질문); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/review/application/fixture/ReviewServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/review/application/fixture/ReviewServiceFixture.java index 57babacdf..538668b20 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/review/application/fixture/ReviewServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/review/application/fixture/ReviewServiceFixture.java @@ -14,7 +14,7 @@ import com.ddang.ddang.review.infrastructure.persistence.JpaReviewRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.domain.repository.UserRepository; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; @@ -28,7 +28,7 @@ public class ReviewServiceFixture { private JpaCategoryRepository categoryRepository; @Autowired - private JpaUserRepository userRepository; + private UserRepository userRepository; @Autowired private AuctionRepository auctionRepository; @@ -105,7 +105,11 @@ void setUp() { .reliability(new Reliability(4.7d)) .oauthId("12347") .build(); - userRepository.saveAll(List.of(판매자1, 판매자2, 평가_안한_경매_판매자, 구매자, 경매_참여자가_아닌_사용자)); + userRepository.save(판매자1); + userRepository.save(판매자2); + userRepository.save(평가_안한_경매_판매자); + userRepository.save(구매자); + userRepository.save(경매_참여자가_아닌_사용자); 판매자1이_평가한_경매 = Auction.builder() .seller(판매자1) diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/application/fixture/UserServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/user/application/fixture/UserServiceFixture.java index 11a3a18aa..6df4ff59c 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/application/fixture/UserServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/application/fixture/UserServiceFixture.java @@ -5,7 +5,7 @@ import com.ddang.ddang.user.application.dto.UpdateUserDto; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.domain.repository.UserRepository; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; @@ -15,7 +15,7 @@ public class UserServiceFixture { @Autowired - private JpaUserRepository userRepository; + private UserRepository userRepository; protected Long 존재하지_않는_사용자_아이디 = -999L; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/ReliabilityUpdateSchedulingServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/ReliabilityUpdateSchedulingServiceTest.java index 557ca3529..7952620af 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/ReliabilityUpdateSchedulingServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/ReliabilityUpdateSchedulingServiceTest.java @@ -4,8 +4,8 @@ import com.ddang.ddang.user.application.schedule.fixture.ReliabilityUpdateSchedulingServiceFixture; import com.ddang.ddang.user.domain.ReliabilityUpdateHistory; import com.ddang.ddang.user.domain.UserReliability; -import com.ddang.ddang.user.infrastructure.persistence.JpaReliabilityUpdateHistoryRepository; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserReliabilityRepository; +import com.ddang.ddang.user.domain.repository.ReliabilityUpdateHistoryRepository; +import com.ddang.ddang.user.domain.repository.UserReliabilityRepository; import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; @@ -25,10 +25,10 @@ class ReliabilityUpdateSchedulingServiceTest extends ReliabilityUpdateScheduling ReliabilityUpdateSchedulingService reliabilityUpdateSchedulingService; @Autowired - JpaReliabilityUpdateHistoryRepository reliabilityUpdateHistoryRepository; + ReliabilityUpdateHistoryRepository reliabilityUpdateHistoryRepository; @Autowired - JpaUserReliabilityRepository userReliabilityRepository; + UserReliabilityRepository userReliabilityRepository; @Test void 사용자의_신뢰도를_갱신한다() { diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/fixture/ReliabilityUpdateSchedulingServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/fixture/ReliabilityUpdateSchedulingServiceFixture.java index 612ba76f6..64b7a6183 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/fixture/ReliabilityUpdateSchedulingServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/fixture/ReliabilityUpdateSchedulingServiceFixture.java @@ -11,18 +11,19 @@ import com.ddang.ddang.user.domain.ReliabilityUpdateHistory; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.UserReliability; -import com.ddang.ddang.user.infrastructure.persistence.JpaReliabilityUpdateHistoryRepository; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserReliabilityRepository; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; -import java.util.List; +import com.ddang.ddang.user.domain.repository.ReliabilityUpdateHistoryRepository; +import com.ddang.ddang.user.domain.repository.UserReliabilityRepository; +import com.ddang.ddang.user.domain.repository.UserRepository; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; +import java.util.List; + @SuppressWarnings("NonAsciiCharacters") public class ReliabilityUpdateSchedulingServiceFixture { @Autowired - private JpaUserRepository userRepository; + private UserRepository userRepository; @Autowired private AuctionRepository auctionRepository; @@ -31,10 +32,10 @@ public class ReliabilityUpdateSchedulingServiceFixture { private JpaReviewRepository reviewRepository; @Autowired - private JpaUserReliabilityRepository userReliabilityRepository; + private UserReliabilityRepository userReliabilityRepository; @Autowired - private JpaReliabilityUpdateHistoryRepository reliabilityUpdateHistoryRepository; + private ReliabilityUpdateHistoryRepository reliabilityUpdateHistoryRepository; private double 구매자1_기존_신뢰도_점수 = 3.5d; private double 구매자2_기존_신뢰도_점수 = 4.0d; @@ -120,14 +121,14 @@ void setUp() { .reliability(Reliability.INITIAL_RELIABILITY) .oauthId("1006") .build(); - userRepository.saveAll(List.of(판매자, - 구매자1_기존_평가_2개_새로운_평가_1개, - 구매자2_기존_평가_3개_새로운_평가_2개, - 구매자3_기존_평가_5개_새로운_평가_1개, - 구매자4_기존_평가_없고_새로운_평가_1개, - 구매자5_기존_평가_없고_새로운_평가_3개, - 구매자6_기존_평가_없고_새로운_평가_없음 - )); + userRepository.save(판매자); + userRepository.save(구매자1_기존_평가_2개_새로운_평가_1개); + userRepository.save(구매자2_기존_평가_3개_새로운_평가_2개); + userRepository.save(구매자3_기존_평가_5개_새로운_평가_1개); + userRepository.save(구매자4_기존_평가_없고_새로운_평가_1개); + userRepository.save(구매자5_기존_평가_없고_새로운_평가_3개); + userRepository.save(구매자6_기존_평가_없고_새로운_평가_없음); + final Auction 경매1 = Auction.builder() .title("경매1") .seller(판매자) @@ -292,7 +293,9 @@ void setUp() { final UserReliability 구매자3_기존_신뢰도_반영_정보 = new UserReliability(구매자3_기존_평가_5개_새로운_평가_1개); 구매자3_기존_신뢰도_반영_정보.updateReliability(new Reviews(List.of(구매자3_기존_평가1, 구매자3_기존_평가2, 구매자3_기존_평가3, 구매자3_기존_평가4, 구매자3_기존_평가5))); - userReliabilityRepository.saveAll(List.of(구매자1_기존_신뢰도_반영_정보, 구매자2_기존_신뢰도_반영_정보, 구매자3_기존_신뢰도_반영_정보)); + userReliabilityRepository.save(구매자1_기존_신뢰도_반영_정보); + userReliabilityRepository.save(구매자2_기존_신뢰도_반영_정보); + userReliabilityRepository.save(구매자3_기존_신뢰도_반영_정보); reliabilityUpdateHistoryRepository.save(new ReliabilityUpdateHistory(기존에_적용된_평가_중_마지막_평가의_아이디)); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaReliabilityUpdateHistoryRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaReliabilityUpdateHistoryRepositoryTest.java index 39e392e2c..3e365aba4 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaReliabilityUpdateHistoryRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaReliabilityUpdateHistoryRepositoryTest.java @@ -3,8 +3,6 @@ import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; import com.ddang.ddang.user.domain.ReliabilityUpdateHistory; -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; @@ -23,12 +21,21 @@ @SuppressWarnings("NonAsciiCharacters") class JpaReliabilityUpdateHistoryRepositoryTest { - @PersistenceContext - EntityManager em; - @Autowired JpaReliabilityUpdateHistoryRepository reliabilityUpdateHistoryRepository; + @Test + void 신뢰도_업데이트_기록을_저장한다() { + // given + final ReliabilityUpdateHistory reliabilityUpdateHistory = new ReliabilityUpdateHistory(); + + // when + final ReliabilityUpdateHistory actual = reliabilityUpdateHistoryRepository.save(reliabilityUpdateHistory); + + // then + assertThat(actual.getId()).isPositive(); + } + @Test void 신뢰도_업데이트_기록이_없으면_빈_Optional을_반환한다() { // when @@ -47,9 +54,6 @@ class JpaReliabilityUpdateHistoryRepositoryTest { reliabilityUpdateHistoryRepository.saveAll(List.of(history1, history2, history3)); - em.flush(); - em.clear(); - // when final Optional actual = reliabilityUpdateHistoryRepository.findFirstByOrderByIdDesc(); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserReliabilityRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserReliabilityRepositoryTest.java index ff9eba8ec..ba2f5aae1 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserReliabilityRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserReliabilityRepositoryTest.java @@ -24,6 +24,15 @@ class JpaUserReliabilityRepositoryTest extends JpaUserReliabilityRepositoryFixtu @Autowired JpaUserReliabilityRepository userReliabilityRepository; + @Test + void 사용자_신뢰도_정보를_저장한다() { + // when + UserReliability actual = userReliabilityRepository.save(저장하기_전_사용자_신뢰도_엔티티); + + // then + assertThat(actual.getId()).isPositive(); + } + @Test void 주어진_사용자_아이디에_해당하는_사용자_신뢰도_정보를_반환한다() { // when diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepositoryTest.java index c86733036..cb3a10d56 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepositoryTest.java @@ -1,15 +1,10 @@ package com.ddang.ddang.user.infrastructure.persistence; -import static org.assertj.core.api.Assertions.assertThat; - import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.infrastructure.persistence.fixture.JpaUserRepositoryFixture; -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; -import java.util.Optional; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; @@ -17,15 +12,16 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.context.annotation.Import; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + @DataJpaTest @Import({JpaConfiguration.class, QuerydslConfiguration.class}) @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @SuppressWarnings("NonAsciiCharacters") class JpaUserRepositoryTest extends JpaUserRepositoryFixture { - @PersistenceContext - EntityManager em; - @Autowired JpaUserRepository userRepository; @@ -43,59 +39,56 @@ class JpaUserRepositoryTest extends JpaUserRepositoryFixture { final User actual = userRepository.save(user); // then - em.flush(); - em.clear(); - assertThat(actual.getId()).isPositive(); } @Test - void 존재하는_oauthId를_전달하면_해당_회원을_Optional로_감싸_반환한다() { + void 존재하는_사용자_아이디를_전달하면_해당_사용자를_Optional로_감싸_반환한다() { // when - final Optional actual = userRepository.findByOauthId(사용자.getOauthInformation().getOauthId()); + final Optional actual = userRepository.findById(사용자.getId()); // then assertThat(actual).contains(사용자); } @Test - void 존재하지_않는_oauthId를_전달하면_해당_회원을_빈_Optional로_반환한다() { + void 존재하지_않는_사용자_아이디를_전달하면_빈_Optional을_반환한다() { // when - final Optional actual = userRepository.findByOauthId(존재하지_않는_oauth_아이디); + final Optional actual = userRepository.findById(존재하지_않는_사용자_아이디); // then assertThat(actual).isEmpty(); } @Test - void 회원가입과_탈퇴하지_않은_회원_id를_전달하면_해당_회원을_Optional로_감싸_반환한다() { + void 회원탈퇴한_사용자의_id를_전달하면_빈_Optional을_반환한다() { // when - final Optional actual = userRepository.findByIdAndDeletedIsFalse(사용자.getId()); + final Optional actual = userRepository.findById(탈퇴한_사용자.getId()); // then - assertThat(actual).contains(사용자); + assertThat(actual).isEmpty(); } @Test - void 회원탈퇴한_회원의_id를_전달하면_빈_Optional을_반환한다() { + void 존재하는_oauthId를_전달하면_해당_사용자를_Optional로_감싸_반환한다() { // when - final Optional actual = userRepository.findByIdAndDeletedIsFalse(탈퇴한_사용자.getId()); + final Optional actual = userRepository.findByOauthId(사용자.getOauthInformation().getOauthId()); // then - assertThat(actual).isEmpty(); + assertThat(actual).contains(사용자); } @Test - void 없는_id를_전달하면_빈_Optional을_반환한다() { + void 존재하지_않는_oauthId를_전달하면_해당_사용자를_빈_Optional로_반환한다() { // when - final Optional actual = userRepository.findByIdAndDeletedIsFalse(존재하지_않는_사용자_아이디); + final Optional actual = userRepository.findByOauthId(존재하지_않는_oauth_아이디); // then assertThat(actual).isEmpty(); } @Test - void 회원탈퇴한_회원의_id를_전달하면_참을_반환한다() { + void 회원탈퇴한_사용자의_id를_전달하면_참을_반환한다() { // when final boolean actual = userRepository.existsByIdAndDeletedIsTrue(탈퇴한_사용자.getId()); @@ -104,7 +97,7 @@ class JpaUserRepositoryTest extends JpaUserRepositoryFixture { } @Test - void 회원탈퇴하지_않거나_회원가입하지_않은_회원의_id를_전달하면_거짓을_반환한다() { + void 회원탈퇴하지_않거나_회원가입하지_않은_사용자의_id를_전달하면_거짓을_반환한다() { // when final boolean actual = userRepository.existsByIdAndDeletedIsTrue(사용자.getId()); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/ReliabilityUpdateHistoryRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/ReliabilityUpdateHistoryRepositoryImplTest.java new file mode 100644 index 000000000..30a854a67 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/ReliabilityUpdateHistoryRepositoryImplTest.java @@ -0,0 +1,70 @@ +package com.ddang.ddang.user.infrastructure.persistence; + +import com.ddang.ddang.configuration.JpaConfiguration; +import com.ddang.ddang.configuration.QuerydslConfiguration; +import com.ddang.ddang.user.domain.ReliabilityUpdateHistory; +import com.ddang.ddang.user.domain.repository.ReliabilityUpdateHistoryRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@Import({JpaConfiguration.class, QuerydslConfiguration.class}) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class ReliabilityUpdateHistoryRepositoryImplTest { + + ReliabilityUpdateHistoryRepository reliabilityUpdateHistoryRepository; + + @BeforeEach + void setUp(@Autowired final JpaReliabilityUpdateHistoryRepository jpaReliabilityUpdateHistoryRepository) { + reliabilityUpdateHistoryRepository = new ReliabilityUpdateHistoryRepositoryImpl(jpaReliabilityUpdateHistoryRepository); + } + + @Test + void 신뢰도_업데이트_기록을_저장한다() { + // given + final ReliabilityUpdateHistory reliabilityUpdateHistory = new ReliabilityUpdateHistory(); + + // when + final ReliabilityUpdateHistory actual = reliabilityUpdateHistoryRepository.save(reliabilityUpdateHistory); + + // then + assertThat(actual.getId()).isPositive(); + } + + @Test + void 신뢰도_업데이트_기록이_없으면_빈_Optional을_반환한다() { + // when + final Optional actual = reliabilityUpdateHistoryRepository.findFirstByOrderByIdDesc(); + + // then + assertThat(actual).isEmpty(); + } + + @Test + void 신뢰도_업데이트_기록의_아이디가_가장_큰_것을_조회한다() { + // given + final ReliabilityUpdateHistory history1 = new ReliabilityUpdateHistory(); + final ReliabilityUpdateHistory history2 = new ReliabilityUpdateHistory(); + final ReliabilityUpdateHistory history3 = new ReliabilityUpdateHistory(); + + reliabilityUpdateHistoryRepository.save(history1); + reliabilityUpdateHistoryRepository.save(history2); + reliabilityUpdateHistoryRepository.save(history3); + + // when + final Optional actual = reliabilityUpdateHistoryRepository.findFirstByOrderByIdDesc(); + + // then + assertThat(actual).contains(history3); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/UserReliabilityRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/UserReliabilityRepositoryImplTest.java new file mode 100644 index 000000000..99bb6fc83 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/UserReliabilityRepositoryImplTest.java @@ -0,0 +1,50 @@ +package com.ddang.ddang.user.infrastructure.persistence; + +import com.ddang.ddang.configuration.JpaConfiguration; +import com.ddang.ddang.configuration.QuerydslConfiguration; +import com.ddang.ddang.user.domain.UserReliability; +import com.ddang.ddang.user.domain.repository.UserReliabilityRepository; +import com.ddang.ddang.user.infrastructure.persistence.fixture.UserReliabilityRepositoryImplFixture; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@Import({JpaConfiguration.class, QuerydslConfiguration.class}) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class UserReliabilityRepositoryImplTest extends UserReliabilityRepositoryImplFixture { + + UserReliabilityRepository userReliabilityRepository; + + @BeforeEach + void setUp(@Autowired final JpaUserReliabilityRepository jpaUserReliabilityRepository) { + userReliabilityRepository = new UserReliabilityRepositoryImpl(jpaUserReliabilityRepository); + } + + @Test + void 사용자_신뢰도_정보를_저장한다() { + // when + final UserReliability actual = userReliabilityRepository.save(저장하기_전_사용자_신뢰도_엔티티); + + // then + assertThat(actual.getId()).isPositive(); + } + + @Test + void 주어진_사용자_아이디에_해당하는_사용자_신뢰도_정보를_반환한다() { + // when + final Optional actual = userReliabilityRepository.findByUserId(사용자.getId()); + + // then + assertThat(actual).contains(사용자_신뢰도_정보); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/UserRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/UserRepositoryImplTest.java new file mode 100644 index 000000000..a7fac4bb8 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/UserRepositoryImplTest.java @@ -0,0 +1,131 @@ +package com.ddang.ddang.user.infrastructure.persistence; + +import com.ddang.ddang.configuration.JpaConfiguration; +import com.ddang.ddang.configuration.QuerydslConfiguration; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.repository.UserRepository; +import com.ddang.ddang.user.infrastructure.persistence.fixture.UserRepositoryImplFixture; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@Import({JpaConfiguration.class, QuerydslConfiguration.class}) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class UserRepositoryImplTest extends UserRepositoryImplFixture { + + UserRepository userRepository; + + @BeforeEach + void setUp(@Autowired final JpaUserRepository jpaUserRepository) { + userRepository = new UserRepositoryImpl(jpaUserRepository); + } + + @Test + void 사용자를_저장한다() { + // given + final User user = User.builder() + .name("새로운 사용자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); + + // when + final User actual = userRepository.save(user); + + // then + assertThat(actual.getId()).isPositive(); + } + + @Test + void 존재하는_사용자_아이디를_전달하면_해당_사용자를_Optional로_감싸_반환한다() { + // when + final Optional actual = userRepository.findById(사용자.getId()); + + // then + assertThat(actual).contains(사용자); + } + + @Test + void 존재하지_않는_사용자_아이디를_전달하면_빈_Optional을_반환한다() { + // when + final Optional actual = userRepository.findById(존재하지_않는_사용자_아이디); + + // then + assertThat(actual).isEmpty(); + } + + @Test + void 회원탈퇴한_사용자의_id를_전달하면_빈_Optional을_반환한다() { + // when + final Optional actual = userRepository.findById(탈퇴한_사용자.getId()); + + // then + assertThat(actual).isEmpty(); + } + + @Test + void 존재하는_oauthId를_전달하면_해당_사용자를_Optional로_감싸_반환한다() { + // when + final Optional actual = userRepository.findByOauthId(사용자.getOauthInformation().getOauthId()); + + // then + assertThat(actual).contains(사용자); + } + + @Test + void 존재하지_않는_oauthId를_전달하면_해당_사용자를_빈_Optional로_반환한다() { + // when + final Optional actual = userRepository.findByOauthId(존재하지_않는_oauth_아이디); + + // then + assertThat(actual).isEmpty(); + } + + @Test + void 회원탈퇴한_사용자의_id를_전달하면_참을_반환한다() { + // when + final boolean actual = userRepository.existsByIdAndDeletedIsTrue(탈퇴한_사용자.getId()); + + // then + assertThat(actual).isTrue(); + } + + @Test + void 회원탈퇴하지_않거나_회원가입하지_않은_사용자의_id를_전달하면_거짓을_반환한다() { + // when + final boolean actual = userRepository.existsByIdAndDeletedIsTrue(사용자.getId()); + + // then + assertThat(actual).isFalse(); + } + + @Test + void 이름이_아직_없다면_거짓을_반환한다() { + // when + final boolean actual = userRepository.existsByNameEndingWith(존재하지_않는_사용자_이름); + + // then + assertThat(actual).isFalse(); + } + + @Test + void 이름이_있다면_참을_반환한다() { + // when + final boolean actual = userRepository.existsByNameEndingWith(존재하는_사용자_이름); + + // then + assertThat(actual).isTrue(); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/JpaUserReliabilityRepositoryFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/JpaUserReliabilityRepositoryFixture.java index c7df2ce66..3a1f5af41 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/JpaUserReliabilityRepositoryFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/JpaUserReliabilityRepositoryFixture.java @@ -24,6 +24,7 @@ public class JpaUserReliabilityRepositoryFixture { private JpaUserReliabilityRepository userReliabilityRepository; protected User 사용자; + protected UserReliability 저장하기_전_사용자_신뢰도_엔티티; protected UserReliability 사용자_신뢰도_정보; @BeforeEach @@ -36,6 +37,8 @@ void setUp() { .build(); userRepository.save(사용자); + 저장하기_전_사용자_신뢰도_엔티티 = new UserReliability(사용자); + 사용자_신뢰도_정보 = new UserReliability(사용자); userReliabilityRepository.save(사용자_신뢰도_정보); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/UserReliabilityRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/UserReliabilityRepositoryImplFixture.java new file mode 100644 index 000000000..3cad48eb2 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/UserReliabilityRepositoryImplFixture.java @@ -0,0 +1,47 @@ +package com.ddang.ddang.user.infrastructure.persistence.fixture; + +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.UserReliability; +import com.ddang.ddang.user.domain.repository.UserReliabilityRepository; +import com.ddang.ddang.user.domain.repository.UserRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserReliabilityRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.infrastructure.persistence.UserReliabilityRepositoryImpl; +import com.ddang.ddang.user.infrastructure.persistence.UserRepositoryImpl; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +@SuppressWarnings("NonAsciiCharacters") +public class UserReliabilityRepositoryImplFixture { + + private UserRepository userRepository; + private UserReliabilityRepository userReliabilityRepository; + + protected User 사용자; + protected UserReliability 저장하기_전_사용자_신뢰도_엔티티; + protected UserReliability 사용자_신뢰도_정보; + + @BeforeEach + void setUp( + @Autowired final JpaUserRepository jpaUserRepository, + @Autowired final JpaUserReliabilityRepository jpaUserReliabilityRepository + ) { + userRepository = new UserRepositoryImpl(jpaUserRepository); + userReliabilityRepository = new UserReliabilityRepositoryImpl(jpaUserReliabilityRepository); + + 사용자 = User.builder() + .name("사용자") + .profileImage(new ProfileImage("uplad.png", "store.png")) + .reliability(Reliability.INITIAL_RELIABILITY) + .oauthId("12345") + .build(); + userRepository.save(사용자); + + 저장하기_전_사용자_신뢰도_엔티티 = new UserReliability(사용자); + + 사용자_신뢰도_정보 = new UserReliability(사용자); + userReliabilityRepository.save(사용자_신뢰도_정보); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/UserRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/UserRepositoryImplFixture.java new file mode 100644 index 000000000..bf9345fa1 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/UserRepositoryImplFixture.java @@ -0,0 +1,50 @@ +package com.ddang.ddang.user.infrastructure.persistence.fixture; + +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.repository.UserRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.infrastructure.persistence.UserRepositoryImpl; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +@SuppressWarnings("NonAsciiCharacters") +public class UserRepositoryImplFixture { + + private UserRepository userRepository; + + protected ProfileImage 프로필_이미지 = new ProfileImage("upload.png", "store.png"); + protected String 존재하지_않는_oauth_아이디 = "invalidOauthId"; + protected Long 존재하지_않는_사용자_아이디 = -999L; + protected String 존재하지_않는_사용자_이름 = "새로운 이름"; + protected String 존재하는_사용자_이름; + protected User 사용자; + protected User 탈퇴한_사용자; + + @BeforeEach + void fixtureSetUp(@Autowired final JpaUserRepository jpaUserRepository) { + userRepository = new UserRepositoryImpl(jpaUserRepository); + + final ProfileImage 사용자_프로필_이미지 = new ProfileImage("upload.png", "store.png"); + 사용자 = User.builder() + .name("사용자") + .profileImage(사용자_프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); + + 탈퇴한_사용자 = User.builder() + .name("탈퇴한 사용자") + .profileImage(사용자_프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); + 탈퇴한_사용자.withdrawal(); + + userRepository.save(사용자); + userRepository.save(탈퇴한_사용자); + + 존재하는_사용자_이름 = 사용자.getName(); + } +} From b386153a03945cca191767862325d07f5bc8eb0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=EC=98=88=EC=A7=84?= <96688810+kwonyj1022@users.noreply.github.com> Date: Sat, 14 Oct 2023 23:52:52 +0900 Subject: [PATCH 17/37] =?UTF-8?q?refactor:=20#656=20ChatRoom=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=9D=B8=ED=94=84=EB=9D=BC=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81=20(#663)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 도메인 영역의 채팅방 Repository 추가 * refactor: 불필요하게 Querydsl을 사용한 코드를 JPQL을 사용하도록 변경 * feat: 도메인 영역의 채팅방 Repository 구현체 추가 * refactor: Service에서 도메인 영역의 채팅방 Repository를 사용하도록 변경 * refactor: 픽스처에서 Jpa 채팅방 Repository 의존 제거 * feat: 도메인 영역의 채팅방 정보(채팅방, 이미지) dto를 반환하는 Repository 추가 * feat: 도메인 영역의 채팅방 정보(채팅방, 이미지) dto를 반환하는 Repository 구현체 추가 * refactor: Service에서 도메인 영역의 채팅방 정보(채팅방, 이미지) dto를 반환하는 Repository를 사용하도록 변경 * feat: 도메인 영역의 채팅방 정보(채팅방, 메시지, 이미지) dto를 반환하는 Repository 추가 * feat: 도메인 영역의 채팅방 정보(채팅방, 메시지, 이미지) dto를 반환하는 Repository 구현체 추가 * feat: Service에서 도메인 영역의 채팅방 정보(채팅방, 메시지, 이미지) dto를 반환하는 Repository를 사용하도록 변경 * style: 개행 추가 * refactor: 누락된 final 추가 * ci: 브랜치 최신화 과정에서 누락된 사항 추가 및 충돌 해결 --- .../chat/application/ChatRoomService.java | 26 +-- .../chat/application/MessageService.java | 4 +- .../dto/ReadChatRoomWithLastMessageDto.java | 2 +- .../dto/ReadParticipatingChatRoomDto.java | 2 +- .../dto/ChatRoomAndImageDto.java | 2 +- .../dto/ChatRoomAndMessageAndImageDto.java | 2 +- .../ChatRoomAndImageRepository.java | 10 + .../ChatRoomAndMessageAndImageRepository.java | 10 + .../domain/repository/ChatRoomRepository.java | 16 ++ .../ChatRoomAndImageRepositoryImpl.java | 20 ++ ...tRoomAndMessageAndImageRepositoryImpl.java | 20 ++ .../persistence/ChatRoomRepositoryImpl.java | 35 +++ .../persistence/JpaChatRoomRepository.java | 12 +- .../QuerydslChatRoomAndImageRepository.java | 44 +++- ...uerydslChatRoomAndImageRepositoryImpl.java | 49 ---- ...lChatRoomAndMessageAndImageRepository.java | 69 +++++- ...tRoomAndMessageAndImageRepositoryImpl.java | 74 ------ .../QuerydslChatRoomRepository.java | 8 - .../QuerydslChatRoomRepositoryImpl.java | 26 --- .../ChatRoomAndImageQueryProjectionDto.java | 1 + ...mAndMessageAndImageQueryProjectionDto.java | 1 + .../application/ChatRoomReportService.java | 4 +- .../fixture/ChatRoomServiceFixture.java | 59 ++--- .../fixture/MessageServiceFixture.java | 8 +- .../ChatRoomAndImageRepositoryImplTest.java | 45 ++++ ...mAndMessageAndImageRepositoryImplTest.java | 54 +++++ .../ChatRoomRepositoryImplTest.java | 80 +++++++ .../JpaChatRoomRepositoryTest.java | 9 + ...erydslChatRoomAndImageRepositoryTest.java} | 8 +- ...RoomAndMessageAndImageRepositoryTest.java} | 8 +- .../QuerydslChatRoomRepositoryImplTest.java | 34 --- ...hatRoomAndImageRepositoryImplFixture.java} | 95 ++++---- ...dMessageAndImageRepositoryImplFixture.java | 217 ++++++++++++++++++ .../ChatRoomRepositoryImplFixture.java | 112 +++++++++ ...dslChatRoomAndImageRepositoryFixture.java} | 7 +- ...mAndMessageAndImageRepositoryFixture.java} | 7 +- .../FcmNotificationServiceFixture.java | 4 +- .../NotificationEventListenerFixture.java | 4 +- .../fixture/ChatRoomReportServiceFixture.java | 9 +- 39 files changed, 873 insertions(+), 324 deletions(-) rename backend/ddang/src/main/java/com/ddang/ddang/chat/{infrastructure/persistence => domain}/dto/ChatRoomAndImageDto.java (75%) rename backend/ddang/src/main/java/com/ddang/ddang/chat/{infrastructure/persistence => domain}/dto/ChatRoomAndMessageAndImageDto.java (80%) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ChatRoomAndImageRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ChatRoomAndMessageAndImageRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ChatRoomRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomAndImageRepositoryImpl.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomAndMessageAndImageRepositoryImpl.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomRepositoryImpl.java delete mode 100644 backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndImageRepositoryImpl.java delete mode 100644 backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepositoryImpl.java delete mode 100644 backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomRepository.java delete mode 100644 backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomRepositoryImpl.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomAndImageRepositoryImplTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomAndMessageAndImageRepositoryImplTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomRepositoryImplTest.java rename backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/{QuerydslChatRoomAndImageRepositoryImplTest.java => QuerydslChatRoomAndImageRepositoryTest.java} (86%) rename backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/{QuerydslChatRoomAndMessageAndImageRepositoryImplTest.java => QuerydslChatRoomAndMessageAndImageRepositoryTest.java} (88%) delete mode 100644 backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomRepositoryImplTest.java rename backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/{QuerydslChatRoomRepositoryImplFixture.java => ChatRoomAndImageRepositoryImplFixture.java} (57%) create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndMessageAndImageRepositoryImplFixture.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomRepositoryImplFixture.java rename backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/{QuerydslChatRoomAndImageRepositoryImplFixture.java => QuerydslChatRoomAndImageRepositoryFixture.java} (98%) rename backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/{QuerydslChatRoomAndMessageAndImageRepositoryImplFixture.java => QuerydslChatRoomAndMessageAndImageRepositoryFixture.java} (99%) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java index 14aa6f786..efb3d78d6 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/ChatRoomService.java @@ -13,11 +13,11 @@ import com.ddang.ddang.chat.application.exception.InvalidAuctionToChatException; import com.ddang.ddang.chat.application.exception.InvalidUserToChat; import com.ddang.ddang.chat.domain.ChatRoom; -import com.ddang.ddang.chat.infrastructure.persistence.JpaChatRoomRepository; -import com.ddang.ddang.chat.infrastructure.persistence.QuerydslChatRoomAndImageRepositoryImpl; -import com.ddang.ddang.chat.infrastructure.persistence.QuerydslChatRoomAndMessageAndImageRepository; -import com.ddang.ddang.chat.infrastructure.persistence.dto.ChatRoomAndImageDto; -import com.ddang.ddang.chat.infrastructure.persistence.dto.ChatRoomAndMessageAndImageDto; +import com.ddang.ddang.chat.domain.dto.ChatRoomAndImageDto; +import com.ddang.ddang.chat.domain.dto.ChatRoomAndMessageAndImageDto; +import com.ddang.ddang.chat.domain.repository.ChatRoomAndImageRepository; +import com.ddang.ddang.chat.domain.repository.ChatRoomAndMessageAndImageRepository; +import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -35,9 +35,9 @@ public class ChatRoomService { private static final Long DEFAULT_CHAT_ROOM_ID = null; - private final JpaChatRoomRepository chatRoomRepository; - private final QuerydslChatRoomAndImageRepositoryImpl querydslChatRoomAndImageRepository; - private final QuerydslChatRoomAndMessageAndImageRepository querydslChatRoomAndMessageAndImageRepository; + private final ChatRoomRepository chatRoomRepository; + private final ChatRoomAndImageRepository chatRoomAndImageRepository; + private final ChatRoomAndMessageAndImageRepository chatRoomAndMessageAndImageRepository; private final UserRepository userRepository; private final AuctionRepository auctionRepository; @@ -87,7 +87,7 @@ public List readAllByUserId(final Long userId) { final User findUser = userRepository.findById(userId) .orElseThrow(() -> new UserNotFoundException("사용자 정보를 찾을 수 없습니다.")); final List chatRoomAndMessageAndImageQueryProjectionDtos = - querydslChatRoomAndMessageAndImageRepository.findAllChatRoomInfoByUserIdOrderByLastMessage(findUser.getId()); + chatRoomAndMessageAndImageRepository.findAllChatRoomInfoByUserIdOrderByLastMessage(findUser.getId()); return chatRoomAndMessageAndImageQueryProjectionDtos.stream() .map(dto -> ReadChatRoomWithLastMessageDto.of(findUser, dto)) @@ -98,10 +98,10 @@ public ReadParticipatingChatRoomDto readByChatRoomId(final Long chatRoomId, fina final User findUser = userRepository.findById(userId) .orElseThrow(() -> new UserNotFoundException("사용자 정보를 찾을 수 없습니다.")); final ChatRoomAndImageDto chatRoomAndImageDto = - querydslChatRoomAndImageRepository.findChatRoomById(chatRoomId) - .orElseThrow(() -> new ChatRoomNotFoundException( - "지정한 아이디에 대한 채팅방을 찾을 수 없습니다." - )); + chatRoomAndImageRepository.findChatRoomById(chatRoomId) + .orElseThrow(() -> new ChatRoomNotFoundException( + "지정한 아이디에 대한 채팅방을 찾을 수 없습니다." + )); checkAccessible(findUser, chatRoomAndImageDto.chatRoom()); return ReadParticipatingChatRoomDto.of(findUser, chatRoomAndImageDto); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java index 280c93ece..72c9947e0 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java @@ -8,7 +8,7 @@ import com.ddang.ddang.chat.application.exception.UnableToChatException; import com.ddang.ddang.chat.domain.ChatRoom; import com.ddang.ddang.chat.domain.Message; -import com.ddang.ddang.chat.infrastructure.persistence.JpaChatRoomRepository; +import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; import com.ddang.ddang.chat.infrastructure.persistence.JpaMessageRepository; import com.ddang.ddang.chat.presentation.dto.request.ReadMessageRequest; import com.ddang.ddang.user.application.exception.UserNotFoundException; @@ -30,7 +30,7 @@ public class MessageService { private final ApplicationEventPublisher messageEventPublisher; private final JpaMessageRepository messageRepository; - private final JpaChatRoomRepository chatRoomRepository; + private final ChatRoomRepository chatRoomRepository; private final UserRepository userRepository; @Transactional diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/dto/ReadChatRoomWithLastMessageDto.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/dto/ReadChatRoomWithLastMessageDto.java index 012b60754..36e3d0382 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/dto/ReadChatRoomWithLastMessageDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/dto/ReadChatRoomWithLastMessageDto.java @@ -2,7 +2,7 @@ import com.ddang.ddang.chat.domain.ChatRoom; import com.ddang.ddang.chat.domain.Message; -import com.ddang.ddang.chat.infrastructure.persistence.dto.ChatRoomAndMessageAndImageDto; +import com.ddang.ddang.chat.domain.dto.ChatRoomAndMessageAndImageDto; import com.ddang.ddang.image.domain.AuctionImage; import com.ddang.ddang.user.domain.User; diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/dto/ReadParticipatingChatRoomDto.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/dto/ReadParticipatingChatRoomDto.java index 318040fc1..7ed2e64b9 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/dto/ReadParticipatingChatRoomDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/dto/ReadParticipatingChatRoomDto.java @@ -1,7 +1,7 @@ package com.ddang.ddang.chat.application.dto; import com.ddang.ddang.chat.domain.ChatRoom; -import com.ddang.ddang.chat.infrastructure.persistence.dto.ChatRoomAndImageDto; +import com.ddang.ddang.chat.domain.dto.ChatRoomAndImageDto; import com.ddang.ddang.user.domain.User; public record ReadParticipatingChatRoomDto( diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndImageDto.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/dto/ChatRoomAndImageDto.java similarity index 75% rename from backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndImageDto.java rename to backend/ddang/src/main/java/com/ddang/ddang/chat/domain/dto/ChatRoomAndImageDto.java index 1b690588c..32cfee842 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndImageDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/dto/ChatRoomAndImageDto.java @@ -1,4 +1,4 @@ -package com.ddang.ddang.chat.infrastructure.persistence.dto; +package com.ddang.ddang.chat.domain.dto; import com.ddang.ddang.chat.domain.ChatRoom; import com.ddang.ddang.image.domain.AuctionImage; diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndMessageAndImageDto.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/dto/ChatRoomAndMessageAndImageDto.java similarity index 80% rename from backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndMessageAndImageDto.java rename to backend/ddang/src/main/java/com/ddang/ddang/chat/domain/dto/ChatRoomAndMessageAndImageDto.java index bafad0a34..2e7e6ea6b 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndMessageAndImageDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/dto/ChatRoomAndMessageAndImageDto.java @@ -1,4 +1,4 @@ -package com.ddang.ddang.chat.infrastructure.persistence.dto; +package com.ddang.ddang.chat.domain.dto; import com.ddang.ddang.chat.domain.ChatRoom; import com.ddang.ddang.chat.domain.Message; diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ChatRoomAndImageRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ChatRoomAndImageRepository.java new file mode 100644 index 000000000..a39b118f0 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ChatRoomAndImageRepository.java @@ -0,0 +1,10 @@ +package com.ddang.ddang.chat.domain.repository; + +import com.ddang.ddang.chat.domain.dto.ChatRoomAndImageDto; + +import java.util.Optional; + +public interface ChatRoomAndImageRepository { + + Optional findChatRoomById(final Long chatRoomId); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ChatRoomAndMessageAndImageRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ChatRoomAndMessageAndImageRepository.java new file mode 100644 index 000000000..027f94c37 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ChatRoomAndMessageAndImageRepository.java @@ -0,0 +1,10 @@ +package com.ddang.ddang.chat.domain.repository; + +import com.ddang.ddang.chat.domain.dto.ChatRoomAndMessageAndImageDto; + +import java.util.List; + +public interface ChatRoomAndMessageAndImageRepository { + + List findAllChatRoomInfoByUserIdOrderByLastMessage(final Long userId); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ChatRoomRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ChatRoomRepository.java new file mode 100644 index 000000000..3935ababc --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/ChatRoomRepository.java @@ -0,0 +1,16 @@ +package com.ddang.ddang.chat.domain.repository; + +import com.ddang.ddang.chat.domain.ChatRoom; + +import java.util.Optional; + +public interface ChatRoomRepository { + + ChatRoom save(final ChatRoom chatRoom); + + Optional findById(final Long id); + + Optional findChatRoomIdByAuctionId(final Long auctionId); + + boolean existsByAuctionId(final Long auctionId); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomAndImageRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomAndImageRepositoryImpl.java new file mode 100644 index 000000000..7c3c10bab --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomAndImageRepositoryImpl.java @@ -0,0 +1,20 @@ +package com.ddang.ddang.chat.infrastructure.persistence; + +import com.ddang.ddang.chat.domain.dto.ChatRoomAndImageDto; +import com.ddang.ddang.chat.domain.repository.ChatRoomAndImageRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +@RequiredArgsConstructor +public class ChatRoomAndImageRepositoryImpl implements ChatRoomAndImageRepository { + + private final QuerydslChatRoomAndImageRepository querydslChatRoomAndImageRepository; + + @Override + public Optional findChatRoomById(final Long chatRoomId) { + return querydslChatRoomAndImageRepository.findChatRoomById(chatRoomId); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomAndMessageAndImageRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomAndMessageAndImageRepositoryImpl.java new file mode 100644 index 000000000..2047c60d5 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomAndMessageAndImageRepositoryImpl.java @@ -0,0 +1,20 @@ +package com.ddang.ddang.chat.infrastructure.persistence; + +import com.ddang.ddang.chat.domain.dto.ChatRoomAndMessageAndImageDto; +import com.ddang.ddang.chat.domain.repository.ChatRoomAndMessageAndImageRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +@RequiredArgsConstructor +public class ChatRoomAndMessageAndImageRepositoryImpl implements ChatRoomAndMessageAndImageRepository { + + private final QuerydslChatRoomAndMessageAndImageRepository querydslChatRoomAndMessageAndImageRepository; + + @Override + public List findAllChatRoomInfoByUserIdOrderByLastMessage(final Long userId) { + return querydslChatRoomAndMessageAndImageRepository.findAllChatRoomInfoByUserIdOrderByLastMessage(userId); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomRepositoryImpl.java new file mode 100644 index 000000000..a2d88ceb8 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomRepositoryImpl.java @@ -0,0 +1,35 @@ +package com.ddang.ddang.chat.infrastructure.persistence; + +import com.ddang.ddang.chat.domain.ChatRoom; +import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +@RequiredArgsConstructor +public class ChatRoomRepositoryImpl implements ChatRoomRepository { + + private final JpaChatRoomRepository jpaChatRoomRepository; + + @Override + public ChatRoom save(final ChatRoom chatRoom) { + return jpaChatRoomRepository.save(chatRoom); + } + + @Override + public Optional findById(final Long id) { + return jpaChatRoomRepository.findById(id); + } + + @Override + public Optional findChatRoomIdByAuctionId(final Long auctionId) { + return jpaChatRoomRepository.findChatRoomIdByAuctionId(auctionId); + } + + @Override + public boolean existsByAuctionId(final Long auctionId) { + return jpaChatRoomRepository.existsByAuctionId(auctionId); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaChatRoomRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaChatRoomRepository.java index 0d4db5168..639a831ca 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaChatRoomRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaChatRoomRepository.java @@ -2,8 +2,18 @@ import com.ddang.ddang.chat.domain.ChatRoom; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; -public interface JpaChatRoomRepository extends JpaRepository, QuerydslChatRoomRepository { +import java.util.Optional; + +public interface JpaChatRoomRepository extends JpaRepository { + + @Query(""" + SELECT c.id + FROM ChatRoom c + WHERE c.auction.id = :auctionId + """) + Optional findChatRoomIdByAuctionId(final Long auctionId); boolean existsByAuctionId(final Long auctionId); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndImageRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndImageRepository.java index 66aa1122b..cfdd83e9e 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndImageRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndImageRepository.java @@ -1,10 +1,48 @@ package com.ddang.ddang.chat.infrastructure.persistence; -import com.ddang.ddang.chat.infrastructure.persistence.dto.ChatRoomAndImageDto; +import com.ddang.ddang.chat.domain.dto.ChatRoomAndImageDto; +import com.ddang.ddang.chat.infrastructure.persistence.dto.ChatRoomAndImageQueryProjectionDto; +import com.ddang.ddang.chat.infrastructure.persistence.dto.QChatRoomAndImageQueryProjectionDto; +import com.querydsl.jpa.JPAExpressions; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; import java.util.Optional; -public interface QuerydslChatRoomAndImageRepository { +import static com.ddang.ddang.auction.domain.QAuction.auction; +import static com.ddang.ddang.chat.domain.QChatRoom.chatRoom; +import static com.ddang.ddang.image.domain.QAuctionImage.auctionImage; - Optional findChatRoomById(final Long chatRoomId); +@Repository +@RequiredArgsConstructor +public class QuerydslChatRoomAndImageRepository { + + private final JPAQueryFactory queryFactory; + + public Optional findChatRoomById(final Long chatRoomId) { + + final ChatRoomAndImageQueryProjectionDto chatRoomAndImageQueryProjectionDto = + queryFactory.select(new QChatRoomAndImageQueryProjectionDto(chatRoom, auctionImage)) + .from(chatRoom) + .leftJoin(chatRoom.buyer).fetchJoin() + .leftJoin(chatRoom.auction, auction).fetchJoin() + .leftJoin(auction.seller).fetchJoin() + .leftJoin(auctionImage).on(auctionImage.id.eq( + JPAExpressions + .select(auctionImage.id.min()) + .from(auctionImage) + .where(auctionImage.auction.id.eq(auction.id)) + .groupBy(auctionImage.auction.id) + )).fetchJoin() + .leftJoin(auction.lastBid).fetchJoin() + .where(chatRoom.id.eq(chatRoomId)) + .fetchOne(); + + if (chatRoomAndImageQueryProjectionDto == null) { + return Optional.empty(); + } + + return Optional.of(chatRoomAndImageQueryProjectionDto.toDto()); + } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndImageRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndImageRepositoryImpl.java deleted file mode 100644 index 89ce4d1e6..000000000 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndImageRepositoryImpl.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.ddang.ddang.chat.infrastructure.persistence; - -import com.ddang.ddang.chat.infrastructure.persistence.dto.ChatRoomAndImageDto; -import com.ddang.ddang.chat.infrastructure.persistence.dto.ChatRoomAndImageQueryProjectionDto; -import com.ddang.ddang.chat.infrastructure.persistence.dto.QChatRoomAndImageQueryProjectionDto; -import com.querydsl.jpa.JPAExpressions; -import com.querydsl.jpa.impl.JPAQueryFactory; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Repository; - -import java.util.Optional; - -import static com.ddang.ddang.auction.domain.QAuction.auction; -import static com.ddang.ddang.chat.domain.QChatRoom.chatRoom; -import static com.ddang.ddang.image.domain.QAuctionImage.auctionImage; - -@Repository -@RequiredArgsConstructor -public class QuerydslChatRoomAndImageRepositoryImpl implements QuerydslChatRoomAndImageRepository { - - private final JPAQueryFactory queryFactory; - - @Override - public Optional findChatRoomById(final Long chatRoomId) { - - final ChatRoomAndImageQueryProjectionDto chatRoomAndImageQueryProjectionDto = - queryFactory.select(new QChatRoomAndImageQueryProjectionDto(chatRoom, auctionImage)) - .from(chatRoom) - .leftJoin(chatRoom.buyer).fetchJoin() - .leftJoin(chatRoom.auction, auction).fetchJoin() - .leftJoin(auction.seller).fetchJoin() - .leftJoin(auctionImage).on(auctionImage.id.eq( - JPAExpressions - .select(auctionImage.id.min()) - .from(auctionImage) - .where(auctionImage.auction.id.eq(auction.id)) - .groupBy(auctionImage.auction.id) - )).fetchJoin() - .leftJoin(auction.lastBid).fetchJoin() - .where(chatRoom.id.eq(chatRoomId)) - .fetchOne(); - - if (chatRoomAndImageQueryProjectionDto == null) { - return Optional.empty(); - } - - return Optional.of(chatRoomAndImageQueryProjectionDto.toDto()); - } -} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepository.java index 9a5cc8092..07e7bc5f7 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepository.java @@ -1,10 +1,73 @@ package com.ddang.ddang.chat.infrastructure.persistence; -import com.ddang.ddang.chat.infrastructure.persistence.dto.ChatRoomAndMessageAndImageDto; +import com.ddang.ddang.chat.domain.dto.ChatRoomAndMessageAndImageDto; +import com.ddang.ddang.chat.infrastructure.persistence.dto.ChatRoomAndMessageAndImageQueryProjectionDto; +import com.ddang.ddang.chat.infrastructure.persistence.dto.QChatRoomAndMessageAndImageQueryProjectionDto; +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.JPAExpressions; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; import java.util.List; +import java.util.Objects; -public interface QuerydslChatRoomAndMessageAndImageRepository { +import static com.ddang.ddang.auction.domain.QAuction.auction; +import static com.ddang.ddang.chat.domain.QChatRoom.chatRoom; +import static com.ddang.ddang.chat.domain.QMessage.message; +import static com.ddang.ddang.image.domain.QAuctionImage.auctionImage; +import static java.util.Comparator.comparing; - List findAllChatRoomInfoByUserIdOrderByLastMessage(final Long userId); +@Repository +@RequiredArgsConstructor +public class QuerydslChatRoomAndMessageAndImageRepository { + + private final JPAQueryFactory queryFactory; + + public List findAllChatRoomInfoByUserIdOrderByLastMessage(final Long userId) { + final List unsortedDtos = + queryFactory.select(new QChatRoomAndMessageAndImageQueryProjectionDto(chatRoom, message, auctionImage)) + .from(chatRoom) + .leftJoin(chatRoom.buyer).fetchJoin() + .leftJoin(chatRoom.auction, auction).fetchJoin() + .leftJoin(auction.seller).fetchJoin() + .leftJoin(auctionImage).on(auctionImage.id.eq( + JPAExpressions + .select(auctionImage.id.min()) + .from(auctionImage) + .where(auctionImage.auction.id.eq(auction.id)) + .groupBy(auctionImage.auction.id) + )).fetchJoin() + .leftJoin(auction.lastBid).fetchJoin() + .leftJoin(message).on(message.id.eq( + JPAExpressions + .select(message.id.max()) + .from(message) + .where(message.chatRoom.id.eq(chatRoom.id)) + .groupBy(message.chatRoom.id) + )).fetchJoin() + .where(isSellerOrWinner(userId)) + .fetch(); + + return sortByLastMessageIdDesc(unsortedDtos); + } + + private List sortByLastMessageIdDesc( + final List unsortedDtos + ) { + return unsortedDtos.stream() + .filter((ChatRoomAndMessageAndImageQueryProjectionDto unsortedDto) -> + Objects.nonNull(unsortedDto.message()) + ).sorted(comparing( + (ChatRoomAndMessageAndImageQueryProjectionDto unsortedDto) -> + unsortedDto.message().getId() + ).reversed() + ).map(ChatRoomAndMessageAndImageQueryProjectionDto::toSortedDto) + .toList(); + } + + private BooleanExpression isSellerOrWinner(final Long userId) { + return (auction.seller.id.eq(userId)) + .or(chatRoom.buyer.id.eq(userId)); + } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepositoryImpl.java deleted file mode 100644 index 6dd6c8509..000000000 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepositoryImpl.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.ddang.ddang.chat.infrastructure.persistence; - -import com.ddang.ddang.chat.infrastructure.persistence.dto.ChatRoomAndMessageAndImageDto; -import com.ddang.ddang.chat.infrastructure.persistence.dto.ChatRoomAndMessageAndImageQueryProjectionDto; -import com.ddang.ddang.chat.infrastructure.persistence.dto.QChatRoomAndMessageAndImageQueryProjectionDto; -import com.querydsl.core.types.dsl.BooleanExpression; -import com.querydsl.jpa.JPAExpressions; -import com.querydsl.jpa.impl.JPAQueryFactory; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Repository; - -import java.util.List; -import java.util.Objects; - -import static com.ddang.ddang.auction.domain.QAuction.auction; -import static com.ddang.ddang.chat.domain.QChatRoom.chatRoom; -import static com.ddang.ddang.chat.domain.QMessage.message; -import static com.ddang.ddang.image.domain.QAuctionImage.auctionImage; -import static java.util.Comparator.comparing; - -@Repository -@RequiredArgsConstructor -public class QuerydslChatRoomAndMessageAndImageRepositoryImpl implements QuerydslChatRoomAndMessageAndImageRepository { - - private final JPAQueryFactory queryFactory; - - @Override - public List findAllChatRoomInfoByUserIdOrderByLastMessage(final Long userId) { - final List unsortedDtos = - queryFactory.select(new QChatRoomAndMessageAndImageQueryProjectionDto(chatRoom, message, auctionImage)) - .from(chatRoom) - .leftJoin(chatRoom.buyer).fetchJoin() - .leftJoin(chatRoom.auction, auction).fetchJoin() - .leftJoin(auction.seller).fetchJoin() - .leftJoin(auctionImage).on(auctionImage.id.eq( - JPAExpressions - .select(auctionImage.id.min()) - .from(auctionImage) - .where(auctionImage.auction.id.eq(auction.id)) - .groupBy(auctionImage.auction.id) - )).fetchJoin() - .leftJoin(auction.lastBid).fetchJoin() - .leftJoin(message).on(message.id.eq( - JPAExpressions - .select(message.id.max()) - .from(message) - .where(message.chatRoom.id.eq(chatRoom.id)) - .groupBy(message.chatRoom.id) - )).fetchJoin() - .where(isSellerOrWinner(userId)) - .fetch(); - - return sortByLastMessageIdDesc(unsortedDtos); - } - - private List sortByLastMessageIdDesc( - final List unsortedDtos - ) { - return unsortedDtos.stream() - .filter((ChatRoomAndMessageAndImageQueryProjectionDto unsortedDto) -> - Objects.nonNull(unsortedDto.message()) - ).sorted(comparing( - (ChatRoomAndMessageAndImageQueryProjectionDto unsortedDto) -> - unsortedDto.message().getId() - ).reversed() - ).map(ChatRoomAndMessageAndImageQueryProjectionDto::toSortedDto) - .toList(); - } - - private BooleanExpression isSellerOrWinner(final Long userId) { - return (auction.seller.id.eq(userId)) - .or(chatRoom.buyer.id.eq(userId)); - } -} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomRepository.java deleted file mode 100644 index c789bff0b..000000000 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.ddang.ddang.chat.infrastructure.persistence; - -import java.util.Optional; - -public interface QuerydslChatRoomRepository { - - Optional findChatRoomIdByAuctionId(final Long auctionId); -} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomRepositoryImpl.java deleted file mode 100644 index b3b8908d6..000000000 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomRepositoryImpl.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.ddang.ddang.chat.infrastructure.persistence; - -import com.querydsl.jpa.impl.JPAQueryFactory; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Repository; - -import java.util.Optional; - -import static com.ddang.ddang.chat.domain.QChatRoom.chatRoom; - -@Repository -@RequiredArgsConstructor -public class QuerydslChatRoomRepositoryImpl implements QuerydslChatRoomRepository { - - private final JPAQueryFactory queryFactory; - - @Override - public Optional findChatRoomIdByAuctionId(final Long auctionId) { - final Long chatRoomId = queryFactory.select(chatRoom.id) - .from(chatRoom) - .where(chatRoom.auction.id.eq(auctionId)) - .fetchFirst(); - - return Optional.ofNullable(chatRoomId); - } -} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndImageQueryProjectionDto.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndImageQueryProjectionDto.java index dd320738c..4de8cde25 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndImageQueryProjectionDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndImageQueryProjectionDto.java @@ -1,6 +1,7 @@ package com.ddang.ddang.chat.infrastructure.persistence.dto; import com.ddang.ddang.chat.domain.ChatRoom; +import com.ddang.ddang.chat.domain.dto.ChatRoomAndImageDto; import com.ddang.ddang.image.domain.AuctionImage; import com.querydsl.core.annotations.QueryProjection; diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndMessageAndImageQueryProjectionDto.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndMessageAndImageQueryProjectionDto.java index 5776bd1fc..c4369d8f3 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndMessageAndImageQueryProjectionDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/dto/ChatRoomAndMessageAndImageQueryProjectionDto.java @@ -2,6 +2,7 @@ import com.ddang.ddang.chat.domain.ChatRoom; import com.ddang.ddang.chat.domain.Message; +import com.ddang.ddang.chat.domain.dto.ChatRoomAndMessageAndImageDto; import com.ddang.ddang.image.domain.AuctionImage; import com.querydsl.core.annotations.QueryProjection; diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/application/ChatRoomReportService.java b/backend/ddang/src/main/java/com/ddang/ddang/report/application/ChatRoomReportService.java index a7a84acf0..11b3c3ed9 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/report/application/ChatRoomReportService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/application/ChatRoomReportService.java @@ -2,7 +2,7 @@ import com.ddang.ddang.chat.application.exception.ChatRoomNotFoundException; import com.ddang.ddang.chat.domain.ChatRoom; -import com.ddang.ddang.chat.infrastructure.persistence.JpaChatRoomRepository; +import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; import com.ddang.ddang.report.application.dto.CreateChatRoomReportDto; import com.ddang.ddang.report.application.dto.ReadChatRoomReportDto; import com.ddang.ddang.report.application.exception.AlreadyReportChatRoomException; @@ -24,7 +24,7 @@ public class ChatRoomReportService { private final UserRepository userRepository; - private final JpaChatRoomRepository chatRoomRepository; + private final ChatRoomRepository chatRoomRepository; private final JpaChatRoomReportRepository chatRoomReportRepository; @Transactional diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java index 20d20ad91..b7da09ec1 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java @@ -19,14 +19,15 @@ import com.ddang.ddang.chat.application.dto.ReadUserInChatRoomDto; import com.ddang.ddang.chat.domain.ChatRoom; import com.ddang.ddang.chat.domain.Message; -import com.ddang.ddang.chat.infrastructure.persistence.JpaChatRoomRepository; +import com.ddang.ddang.chat.domain.dto.ChatRoomAndImageDto; +import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; import com.ddang.ddang.chat.infrastructure.persistence.JpaMessageRepository; -import com.ddang.ddang.chat.infrastructure.persistence.dto.ChatRoomAndImageDto; import com.ddang.ddang.image.domain.AuctionImage; import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; @@ -49,7 +50,7 @@ public class ChatRoomServiceFixture { private JpaBidRepository bidRepository; @Autowired - private JpaChatRoomRepository chatRoomRepository; + private ChatRoomRepository chatRoomRepository; @Autowired private JpaMessageRepository messageRepository; @@ -157,23 +158,23 @@ void setUp() { .closingTime(LocalDateTime.now()) .build(); final Auction 종료되지_않은_경매 = Auction.builder() - .seller(판매자) - .title("맥북") - .description("맥북 팔아요") - .subCategory(전자기기_서브_노트북_카테고리) - .startPrice(new Price(10_000)) - .bidUnit(new BidUnit(1_000)) - .closingTime(LocalDateTime.now().plusDays(10L)) - .build(); + .seller(판매자) + .title("맥북") + .description("맥북 팔아요") + .subCategory(전자기기_서브_노트북_카테고리) + .startPrice(new Price(10_000)) + .bidUnit(new BidUnit(1_000)) + .closingTime(LocalDateTime.now().plusDays(10L)) + .build(); final Auction 낙찰자가_없는_경매 = Auction.builder() - .seller(판매자) - .title("맥북") - .description("맥북 팔아요") - .subCategory(전자기기_서브_노트북_카테고리) - .startPrice(new Price(10_000)) - .bidUnit(new BidUnit(1_000)) - .closingTime(LocalDateTime.now()) - .build(); + .seller(판매자) + .title("맥북") + .description("맥북 팔아요") + .subCategory(전자기기_서브_노트북_카테고리) + .startPrice(new Price(10_000)) + .bidUnit(new BidUnit(1_000)) + .closingTime(LocalDateTime.now()) + .build(); 판매자_엔초_구매자_지토_경매 = Auction.builder() .seller(엔초) .title("엔초 맥북") @@ -184,14 +185,14 @@ void setUp() { .closingTime(LocalDateTime.now()) .build(); final Auction 판매자_제이미_구매자_엔초_경매 = Auction.builder() - .seller(제이미) - .title("제이미 맥북") - .description("제이미 맥북 팔아요") - .subCategory(전자기기_서브_노트북_카테고리) - .startPrice(new Price(10_000)) - .bidUnit(new BidUnit(1_000)) - .closingTime(LocalDateTime.now()) - .build(); + .seller(제이미) + .title("제이미 맥북") + .description("제이미 맥북 팔아요") + .subCategory(전자기기_서브_노트북_카테고리) + .startPrice(new Price(10_000)) + .bidUnit(new BidUnit(1_000)) + .closingTime(LocalDateTime.now()) + .build(); 채팅방이_없는_경매.addAuctionImages(List.of(경매_대표_이미지, 대표_이미지가_아닌_경매_이미지)); 판매자_엔초_구매자_지토_경매.addAuctionImages(List.of(엔초의_경매_대표_이미지, 엔초의_대표_이미지가_아닌_경매_이미지)); 판매자_제이미_구매자_엔초_경매.addAuctionImages(List.of(제이미의_경매_대표_이미지, 제이미의_대표_이미지가_아닌_경매_이미지)); @@ -212,7 +213,9 @@ void setUp() { 엔초_지토_채팅방 = new ChatRoom(판매자_엔초_구매자_지토_경매, 지토); 제이미_엔초_채팅방 = new ChatRoom(판매자_제이미_구매자_엔초_경매, 엔초); - chatRoomRepository.saveAll(List.of(엔초_지토_채팅방, 제이미_엔초_채팅방)); + + chatRoomRepository.save(엔초_지토_채팅방); + chatRoomRepository.save(제이미_엔초_채팅방); 엔초가_지토에게_1시에_보낸_쪽지 = Message.builder() .chatRoom(엔초_지토_채팅방) diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java index 16a2016ee..185fc5783 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java @@ -9,7 +9,7 @@ import com.ddang.ddang.chat.application.dto.CreateMessageDto; import com.ddang.ddang.chat.domain.ChatRoom; import com.ddang.ddang.chat.domain.Message; -import com.ddang.ddang.chat.infrastructure.persistence.JpaChatRoomRepository; +import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; import com.ddang.ddang.chat.infrastructure.persistence.JpaMessageRepository; import com.ddang.ddang.chat.presentation.dto.request.ReadMessageRequest; import com.ddang.ddang.image.domain.ProfileImage; @@ -36,7 +36,7 @@ public class MessageServiceFixture { private UserRepository userRepository; @Autowired - private JpaChatRoomRepository chatRoomRepository; + private ChatRoomRepository chatRoomRepository; @Autowired private JpaCategoryRepository categoryRepository; @@ -97,7 +97,9 @@ void setUp() { final ChatRoom 채팅방 = new ChatRoom(경매, 발신자); final ChatRoom 탈퇴한_사용자와의_채팅방 = new ChatRoom(경매, 탈퇴한_사용자); - chatRoomRepository.saveAll(List.of(채팅방, 탈퇴한_사용자와의_채팅방)); + + chatRoomRepository.save(채팅방); + chatRoomRepository.save(탈퇴한_사용자와의_채팅방); 메시지_생성_DTO = new CreateMessageDto( 채팅방.getId(), diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomAndImageRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomAndImageRepositoryImplTest.java new file mode 100644 index 000000000..8a145065e --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomAndImageRepositoryImplTest.java @@ -0,0 +1,45 @@ +package com.ddang.ddang.chat.infrastructure.persistence; + +import com.ddang.ddang.chat.domain.dto.ChatRoomAndImageDto; +import com.ddang.ddang.chat.domain.repository.ChatRoomAndImageRepository; +import com.ddang.ddang.chat.infrastructure.persistence.fixture.ChatRoomAndImageRepositoryImplFixture; +import com.ddang.ddang.configuration.JpaConfiguration; +import com.ddang.ddang.configuration.QuerydslConfiguration; +import com.querydsl.jpa.impl.JPAQueryFactory; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.Optional; + +@DataJpaTest +@Import({JpaConfiguration.class, QuerydslConfiguration.class}) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class ChatRoomAndImageRepositoryImplTest extends ChatRoomAndImageRepositoryImplFixture { + + ChatRoomAndImageRepository chatRoomAndImageRepository; + + @BeforeEach + void setUp(@Autowired final JPAQueryFactory queryFactory) { + chatRoomAndImageRepository = new ChatRoomAndImageRepositoryImpl(new QuerydslChatRoomAndImageRepository(queryFactory)); + } + + @Test + void 지정한_채팅방_아이디에_해당하는_채팅방을_조회한다() { + // when + final Optional actual = chatRoomAndImageRepository.findChatRoomById(채팅방.getId()); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).isPresent(); + softAssertions.assertThat(actual.get().chatRoom()).isEqualTo(채팅방); + softAssertions.assertThat(actual.get().thumbnailImage()).isEqualTo(경매_대표_이미지); + }); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomAndMessageAndImageRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomAndMessageAndImageRepositoryImplTest.java new file mode 100644 index 000000000..b93f53f7e --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomAndMessageAndImageRepositoryImplTest.java @@ -0,0 +1,54 @@ +package com.ddang.ddang.chat.infrastructure.persistence; + +import com.ddang.ddang.chat.domain.dto.ChatRoomAndMessageAndImageDto; +import com.ddang.ddang.chat.domain.repository.ChatRoomAndMessageAndImageRepository; +import com.ddang.ddang.chat.infrastructure.persistence.fixture.ChatRoomAndMessageAndImageRepositoryImplFixture; +import com.ddang.ddang.configuration.JpaConfiguration; +import com.ddang.ddang.configuration.QuerydslConfiguration; +import com.querydsl.jpa.impl.JPAQueryFactory; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.List; + +@DataJpaTest +@Import({JpaConfiguration.class, QuerydslConfiguration.class}) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class ChatRoomAndMessageAndImageRepositoryImplTest extends ChatRoomAndMessageAndImageRepositoryImplFixture { + + ChatRoomAndMessageAndImageRepository chatRoomAndMessageAndImageRepository; + + @BeforeEach + void setUp(@Autowired final JPAQueryFactory queryFactory) { + chatRoomAndMessageAndImageRepository = + new ChatRoomAndMessageAndImageRepositoryImpl(new QuerydslChatRoomAndMessageAndImageRepository(queryFactory)); + } + + @Test + void 지정한_사용자_아이디가_포함된_채팅방을_조회한다() { + // when + final List actual = + chatRoomAndMessageAndImageRepository.findAllChatRoomInfoByUserIdOrderByLastMessage(엔초.getId()); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).hasSize(3); + softAssertions.assertThat(actual.get(0).chatRoom()).isEqualTo(엔초_지토_채팅방); + softAssertions.assertThat(actual.get(0).message()).isEqualTo(엔초가_지토에게_5시에_보낸_쪽지); + softAssertions.assertThat(actual.get(0).thumbnailImage()).isEqualTo(엔초의_경매_대표_이미지); + softAssertions.assertThat(actual.get(1).chatRoom()).isEqualTo(제이미_엔초_채팅방); + softAssertions.assertThat(actual.get(1).message()).isEqualTo(제이미가_엔초에게_4시에_보낸_쪽지); + softAssertions.assertThat(actual.get(1).thumbnailImage()).isEqualTo(제이미의_경매_대표_이미지); + softAssertions.assertThat(actual.get(2).chatRoom()).isEqualTo(메리_엔초_채팅방); + softAssertions.assertThat(actual.get(2).message()).isEqualTo(메리가_엔초에게_3시에_보낸_쪽지); + softAssertions.assertThat(actual.get(2).thumbnailImage()).isEqualTo(메리의_경매_대표_이미지); + }); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomRepositoryImplTest.java new file mode 100644 index 000000000..51b38d031 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomRepositoryImplTest.java @@ -0,0 +1,80 @@ +package com.ddang.ddang.chat.infrastructure.persistence; + +import com.ddang.ddang.chat.domain.ChatRoom; +import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; +import com.ddang.ddang.chat.infrastructure.persistence.fixture.ChatRoomRepositoryImplFixture; +import com.ddang.ddang.configuration.JpaConfiguration; +import com.ddang.ddang.configuration.QuerydslConfiguration; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@Import({JpaConfiguration.class, QuerydslConfiguration.class}) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class ChatRoomRepositoryImplTest extends ChatRoomRepositoryImplFixture { + + ChatRoomRepository chatRoomRepository; + + @BeforeEach + void setUp(@Autowired final JpaChatRoomRepository jpaChatRoomRepository) { + chatRoomRepository = new ChatRoomRepositoryImpl(jpaChatRoomRepository); + } + + @Test + void 채팅방을_저장한다() { + // given + final ChatRoom chatRoom = new ChatRoom(경매, 구매자); + + // when + chatRoomRepository.save(chatRoom); + + assertThat(chatRoom.getId()).isPositive(); + } + + @Test + void 지정한_아이디에_대한_채팅방을_조회한다() { + // when + final Optional actual = chatRoomRepository.findById(채팅방.getId()); + + // then + assertThat(actual).contains(채팅방); + } + + @Test + void 지정한_경매_아이디가_포함된_채팅방의_아이디를_조회한다() { + // when + final Optional actual = chatRoomRepository.findChatRoomIdByAuctionId(경매.getId()); + + // then + assertThat(actual).contains(채팅방.getId()); + } + + @Test + void 지정한_경매_아이디가_포함된_채팅방이_존재한다면_참을_반환한다() { + // when + final boolean actual = chatRoomRepository.existsByAuctionId(경매.getId()); + + // then + assertThat(actual).isTrue(); + } + + @Test + void 지정한_경매_아이디가_포함된_채팅방이_존재하지_않는다면_거짓을_반환한다() { + // when + final boolean actual = chatRoomRepository.existsByAuctionId(존재하지_않는_채팅방_아이디); + + // then + assertThat(actual).isFalse(); + } + +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/JpaChatRoomRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/JpaChatRoomRepositoryTest.java index 074ef8d34..5e5d0da01 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/JpaChatRoomRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/JpaChatRoomRepositoryTest.java @@ -53,6 +53,15 @@ class JpaChatRoomRepositoryTest extends JpaChatRoomRepositoryFixture { assertThat(actual).contains(채팅방); } + @Test + void 지정한_경매_아이디가_포함된_채팅방의_아이디를_조회한다() { + // when + final Optional actual = chatRoomRepository.findChatRoomIdByAuctionId(경매.getId()); + + // then + assertThat(actual).contains(채팅방.getId()); + } + @Test void 지정한_경매_아이디가_포함된_채팅방이_존재한다면_참을_반환한다() { // when diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndImageRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndImageRepositoryTest.java similarity index 86% rename from backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndImageRepositoryImplTest.java rename to backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndImageRepositoryTest.java index 052546a56..9000193fc 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndImageRepositoryImplTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndImageRepositoryTest.java @@ -1,7 +1,7 @@ package com.ddang.ddang.chat.infrastructure.persistence; -import com.ddang.ddang.chat.infrastructure.persistence.dto.ChatRoomAndImageDto; -import com.ddang.ddang.chat.infrastructure.persistence.fixture.QuerydslChatRoomAndImageRepositoryImplFixture; +import com.ddang.ddang.chat.domain.dto.ChatRoomAndImageDto; +import com.ddang.ddang.chat.infrastructure.persistence.fixture.QuerydslChatRoomAndImageRepositoryFixture; import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; import com.querydsl.jpa.impl.JPAQueryFactory; @@ -20,13 +20,13 @@ @Import({JpaConfiguration.class, QuerydslConfiguration.class}) @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @SuppressWarnings("NonAsciiCharacters") -class QuerydslChatRoomAndImageRepositoryImplTest extends QuerydslChatRoomAndImageRepositoryImplFixture { +class QuerydslChatRoomAndImageRepositoryTest extends QuerydslChatRoomAndImageRepositoryFixture { QuerydslChatRoomAndImageRepository querydslChatRoomAndImageRepository; @BeforeEach void setUp(@Autowired final JPAQueryFactory queryFactory) { - querydslChatRoomAndImageRepository = new QuerydslChatRoomAndImageRepositoryImpl(queryFactory); + querydslChatRoomAndImageRepository = new QuerydslChatRoomAndImageRepository(queryFactory); } @Test diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepositoryTest.java similarity index 88% rename from backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepositoryImplTest.java rename to backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepositoryTest.java index ed1804b90..694cb6999 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepositoryImplTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomAndMessageAndImageRepositoryTest.java @@ -1,7 +1,7 @@ package com.ddang.ddang.chat.infrastructure.persistence; -import com.ddang.ddang.chat.infrastructure.persistence.dto.ChatRoomAndMessageAndImageDto; -import com.ddang.ddang.chat.infrastructure.persistence.fixture.QuerydslChatRoomAndMessageAndImageRepositoryImplFixture; +import com.ddang.ddang.chat.domain.dto.ChatRoomAndMessageAndImageDto; +import com.ddang.ddang.chat.infrastructure.persistence.fixture.QuerydslChatRoomAndMessageAndImageRepositoryFixture; import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; import com.querydsl.jpa.impl.JPAQueryFactory; @@ -20,13 +20,13 @@ @Import({JpaConfiguration.class, QuerydslConfiguration.class}) @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @SuppressWarnings("NonAsciiCharacters") -class QuerydslChatRoomAndMessageAndImageRepositoryImplTest extends QuerydslChatRoomAndMessageAndImageRepositoryImplFixture { +class QuerydslChatRoomAndMessageAndImageRepositoryTest extends QuerydslChatRoomAndMessageAndImageRepositoryFixture { QuerydslChatRoomAndMessageAndImageRepository querydslChatRoomAndMessageAndImageRepository; @BeforeEach void setUp(@Autowired final JPAQueryFactory queryFactory) { - querydslChatRoomAndMessageAndImageRepository = new QuerydslChatRoomAndMessageAndImageRepositoryImpl(queryFactory); + querydslChatRoomAndMessageAndImageRepository = new QuerydslChatRoomAndMessageAndImageRepository(queryFactory); } @Test diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomRepositoryImplTest.java deleted file mode 100644 index b9bf60cd8..000000000 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslChatRoomRepositoryImplTest.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.ddang.ddang.chat.infrastructure.persistence; - -import com.ddang.ddang.chat.infrastructure.persistence.fixture.QuerydslChatRoomRepositoryImplFixture; -import com.ddang.ddang.configuration.JpaConfiguration; -import com.ddang.ddang.configuration.QuerydslConfiguration; -import org.junit.jupiter.api.DisplayNameGeneration; -import org.junit.jupiter.api.DisplayNameGenerator; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.context.annotation.Import; - -import java.util.Optional; - -import static org.assertj.core.api.Assertions.assertThat; - -@DataJpaTest -@Import({JpaConfiguration.class, QuerydslConfiguration.class}) -@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) -@SuppressWarnings("NonAsciiCharacters") -class QuerydslChatRoomRepositoryImplTest extends QuerydslChatRoomRepositoryImplFixture { - - @Autowired - JpaChatRoomRepository chatRoomRepository; - - @Test - void 지정한_경매_아이디가_포함된_채팅방의_아이디를_조회한다() { - // when - final Optional actual = chatRoomRepository.findChatRoomIdByAuctionId(경매.getId()); - - // then - assertThat(actual).contains(채팅방.getId()); - } -} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndImageRepositoryImplFixture.java similarity index 57% rename from backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomRepositoryImplFixture.java rename to backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndImageRepositoryImplFixture.java index 36ddea388..238f76175 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndImageRepositoryImplFixture.java @@ -13,103 +13,92 @@ import com.ddang.ddang.category.domain.Category; import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; import com.ddang.ddang.chat.domain.ChatRoom; +import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; +import com.ddang.ddang.chat.infrastructure.persistence.ChatRoomRepositoryImpl; import com.ddang.ddang.chat.infrastructure.persistence.JpaChatRoomRepository; import com.ddang.ddang.image.domain.AuctionImage; import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.repository.UserRepository; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.infrastructure.persistence.UserRepositoryImpl; import com.querydsl.jpa.impl.JPAQueryFactory; -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; -import java.time.LocalDateTime; -import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; -@SuppressWarnings("NonAsciiCharacters") -public class QuerydslChatRoomRepositoryImplFixture { - - @PersistenceContext - private EntityManager em; +import java.time.LocalDateTime; +import java.util.List; - @Autowired - private JPAQueryFactory queryFactory; +@SuppressWarnings("NonAsciiCharacters") +public class ChatRoomAndImageRepositoryImplFixture { - @Autowired - private JpaAuctionRepository jpaAuctionRepository; + private AuctionRepository auctionRepository; @Autowired private JpaCategoryRepository categoryRepository; - @Autowired - private JpaUserRepository userRepository; + private UserRepository userRepository; @Autowired private JpaBidRepository bidRepository; - @Autowired - private JpaChatRoomRepository chatRoomRepository; + private ChatRoomRepository chatRoomRepository; protected AuctionImage 경매_대표_이미지; - protected Auction 경매; protected ChatRoom 채팅방; @BeforeEach - void setUp() { + void fixtureSetUp( + @Autowired final JPAQueryFactory jpaQueryFactory, + @Autowired final JpaAuctionRepository jpaAuctionRepository, + @Autowired final JpaUserRepository jpaUserRepository, + @Autowired final JpaChatRoomRepository jpaChatRoomRepository) { + auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(jpaQueryFactory)); + userRepository = new UserRepositoryImpl(jpaUserRepository); + chatRoomRepository = new ChatRoomRepositoryImpl(jpaChatRoomRepository); + final Category 전자기기_카테고리 = new Category("전자기기"); final Category 전자기기_서브_노트북_카테고리 = new Category("노트북 카테고리"); final ProfileImage 프로필_이미지 = new ProfileImage("upload.png", "store.png"); final User 판매자 = User.builder() - .name("판매자") - .profileImage(프로필_이미지) - .reliability(new Reliability(4.7d)) - .oauthId("12345") - .build(); + .name("판매자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); final User 구매자 = User.builder() - .name("구매자") - .profileImage(프로필_이미지) - .reliability(new Reliability(4.7d)) - .oauthId("12346") - .build(); + .name("구매자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12346") + .build(); final AuctionImage 대표_이미지가_아닌_경매_이미지 = new AuctionImage("대표 이미지가_아닌_경매_이미지.png", "대표 이미지가_아닌_경매_이미지.png"); - - 경매 = Auction.builder() - .seller(판매자) - .title("맥북") - .description("맥북 팔아요") - .subCategory(전자기기_서브_노트북_카테고리) - .startPrice(new Price(10_000)) - .bidUnit(new BidUnit(1_000)) - .closingTime(LocalDateTime.now()) - .build(); - + final Auction 경매 = Auction.builder() + .seller(판매자) + .title("맥북") + .description("맥북 팔아요") + .subCategory(전자기기_서브_노트북_카테고리) + .startPrice(new Price(10_000)) + .bidUnit(new BidUnit(1_000)) + .closingTime(LocalDateTime.now()) + .build(); final Bid 입찰 = new Bid(경매, 구매자, new BidPrice(15_000)); 경매_대표_이미지 = new AuctionImage("경매_대표_이미지.png", "경매_대표_이미지.png"); 채팅방 = new ChatRoom(경매, 구매자); + auctionRepository.save(경매); 전자기기_카테고리.addSubCategory(전자기기_서브_노트북_카테고리); categoryRepository.save(전자기기_카테고리); - userRepository.saveAll(List.of(판매자, 구매자)); + userRepository.save(판매자); + userRepository.save(구매자); 경매.addAuctionImages(List.of(경매_대표_이미지, 대표_이미지가_아닌_경매_이미지)); - - final AuctionRepository auctionRepository = new AuctionRepositoryImpl( - jpaAuctionRepository, - new QuerydslAuctionRepository(queryFactory) - ); - - auctionRepository.save(경매); - bidRepository.save(입찰); 경매.updateLastBid(입찰); - chatRoomRepository.save(채팅방); - - em.flush(); - em.clear(); } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndMessageAndImageRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndMessageAndImageRepositoryImplFixture.java new file mode 100644 index 000000000..910a036b0 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndMessageAndImageRepositoryImplFixture.java @@ -0,0 +1,217 @@ +package com.ddang.ddang.chat.infrastructure.persistence.fixture; + +import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.domain.BidUnit; +import com.ddang.ddang.auction.domain.Price; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.AuctionRepositoryImpl; +import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.bid.domain.Bid; +import com.ddang.ddang.bid.domain.BidPrice; +import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; +import com.ddang.ddang.category.domain.Category; +import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; +import com.ddang.ddang.chat.domain.ChatRoom; +import com.ddang.ddang.chat.domain.Message; +import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; +import com.ddang.ddang.chat.infrastructure.persistence.ChatRoomRepositoryImpl; +import com.ddang.ddang.chat.infrastructure.persistence.JpaChatRoomRepository; +import com.ddang.ddang.chat.infrastructure.persistence.JpaMessageRepository; +import com.ddang.ddang.image.domain.AuctionImage; +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.repository.UserRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.infrastructure.persistence.UserRepositoryImpl; +import com.querydsl.jpa.impl.JPAQueryFactory; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +import java.time.LocalDateTime; +import java.util.List; + +@SuppressWarnings("NonAsciiCharacters") +public class ChatRoomAndMessageAndImageRepositoryImplFixture { + + private AuctionRepository auctionRepository; + + @Autowired + private JpaCategoryRepository categoryRepository; + + private UserRepository userRepository; + + @Autowired + private JpaBidRepository bidRepository; + + private ChatRoomRepository chatRoomRepository; + + @Autowired + private JpaMessageRepository messageRepository; + + protected User 엔초; + protected AuctionImage 메리의_경매_대표_이미지; + protected AuctionImage 엔초의_경매_대표_이미지; + protected AuctionImage 제이미의_경매_대표_이미지; + protected ChatRoom 메리_엔초_채팅방; + protected ChatRoom 엔초_지토_채팅방; + protected ChatRoom 제이미_엔초_채팅방; + protected Message 메리가_엔초에게_3시에_보낸_쪽지; + protected Message 제이미가_엔초에게_4시에_보낸_쪽지; + protected Message 엔초가_지토에게_5시에_보낸_쪽지; + + @BeforeEach + void fixtureSetUp( + @Autowired final JPAQueryFactory jpaQueryFactory, + @Autowired final JpaAuctionRepository jpaAuctionRepository, + @Autowired final JpaUserRepository jpaUserRepository, + @Autowired final JpaChatRoomRepository jpaChatRoomRepository + ) { + auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(jpaQueryFactory)); + userRepository = new UserRepositoryImpl(jpaUserRepository); + chatRoomRepository = new ChatRoomRepositoryImpl(jpaChatRoomRepository); + + final Category 전자기기_카테고리 = new Category("전자기기"); + final Category 전자기기_서브_노트북_카테고리 = new Category("노트북 카테고리"); + final ProfileImage 프로필_이미지 = new ProfileImage("upload.png", "store.png"); + + 엔초 = User.builder() + .name("엔초") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12346") + .build(); + final User 메리 = User.builder() + .name("메리") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); + final User 제이미 = User.builder() + .name("제이미") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12347") + .build(); + final User 지토 = User.builder() + .name("지토") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12348") + .build(); + + 메리의_경매_대표_이미지 = new AuctionImage("메리의_경매_대표_이미지.png", "메리의_경매_대표_이미지.png"); + final AuctionImage 메리의_대표_이미지가_아닌_경매_이미지 = + new AuctionImage("메리의_대표 이미지가_아닌_경매_이미지.png", "메리의_대표 이미지가_아닌_경매_이미지.png"); + 엔초의_경매_대표_이미지 = new AuctionImage("엔초의_경매_대표_이미지.png", "엔초의_경매_대표_이미지.png"); + final AuctionImage 엔초의_대표_이미지가_아닌_경매_이미지 = + new AuctionImage("엔초의_대표 이미지가_아닌_경매_이미지.png", "엔초의_대표 이미지가_아닌_경매_이미지.png"); + 제이미의_경매_대표_이미지 = new AuctionImage("제이미의_경매_대표_이미지.png", "제이미의_경매_대표_이미지.png"); + final AuctionImage 제이미의_대표_이미지가_아닌_경매_이미지 = + new AuctionImage("제이미의_대표 이미지가_아닌_경매_이미지.png", "제이미의_대표 이미지가_아닌_경매_이미지.png"); + + final Auction 메리의_경매 = Auction.builder() + .seller(메리) + .title("메리 맥북") + .description("메리 맥북 팔아요") + .subCategory(전자기기_서브_노트북_카테고리) + .startPrice(new Price(10_000)) + .bidUnit(new BidUnit(1_000)) + .closingTime(LocalDateTime.now()) + .build(); + final Auction 엔초의_경매 = Auction.builder() + .seller(엔초) + .title("엔초 맥북") + .description("엔초 맥북 팔아요") + .subCategory(전자기기_서브_노트북_카테고리) + .startPrice(new Price(10_000)) + .bidUnit(new BidUnit(1_000)) + .closingTime(LocalDateTime.now()) + .build(); + final Auction 제이미의_경매 = Auction.builder() + .seller(제이미) + .title("제이미 맥북") + .description("제이미 맥북 팔아요") + .subCategory(전자기기_서브_노트북_카테고리) + .startPrice(new Price(10_000)) + .bidUnit(new BidUnit(1_000)) + .closingTime(LocalDateTime.now()) + .build(); + + final Bid 엔초가_메리_경매에_입찰 = new Bid(메리의_경매, 엔초, new BidPrice(15_000)); + final Bid 지토가_엔초_경매에_입찰 = new Bid(엔초의_경매, 지토, new BidPrice(15_000)); + final Bid 엔초가_제이미_경매에_입찰 = new Bid(제이미의_경매, 엔초, new BidPrice(15_000)); + + 메리_엔초_채팅방 = new ChatRoom(메리의_경매, 엔초); + 엔초_지토_채팅방 = new ChatRoom(엔초의_경매, 지토); + 제이미_엔초_채팅방 = new ChatRoom(제이미의_경매, 엔초); + + final Message 제이미가_엔초에게_1시에_보낸_쪽지 = Message.builder() + .chatRoom(제이미_엔초_채팅방) + .contents("제이미가 엔초에게 1시애 보낸 쪽지") + .writer(제이미) + .receiver(엔초) + .build(); + final Message 엔초가_지토에게_2시에_보낸_쪽지 = Message.builder() + .chatRoom(엔초_지토_채팅방) + .contents("엔초가 지토에게 2시애 보낸 쪽지") + .writer(엔초) + .receiver(지토) + .build(); + 메리가_엔초에게_3시에_보낸_쪽지 = Message.builder() + .chatRoom(메리_엔초_채팅방) + .contents("메리가 엔초에게 3시에 보낸 쪽지") + .writer(엔초) + .receiver(지토) + .build(); + 제이미가_엔초에게_4시에_보낸_쪽지 = Message.builder() + .chatRoom(제이미_엔초_채팅방) + .contents("제이미가 엔초에게 4시애 보낸 쪽지") + .writer(제이미) + .receiver(엔초) + .build(); + 엔초가_지토에게_5시에_보낸_쪽지 = Message.builder() + .chatRoom(엔초_지토_채팅방) + .contents("엔초가 지토에게 5시애 보낸 쪽지") + .writer(엔초) + .receiver(지토) + .build(); + + + 전자기기_카테고리.addSubCategory(전자기기_서브_노트북_카테고리); + categoryRepository.save(전자기기_카테고리); + + userRepository.save(메리); + userRepository.save(엔초); + userRepository.save(제이미); + userRepository.save(지토); + + 메리의_경매.addAuctionImages(List.of(메리의_경매_대표_이미지, 메리의_대표_이미지가_아닌_경매_이미지)); + 엔초의_경매.addAuctionImages(List.of(엔초의_경매_대표_이미지, 엔초의_대표_이미지가_아닌_경매_이미지)); + 제이미의_경매.addAuctionImages(List.of(제이미의_경매_대표_이미지, 제이미의_대표_이미지가_아닌_경매_이미지)); + + auctionRepository.save(메리의_경매); + auctionRepository.save(엔초의_경매); + auctionRepository.save(제이미의_경매); + + bidRepository.saveAll(List.of(엔초가_메리_경매에_입찰, 지토가_엔초_경매에_입찰, 엔초가_제이미_경매에_입찰)); + 메리의_경매.updateLastBid(엔초가_메리_경매에_입찰); + 엔초의_경매.updateLastBid(지토가_엔초_경매에_입찰); + 제이미의_경매.updateLastBid(엔초가_제이미_경매에_입찰); + + chatRoomRepository.save(메리_엔초_채팅방); + chatRoomRepository.save(엔초_지토_채팅방); + chatRoomRepository.save(제이미_엔초_채팅방); + + messageRepository.saveAll( + List.of( + 제이미가_엔초에게_1시에_보낸_쪽지, + 엔초가_지토에게_2시에_보낸_쪽지, + 메리가_엔초에게_3시에_보낸_쪽지, + 제이미가_엔초에게_4시에_보낸_쪽지, + 엔초가_지토에게_5시에_보낸_쪽지 + ) + ); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomRepositoryImplFixture.java new file mode 100644 index 000000000..54d23f007 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomRepositoryImplFixture.java @@ -0,0 +1,112 @@ +package com.ddang.ddang.chat.infrastructure.persistence.fixture; + +import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.domain.BidUnit; +import com.ddang.ddang.auction.domain.Price; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.AuctionRepositoryImpl; +import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.bid.domain.Bid; +import com.ddang.ddang.bid.domain.BidPrice; +import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; +import com.ddang.ddang.category.domain.Category; +import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; +import com.ddang.ddang.chat.domain.ChatRoom; +import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; +import com.ddang.ddang.chat.infrastructure.persistence.ChatRoomRepositoryImpl; +import com.ddang.ddang.chat.infrastructure.persistence.JpaChatRoomRepository; +import com.ddang.ddang.image.domain.AuctionImage; +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.repository.UserRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.infrastructure.persistence.UserRepositoryImpl; +import com.querydsl.jpa.impl.JPAQueryFactory; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +import java.time.LocalDateTime; +import java.util.List; + +@SuppressWarnings("NonAsciiCharacters") +public class ChatRoomRepositoryImplFixture { + + @Autowired + private JpaCategoryRepository categoryRepository; + + private UserRepository userRepository; + + private AuctionRepository auctionRepository; + + @Autowired + private JpaBidRepository bidRepository; + + private ChatRoomRepository chatRoomRepository; + + protected User 판매자; + protected User 구매자; + protected Auction 경매; + private Bid 입찰; + protected ChatRoom 채팅방; + protected Long 존재하지_않는_채팅방_아이디 = -999L; + + @BeforeEach + void fixtureSetUp( + @Autowired final JPAQueryFactory queryFactory, + @Autowired final JpaAuctionRepository jpaAuctionRepository, + @Autowired final JpaUserRepository jpaUserRepository, + @Autowired final JpaChatRoomRepository jpaChatRoomRepository + ) { + auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(queryFactory)); + userRepository = new UserRepositoryImpl(jpaUserRepository); + chatRoomRepository = new ChatRoomRepositoryImpl(jpaChatRoomRepository); + + final Category 전자기기_카테고리 = new Category("전자기기"); + final Category 전자기기_서브_노트북_카테고리 = new Category("노트북 카테고리"); + final ProfileImage 프로필_이미지 = new ProfileImage("upload.png", "store.png"); + final AuctionImage 경매이미지1 = new AuctionImage("경매이미지1.png", "경매이미지1.png"); + final AuctionImage 경매이미지2 = new AuctionImage("경매이미지2.png", "경매이미지2.png"); + + 판매자 = User.builder() + .name("판매자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); + 구매자 = User.builder() + .name("구매자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12346") + .build(); + 경매 = Auction.builder() + .seller(판매자) + .title("맥북") + .description("맥북 팔아요") + .subCategory(전자기기_서브_노트북_카테고리) + .startPrice(new Price(10_000)) + .bidUnit(new BidUnit(1_000)) + .closingTime(LocalDateTime.now()) + .build(); + + 입찰 = new Bid(경매, 구매자, new BidPrice(15_000)); + + 채팅방 = new ChatRoom(경매, 구매자); + + 전자기기_카테고리.addSubCategory(전자기기_서브_노트북_카테고리); + categoryRepository.save(전자기기_카테고리); + + userRepository.save(판매자); + userRepository.save(구매자); + + 경매.addAuctionImages(List.of(경매이미지1, 경매이미지2)); + auctionRepository.save(경매); + + bidRepository.save(입찰); + 경매.updateLastBid(입찰); + + chatRoomRepository.save(채팅방); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndImageRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndImageRepositoryFixture.java similarity index 98% rename from backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndImageRepositoryImplFixture.java rename to backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndImageRepositoryFixture.java index 4d3898633..8285b0a5c 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndImageRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndImageRepositoryFixture.java @@ -22,13 +22,14 @@ import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; -import java.time.LocalDateTime; -import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; +import java.time.LocalDateTime; +import java.util.List; + @SuppressWarnings("NonAsciiCharacters") -public class QuerydslChatRoomAndImageRepositoryImplFixture { +public class QuerydslChatRoomAndImageRepositoryFixture { @PersistenceContext private EntityManager em; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndMessageAndImageRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndMessageAndImageRepositoryFixture.java similarity index 99% rename from backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndMessageAndImageRepositoryImplFixture.java rename to backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndMessageAndImageRepositoryFixture.java index e82911db1..49bdf7e18 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndMessageAndImageRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslChatRoomAndMessageAndImageRepositoryFixture.java @@ -24,13 +24,14 @@ import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; -import java.time.LocalDateTime; -import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; +import java.time.LocalDateTime; +import java.util.List; + @SuppressWarnings("NonAsciiCharacters") -public class QuerydslChatRoomAndMessageAndImageRepositoryImplFixture { +public class QuerydslChatRoomAndMessageAndImageRepositoryFixture { @PersistenceContext private EntityManager em; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java index 1850fa822..083220f23 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java @@ -9,7 +9,7 @@ import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; import com.ddang.ddang.chat.domain.ChatRoom; import com.ddang.ddang.chat.domain.Message; -import com.ddang.ddang.chat.infrastructure.persistence.JpaChatRoomRepository; +import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; import com.ddang.ddang.chat.infrastructure.persistence.JpaMessageRepository; import com.ddang.ddang.device.domain.DeviceToken; import com.ddang.ddang.device.infrastructure.persistence.JpaDeviceTokenRepository; @@ -37,7 +37,7 @@ public class FcmNotificationServiceFixture { private JpaMessageRepository messageRepository; @Autowired - private JpaChatRoomRepository chatRoomRepository; + private ChatRoomRepository chatRoomRepository; @Autowired private JpaDeviceTokenRepository deviceTokenRepository; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java index b1a1db5d7..81fb61456 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java @@ -15,7 +15,7 @@ import com.ddang.ddang.chat.application.event.MessageNotificationEvent; import com.ddang.ddang.chat.domain.ChatRoom; import com.ddang.ddang.chat.domain.Message; -import com.ddang.ddang.chat.infrastructure.persistence.JpaChatRoomRepository; +import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; import com.ddang.ddang.chat.infrastructure.persistence.JpaMessageRepository; import com.ddang.ddang.image.domain.AuctionImage; import com.ddang.ddang.image.domain.ProfileImage; @@ -40,7 +40,7 @@ public class NotificationEventListenerFixture { private UserRepository userRepository; @Autowired - private JpaChatRoomRepository chatRoomRepository; + private ChatRoomRepository chatRoomRepository; @Autowired private AuctionRepository auctionRepository; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/ChatRoomReportServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/ChatRoomReportServiceFixture.java index 5667e7670..56e34897d 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/ChatRoomReportServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/ChatRoomReportServiceFixture.java @@ -7,7 +7,7 @@ import com.ddang.ddang.category.domain.Category; import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; import com.ddang.ddang.chat.domain.ChatRoom; -import com.ddang.ddang.chat.infrastructure.persistence.JpaChatRoomRepository; +import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; import com.ddang.ddang.image.domain.AuctionImage; import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.image.infrastructure.persistence.JpaAuctionImageRepository; @@ -18,6 +18,7 @@ import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; @@ -46,7 +47,7 @@ public class ChatRoomReportServiceFixture { private JpaChatRoomReportRepository chatRoomReportRepository; @Autowired - private JpaChatRoomRepository chatRoomRepository; + private ChatRoomRepository chatRoomRepository; protected User 이미_신고한_구매자1; protected User 이미_신고한_구매자2; @@ -156,7 +157,9 @@ void setUp() { auctionRepository.save(경매2); auctionRepository.save(경매3); - chatRoomRepository.saveAll(List.of(채팅방1, 채팅방2, 채팅방3)); + chatRoomRepository.save(채팅방1); + chatRoomRepository.save(채팅방2); + chatRoomRepository.save(채팅방3); chatRoomReportRepository.saveAll(List.of(채팅방_신고1, 채팅방_신고2, 채팅방_신고3)); From 3f630373e26e52bcd267638b2a4400b7fa420613 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=EC=98=88=EC=A7=84?= <96688810+kwonyj1022@users.noreply.github.com> Date: Sun, 15 Oct 2023 00:00:57 +0900 Subject: [PATCH 18/37] =?UTF-8?q?refactor:=20#658=20Region=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=9D=B8=ED=94=84=EB=9D=BC=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81=20(#665)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 도메인 영역의 지역 Repository 추가 * feat: 도메인 영역의 지역 Repository 구현체 추가 * test: 누락된 테스트 케이스 추가 * refactor: Service에서 도메인 영역의 지역 Repository를 사용하도록 변경 * test: 테스트에서 Jpa 의존 제거 * test: 테스트에서 Jpa 의존 제거 * style: 공백 추가 * refactor: 누락된 final 추가 --- .../auction/application/AuctionService.java | 4 +- .../region/application/RegionService.java | 4 +- .../domain/repository/RegionRepository.java | 23 +++ .../persistence/RegionRepositoryImpl.java | 51 +++++++ .../fixture/AuctionServiceFixture.java | 14 +- .../fixture/AuctionRepositoryImplFixture.java | 9 +- .../fixture/QuestionServiceFixture.java | 4 +- .../region/application/RegionServiceTest.java | 43 +++--- .../fixture/RegionServiceFixture.java | 4 +- .../persistence/JpaRegionRepositoryTest.java | 28 ++++ .../persistence/RegionRepositoryImplTest.java | 142 ++++++++++++++++++ .../fixture/RegionRepositoryImplFixture.java | 42 ++++++ 12 files changed, 331 insertions(+), 37 deletions(-) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/region/domain/repository/RegionRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/region/infrastructure/persistence/RegionRepositoryImpl.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/region/infrastructure/persistence/RegionRepositoryImplTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/region/infrastructure/persistence/fixture/RegionRepositoryImplFixture.java diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/application/AuctionService.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/application/AuctionService.java index 40d66f714..cc9164410 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/application/AuctionService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/application/AuctionService.java @@ -18,7 +18,7 @@ import com.ddang.ddang.region.application.exception.RegionNotFoundException; import com.ddang.ddang.region.domain.AuctionRegion; import com.ddang.ddang.region.domain.Region; -import com.ddang.ddang.region.infrastructure.persistence.JpaRegionRepository; +import com.ddang.ddang.region.domain.repository.RegionRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -38,7 +38,7 @@ public class AuctionService { private final UserRepository userRepository; private final AuctionRepository auctionRepository; - private final JpaRegionRepository regionRepository; + private final RegionRepository regionRepository; private final CategoryRepository categoryRepository; private final StoreImageProcessor imageProcessor; diff --git a/backend/ddang/src/main/java/com/ddang/ddang/region/application/RegionService.java b/backend/ddang/src/main/java/com/ddang/ddang/region/application/RegionService.java index 9b6583f27..9df0a51ad 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/region/application/RegionService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/region/application/RegionService.java @@ -4,7 +4,7 @@ import com.ddang.ddang.region.application.exception.RegionNotFoundException; import com.ddang.ddang.region.domain.InitializationRegionProcessor; import com.ddang.ddang.region.domain.Region; -import com.ddang.ddang.region.infrastructure.persistence.JpaRegionRepository; +import com.ddang.ddang.region.domain.repository.RegionRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -16,7 +16,7 @@ @RequiredArgsConstructor public class RegionService { - private final JpaRegionRepository regionRepository; + private final RegionRepository regionRepository; private final InitializationRegionProcessor regionProcessor; @Transactional diff --git a/backend/ddang/src/main/java/com/ddang/ddang/region/domain/repository/RegionRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/region/domain/repository/RegionRepository.java new file mode 100644 index 000000000..0f2f039ea --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/region/domain/repository/RegionRepository.java @@ -0,0 +1,23 @@ +package com.ddang.ddang.region.domain.repository; + +import com.ddang.ddang.region.domain.Region; + +import java.util.List; +import java.util.Optional; + +public interface RegionRepository { + + Region save(final Region region); + + List saveAll(final List regions); + + List findFirstAll(); + + List findSecondAllByFirstRegionId(final Long firstRegionId); + + List findThirdAllByFirstAndSecondRegionId(final Long firstRegionId, final Long secondRegionId); + + Optional findThirdRegionById(final Long thirdRegionId); + + List findAllThirdRegionByIds(final List thirdRegionIds); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/region/infrastructure/persistence/RegionRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/region/infrastructure/persistence/RegionRepositoryImpl.java new file mode 100644 index 000000000..0847afd30 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/region/infrastructure/persistence/RegionRepositoryImpl.java @@ -0,0 +1,51 @@ +package com.ddang.ddang.region.infrastructure.persistence; + +import com.ddang.ddang.region.domain.Region; +import com.ddang.ddang.region.domain.repository.RegionRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +@RequiredArgsConstructor +public class RegionRepositoryImpl implements RegionRepository { + + private final JpaRegionRepository jpaRegionRepository; + + @Override + public Region save(final Region region) { + return jpaRegionRepository.save(region); + } + + @Override + public List saveAll(final List regions) { + return jpaRegionRepository.saveAll(regions); + } + + @Override + public List findFirstAll() { + return jpaRegionRepository.findFirstAll(); + } + + @Override + public List findSecondAllByFirstRegionId(final Long firstRegionId) { + return jpaRegionRepository.findSecondAllByFirstRegionId(firstRegionId); + } + + @Override + public List findThirdAllByFirstAndSecondRegionId(final Long firstRegionId, final Long secondRegionId) { + return jpaRegionRepository.findThirdAllByFirstAndSecondRegionId(firstRegionId, secondRegionId); + } + + @Override + public Optional findThirdRegionById(final Long thirdRegionId) { + return jpaRegionRepository.findThirdRegionById(thirdRegionId); + } + + @Override + public List findAllThirdRegionByIds(final List thirdRegionIds) { + return jpaRegionRepository.findAllThirdRegionByIds(thirdRegionIds); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/application/fixture/AuctionServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/application/fixture/AuctionServiceFixture.java index 69f0fb77f..cd395f802 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/application/fixture/AuctionServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/application/fixture/AuctionServiceFixture.java @@ -12,7 +12,7 @@ import com.ddang.ddang.image.domain.dto.StoreImageDto; import com.ddang.ddang.region.domain.AuctionRegion; import com.ddang.ddang.region.domain.Region; -import com.ddang.ddang.region.infrastructure.persistence.JpaRegionRepository; +import com.ddang.ddang.region.domain.repository.RegionRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -31,7 +31,7 @@ public class AuctionServiceFixture { private AuctionRepository auctionRepository; @Autowired - private JpaRegionRepository regionRepository; + private RegionRepository regionRepository; @Autowired private JpaCategoryRepository categoryRepository; @@ -52,11 +52,11 @@ public class AuctionServiceFixture { .oauthId("12345") .build(); protected User 구매자 = User.builder() - .name("구매자") - .profileImage(new ProfileImage("upload.png", "store.png")) - .reliability(new Reliability(4.7d)) - .oauthId("54321") - .build(); + .name("구매자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("54321") + .build(); private MockMultipartFile 경매_이미지_파일 = new MockMultipartFile( "image.png", diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java index 78ea8a4d7..39c030a62 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java @@ -16,7 +16,9 @@ import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.region.domain.AuctionRegion; import com.ddang.ddang.region.domain.Region; +import com.ddang.ddang.region.domain.repository.RegionRepository; import com.ddang.ddang.region.infrastructure.persistence.JpaRegionRepository; +import com.ddang.ddang.region.infrastructure.persistence.RegionRepositoryImpl; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -41,8 +43,7 @@ public class AuctionRepositoryImplFixture { private UserRepository userRepository; - @Autowired - private JpaRegionRepository regionRepository; + private RegionRepository regionRepository; @Autowired private JpaCategoryRepository categoryRepository; @@ -73,10 +74,12 @@ public class AuctionRepositoryImplFixture { void fixtureSetUp( @Autowired final JPAQueryFactory jpaQueryFactory, @Autowired final JpaAuctionRepository jpaAuctionRepository, - @Autowired final JpaUserRepository jpaUserRepository + @Autowired final JpaUserRepository jpaUserRepository, + @Autowired final JpaRegionRepository jpaRegionRepository ) { auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(jpaQueryFactory)); userRepository = new UserRepositoryImpl(jpaUserRepository); + regionRepository = new RegionRepositoryImpl(jpaRegionRepository); final Region 서울특별시 = new Region("서울특별시"); final Region 강남구 = new Region("강남구"); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java index 37e4d8019..477e6a4fa 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java @@ -16,7 +16,7 @@ import com.ddang.ddang.qna.infrastructure.JpaAnswerRepository; import com.ddang.ddang.qna.infrastructure.JpaQuestionRepository; import com.ddang.ddang.region.domain.Region; -import com.ddang.ddang.region.infrastructure.persistence.JpaRegionRepository; +import com.ddang.ddang.region.domain.repository.RegionRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -42,7 +42,7 @@ public class QuestionServiceFixture { private JpaAnswerRepository answerRepository; @Autowired - private JpaRegionRepository regionRepository; + private RegionRepository regionRepository; @Autowired private JpaCategoryRepository categoryRepository; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/region/application/RegionServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/region/application/RegionServiceTest.java index 017f1bca1..58549f268 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/region/application/RegionServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/region/application/RegionServiceTest.java @@ -5,7 +5,7 @@ import com.ddang.ddang.region.application.fixture.RegionServiceFixture; import com.ddang.ddang.region.domain.InitializationRegionProcessor; import com.ddang.ddang.region.domain.Region; -import com.ddang.ddang.region.infrastructure.persistence.JpaRegionRepository; +import com.ddang.ddang.region.domain.repository.RegionRepository; import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; @@ -15,6 +15,7 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.transaction.annotation.Transactional; +import java.util.ArrayList; import java.util.List; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -33,7 +34,7 @@ class RegionServiceTest extends RegionServiceFixture { RegionService regionService; @Autowired - JpaRegionRepository regionRepository; + RegionRepository regionRepository; @Test void 대한민국_전국의_지역을_초기화한다() { @@ -44,25 +45,29 @@ class RegionServiceTest extends RegionServiceFixture { regionService.createRegions(); // then - final List actual = regionRepository.findAll(); + final List actualAllFirsts = regionRepository.findFirstAll(); - final Region actualFirstRegion1 = actual.get(0); - final Region actualFirstRegion2 = actual.get(5); - final Region actualSecondRegion1OfFirstRegion1 = actualFirstRegion1.getSecondRegions().get(0); - final Region actualSecondRegion2OfFirstRegion1 = actualFirstRegion1.getSecondRegions().get(1); - final Region actualThirdRegion1OfSecondRegion1 = actualSecondRegion1OfFirstRegion1.getThirdRegions().get(0); - final Region actualThirdRegion2OfSecondRegion1 = actualSecondRegion1OfFirstRegion1.getThirdRegions().get(1); + List actualAllSeconds = new ArrayList<>(); + for (final Region first : actualAllFirsts) { + actualAllSeconds.addAll(regionRepository.findSecondAllByFirstRegionId(first.getId())); + } + + List actualAllThirds = new ArrayList<>(); + for (final Region second : actualAllSeconds) { + final Region first = second.getFirstRegion(); + actualAllThirds.addAll(regionRepository.findThirdAllByFirstAndSecondRegionId(first.getId(), second.getId())); + } SoftAssertions.assertSoftly(softAssertions -> { - softAssertions.assertThat(actual).hasSize(6); - softAssertions.assertThat(actualFirstRegion1).isEqualTo(서울특별시); - softAssertions.assertThat(actualFirstRegion2).isEqualTo(두번째_지역이_없는_첫번째_지역); - softAssertions.assertThat(actualFirstRegion1.getSecondRegions()).hasSize(2); - softAssertions.assertThat(actualSecondRegion1OfFirstRegion1).isEqualTo(서울특별시_강남구); - softAssertions.assertThat(actualSecondRegion2OfFirstRegion1).isEqualTo(세번째_지역이_없는_두번째_지역); - softAssertions.assertThat(actualSecondRegion1OfFirstRegion1.getThirdRegions()).hasSize(2); - softAssertions.assertThat(actualThirdRegion1OfSecondRegion1).isEqualTo(서울특별시_강남구_삼성동); - softAssertions.assertThat(actualThirdRegion2OfSecondRegion1).isEqualTo(서울특별시_강남구_대치동); + softAssertions.assertThat(actualAllFirsts).hasSize(2); + softAssertions.assertThat(actualAllSeconds).hasSize(2); + softAssertions.assertThat(actualAllThirds).hasSize(2); + softAssertions.assertThat(actualAllFirsts.get(0)).isEqualTo(서울특별시); + softAssertions.assertThat(actualAllFirsts.get(1)).isEqualTo(두번째_지역이_없는_첫번째_지역); + softAssertions.assertThat(actualAllSeconds.get(0)).isEqualTo(서울특별시_강남구); + softAssertions.assertThat(actualAllSeconds.get(1)).isEqualTo(세번째_지역이_없는_두번째_지역); + softAssertions.assertThat(actualAllThirds.get(0)).isEqualTo(서울특별시_강남구_삼성동); + softAssertions.assertThat(actualAllThirds.get(1)).isEqualTo(서울특별시_강남구_대치동); }); } @@ -103,7 +108,7 @@ class RegionServiceTest extends RegionServiceFixture { @Test void 두번째_지역에_해당하는_모든_세번째_지역을_조회한다() { // when - final List actual = + final List actual = regionService.readAllThirdByFirstAndSecondRegionId(서울특별시.getId(), 서울특별시_강남구.getId()); // then diff --git a/backend/ddang/src/test/java/com/ddang/ddang/region/application/fixture/RegionServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/region/application/fixture/RegionServiceFixture.java index 4a55a76e9..dc3d8a04c 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/region/application/fixture/RegionServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/region/application/fixture/RegionServiceFixture.java @@ -1,7 +1,7 @@ package com.ddang.ddang.region.application.fixture; import com.ddang.ddang.region.domain.Region; -import com.ddang.ddang.region.infrastructure.persistence.JpaRegionRepository; +import com.ddang.ddang.region.domain.repository.RegionRepository; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; @@ -9,7 +9,7 @@ public class RegionServiceFixture { @Autowired - private JpaRegionRepository regionRepository; + private RegionRepository regionRepository; protected Region 서울특별시; protected Region 두번째_지역이_없는_첫번째_지역; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/region/infrastructure/persistence/JpaRegionRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/region/infrastructure/persistence/JpaRegionRepositoryTest.java index 2461e0ac3..0bbb9b402 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/region/infrastructure/persistence/JpaRegionRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/region/infrastructure/persistence/JpaRegionRepositoryTest.java @@ -25,6 +25,34 @@ class JpaRegionRepositoryTest extends JpaRegionRepositoryFixture { @Autowired JpaRegionRepository regionRepository; + @Test + void 지역을_저장한다() { + // given + final Region region = new Region("region1"); + + // when + final Region actual = regionRepository.save(region); + + // then + assertThat(actual.getId()).isPositive(); + } + + @Test + void 지역을_여러개_한번에_저장한다() { + // given + final Region region1 = new Region("region1"); + final Region region2 = new Region("region2"); + + // when + final List actual = regionRepository.saveAll(List.of(region1, region2)); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual.get(0).getId()).isPositive(); + softAssertions.assertThat(actual.get(1).getId()).isPositive(); + }); + } + @Test void 모든_첫번째_지역을_조회한다() { // when diff --git a/backend/ddang/src/test/java/com/ddang/ddang/region/infrastructure/persistence/RegionRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/region/infrastructure/persistence/RegionRepositoryImplTest.java new file mode 100644 index 000000000..fb4be9bdd --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/region/infrastructure/persistence/RegionRepositoryImplTest.java @@ -0,0 +1,142 @@ +package com.ddang.ddang.region.infrastructure.persistence; + +import com.ddang.ddang.configuration.QuerydslConfiguration; +import com.ddang.ddang.region.domain.Region; +import com.ddang.ddang.region.domain.repository.RegionRepository; +import com.ddang.ddang.region.infrastructure.persistence.fixture.RegionRepositoryImplFixture; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@Import(QuerydslConfiguration.class) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class RegionRepositoryImplTest extends RegionRepositoryImplFixture { + + RegionRepository regionRepository; + + @BeforeEach + void setUp(@Autowired final JpaRegionRepository jpaRegionRepository) { + regionRepository = new RegionRepositoryImpl(jpaRegionRepository); + } + + @Test + void 지역을_저장한다() { + // given + final Region region = new Region("region1"); + + // when + final Region actual = regionRepository.save(region); + + // then + assertThat(actual.getId()).isPositive(); + } + + @Test + void 지역을_여러개_한번에_저장한다() { + // given + final Region region1 = new Region("region1"); + final Region region2 = new Region("region2"); + + // when + final List actual = regionRepository.saveAll(List.of(region1, region2)); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual.get(0).getId()).isPositive(); + softAssertions.assertThat(actual.get(1).getId()).isPositive(); + }); + } + + @Test + void 모든_첫번째_지역을_조회한다() { + // when + final List actual = regionRepository.findFirstAll(); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).hasSize(2); + softAssertions.assertThat(actual.get(0)).isEqualTo(서울특별시); + softAssertions.assertThat(actual.get(1)).isEqualTo(경기도); + }); + } + + @Test + void 첫번째_지역에_해당하는_모든_두번째_지역을_조회한다() { + // when + final List actual = regionRepository.findSecondAllByFirstRegionId(서울특별시.getId()); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).hasSize(2); + softAssertions.assertThat(actual.get(0)).isEqualTo(서울특별시_강남구); + softAssertions.assertThat(actual.get(1)).isEqualTo(서울특별시_송파구); + }); + } + + @Test + void 두번째_지역에_해당하는_모든_세번째_지역을_조회한다() { + // when + final List actual = + regionRepository.findThirdAllByFirstAndSecondRegionId(서울특별시.getId(), 서울특별시_강남구.getId()); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).hasSize(2); + softAssertions.assertThat(actual.get(0)).isEqualTo(서울특별시_강남구_삼성동); + softAssertions.assertThat(actual.get(1)).isEqualTo(서울특별시_강남구_대치동); + }); + } + + @Test + void 세번째_지역을_조회한다() { + // when + final Optional actual = regionRepository.findThirdRegionById(서울특별시_강남구_삼성동.getId()); + + // then + assertThat(actual).contains(서울특별시_강남구_삼성동); + } + + @Test + void 세번째_지역이_아닌_아이디를_전달하면_빈_Optional을_반환한다() { + // when + final Optional actual = regionRepository.findThirdRegionById(서울특별시.getId()); + + // then + assertThat(actual).isEmpty(); + } + + @Test + void 세번째_지역에_해당하는_모든_id를_전달하면_그에_맞는_thirdRegions를_반환한다() { + // when + final List thirdRegionIds = List.of(서울특별시_강남구_삼성동.getId(), 서울특별시_강남구_대치동.getId()); + final List actual = regionRepository.findAllThirdRegionByIds(thirdRegionIds); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).hasSize(2); + softAssertions.assertThat(actual.get(0)).isEqualTo(서울특별시_강남구_삼성동); + softAssertions.assertThat(actual.get(1)).isEqualTo(서울특별시_강남구_대치동); + }); + } + + @Test + void 세번째_지역이_아닌_아이디를_전달하면_빈_List를_반환한다() { + // when + final List actual = regionRepository.findAllThirdRegionByIds(List.of(서울특별시.getId())); + + // then + assertThat(actual).isEmpty(); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/region/infrastructure/persistence/fixture/RegionRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/region/infrastructure/persistence/fixture/RegionRepositoryImplFixture.java new file mode 100644 index 000000000..3226cced4 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/region/infrastructure/persistence/fixture/RegionRepositoryImplFixture.java @@ -0,0 +1,42 @@ +package com.ddang.ddang.region.infrastructure.persistence.fixture; + +import com.ddang.ddang.region.domain.Region; +import com.ddang.ddang.region.domain.repository.RegionRepository; +import com.ddang.ddang.region.infrastructure.persistence.JpaRegionRepository; +import com.ddang.ddang.region.infrastructure.persistence.RegionRepositoryImpl; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +@SuppressWarnings("NonAsciiCharacters") +public class RegionRepositoryImplFixture { + + private RegionRepository regionRepository; + + protected Region 서울특별시; + protected Region 경기도; + protected Region 서울특별시_강남구; + protected Region 서울특별시_송파구; + protected Region 서울특별시_강남구_삼성동; + protected Region 서울특별시_강남구_대치동; + + @BeforeEach + void fixtureSetUp(@Autowired final JpaRegionRepository jpaRegionRepository) { + regionRepository = new RegionRepositoryImpl(jpaRegionRepository); + + 서울특별시 = new Region("서울특별시"); + 경기도 = new Region("경기도"); + 서울특별시_강남구 = new Region("강남구"); + 서울특별시_송파구 = new Region("송파구"); + 서울특별시_강남구_삼성동 = new Region("삼성동"); + 서울특별시_강남구_대치동 = new Region("대치동"); + + 서울특별시.addSecondRegion(서울특별시_강남구); + 서울특별시.addSecondRegion(서울특별시_송파구); + + 서울특별시_강남구.addThirdRegion(서울특별시_강남구_삼성동); + 서울특별시_강남구.addThirdRegion(서울특별시_강남구_대치동); + + regionRepository.save(서울특별시); + regionRepository.save(경기도); + } +} From 34aa5fa59d3a8a30e7727b40fd34746c38066372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=EC=98=88=EC=A7=84?= <96688810+kwonyj1022@users.noreply.github.com> Date: Sun, 15 Oct 2023 00:11:39 +0900 Subject: [PATCH 19/37] =?UTF-8?q?refactor:=20#657=20Review=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=9D=B8=ED=94=84=EB=9D=BC=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81=20(#664)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 도메인 영역의 평가 Repository 추가 * feat: 도메인 영역의 평가 Repository 구현체 추가 * refactor: Service에서 도메인 영역의 평가 Repository를 사용하도록 변경 * test: 픽스처에서 Jpa 의존 제거 * test: 테스트 실패 케이스 해결 * refactor: 누락된 final 추가 * ci: 브랜치 최신화 과정에서 누락된 사항 추가 및 충돌 해결 --- .../review/application/ReviewService.java | 4 +- .../domain/repository/ReviewRepository.java | 21 +++ .../persistence/ReviewRepositoryImpl.java | 46 +++++ .../ReliabilityUpdateSchedulingService.java | 4 +- .../fixture/ReviewServiceFixture.java | 8 +- .../persistence/ReviewRepositoryImplTest.java | 106 +++++++++++ .../fixture/ReviewRepositoryImplFixture.java | 169 ++++++++++++++++++ ...abilityUpdateSchedulingServiceFixture.java | 28 ++- 8 files changed, 373 insertions(+), 13 deletions(-) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/review/domain/repository/ReviewRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/review/infrastructure/persistence/ReviewRepositoryImpl.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/review/infrastructure/persistence/ReviewRepositoryImplTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/review/infrastructure/persistence/fixture/ReviewRepositoryImplFixture.java diff --git a/backend/ddang/src/main/java/com/ddang/ddang/review/application/ReviewService.java b/backend/ddang/src/main/java/com/ddang/ddang/review/application/ReviewService.java index 0b405c60f..187c85b90 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/review/application/ReviewService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/review/application/ReviewService.java @@ -10,7 +10,7 @@ import com.ddang.ddang.review.application.exception.InvalidUserToReview; import com.ddang.ddang.review.application.exception.ReviewNotFoundException; import com.ddang.ddang.review.domain.Review; -import com.ddang.ddang.review.infrastructure.persistence.JpaReviewRepository; +import com.ddang.ddang.review.domain.repository.ReviewRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -26,7 +26,7 @@ @RequiredArgsConstructor public class ReviewService { - private final JpaReviewRepository reviewRepository; + private final ReviewRepository reviewRepository; private final AuctionRepository auctionRepository; private final UserRepository userRepository; diff --git a/backend/ddang/src/main/java/com/ddang/ddang/review/domain/repository/ReviewRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/review/domain/repository/ReviewRepository.java new file mode 100644 index 000000000..fb726b725 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/review/domain/repository/ReviewRepository.java @@ -0,0 +1,21 @@ +package com.ddang.ddang.review.domain.repository; + +import com.ddang.ddang.review.domain.Review; + +import java.util.List; +import java.util.Optional; + +public interface ReviewRepository { + + Review save(final Review review); + + Optional findById(final Long id); + + List findAllByTargetId(final Long targetId); + + Optional findByAuctionIdAndWriterId(final Long auctionId, final Long writerId); + + List findAllByIdGreaterThan(final Long id); + + boolean existsByAuctionIdAndWriterId(final Long auctionId, final Long writerId); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/review/infrastructure/persistence/ReviewRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/review/infrastructure/persistence/ReviewRepositoryImpl.java new file mode 100644 index 000000000..cf5581243 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/review/infrastructure/persistence/ReviewRepositoryImpl.java @@ -0,0 +1,46 @@ +package com.ddang.ddang.review.infrastructure.persistence; + +import com.ddang.ddang.review.domain.Review; +import com.ddang.ddang.review.domain.repository.ReviewRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +@RequiredArgsConstructor +public class ReviewRepositoryImpl implements ReviewRepository { + + private final JpaReviewRepository jpaReviewRepository; + + @Override + public Review save(final Review review) { + return jpaReviewRepository.save(review); + } + + @Override + public Optional findById(final Long id) { + return jpaReviewRepository.findById(id); + } + + @Override + public List findAllByTargetId(final Long targetId) { + return jpaReviewRepository.findAllByTargetId(targetId); + } + + @Override + public Optional findByAuctionIdAndWriterId(final Long auctionId, final Long writerId) { + return jpaReviewRepository.findByAuctionIdAndWriterId(auctionId, writerId); + } + + @Override + public List findAllByIdGreaterThan(final Long id) { + return jpaReviewRepository.findAllByIdGreaterThan(id); + } + + @Override + public boolean existsByAuctionIdAndWriterId(final Long auctionId, final Long writerId) { + return jpaReviewRepository.existsByAuctionIdAndWriterId(auctionId, writerId); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/application/schedule/ReliabilityUpdateSchedulingService.java b/backend/ddang/src/main/java/com/ddang/ddang/user/application/schedule/ReliabilityUpdateSchedulingService.java index 4ffb2d732..9601e3615 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/user/application/schedule/ReliabilityUpdateSchedulingService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/application/schedule/ReliabilityUpdateSchedulingService.java @@ -2,7 +2,7 @@ import com.ddang.ddang.review.domain.Review; import com.ddang.ddang.review.domain.Reviews; -import com.ddang.ddang.review.infrastructure.persistence.JpaReviewRepository; +import com.ddang.ddang.review.domain.repository.ReviewRepository; import com.ddang.ddang.user.domain.ReliabilityUpdateHistory; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.UserReliability; @@ -22,7 +22,7 @@ public class ReliabilityUpdateSchedulingService { private final ReliabilityUpdateHistoryRepository updateHistoryRepository; - private final JpaReviewRepository reviewRepository; + private final ReviewRepository reviewRepository; private final UserReliabilityRepository userReliabilityRepository; @Transactional diff --git a/backend/ddang/src/test/java/com/ddang/ddang/review/application/fixture/ReviewServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/review/application/fixture/ReviewServiceFixture.java index 538668b20..d9ca8775c 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/review/application/fixture/ReviewServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/review/application/fixture/ReviewServiceFixture.java @@ -11,7 +11,7 @@ import com.ddang.ddang.review.application.dto.CreateReviewDto; import com.ddang.ddang.review.domain.Review; import com.ddang.ddang.review.domain.Score; -import com.ddang.ddang.review.infrastructure.persistence.JpaReviewRepository; +import com.ddang.ddang.review.domain.repository.ReviewRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -34,7 +34,7 @@ public class ReviewServiceFixture { private AuctionRepository auctionRepository; @Autowired - private JpaReviewRepository reviewRepository; + private ReviewRepository reviewRepository; private double 구매자가_판매자1에게_받은_평가_점수 = 5.0d; private double 구매자가_판매자2에게_받은_평가_점수 = 1.0d; @@ -159,7 +159,9 @@ void setUp() { .content("별로다.") .score(new Score(구매자가_판매자2에게_받은_평가_점수)) .build(); - reviewRepository.saveAll(List.of(구매자가_판매자1에게_받은_평가, 구매자가_판매자2에게_받은_평가)); + + reviewRepository.save(구매자가_판매자1에게_받은_평가); + reviewRepository.save(구매자가_판매자2에게_받은_평가); 구매자가_이전까지_받은_평가_총2개 = List.of(구매자가_판매자1에게_받은_평가, 구매자가_판매자2에게_받은_평가); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/review/infrastructure/persistence/ReviewRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/review/infrastructure/persistence/ReviewRepositoryImplTest.java new file mode 100644 index 000000000..e69b34a68 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/review/infrastructure/persistence/ReviewRepositoryImplTest.java @@ -0,0 +1,106 @@ +package com.ddang.ddang.review.infrastructure.persistence; + +import com.ddang.ddang.configuration.JpaConfiguration; +import com.ddang.ddang.configuration.QuerydslConfiguration; +import com.ddang.ddang.review.domain.Review; +import com.ddang.ddang.review.domain.repository.ReviewRepository; +import com.ddang.ddang.review.infrastructure.persistence.fixture.ReviewRepositoryImplFixture; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@Import({JpaConfiguration.class, QuerydslConfiguration.class}) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class ReviewRepositoryImplTest extends ReviewRepositoryImplFixture { + + ReviewRepository reviewRepository; + + @BeforeEach + void setUp(@Autowired final JpaReviewRepository jpaReviewRepository) { + reviewRepository = new ReviewRepositoryImpl(jpaReviewRepository); + } + + @Test + void 평가를_저장한다() { + // when + reviewRepository.save(저장하려는_평가); + + // then + assertThat(저장하려는_평가.getId()).isPositive(); + } + + @Test + void 지정한_경매_아이디와_작성자_아이디를_포함하는_평가가_존재하면_참을_반환한다() { + // when + final boolean actual = reviewRepository.existsByAuctionIdAndWriterId(판매자1이_평가한_경매.getId(), 판매자1.getId()); + + // then + assertThat(actual).isTrue(); + } + + @Test + void 지정한_채팅방_아이디를_포함하는_평가가_존재하지_않는다면_거짓을_반환한다() { + // when + final boolean actual = reviewRepository.existsByAuctionIdAndWriterId(평가_안한_경매.getId(), 평가_안한_경매_판매자.getId()); + + // then + assertThat(actual).isFalse(); + } + + @Test + void 지정한_아이디가_평가_대상_아이디에_해당하는_평가_목록을_최신순으로_조회한다() { + // when + final List actual = reviewRepository.findAllByTargetId(구매자.getId()); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).hasSize(2); + softAssertions.assertThat(actual.get(0)).isEqualTo(구매자가_판매자2에게_받은_평가); + softAssertions.assertThat(actual.get(1)).isEqualTo(구매자가_판매자1에게_받은_평가); + }); + } + + @Test + void 지정한_경매_아이디와_작성자_아이디가_해당하는_평가가_존재한다면_optional에_넣어_반환한다() { + // when + final Optional actual = + reviewRepository.findByAuctionIdAndWriterId(판매자1이_평가한_경매.getId(), 판매자1.getId()); + + // then + assertThat(actual).contains(구매자가_판매자1에게_받은_평가); + } + + @Test + void 지정한_경매_아이디와_작성자_아이디가_해당하는_평가가_존재하지_않는다면_빈_optional을_반환한다() { + // when + final Optional actual = + reviewRepository.findByAuctionIdAndWriterId(평가_안한_경매.getId(), 평가_안한_경매_판매자.getId()); + + // then + assertThat(actual).isEmpty(); + } + + @Test + void 지정한_평가_아이디보다_아이디가_큰_평가_목록을_조회한다() { + // when + final List actual = reviewRepository.findAllByIdGreaterThan(구매자가_판매자1에게_받은_평가.getId()); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).hasSize(1); + softAssertions.assertThat(actual.get(0)).isEqualTo(구매자가_판매자2에게_받은_평가); + }); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/review/infrastructure/persistence/fixture/ReviewRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/review/infrastructure/persistence/fixture/ReviewRepositoryImplFixture.java new file mode 100644 index 000000000..55e9a4554 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/review/infrastructure/persistence/fixture/ReviewRepositoryImplFixture.java @@ -0,0 +1,169 @@ +package com.ddang.ddang.review.infrastructure.persistence.fixture; + +import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.domain.BidUnit; +import com.ddang.ddang.auction.domain.Price; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.AuctionRepositoryImpl; +import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.category.domain.Category; +import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; +import com.ddang.ddang.image.domain.AuctionImage; +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.review.domain.Review; +import com.ddang.ddang.review.domain.Score; +import com.ddang.ddang.review.domain.repository.ReviewRepository; +import com.ddang.ddang.review.infrastructure.persistence.JpaReviewRepository; +import com.ddang.ddang.review.infrastructure.persistence.ReviewRepositoryImpl; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.repository.UserRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.infrastructure.persistence.UserRepositoryImpl; +import com.querydsl.jpa.impl.JPAQueryFactory; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +import java.time.LocalDateTime; +import java.util.List; + +@SuppressWarnings("NonAsciiCharacters") +public class ReviewRepositoryImplFixture { + + @Autowired + private JpaCategoryRepository categoryRepository; + + private UserRepository userRepository; + + private AuctionRepository auctionRepository; + + private ReviewRepository reviewRepository; + + protected User 판매자1; + protected User 판매자2; + protected User 평가_안한_경매_판매자; + protected User 구매자; + protected Auction 판매자1이_평가한_경매; + protected Auction 판매자2가_평가한_경매; + protected Auction 평가_안한_경매; + protected Review 저장하려는_평가; + protected Review 구매자가_판매자1에게_받은_평가; + protected Review 구매자가_판매자2에게_받은_평가; + + @BeforeEach + void fixtureSetUp( + @Autowired final JPAQueryFactory jpaQueryFactory, + @Autowired final JpaAuctionRepository jpaAuctionRepository, + @Autowired final JpaUserRepository jpaUserRepository, + @Autowired final JpaReviewRepository jpaReviewRepository + ) { + auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(jpaQueryFactory)); + userRepository = new UserRepositoryImpl(jpaUserRepository); + reviewRepository = new ReviewRepositoryImpl(jpaReviewRepository); + + final Category 전자기기_카테고리 = new Category("전자기기"); + final Category 전자기기_서브_노트북_카테고리 = new Category("노트북 카테고리"); + 전자기기_카테고리.addSubCategory(전자기기_서브_노트북_카테고리); + categoryRepository.save(전자기기_카테고리); + + final ProfileImage 평가_안한_판매자_프로필_이미지 = new ProfileImage("no_review_seller_profile.png", "no_review_seller_profile.png"); + final ProfileImage 판매자1_프로필_이미지 = new ProfileImage("seller1_profile.png", "seller1_profile.png"); + final ProfileImage 판매자2_프로필_이미지 = new ProfileImage("seller2_profile.png", "seller2_profile.png"); + final ProfileImage 구매자_프로필_이미지 = new ProfileImage("buyer_profile.png", "buyer_profile.png"); + + 판매자1 = User.builder() + .name("판매자1") + .profileImage(판매자1_프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); + 판매자2 = User.builder() + .name("판매자2") + .profileImage(판매자2_프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12346") + .build(); + 평가_안한_경매_판매자 = User.builder() + .name("평가 안한 판매자") + .profileImage(평가_안한_판매자_프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12346") + .build(); + 구매자 = User.builder() + .name("구매자") + .profileImage(구매자_프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12347") + .build(); + + userRepository.save(판매자1); + userRepository.save(판매자2); + userRepository.save(평가_안한_경매_판매자); + userRepository.save(구매자); + + final AuctionImage 경매1_대표_이미지 = new AuctionImage("경매1_대표_이미지.png", "경매1_대표_이미지.png"); + final AuctionImage 경매2_대표_이미지 = new AuctionImage("경매2_대표_이미지.png", "경매2_대표_이미지.png"); + final AuctionImage 평가_안한_경매_대표_이미지 = new AuctionImage("평가_안한_경매_대표_이미지.png", "평가_안한_경매_대표_이미지.png"); + + 판매자1이_평가한_경매 = Auction.builder() + .seller(판매자1) + .title("맥북") + .description("맥북 팔아요") + .subCategory(전자기기_서브_노트북_카테고리) + .startPrice(new Price(10_000)) + .bidUnit(new BidUnit(1_000)) + .closingTime(LocalDateTime.now()) + .build(); + 판매자2가_평가한_경매 = Auction.builder() + .seller(판매자2) + .title("맥북") + .description("맥북 팔아요") + .subCategory(전자기기_서브_노트북_카테고리) + .startPrice(new Price(10_000)) + .bidUnit(new BidUnit(1_000)) + .closingTime(LocalDateTime.now()) + .build(); + 평가_안한_경매 = Auction.builder() + .seller(판매자2) + .title("맥북") + .description("맥북 팔아요") + .subCategory(전자기기_서브_노트북_카테고리) + .startPrice(new Price(10_000)) + .bidUnit(new BidUnit(1_000)) + .closingTime(LocalDateTime.now()) + .build(); + + 판매자1이_평가한_경매.addAuctionImages(List.of(경매1_대표_이미지)); + 판매자2가_평가한_경매.addAuctionImages(List.of(경매2_대표_이미지)); + 평가_안한_경매.addAuctionImages(List.of(평가_안한_경매_대표_이미지)); + auctionRepository.save(판매자1이_평가한_경매); + auctionRepository.save(판매자2가_평가한_경매); + auctionRepository.save(평가_안한_경매); + + 저장하려는_평가 = Review.builder() + .auction(평가_안한_경매) + .writer(판매자1) + .target(구매자) + .content("친절하다.") + .score(new Score(5.0d)) + .build(); + 구매자가_판매자1에게_받은_평가 = Review.builder() + .auction(판매자1이_평가한_경매) + .writer(판매자1) + .target(구매자) + .content("친절하다.") + .score(new Score(5.0d)) + .build(); + 구매자가_판매자2에게_받은_평가 = Review.builder() + .auction(판매자2가_평가한_경매) + .writer(판매자2) + .target(구매자) + .content("별로다.") + .score(new Score(1.0d)) + .build(); + + reviewRepository.save(구매자가_판매자1에게_받은_평가); + reviewRepository.save(구매자가_판매자2에게_받은_평가); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/fixture/ReliabilityUpdateSchedulingServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/fixture/ReliabilityUpdateSchedulingServiceFixture.java index 64b7a6183..bfeee8785 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/fixture/ReliabilityUpdateSchedulingServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/application/schedule/fixture/ReliabilityUpdateSchedulingServiceFixture.java @@ -6,7 +6,7 @@ import com.ddang.ddang.review.domain.Review; import com.ddang.ddang.review.domain.Reviews; import com.ddang.ddang.review.domain.Score; -import com.ddang.ddang.review.infrastructure.persistence.JpaReviewRepository; +import com.ddang.ddang.review.domain.repository.ReviewRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.ReliabilityUpdateHistory; import com.ddang.ddang.user.domain.User; @@ -29,7 +29,7 @@ public class ReliabilityUpdateSchedulingServiceFixture { private AuctionRepository auctionRepository; @Autowired - private JpaReviewRepository reviewRepository; + private ReviewRepository reviewRepository; @Autowired private UserReliabilityRepository userReliabilityRepository; @@ -281,8 +281,17 @@ void setUp() { .target(구매자3_기존_평가_5개_새로운_평가_1개) .score(new Score(구매자3_기존_신뢰도_점수)) .build(); - reviewRepository.saveAll(List.of(구매자1_기존_평가1, 구매자1_기존_평가2, 구매자2_기존_평가1, 구매자2_기존_평가2, 구매자2_기존_평가3, 구매자3_기존_평가1, 구매자3_기존_평가2, 구매자3_기존_평가3, 구매자3_기존_평가4, 구매자3_기존_평가5 - )); + + reviewRepository.save(구매자1_기존_평가1); + reviewRepository.save(구매자1_기존_평가2); + reviewRepository.save(구매자2_기존_평가1); + reviewRepository.save(구매자2_기존_평가2); + reviewRepository.save(구매자2_기존_평가3); + reviewRepository.save(구매자3_기존_평가1); + reviewRepository.save(구매자3_기존_평가2); + reviewRepository.save(구매자3_기존_평가3); + reviewRepository.save(구매자3_기존_평가4); + reviewRepository.save(구매자3_기존_평가5); final UserReliability 구매자1_기존_신뢰도_반영_정보 = new UserReliability(구매자1_기존_평가_2개_새로운_평가_1개); 구매자1_기존_신뢰도_반영_정보.updateReliability(new Reviews(List.of(구매자1_기존_평가1, 구매자1_기존_평가2))); @@ -347,7 +356,14 @@ void setUp() { .target(구매자5_기존_평가_없고_새로운_평가_3개) .score(new Score(구매자5_새로운_평가3_점수)) .build(); - reviewRepository.saveAll(List.of(구매자1_새로운_평가1, 구매자2_새로운_평가1, 구매자2_새로운_평가2, 구매자3_새로운_평가1, 구매자4_새로운_평가1, 구매자5_새로운_평가1, 구매자5_새로운_평가2, 구매자5_새로운_평가3 - )); + + reviewRepository.save(구매자1_새로운_평가1); + reviewRepository.save(구매자2_새로운_평가1); + reviewRepository.save(구매자2_새로운_평가2); + reviewRepository.save(구매자3_새로운_평가1); + reviewRepository.save(구매자4_새로운_평가1); + reviewRepository.save(구매자5_새로운_평가1); + reviewRepository.save(구매자5_새로운_평가2); + reviewRepository.save(구매자5_새로운_평가3); } } From a45c7d294733fd8ece737eeabd7d12bb33289659 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=9C=EC=9D=B4=EB=AF=B8?= <63184334+JJ503@users.noreply.github.com> Date: Sun, 15 Oct 2023 01:34:35 +0900 Subject: [PATCH 20/37] =?UTF-8?q?refactor:=20#659=20=EC=9E=85=EC=B0=B0=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20API=20=EB=AA=85?= =?UTF-8?q?=EC=84=B8=20=EB=B3=80=EA=B2=BD=EC=97=90=20=EB=94=B0=EB=A5=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#667)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 입찰 목록 조회 시 배열이 그대로 반환되도록 수정 * docs: 문서화 최신화 * refactor: 체이닝 개행 수정 --- .../ddang/bid/presentation/BidController.java | 11 +-- .../dto/response/ReadBidsResponse.java | 6 -- .../src/main/resources/static/docs/docs.html | 90 +++++++++---------- .../bid/presentation/BidControllerTest.java | 36 ++++---- 4 files changed, 66 insertions(+), 77 deletions(-) delete mode 100644 backend/ddang/src/main/java/com/ddang/ddang/bid/presentation/dto/response/ReadBidsResponse.java diff --git a/backend/ddang/src/main/java/com/ddang/ddang/bid/presentation/BidController.java b/backend/ddang/src/main/java/com/ddang/ddang/bid/presentation/BidController.java index 89cba81ba..1da1c3378 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/bid/presentation/BidController.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/bid/presentation/BidController.java @@ -7,7 +7,6 @@ import com.ddang.ddang.bid.application.dto.ReadBidDto; import com.ddang.ddang.bid.presentation.dto.request.CreateBidRequest; import com.ddang.ddang.bid.presentation.dto.response.ReadBidResponse; -import com.ddang.ddang.bid.presentation.dto.response.ReadBidsResponse; import com.ddang.ddang.image.presentation.util.ImageRelativeUrl; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -41,13 +40,11 @@ public ResponseEntity create( } @GetMapping("/{auctionId}") - public ResponseEntity readAllByAuctionId(@PathVariable final Long auctionId) { + public ResponseEntity> readAllByAuctionId(@PathVariable final Long auctionId) { final List readBidDtos = bidService.readAllByAuctionId(auctionId); - final List readBidResponses = readBidDtos.stream() - .map(ReadBidResponse::from) - .toList(); - - final ReadBidsResponse response = new ReadBidsResponse(readBidResponses); + final List response = readBidDtos.stream() + .map(ReadBidResponse::from) + .toList(); return ResponseEntity.ok(response); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/bid/presentation/dto/response/ReadBidsResponse.java b/backend/ddang/src/main/java/com/ddang/ddang/bid/presentation/dto/response/ReadBidsResponse.java deleted file mode 100644 index 31bca3148..000000000 --- a/backend/ddang/src/main/java/com/ddang/ddang/bid/presentation/dto/response/ReadBidsResponse.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.ddang.ddang.bid.presentation.dto.response; - -import java.util.List; - -public record ReadBidsResponse(List bids) { -} diff --git a/backend/ddang/src/main/resources/static/docs/docs.html b/backend/ddang/src/main/resources/static/docs/docs.html index 0054f2344..fe00d2198 100644 --- a/backend/ddang/src/main/resources/static/docs/docs.html +++ b/backend/ddang/src/main/resources/static/docs/docs.html @@ -655,7 +655,7 @@

응답

{ "accessToken" : "Bearer accessToken", "refreshToken" : "Bearer refreshToken", - "persisted" : false + "isSignUpUser" : false } @@ -684,7 +684,7 @@

응답

Refresh Token

-

persisted

+

isSignUpUser

Boolean

최초 로그인 여부(회원가입)

@@ -904,7 +904,7 @@

탈퇴

요청

-
POST /oauth2/withdrawal/kakao HTTP/1.1
+
POST /oauth2/withdrawal HTTP/1.1
 Content-Type: application/json
 Authorization: Bearer accessToken
 
@@ -1469,7 +1469,7 @@ 

요청

Content-Disposition: form-data; name=request; filename=request Content-Type: application/json -{"title":"제목","description":"내용","bidUnit":1000,"startPrice":1000,"closingTime":"2023-10-14T14:17:47.075705","subCategoryId":2,"thirdRegionIds":[3]} +{"title":"제목","description":"내용","bidUnit":1000,"startPrice":1000,"closingTime":"2023-10-18T00:23:05.544558","subCategoryId":2,"thirdRegionIds":[3]} --6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm--
@@ -2076,8 +2076,8 @@

응답

"lastBidPrice" : null, "status" : "UNBIDDEN", "bidUnit" : 1000, - "registerTime" : "2023-10-11T14:17:47", - "closingTime" : "2023-10-11T14:17:47", + "registerTime" : "2023-10-15T00:23:05", + "closingTime" : "2023-10-15T00:23:05", "directRegions" : [ { "first" : "서울특별시", "second" : "강서구", @@ -2599,7 +2599,7 @@

응답

"name" : "질문자", "image" : "http://localhost:8080/users/images/1" }, - "createdTime" : "2023-10-11T14:17:47", + "createdTime" : "2023-10-15T00:23:05", "content" : "질문1" }, "answer" : { @@ -2609,7 +2609,7 @@

응답

"name" : "판매자", "image" : "http://localhost:8080/users/images/2" }, - "createdTime" : "2023-10-11T14:17:47", + "createdTime" : "2023-10-15T00:23:05", "content" : "답변1" } }, { @@ -2620,7 +2620,7 @@

응답

"name" : "질문자", "image" : "http://localhost:8080/users/images/1" }, - "createdTime" : "2023-10-11T14:17:47", + "createdTime" : "2023-10-15T00:23:05", "content" : "질문2" }, "answer" : { @@ -2630,7 +2630,7 @@

응답

"name" : "판매자", "image" : "http://localhost:8080/users/images/2" }, - "createdTime" : "2023-10-11T14:17:47", + "createdTime" : "2023-10-15T00:23:05", "content" : "답변1" } } ] @@ -2834,19 +2834,17 @@

응답

HTTP/1.1 200 OK
 Content-Type: application/json
 
-{
-  "bids" : [ {
-    "name" : "사용자1",
-    "profileImage" : "http://localhost:8080/users/images/1",
-    "price" : 10000,
-    "bidTime" : "2023-10-11T14:17:53"
-  }, {
-    "name" : "사용자2",
-    "profileImage" : "http://localhost:8080/users/images/2",
-    "price" : 12000,
-    "bidTime" : "2023-10-11T14:17:53"
-  } ]
-}
+[ { + "name" : "사용자1", + "profileImage" : "http://localhost:8080/users/images/1", + "price" : 10000, + "bidTime" : "2023-10-15T00:23:10" +}, { + "name" : "사용자2", + "profileImage" : "http://localhost:8080/users/images/2", + "price" : 12000, + "bidTime" : "2023-10-15T00:23:10" +} ]
@@ -2864,27 +2862,27 @@

응답

- + - + - + - + - + @@ -3039,7 +3037,7 @@

응답

"price" : 10000 }, "lastMessage" : { - "createdAt" : "2023-10-11T14:17:54", + "createdAt" : "2023-10-15T00:23:11", "contents" : "메시지1" }, "isChatAvailable" : true @@ -3057,7 +3055,7 @@

응답

"price" : 20000 }, "lastMessage" : { - "createdAt" : "2023-10-11T14:17:54", + "createdAt" : "2023-10-15T00:23:11", "contents" : "메시지2" }, "isChatAvailable" : true @@ -3495,7 +3493,7 @@

응답

[ { "id" : 1, - "createdAt" : "2023-10-11T14:17:54", + "createdAt" : "2023-10-15T00:23:11", "isMyMessage" : true, "contents" : "메시지내용" } ] @@ -3645,7 +3643,7 @@

응답

"id" : 2, "name" : "회원1" }, - "createdTime" : "2023-10-11T14:18:01", + "createdTime" : "2023-10-15T00:23:18", "auction" : { "id" : 1, "title" : "제목" @@ -3657,7 +3655,7 @@

응답

"id" : 3, "name" : "회원2" }, - "createdTime" : "2023-10-11T14:18:01", + "createdTime" : "2023-10-15T00:23:18", "auction" : { "id" : 1, "title" : "제목" @@ -3669,7 +3667,7 @@

응답

"id" : 4, "name" : "회원3" }, - "createdTime" : "2023-10-11T14:18:01", + "createdTime" : "2023-10-15T00:23:18", "auction" : { "id" : 1, "title" : "제목" @@ -3833,7 +3831,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-11T14:18:01", + "createdTime" : "2023-10-15T00:23:18", "chatRoom" : { "id" : 1 }, @@ -3844,7 +3842,7 @@

응답

"id" : 3, "name" : "구매자2" }, - "createdTime" : "2023-10-11T14:18:01", + "createdTime" : "2023-10-15T00:23:18", "chatRoom" : { "id" : 1 }, @@ -3855,7 +3853,7 @@

응답

"id" : 3, "name" : "구매자2" }, - "createdTime" : "2023-10-11T14:18:01", + "createdTime" : "2023-10-15T00:23:18", "chatRoom" : { "id" : 1 }, @@ -4019,7 +4017,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-11T14:18:01", + "createdTime" : "2023-10-15T00:23:18", "question" : { "id" : 1 }, @@ -4030,7 +4028,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-11T14:18:01", + "createdTime" : "2023-10-15T00:23:18", "question" : { "id" : 2 }, @@ -4041,7 +4039,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-11T14:18:01", + "createdTime" : "2023-10-15T00:23:18", "question" : { "id" : 3 }, @@ -4205,7 +4203,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-11T14:18:01", + "createdTime" : "2023-10-15T00:23:18", "answer" : { "id" : 1 }, @@ -4216,7 +4214,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-11T14:18:01", + "createdTime" : "2023-10-15T00:23:18", "answer" : { "id" : 2 }, @@ -4227,7 +4225,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-11T14:18:01", + "createdTime" : "2023-10-15T00:23:18", "answer" : { "id" : 3 }, @@ -4563,7 +4561,7 @@

응답

}, "content" : "친절하다.", "score" : 5.0, - "createdTime" : "2023-10-11T14:18:02" + "createdTime" : "2023-10-15T00:23:19" }, { "id" : 2, "writer" : { @@ -4573,7 +4571,7 @@

응답

}, "content" : "친절하다.", "score" : 5.0, - "createdTime" : "2023-10-11T14:18:02" + "createdTime" : "2023-10-15T00:23:19" } ] @@ -4731,7 +4729,7 @@

응답

diff --git a/backend/ddang/src/test/java/com/ddang/ddang/bid/presentation/BidControllerTest.java b/backend/ddang/src/test/java/com/ddang/ddang/bid/presentation/BidControllerTest.java index 5a37badd4..6ec3319da 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/bid/presentation/BidControllerTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/bid/presentation/BidControllerTest.java @@ -377,14 +377,14 @@ private static Stream provideBidRequestWithNotPositiveBidPrice ) .andExpectAll( status().isOk(), - jsonPath("$.bids.[0].name", is(입찰_정보_dto1.name())), - jsonPath("$.bids.[0].profileImage").exists(), - jsonPath("$.bids.[0].price", is(입찰_정보_dto1.price())), - jsonPath("$.bids.[0].bidTime").exists(), - jsonPath("$.bids.[1].name", is(입찰_정보_dto2.name())), - jsonPath("$.bids.[1].profileImage").exists(), - jsonPath("$.bids.[1].price", is(입찰_정보_dto2.price())), - jsonPath("$.bids.[1].bidTime").exists() + jsonPath("$.[0].name", is(입찰_정보_dto1.name())), + jsonPath("$.[0].profileImage").exists(), + jsonPath("$.[0].price", is(입찰_정보_dto1.price())), + jsonPath("$.[0].bidTime").exists(), + jsonPath("$.[1].name", is(입찰_정보_dto2.name())), + jsonPath("$.[1].profileImage").exists(), + jsonPath("$.[1].price", is(입찰_정보_dto2.price())), + jsonPath("$.[1].bidTime").exists() ); readAllByAuctionId_문서화(resultActions); @@ -423,16 +423,16 @@ private static Stream provideBidRequestWithNotPositiveBidPrice resultActions.andDo( restDocs.document( responseFields( - fieldWithPath("bids.[]").type(JsonFieldType.ARRAY) - .description("특정 경매의 모든 입찰 목록"), - fieldWithPath("bids.[].name").type(JsonFieldType.STRING) - .description("입찰한 사용자의 닉네임"), - fieldWithPath("bids.[].profileImage").type(JsonFieldType.STRING) - .description("입찰한 사용자의 프로필 이미지 URL"), - fieldWithPath("bids.[].price").type(JsonFieldType.NUMBER) - .description("입찰한 금액"), - fieldWithPath("bids.[].bidTime").type(JsonFieldType.STRING) - .description("입찰한 시간") + fieldWithPath("[]").type(JsonFieldType.ARRAY) + .description("특정 경매의 모든 입찰 목록"), + fieldWithPath("[].name").type(JsonFieldType.STRING) + .description("입찰한 사용자의 닉네임"), + fieldWithPath("[].profileImage").type(JsonFieldType.STRING) + .description("입찰한 사용자의 프로필 이미지 URL"), + fieldWithPath("[].price").type(JsonFieldType.NUMBER) + .description("입찰한 금액"), + fieldWithPath("[].bidTime").type(JsonFieldType.STRING) + .description("입찰한 시간") ) ) ); From d9a302615d704002e628189130d1ae3afd8650bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=9C=EC=9D=B4=EB=AF=B8?= <63184334+JJ503@users.noreply.github.com> Date: Sun, 15 Oct 2023 01:35:07 +0900 Subject: [PATCH 21/37] =?UTF-8?q?refactor:=20#660=20Q&A=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20API=20=EB=AA=85=EC=84=B8=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20(#669)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 컨벤션에 따른 개행 수정 * feat: 질문과 답변 조회 시 질문 작성자인지 판단하는 값 추가 * refactor: 컨벤션에 따른 개행 수정 * refactor: 메서드 순서 변경 * fix: 충돌로 발생한 문제 해결 * refactor: import 와일드카드 제거 --- .../presentation/AuctionQnaController.java | 9 ++++-- .../dto/response/ReadQuestionResponse.java | 7 +++-- .../ReadUserInAuctionQuestionResponse.java | 4 +-- .../qna/application/QuestionService.java | 8 +++-- .../ddang/qna/application/dto/ReadQnaDto.java | 5 ++-- .../qna/application/dto/ReadQnasDto.java | 5 ++-- .../qna/application/dto/ReadQuestionDto.java | 19 ++++++++++-- .../ddang/qna/presentation/QnaController.java | 30 +++++++++++-------- .../dto/response/ReadReporterResponse.java | 1 + .../AuctionQnaControllerTest.java | 8 +++-- .../AuctionQuestionControllerFixture.java | 4 +-- .../qna/application/QuestionServiceTest.java | 7 +++-- .../fixture/QuestionServiceFixture.java | 17 ++++++++--- .../QuestionReportServiceTest.java | 2 +- 14 files changed, 86 insertions(+), 40 deletions(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/AuctionQnaController.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/AuctionQnaController.java index 42f9da78f..9a9c4e12d 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/AuctionQnaController.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/AuctionQnaController.java @@ -1,6 +1,8 @@ package com.ddang.ddang.auction.presentation; import com.ddang.ddang.auction.presentation.dto.response.ReadQnasResponse; +import com.ddang.ddang.authentication.configuration.AuthenticateUser; +import com.ddang.ddang.authentication.domain.dto.AuthenticationUserInfo; import com.ddang.ddang.qna.application.QuestionService; import com.ddang.ddang.qna.application.dto.ReadQnasDto; import lombok.RequiredArgsConstructor; @@ -18,8 +20,11 @@ public class AuctionQnaController { private final QuestionService questionService; @GetMapping("/{auctionId}/questions") - public ResponseEntity readAllByAuctionId(@PathVariable final Long auctionId) { - final ReadQnasDto readQnasDto = questionService.readAllByAuctionId(auctionId); + public ResponseEntity readAllByAuctionId( + @AuthenticateUser AuthenticationUserInfo userInfo, + @PathVariable final Long auctionId + ) { + final ReadQnasDto readQnasDto = questionService.readAllByAuctionId(auctionId, userInfo.userId()); final ReadQnasResponse response = ReadQnasResponse.from(readQnasDto); return ResponseEntity.ok(response); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadQuestionResponse.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadQuestionResponse.java index 9a3305a8a..efc17e944 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadQuestionResponse.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadQuestionResponse.java @@ -13,7 +13,9 @@ public record ReadQuestionResponse( @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss", timezone = "Asia/Seoul") LocalDateTime createdTime, - String content + String content, + + boolean isQuestioner ) { public static ReadQuestionResponse from(final ReadQuestionDto readQuestionDto) { @@ -21,7 +23,8 @@ public static ReadQuestionResponse from(final ReadQuestionDto readQuestionDto) { readQuestionDto.id(), ReadUserInAuctionQuestionResponse.from(readQuestionDto.readUserInQnaDto()), readQuestionDto.createdTime(), - readQuestionDto.content() + readQuestionDto.content(), + readQuestionDto.isQuestioner() ); } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadUserInAuctionQuestionResponse.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadUserInAuctionQuestionResponse.java index b9f3d7051..96691511a 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadUserInAuctionQuestionResponse.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadUserInAuctionQuestionResponse.java @@ -6,9 +6,7 @@ public record ReadUserInAuctionQuestionResponse(Long id, String name, String image) { - public static ReadUserInAuctionQuestionResponse from( - final ReadUserInQnaDto writerDto - ) { + public static ReadUserInAuctionQuestionResponse from(final ReadUserInQnaDto writerDto) { return new ReadUserInAuctionQuestionResponse( writerDto.id(), writerDto.name(), diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java index 3eedae7b3..49a758758 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java @@ -14,8 +14,8 @@ import com.ddang.ddang.qna.infrastructure.JpaQuestionRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.domain.repository.UserRepository; import lombok.RequiredArgsConstructor; +import com.ddang.ddang.user.domain.repository.UserRepository; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -64,14 +64,16 @@ private void checkInvalidQuestioner(final Auction auction, final User questioner } } - public ReadQnasDto readAllByAuctionId(final Long auctionId) { + public ReadQnasDto readAllByAuctionId(final Long auctionId, final Long userId) { if (!auctionRepository.existsById(auctionId)) { throw new AuctionNotFoundException("해당 경매를 찾을 수 없습니다."); } + final User user = userRepository.findById(userId) + .orElse(User.EMPTY_USER); final List questions = questionRepository.findAllByAuctionId(auctionId); - return ReadQnasDto.from(questions); + return ReadQnasDto.of(questions, user); } @Transactional diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadQnaDto.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadQnaDto.java index 4b99a000a..2927b3fbe 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadQnaDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadQnaDto.java @@ -1,14 +1,15 @@ package com.ddang.ddang.qna.application.dto; import com.ddang.ddang.qna.domain.Question; +import com.ddang.ddang.user.domain.User; public record ReadQnaDto( ReadQuestionDto readQuestionDto, ReadAnswerDto readAnswerDto ) { - public static ReadQnaDto from(final Question question) { - final ReadQuestionDto readQuestionDto = ReadQuestionDto.from(question); + public static ReadQnaDto of(final Question question, final User user) { + final ReadQuestionDto readQuestionDto = ReadQuestionDto.of(question, user); final ReadAnswerDto readAnswerDto = processReadAnswerDto(question); return new ReadQnaDto(readQuestionDto, readAnswerDto); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadQnasDto.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadQnasDto.java index 92d776a5a..ba5d72c85 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadQnasDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadQnasDto.java @@ -1,14 +1,15 @@ package com.ddang.ddang.qna.application.dto; import com.ddang.ddang.qna.domain.Question; +import com.ddang.ddang.user.domain.User; import java.util.List; public record ReadQnasDto(List readQnaDtos) { - public static ReadQnasDto from(final List questions) { + public static ReadQnasDto of(final List questions, final User user) { final List readQnaDtos = questions.stream() - .map(ReadQnaDto::from) + .map(question -> ReadQnaDto.of(question, user)) .toList(); return new ReadQnasDto(readQnaDtos); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadQuestionDto.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadQuestionDto.java index edca5530e..07123720f 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadQuestionDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadQuestionDto.java @@ -1,6 +1,7 @@ package com.ddang.ddang.qna.application.dto; import com.ddang.ddang.qna.domain.Question; +import com.ddang.ddang.user.domain.User; import java.time.LocalDateTime; @@ -8,15 +9,27 @@ public record ReadQuestionDto( Long id, ReadUserInQnaDto readUserInQnaDto, String content, - LocalDateTime createdTime + LocalDateTime createdTime, + boolean isQuestioner ) { - public static ReadQuestionDto from(final Question question) { + private static final boolean IS_NOT_WRITER = false; + + public static ReadQuestionDto of(final Question question, final User user) { return new ReadQuestionDto( question.getId(), ReadUserInQnaDto.from(question.getWriter()), question.getContent(), - question.getCreatedTime() + question.getCreatedTime(), + isWriter(question, user) ); } + + private static boolean isWriter(final Question question, final User user) { + if (user == User.EMPTY_USER) { + return IS_NOT_WRITER; + } + + return question.isWriter(user); + } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/presentation/QnaController.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/presentation/QnaController.java index 5641fa81b..0c56c7f5e 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/presentation/QnaController.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/presentation/QnaController.java @@ -34,32 +34,38 @@ public ResponseEntity createQuestion( @AuthenticateUser AuthenticationUserInfo userInfo, @RequestBody @Valid final CreateQuestionRequest questionRequest ) { - questionService.create(CreateQuestionDto.of(questionRequest, userInfo.userId()), ImageRelativeUrl.AUCTION.calculateAbsoluteUrl()); + questionService.create( + CreateQuestionDto.of(questionRequest, userInfo.userId()), + ImageRelativeUrl.AUCTION.calculateAbsoluteUrl() + ); return ResponseEntity.created(URI.create("/auctions/" + questionRequest.auctionId())) .build(); } - @PostMapping("/{questionId}/answers") - public ResponseEntity createAnswer( + @DeleteMapping("/{questionId}") + public ResponseEntity deleteQuestion( @AuthenticateUser AuthenticationUserInfo userInfo, - @PathVariable final Long questionId, - @RequestBody @Valid final CreateAnswerRequest answerRequest + @PathVariable final Long questionId ) { - answerService.create(CreateAnswerDto.of(questionId, answerRequest, userInfo.userId()), ImageRelativeUrl.AUCTION.calculateAbsoluteUrl()); + questionService.deleteById(questionId, userInfo.userId()); - return ResponseEntity.created(URI.create("/auctions/" + answerRequest.auctionId())) + return ResponseEntity.noContent() .build(); } - @DeleteMapping("/{questionId}") - public ResponseEntity deleteQuestion( + @PostMapping("/{questionId}/answers") + public ResponseEntity createAnswer( @AuthenticateUser AuthenticationUserInfo userInfo, - @PathVariable final Long questionId + @PathVariable final Long questionId, + @RequestBody @Valid final CreateAnswerRequest answerRequest ) { - questionService.deleteById(questionId, userInfo.userId()); + answerService.create( + CreateAnswerDto.of(questionId, answerRequest, userInfo.userId()), + ImageRelativeUrl.AUCTION.calculateAbsoluteUrl() + ); - return ResponseEntity.noContent() + return ResponseEntity.created(URI.create("/auctions/" + answerRequest.auctionId())) .build(); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/presentation/dto/response/ReadReporterResponse.java b/backend/ddang/src/main/java/com/ddang/ddang/report/presentation/dto/response/ReadReporterResponse.java index 7cc03e1a0..9a17baa3d 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/report/presentation/dto/response/ReadReporterResponse.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/presentation/dto/response/ReadReporterResponse.java @@ -7,6 +7,7 @@ public record ReadReporterResponse(Long id, String name) { public static ReadReporterResponse from(final ReadReporterDto reporterDto) { final String name = NameProcessor.process(reporterDto.isDeleted(), reporterDto.name()); + return new ReadReporterResponse(reporterDto.id(), name); } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/presentation/AuctionQnaControllerTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/presentation/AuctionQnaControllerTest.java index ca0ab7c8c..0ed09b1ef 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/presentation/AuctionQnaControllerTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/presentation/AuctionQnaControllerTest.java @@ -67,7 +67,7 @@ void setUp() { void 경매_아이디를_통해_질문과_답변을_모두_조회한다() throws Exception { // given given(tokenDecoder.decode(eq(TokenType.ACCESS), anyString())).willReturn(Optional.of(사용자_ID_클레임)); - given(questionService.readAllByAuctionId(anyLong())).willReturn(질문과_답변_정보들_dto); + given(questionService.readAllByAuctionId(anyLong(), anyLong())).willReturn(질문과_답변_정보들_dto); // when & then final ResultActions resultActions = @@ -83,6 +83,7 @@ void setUp() { jsonPath("$.qnas.[0].question.writer.image").exists(), jsonPath("$.qnas.[0].question.createdTime").exists(), jsonPath("$.qnas.[0].question.content", is(질문_정보_dto1.content())), + jsonPath("$.qnas.[0].question.isQuestioner", is(질문_정보_dto1.isQuestioner()), Boolean.class), jsonPath("$.qnas.[0].answer.id", is(답변_정보_dto1.id()), Long.class), jsonPath("$.qnas.[0].answer.writer.id", is(판매자_정보_dto.id()), Long.class), jsonPath("$.qnas.[0].answer.writer.name", is(판매자_정보_dto.name())), @@ -95,6 +96,7 @@ void setUp() { jsonPath("$.qnas.[1].question.writer.image").exists(), jsonPath("$.qnas.[1].question.createdTime").exists(), jsonPath("$.qnas.[1].question.content", is(질문_정보_dto2.content())), + jsonPath("$.qnas.[1].question.isQuestioner", is(질문_정보_dto2.isQuestioner()), Boolean.class), jsonPath("$.qnas.[1].answer.id", is(답변_정보_dto2.id()), Long.class), jsonPath("$.qnas.[1].answer.writer.id", is(판매자_정보_dto.id()), Long.class), jsonPath("$.qnas.[1].answer.writer.name", is(판매자_정보_dto.name())), @@ -110,7 +112,7 @@ void setUp() { void 존재하지_않는_경매_아이디를_통해_질문과_답변을_모두_조회할시_404를_반환한다() throws Exception { // given given(tokenDecoder.decode(eq(TokenType.ACCESS), anyString())).willReturn(Optional.of(사용자_ID_클레임)); - given(questionService.readAllByAuctionId(anyLong())) + given(questionService.readAllByAuctionId(anyLong(), anyLong())) .willThrow(new AuctionNotFoundException("해당 경매를 찾을 수 없습니다.")); // when & then @@ -146,6 +148,8 @@ void setUp() { .description("질문 등록 시간"), fieldWithPath("qnas.[].question.content").type(JsonFieldType.STRING) .description("질문 내용"), + fieldWithPath("qnas.[].question.isQuestioner").type(JsonFieldType.BOOLEAN) + .description("질문 작성자 여부 확인"), fieldWithPath("qnas.[].answer").type(JsonFieldType.OBJECT) .description("답변 정보 JSON"), fieldWithPath("qnas.[].answer.id").type(JsonFieldType.NUMBER) diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/presentation/fixture/AuctionQuestionControllerFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/presentation/fixture/AuctionQuestionControllerFixture.java index 2ee6bd63c..19f240ede 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/presentation/fixture/AuctionQuestionControllerFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/presentation/fixture/AuctionQuestionControllerFixture.java @@ -34,8 +34,8 @@ public class AuctionQuestionControllerFixture extends CommonControllerSliceTest "12346", false ); - protected ReadQuestionDto 질문_정보_dto1 = new ReadQuestionDto(1L, 질문자_정보_dto, "질문1", LocalDateTime.now()); - protected ReadQuestionDto 질문_정보_dto2 = new ReadQuestionDto(2L, 질문자_정보_dto, "질문2", LocalDateTime.now()); + protected ReadQuestionDto 질문_정보_dto1 = new ReadQuestionDto(1L, 질문자_정보_dto, "질문1", LocalDateTime.now(), false); + protected ReadQuestionDto 질문_정보_dto2 = new ReadQuestionDto(2L, 질문자_정보_dto, "질문2", LocalDateTime.now(), false); protected ReadAnswerDto 답변_정보_dto1 = new ReadAnswerDto(1L, 판매자_정보_dto, "답변1", LocalDateTime.now()); protected ReadAnswerDto 답변_정보_dto2 = new ReadAnswerDto(2L, 판매자_정보_dto, "답변1", LocalDateTime.now()); private ReadQnaDto 질문과_답변_정보_dto1 = new ReadQnaDto(질문_정보_dto1, 답변_정보_dto1); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/QuestionServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/QuestionServiceTest.java index 1801e8490..3a629fa94 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/QuestionServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/QuestionServiceTest.java @@ -88,7 +88,7 @@ class QuestionServiceTest extends QuestionServiceFixture { @Test void 경매_아이디를_통해_질문과_답변을_모두_조회한다() { // when - final ReadQnasDto actual = questionService.readAllByAuctionId(질문_3개_답변_2개가_존재하는_경매_아이디); + final ReadQnasDto actual = questionService.readAllByAuctionId(질문_3개_답변_2개가_존재하는_경매_아이디, 두번째_질문을_작성한_사용자.getId()); // then SoftAssertions.assertSoftly(softAssertions -> { @@ -97,14 +97,17 @@ class QuestionServiceTest extends QuestionServiceFixture { final ReadQnaDto 첫번째_질문 = questionAndAnswerDtos.get(0); softAssertions.assertThat(첫번째_질문.readQuestionDto()).isEqualTo(질문_정보_dto1); + softAssertions.assertThat(첫번째_질문.readQuestionDto().isQuestioner()).isFalse(); softAssertions.assertThat(첫번째_질문.readAnswerDto()).isEqualTo(답변_정보_dto1); final ReadQnaDto 두번째_질문 = questionAndAnswerDtos.get(1); softAssertions.assertThat(두번째_질문.readQuestionDto()).isEqualTo(질문_정보_dto2); + softAssertions.assertThat(두번째_질문.readQuestionDto().isQuestioner()).isTrue(); softAssertions.assertThat(두번째_질문.readAnswerDto()).isEqualTo(답변_정보_dto2); final ReadQnaDto 세번째_질문 = questionAndAnswerDtos.get(2); softAssertions.assertThat(세번째_질문.readQuestionDto()).isEqualTo(질문_정보_dto3); + softAssertions.assertThat(세번째_질문.readQuestionDto().isQuestioner()).isFalse(); softAssertions.assertThat(세번째_질문.readAnswerDto()).isNull(); }); } @@ -112,7 +115,7 @@ class QuestionServiceTest extends QuestionServiceFixture { @Test void 존재하지_않는_경매_아이디를_통해_질문과_답변을_모두_조회할시_예외가_발생한다() { // when & then - assertThatThrownBy(() -> questionService.readAllByAuctionId(존재하지_않는_경매_아이디)) + assertThatThrownBy(() -> questionService.readAllByAuctionId(존재하지_않는_경매_아이디, 질문하지_않은_사용자.getId())) .isInstanceOf(AuctionNotFoundException.class) .hasMessage("해당 경매를 찾을 수 없습니다."); } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java index 477e6a4fa..63818f386 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java @@ -54,6 +54,7 @@ public class QuestionServiceFixture { protected Question 질문; protected User 질문자; protected User 질문하지_않은_사용자; + protected User 두번째_질문을_작성한_사용자; protected CreateQuestionDto 경매_질문_등록_요청_dto; protected CreateQuestionDto 존재하지_않는_사용자가_경매_질문_등록_요청_dto; protected CreateQuestionDto 존재하지_않는_경매_질문_등록_요청_dto; @@ -142,8 +143,14 @@ void setUp() { .reliability(new Reliability(4.7d)) .oauthId("12346") .build(); + 두번째_질문을_작성한_사용자 = User.builder() + .name("두번째 질문자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12347") + .build(); 질문 = new Question(질문과_답변이_존재하는_경매, 질문자, "질문1"); - final Question 질문2 = new Question(질문과_답변이_존재하는_경매, 질문자, "질문2"); + final Question 질문2 = new Question(질문과_답변이_존재하는_경매, 두번째_질문을_작성한_사용자, "질문2"); final Question 질문3 = new Question(질문과_답변이_존재하는_경매, 질문자, "질문3"); final Answer 답변1 = new Answer("답변1"); final Answer 답변2 = new Answer("답변2"); @@ -153,6 +160,7 @@ void setUp() { userRepository.save(판매자); userRepository.save(질문자); userRepository.save(질문하지_않은_사용자); + userRepository.save(두번째_질문을_작성한_사용자); auctionRepository.save(경매); auctionRepository.save(질문과_답변이_존재하는_경매); @@ -172,9 +180,10 @@ void setUp() { final ReadUserInQnaDto 판매자_정보_dto = ReadUserInQnaDto.from(판매자); final ReadUserInQnaDto 질문자_정보_dto = ReadUserInQnaDto.from(질문자); - 질문_정보_dto1 = new ReadQuestionDto(질문.getId(), 질문자_정보_dto, 질문.getContent(), 질문.getCreatedTime()); - 질문_정보_dto2 = new ReadQuestionDto(질문2.getId(), 질문자_정보_dto, 질문2.getContent(), 질문2.getCreatedTime()); - 질문_정보_dto3 = new ReadQuestionDto(질문3.getId(), 질문자_정보_dto, 질문3.getContent(), 질문3.getCreatedTime()); + final ReadUserInQnaDto 두번째_질문자_정보_dto = ReadUserInQnaDto.from(두번째_질문을_작성한_사용자); + 질문_정보_dto1 = new ReadQuestionDto(질문.getId(), 질문자_정보_dto, 질문.getContent(), 질문.getCreatedTime(), false); + 질문_정보_dto2 = new ReadQuestionDto(질문2.getId(), 두번째_질문자_정보_dto, 질문2.getContent(), 질문2.getCreatedTime(), true); + 질문_정보_dto3 = new ReadQuestionDto(질문3.getId(), 질문자_정보_dto, 질문3.getContent(), 질문3.getCreatedTime(), false); 답변_정보_dto1 = new ReadAnswerDto(답변1.getId(), 판매자_정보_dto, 답변1.getContent(), 답변1.getCreatedTime()); 답변_정보_dto2 = new ReadAnswerDto(답변2.getId(), 판매자_정보_dto, 답변2.getContent(), 답변2.getCreatedTime()); } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/application/QuestionReportServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/report/application/QuestionReportServiceTest.java index aea629942..659382b9e 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/application/QuestionReportServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/application/QuestionReportServiceTest.java @@ -6,7 +6,7 @@ import com.ddang.ddang.report.application.exception.InvalidQuestionReportException; import com.ddang.ddang.report.application.fixture.QuestionReportServiceFixture; import com.ddang.ddang.user.application.exception.UserNotFoundException; -import org.assertj.core.api.*; +import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; From d516c378268f088558fbc02a5df827c8c5df5dd5 Mon Sep 17 00:00:00 2001 From: apptie <57691173+apptie@users.noreply.github.com> Date: Sun, 15 Oct 2023 13:52:05 +0900 Subject: [PATCH 22/37] =?UTF-8?q?fix:=20#680=20=EC=8B=A0=EA=B7=9C=20?= =?UTF-8?q?=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85=EC=9D=B4=20=EC=95=88?= =?UTF-8?q?=EB=90=98=EB=8A=94=20=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?(#681)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 신규 회원 가입 시 null이 될 수 없는 필드를 초기화하지 않아 레코드 저장에 실패하던 문제 수정 * test: 테스트 케이스 검증 부분 추가 및 잘못된 테스트 케이스 수정 * test: Fixture 네이밍과 테스트 메서드 네이밍을 명확하게 변경 * refactor: 초기 신뢰도를 상수로 초기화 * refactor: 초기 신뢰도 상수 변경 --- .../application/AuthenticationService.java | 18 ++++++++------- .../AuthenticationServiceTest.java | 22 ++++++++++--------- .../fixture/AuthenticationServiceFixture.java | 2 +- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java index 9656de5e3..8d7eaddde 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java @@ -1,5 +1,7 @@ package com.ddang.ddang.authentication.application; +import static com.ddang.ddang.image.domain.ProfileImage.DEFAULT_PROFILE_IMAGE_STORE_NAME; + import com.ddang.ddang.authentication.application.dto.LoginInformationDto; import com.ddang.ddang.authentication.application.dto.LoginUserInformationDto; import com.ddang.ddang.authentication.application.dto.TokenDto; @@ -23,21 +25,19 @@ import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - import java.time.LocalDateTime; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; - -import static com.ddang.ddang.image.domain.ProfileImage.DEFAULT_PROFILE_IMAGE_STORE_NAME; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Service @Transactional(readOnly = true) @RequiredArgsConstructor public class AuthenticationService { + private static final Reliability INITIALIZE_USER_RELIABILITY = new Reliability(0.0d); private static final String PRIVATE_CLAIMS_KEY = "userId"; private final DeviceTokenService deviceTokenService; @@ -80,10 +80,12 @@ private LoginUserInformationDto findOrPersistUser( .orElseGet(() -> { final User user = User.builder() .name(oauth2Type.calculateNickname( - calculateRandomNumber())) + calculateRandomNumber()) + ) .profileImage(findDefaultProfileImage()) - .reliability(new Reliability(0.0d)) + .reliability(INITIALIZE_USER_RELIABILITY) .oauthId(userInformationDto.findUserId()) + .oauth2Type(oauth2Type) .build(); isSignUpUser.set(true); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java index 60af9fddf..ac5fa048c 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java @@ -1,5 +1,10 @@ package com.ddang.ddang.authentication.application; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; + import com.ddang.ddang.authentication.application.dto.LoginInformationDto; import com.ddang.ddang.authentication.application.dto.TokenDto; import com.ddang.ddang.authentication.application.exception.InvalidWithdrawalException; @@ -25,11 +30,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.MockBean; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.BDDMockito.given; - @IsolateDatabase @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @SuppressWarnings("NonAsciiCharacters") @@ -120,7 +120,7 @@ void setUp() { void 가입한_회원이_소셜_로그인을_할_경우_accessToken과_refreshToken을_반환한다() { // given given(providerComposite.findProvider(지원하는_소셜_로그인_타입)).willReturn(userInfoProvider); - given(userInfoProvider.findUserInformation(anyString())).willReturn(사용자_회원_정보); + given(userInfoProvider.findUserInformation(anyString())).willReturn(가입한_사용자_회원_정보); // when final LoginInformationDto actual = authenticationService.login(지원하는_소셜_로그인_타입, 유효한_소셜_로그인_토큰, 디바이스_토큰); @@ -146,10 +146,10 @@ void setUp() { } @Test - void 가입하지_않은_회원이_소셜_로그인을_할_경우_accessToken과_refreshToken을_반환한다() { + void 가입하지_않은_사용자가_소셜_로그인을_할_경우_accessToken과_refreshToken을_반환한다() { // given given(providerComposite.findProvider(지원하는_소셜_로그인_타입)).willReturn(userInfoProvider); - given(userInfoProvider.findUserInformation(anyString())).willReturn(사용자_회원_정보); + given(userInfoProvider.findUserInformation(anyString())).willReturn(가입하지_않은_사용자_회원_정보); // when final LoginInformationDto actual = authenticationService.login(지원하는_소셜_로그인_타입, 유효한_소셜_로그인_토큰, 디바이스_토큰); @@ -158,6 +158,7 @@ void setUp() { SoftAssertions.assertSoftly(softAssertions -> { softAssertions.assertThat(actual.tokenDto().accessToken()).isNotEmpty(); softAssertions.assertThat(actual.tokenDto().refreshToken()).isNotEmpty(); + softAssertions.assertThat(actual.isSignUpUser()).isTrue(); }); } @@ -165,7 +166,7 @@ void setUp() { void 탈퇴한_회원이_소셜_로그인을_할_경우_accessToken과_refreshToken을_반환한다() { // given given(providerComposite.findProvider(지원하는_소셜_로그인_타입)).willReturn(userInfoProvider); - given(userInfoProvider.findUserInformation(anyString())).willReturn(사용자_회원_정보); + given(userInfoProvider.findUserInformation(anyString())).willReturn(가입한_사용자_회원_정보); // when final LoginInformationDto actual = authenticationService.login(지원하는_소셜_로그인_타입, 유효한_소셜_로그인_토큰, 디바이스_토큰); @@ -174,6 +175,7 @@ void setUp() { SoftAssertions.assertSoftly(softAssertions -> { softAssertions.assertThat(actual.tokenDto().accessToken()).isNotEmpty(); softAssertions.assertThat(actual.tokenDto().refreshToken()).isNotEmpty(); + softAssertions.assertThat(actual.isSignUpUser()).isFalse(); }); } @@ -227,7 +229,7 @@ void setUp() { void 가입한_회원이_탈퇴하는_경우_정상처리한다() throws InvalidWithdrawalException { // given given(providerComposite.findProvider(지원하는_소셜_로그인_타입)).willReturn(userInfoProvider); - given(userInfoProvider.findUserInformation(anyString())).willReturn(사용자_회원_정보); + given(userInfoProvider.findUserInformation(anyString())).willReturn(가입한_사용자_회원_정보); // when authenticationService.withdrawal(유효한_액세스_토큰, 유효한_리프레시_토큰); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java index 76e459ef7..d5e7457b1 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java @@ -36,7 +36,7 @@ public class AuthenticationServiceFixture { protected PrivateClaims 사용자_id_클레임 = new PrivateClaims(1L); - protected UserInformationDto 사용자_회원_정보 = new UserInformationDto(12345L); + protected UserInformationDto 가입한_사용자_회원_정보 = new UserInformationDto(12345L); protected UserInformationDto 탈퇴한_사용자_회원_정보 = new UserInformationDto(54321L); protected UserInformationDto 가입하지_않은_사용자_회원_정보 = new UserInformationDto(-99999L); From 7d1f855c3480a66f7fb8c1f651724d21b2ddf43f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=9C=EC=9D=B4=EB=AF=B8?= <63184334+JJ503@users.noreply.github.com> Date: Sun, 15 Oct 2023 15:53:06 +0900 Subject: [PATCH 23/37] =?UTF-8?q?refactor:=20#670=20Image=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=9D=B8=ED=94=84=EB=9D=BC=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81=20(#678)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 변수명을 명확하게 수정 * feat: 도메인 영역에 경매 이미지 repository 추가 * feat: 도메인 영역에 경매 이미지 repository의 구현체 추가 * refactor: service에서 도메인 영역의 repository를 사용하도록 변경 * feat: 도메인 영역에 프로필 이미지 repository 추가 * feat: 도메인 영역에 프로필 이미지 repository의 구현체 추가 * refactor: service에서 도메인 영역의 프로필 이미지 repository를 사용하도록 변경 * refactor: 변수명을 의도에 맞게 수정 * refactor: 레파지토리 어노테이션 누락 추가 * test: final 추가 * test: final 추가 * refactor: import 와일드카드 제거 * refactor: 쿼리문 명령어를 대문자로 수정 * refactor: 세팅 메서드명 수정 * refactor: 잘못된 클래스명 수정 --- .../application/AuthenticationService.java | 4 +- .../ddang/image/application/ImageService.java | 12 ++--- .../repository/AuctionImageRepository.java | 10 ++++ .../repository/ProfileImageRepository.java | 12 +++++ .../AuctionImageRepositoryImpl.java | 20 ++++++++ .../JpaAuctionImageRepository.java | 1 - .../JpaProfileImageRepository.java | 2 +- .../ProfileImageRepositoryImpl.java | 25 ++++++++++ .../AuthenticationServiceTest.java | 11 +++-- .../AuctionImageRepositoryImplTest.java | 40 +++++++++++++++ .../ProfileImageRepositoryImplTest.java | 49 +++++++++++++++++++ .../AuctionImageRepositoryImplFixture.java | 30 ++++++++++++ .../ProfileImageRepositoryImplFixture.java | 30 ++++++++++++ 13 files changed, 232 insertions(+), 14 deletions(-) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/image/domain/repository/AuctionImageRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/image/domain/repository/ProfileImageRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/image/infrastructure/persistence/AuctionImageRepositoryImpl.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/image/infrastructure/persistence/ProfileImageRepositoryImpl.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/image/infrastructure/persistence/AuctionImageRepositoryImplTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/image/infrastructure/persistence/ProfileImageRepositoryImplTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/image/infrastructure/persistence/fixture/AuctionImageRepositoryImplFixture.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/image/infrastructure/persistence/fixture/ProfileImageRepositoryImplFixture.java diff --git a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java index 8d7eaddde..c3a2d41b7 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java @@ -21,7 +21,7 @@ import com.ddang.ddang.device.infrastructure.persistence.JpaDeviceTokenRepository; import com.ddang.ddang.image.application.exception.ImageNotFoundException; import com.ddang.ddang.image.domain.ProfileImage; -import com.ddang.ddang.image.infrastructure.persistence.JpaProfileImageRepository; +import com.ddang.ddang.image.domain.repository.ProfileImageRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -43,7 +43,7 @@ public class AuthenticationService { private final DeviceTokenService deviceTokenService; private final Oauth2UserInformationProviderComposite providerComposite; private final UserRepository userRepository; - private final JpaProfileImageRepository profileImageRepository; + private final ProfileImageRepository profileImageRepository; private final TokenEncoder tokenEncoder; private final TokenDecoder tokenDecoder; private final BlackListTokenService blackListTokenService; diff --git a/backend/ddang/src/main/java/com/ddang/ddang/image/application/ImageService.java b/backend/ddang/src/main/java/com/ddang/ddang/image/application/ImageService.java index bb64c5dca..7b9f240e3 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/image/application/ImageService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/image/application/ImageService.java @@ -2,8 +2,8 @@ import com.ddang.ddang.image.domain.AuctionImage; import com.ddang.ddang.image.domain.ProfileImage; -import com.ddang.ddang.image.infrastructure.persistence.JpaAuctionImageRepository; -import com.ddang.ddang.image.infrastructure.persistence.JpaProfileImageRepository; +import com.ddang.ddang.image.domain.repository.AuctionImageRepository; +import com.ddang.ddang.image.domain.repository.ProfileImageRepository; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; @@ -22,12 +22,12 @@ public class ImageService { @Value("${image.store.dir}") private String imageStoreDir; - private final JpaProfileImageRepository imageRepository; - private final JpaAuctionImageRepository auctionImageRepository; + private final ProfileImageRepository profileImageRepository; + private final AuctionImageRepository auctionImageRepository; public Resource readProfileImage(final Long id) throws MalformedURLException { - final ProfileImage profileImage = imageRepository.findById(id) - .orElse(null); + final ProfileImage profileImage = profileImageRepository.findById(id) + .orElse(null); if (profileImage == null) { return null; diff --git a/backend/ddang/src/main/java/com/ddang/ddang/image/domain/repository/AuctionImageRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/image/domain/repository/AuctionImageRepository.java new file mode 100644 index 000000000..586bca166 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/image/domain/repository/AuctionImageRepository.java @@ -0,0 +1,10 @@ +package com.ddang.ddang.image.domain.repository; + +import com.ddang.ddang.image.domain.AuctionImage; + +import java.util.Optional; + +public interface AuctionImageRepository { + + Optional findById(final Long id); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/image/domain/repository/ProfileImageRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/image/domain/repository/ProfileImageRepository.java new file mode 100644 index 000000000..b0491a5d6 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/image/domain/repository/ProfileImageRepository.java @@ -0,0 +1,12 @@ +package com.ddang.ddang.image.domain.repository; + +import com.ddang.ddang.image.domain.ProfileImage; + +import java.util.Optional; + +public interface ProfileImageRepository { + + Optional findById(final Long id); + + Optional findByStoreName(final String storeName); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/image/infrastructure/persistence/AuctionImageRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/image/infrastructure/persistence/AuctionImageRepositoryImpl.java new file mode 100644 index 000000000..c24799bca --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/image/infrastructure/persistence/AuctionImageRepositoryImpl.java @@ -0,0 +1,20 @@ +package com.ddang.ddang.image.infrastructure.persistence; + +import com.ddang.ddang.image.domain.AuctionImage; +import com.ddang.ddang.image.domain.repository.AuctionImageRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +@RequiredArgsConstructor +public class AuctionImageRepositoryImpl implements AuctionImageRepository { + + private final JpaAuctionImageRepository jpaAuctionImageRepository; + + @Override + public Optional findById(final Long id) { + return jpaAuctionImageRepository.findById(id); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/image/infrastructure/persistence/JpaAuctionImageRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/image/infrastructure/persistence/JpaAuctionImageRepository.java index da66d1e6a..87f345983 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/image/infrastructure/persistence/JpaAuctionImageRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/image/infrastructure/persistence/JpaAuctionImageRepository.java @@ -4,5 +4,4 @@ import org.springframework.data.jpa.repository.JpaRepository; public interface JpaAuctionImageRepository extends JpaRepository { - } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/image/infrastructure/persistence/JpaProfileImageRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/image/infrastructure/persistence/JpaProfileImageRepository.java index f30774152..39b321bad 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/image/infrastructure/persistence/JpaProfileImageRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/image/infrastructure/persistence/JpaProfileImageRepository.java @@ -8,6 +8,6 @@ public interface JpaProfileImageRepository extends JpaRepository { - @Query("select i from ProfileImage i where i.image.storeName = :storeName") + @Query("SELECT i FROM ProfileImage i WHERE i.image.storeName = :storeName") Optional findByStoreName(final String storeName); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/image/infrastructure/persistence/ProfileImageRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/image/infrastructure/persistence/ProfileImageRepositoryImpl.java new file mode 100644 index 000000000..12fa367f7 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/image/infrastructure/persistence/ProfileImageRepositoryImpl.java @@ -0,0 +1,25 @@ +package com.ddang.ddang.image.infrastructure.persistence; + +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.image.domain.repository.ProfileImageRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +@RequiredArgsConstructor +public class ProfileImageRepositoryImpl implements ProfileImageRepository { + + private final JpaProfileImageRepository jpaProfileImageRepository; + + @Override + public Optional findById(final Long id) { + return jpaProfileImageRepository.findById(id); + } + + @Override + public Optional findByStoreName(final String storeName) { + return jpaProfileImageRepository.findByStoreName(storeName); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java index ac5fa048c..cc952942b 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java @@ -19,7 +19,9 @@ import com.ddang.ddang.device.application.DeviceTokenService; import com.ddang.ddang.device.infrastructure.persistence.JpaDeviceTokenRepository; import com.ddang.ddang.image.application.exception.ImageNotFoundException; +import com.ddang.ddang.image.domain.repository.ProfileImageRepository; import com.ddang.ddang.image.infrastructure.persistence.JpaProfileImageRepository; +import com.ddang.ddang.image.infrastructure.persistence.ProfileImageRepositoryImpl; import com.ddang.ddang.user.domain.repository.UserRepository; import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.BeforeEach; @@ -36,7 +38,7 @@ class AuthenticationServiceTest extends AuthenticationServiceFixture { @Mock - JpaProfileImageRepository defaultProfileImageRepository; + ProfileImageRepository defaultProfileImageRepository; @MockBean Oauth2UserInformationProviderComposite providerComposite; @@ -50,8 +52,7 @@ class AuthenticationServiceTest extends AuthenticationServiceFixture { @Autowired UserRepository userRepository; - @Autowired - JpaProfileImageRepository profileImageRepository; + ProfileImageRepository profileImageRepository; @Autowired TokenEncoder tokenEncoder; @@ -69,7 +70,9 @@ class AuthenticationServiceTest extends AuthenticationServiceFixture { AuthenticationService profileImageNotFoundAuthenticationService; @BeforeEach - void setUp() { + void fixtureSetUp(@Autowired final JpaProfileImageRepository jpaProfileImageRepository) { + profileImageRepository = new ProfileImageRepositoryImpl(jpaProfileImageRepository); + authenticationService = new AuthenticationService( deviceTokenService, providerComposite, diff --git a/backend/ddang/src/test/java/com/ddang/ddang/image/infrastructure/persistence/AuctionImageRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/image/infrastructure/persistence/AuctionImageRepositoryImplTest.java new file mode 100644 index 000000000..a77fea90e --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/image/infrastructure/persistence/AuctionImageRepositoryImplTest.java @@ -0,0 +1,40 @@ +package com.ddang.ddang.image.infrastructure.persistence; + +import com.ddang.ddang.configuration.QuerydslConfiguration; +import com.ddang.ddang.image.domain.AuctionImage; +import com.ddang.ddang.image.domain.repository.AuctionImageRepository; +import com.ddang.ddang.image.infrastructure.persistence.fixture.AuctionImageRepositoryImplFixture; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@Import(QuerydslConfiguration.class) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class AuctionImageRepositoryImplTest extends AuctionImageRepositoryImplFixture { + + AuctionImageRepository auctionImageRepository; + + @BeforeEach + void setUp(@Autowired final JpaAuctionImageRepository jpaAuctionImageRepository) { + auctionImageRepository = new AuctionImageRepositoryImpl(jpaAuctionImageRepository); + } + + @Test + void 경매_이미지를_아이디를_통해_조회한다() { + // when + final Optional actual = auctionImageRepository.findById(경매_이미지.getId()); + + // then + assertThat(actual).contains(경매_이미지); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/image/infrastructure/persistence/ProfileImageRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/image/infrastructure/persistence/ProfileImageRepositoryImplTest.java new file mode 100644 index 000000000..7f733ae97 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/image/infrastructure/persistence/ProfileImageRepositoryImplTest.java @@ -0,0 +1,49 @@ +package com.ddang.ddang.image.infrastructure.persistence; + +import com.ddang.ddang.configuration.QuerydslConfiguration; +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.image.domain.repository.ProfileImageRepository; +import com.ddang.ddang.image.infrastructure.persistence.fixture.ProfileImageRepositoryImplFixture; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@Import(QuerydslConfiguration.class) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class ProfileImageRepositoryImplTest extends ProfileImageRepositoryImplFixture { + + ProfileImageRepository profileImageRepository; + + @BeforeEach + void setUp(@Autowired final JpaProfileImageRepository jpaProfileImageRepository) { + profileImageRepository = new ProfileImageRepositoryImpl(jpaProfileImageRepository); + } + + @Test + void 프로필을_이미지를_아이디를_통해_조회한다() { + // when + final Optional actual = profileImageRepository.findById(프로필_이미지.getId()); + + // then + assertThat(actual).contains(프로필_이미지); + } + + @Test + void 프로필을_이미지를_저장_이미지를_통해_조회한다() { + // when + final Optional actual = profileImageRepository.findByStoreName(프로필_이미지.getImage().getStoreName()); + + // then + assertThat(actual).contains(프로필_이미지); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/image/infrastructure/persistence/fixture/AuctionImageRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/image/infrastructure/persistence/fixture/AuctionImageRepositoryImplFixture.java new file mode 100644 index 000000000..a3a88d949 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/image/infrastructure/persistence/fixture/AuctionImageRepositoryImplFixture.java @@ -0,0 +1,30 @@ +package com.ddang.ddang.image.infrastructure.persistence.fixture; + +import com.ddang.ddang.image.domain.AuctionImage; +import com.ddang.ddang.image.infrastructure.persistence.JpaAuctionImageRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +@SuppressWarnings("NonAsciiCharacters") +public class AuctionImageRepositoryImplFixture { + + @PersistenceContext + private EntityManager em; + + @Autowired + private JpaAuctionImageRepository jpaAuctionImageRepository; + + protected AuctionImage 경매_이미지; + + @BeforeEach + void fixtureSetUp() { + 경매_이미지 = new AuctionImage("경매이미지.png", "경매이미지.png"); + + jpaAuctionImageRepository.save(경매_이미지); + + em.flush(); + em.clear(); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/image/infrastructure/persistence/fixture/ProfileImageRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/image/infrastructure/persistence/fixture/ProfileImageRepositoryImplFixture.java new file mode 100644 index 000000000..719737f47 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/image/infrastructure/persistence/fixture/ProfileImageRepositoryImplFixture.java @@ -0,0 +1,30 @@ +package com.ddang.ddang.image.infrastructure.persistence.fixture; + +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.image.infrastructure.persistence.JpaProfileImageRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +@SuppressWarnings("NonAsciiCharacters") +public class ProfileImageRepositoryImplFixture { + + @PersistenceContext + private EntityManager em; + + @Autowired + private JpaProfileImageRepository profileImageRepository; + + protected ProfileImage 프로필_이미지; + + @BeforeEach + void fixtureSetUp() { + 프로필_이미지 = new ProfileImage("프로필이미지.png", "프로필이미지.png"); + + profileImageRepository.save(프로필_이미지); + + em.flush(); + em.clear(); + } +} From 57026a2433c781521ad83b610bd9de69b4d63972 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=9C=EC=9D=B4=EB=AF=B8?= <63184334+JJ503@users.noreply.github.com> Date: Sun, 15 Oct 2023 15:54:27 +0900 Subject: [PATCH 24/37] =?UTF-8?q?refactor:=20#671=20Bid=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=9D=B8=ED=94=84=EB=9D=BC=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81=20(#684)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 도메인 영역에 입찰 repository 추가 * refactor: 메서드 네이밍과 파라미터 변수명을 명확하게 수정 * feat: 도메인 영역에 입찰 repository의 구현체 추가 * refactor: service에서 도메인 영역의 입찰 repository를 사용하도록 변경 * refactor: 레파지토리 어노테이션 누락 추가 * test: 테스트 영역에서 도메인 영역의 입찰 repository를 사용하도록 변경 * refactor: 쿼리문 명령어를 대문자로 수정 * refactor: 레파지토리에서 null이 아닌 Optional을 통해 반환되도록 수정 * test: 도메인 영역에 입찰 repository의 구현체 테스트 추가 * test: 테스트 영역에서 도메인 영역의 repository를 사용하도록 변경 --- .../ddang/bid/application/BidService.java | 16 +-- .../bid/domain/repository/BidRepository.java | 15 +++ .../persistence/BidRepositoryImpl.java | 31 +++++ .../persistence/JpaBidRepository.java | 7 +- .../fixture/AuctionServiceFixture.java | 7 +- .../fixture/AuctionRepositoryImplFixture.java | 12 +- ...erydslAuctionRepositoryForListFixture.java | 5 +- .../fixture/BidServiceFixture.java | 4 +- .../persistence/BidRepositoryImplTest.java | 68 ++++++++++ .../persistence/JpaBidRepositoryTest.java | 16 +-- .../fixture/BidRepositoryImplFixture.java | 126 ++++++++++++++++++ .../fixture/ChatRoomServiceFixture.java | 9 +- ...ChatRoomAndImageRepositoryImplFixture.java | 10 +- ...dMessageAndImageRepositoryImplFixture.java | 13 +- .../ChatRoomRepositoryImplFixture.java | 9 +- .../FcmNotificationServiceFixture.java | 4 +- .../NotificationEventListenerFixture.java | 6 +- 17 files changed, 303 insertions(+), 55 deletions(-) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/bid/domain/repository/BidRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/bid/infrastructure/persistence/BidRepositoryImpl.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/bid/infrastructure/persistence/BidRepositoryImplTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/bid/infrastructure/persistence/fixture/BidRepositoryImplFixture.java diff --git a/backend/ddang/src/main/java/com/ddang/ddang/bid/application/BidService.java b/backend/ddang/src/main/java/com/ddang/ddang/bid/application/BidService.java index 5920d13ac..d2c6a4e97 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/bid/application/BidService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/bid/application/BidService.java @@ -14,7 +14,7 @@ import com.ddang.ddang.bid.application.exception.InvalidBidderException; import com.ddang.ddang.bid.domain.Bid; import com.ddang.ddang.bid.domain.BidPrice; -import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; +import com.ddang.ddang.bid.domain.repository.BidRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -36,7 +36,7 @@ public class BidService { private final AuctionRepository auctionRepository; private final AuctionAndImageRepository auctionAndImageRepository; private final UserRepository userRepository; - private final JpaBidRepository bidRepository; + private final BidRepository bidRepository; @Transactional public Long create(final CreateBidDto bidDto, final String auctionImageAbsoluteUrl) { @@ -87,18 +87,18 @@ private void checkInvalidAuction(final Auction auction) { } private void checkInvalidBid(final Auction auction, final User bidder, final CreateBidDto bidDto) { - final Bid lastBid = bidRepository.findLastBidByAuctionId(bidDto.auctionId()); + final Optional lastBid = bidRepository.findLastBidByAuctionId(bidDto.auctionId()); final BidPrice bidPrice = processBidPrice(bidDto.bidPrice()); checkIsSeller(auction, bidder); - if (lastBid == null) { - checkInvalidFirstBidPrice(auction, bidPrice); + if (lastBid.isPresent()) { + checkIsNotLastBidder(lastBid.get(), bidder); + checkInvalidBidPrice(lastBid.get(), bidPrice); return; } - checkIsNotLastBidder(lastBid, bidder); - checkInvalidBidPrice(lastBid, bidPrice); + checkInvalidFirstBidPrice(auction, bidPrice); } private BidPrice processBidPrice(final int value) { @@ -144,7 +144,7 @@ private Bid saveAndUpdateLastBid(final CreateBidDto bidDto, final Auction auctio public List readAllByAuctionId(final Long auctionId) { if (auctionRepository.existsById(auctionId)) { - final List bids = bidRepository.findByAuctionIdOrderByIdAsc(auctionId); + final List bids = bidRepository.findAllByAuctionId(auctionId); return bids.stream() .map(ReadBidDto::from) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/bid/domain/repository/BidRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/bid/domain/repository/BidRepository.java new file mode 100644 index 000000000..2005c8b69 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/bid/domain/repository/BidRepository.java @@ -0,0 +1,15 @@ +package com.ddang.ddang.bid.domain.repository; + +import com.ddang.ddang.bid.domain.Bid; + +import java.util.List; +import java.util.Optional; + +public interface BidRepository { + + Bid save(final Bid bid); + + List findAllByAuctionId(final Long auctionId); + + Optional findLastBidByAuctionId(final Long auctionId); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/bid/infrastructure/persistence/BidRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/bid/infrastructure/persistence/BidRepositoryImpl.java new file mode 100644 index 000000000..4b1ca7073 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/bid/infrastructure/persistence/BidRepositoryImpl.java @@ -0,0 +1,31 @@ +package com.ddang.ddang.bid.infrastructure.persistence; + +import com.ddang.ddang.bid.domain.Bid; +import com.ddang.ddang.bid.domain.repository.BidRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +@RequiredArgsConstructor +public class BidRepositoryImpl implements BidRepository { + + private final JpaBidRepository jpaBidRepository; + + @Override + public Bid save(final Bid bid) { + return jpaBidRepository.save(bid); + } + + @Override + public List findAllByAuctionId(final Long auctionId) { + return jpaBidRepository.findAllByAuctionIdOrderByIdAsc(auctionId); + } + + @Override + public Optional findLastBidByAuctionId(final Long auctionId) { + return jpaBidRepository.findLastBidByAuctionId(auctionId); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/bid/infrastructure/persistence/JpaBidRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/bid/infrastructure/persistence/JpaBidRepository.java index 7d12de1de..9c3a2e690 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/bid/infrastructure/persistence/JpaBidRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/bid/infrastructure/persistence/JpaBidRepository.java @@ -6,11 +6,12 @@ import org.springframework.data.repository.query.Param; import java.util.List; +import java.util.Optional; public interface JpaBidRepository extends JpaRepository { - List findByAuctionIdOrderByIdAsc(final Long id); + List findAllByAuctionIdOrderByIdAsc(final Long auctionId); - @Query("select b from Bid b where b.auction.id = :auctionId order by b.id desc limit 1") - Bid findLastBidByAuctionId(@Param("auctionId") final Long id); + @Query("SELECT b FROM Bid b WHERE b.auction.id = :auctionId ORDER BY b.id DESC LIMIT 1") + Optional findLastBidByAuctionId(@Param("auctionId") final Long auctionId); } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/application/fixture/AuctionServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/application/fixture/AuctionServiceFixture.java index cd395f802..7f52a1832 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/application/fixture/AuctionServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/application/fixture/AuctionServiceFixture.java @@ -5,7 +5,7 @@ import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.bid.domain.Bid; import com.ddang.ddang.bid.domain.BidPrice; -import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; +import com.ddang.ddang.bid.domain.repository.BidRepository; import com.ddang.ddang.category.domain.Category; import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; import com.ddang.ddang.image.domain.ProfileImage; @@ -40,7 +40,7 @@ public class AuctionServiceFixture { private UserRepository userRepository; @Autowired - private JpaBidRepository bidRepository; + private BidRepository bidRepository; private Category 가구_카테고리 = new Category("가구"); private Category 가구_서브_의자_카테고리 = new Category("의자"); @@ -214,7 +214,8 @@ void setUp() { 구매자가_입찰한_경매1_입찰 = new Bid(구매자가_입찰한_경매1, 구매자, 구매자가_입찰한_경매1_입찰_가격); 구매자가_입찰한_경매2_입찰 = new Bid(구매자가_입찰한_경매2, 구매자, 구매자가_입찰한_경매2_입찰_가격); - bidRepository.saveAll(List.of(구매자가_입찰한_경매1_입찰, 구매자가_입찰한_경매2_입찰)); + bidRepository.save(구매자가_입찰한_경매1_입찰); + bidRepository.save(구매자가_입찰한_경매2_입찰); 구매자가_입찰한_경매1.updateLastBid(구매자가_입찰한_경매1_입찰); 구매자가_입찰한_경매2.updateLastBid(구매자가_입찰한_경매2_입찰); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java index 39c030a62..f6e039530 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java @@ -10,6 +10,8 @@ import com.ddang.ddang.auction.presentation.dto.request.ReadAuctionSearchCondition; import com.ddang.ddang.bid.domain.Bid; import com.ddang.ddang.bid.domain.BidPrice; +import com.ddang.ddang.bid.domain.repository.BidRepository; +import com.ddang.ddang.bid.infrastructure.persistence.BidRepositoryImpl; import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; import com.ddang.ddang.category.domain.Category; import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; @@ -38,9 +40,6 @@ public class AuctionRepositoryImplFixture { private AuctionRepository auctionRepository; - @Autowired - private JPAQueryFactory queryFactory; - private UserRepository userRepository; private RegionRepository regionRepository; @@ -48,8 +47,7 @@ public class AuctionRepositoryImplFixture { @Autowired private JpaCategoryRepository categoryRepository; - @Autowired - private JpaBidRepository bidRepository; + private BidRepository bidRepository; private Instant 시간 = Instant.parse("2023-07-08T22:21:20Z"); private ZoneId 위치 = ZoneId.of("UTC"); @@ -75,11 +73,13 @@ void fixtureSetUp( @Autowired final JPAQueryFactory jpaQueryFactory, @Autowired final JpaAuctionRepository jpaAuctionRepository, @Autowired final JpaUserRepository jpaUserRepository, - @Autowired final JpaRegionRepository jpaRegionRepository + @Autowired final JpaRegionRepository jpaRegionRepository, + @Autowired final JpaBidRepository jpaBidRepository ) { auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(jpaQueryFactory)); userRepository = new UserRepositoryImpl(jpaUserRepository); regionRepository = new RegionRepositoryImpl(jpaRegionRepository); + bidRepository = new BidRepositoryImpl(jpaBidRepository); final Region 서울특별시 = new Region("서울특별시"); final Region 강남구 = new Region("강남구"); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionRepositoryForListFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionRepositoryForListFixture.java index 05333d2a1..9e041f173 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionRepositoryForListFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionRepositoryForListFixture.java @@ -19,11 +19,12 @@ import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; -import java.time.LocalDateTime; -import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; +import java.time.LocalDateTime; +import java.util.List; + @SuppressWarnings("NonAsciiCharacters") public class QuerydslAuctionRepositoryForListFixture { diff --git a/backend/ddang/src/test/java/com/ddang/ddang/bid/application/fixture/BidServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/bid/application/fixture/BidServiceFixture.java index d0b2d5564..16b5cf6f2 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/bid/application/fixture/BidServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/bid/application/fixture/BidServiceFixture.java @@ -7,7 +7,7 @@ import com.ddang.ddang.bid.application.dto.CreateBidDto; import com.ddang.ddang.bid.domain.Bid; import com.ddang.ddang.bid.domain.BidPrice; -import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; +import com.ddang.ddang.bid.domain.repository.BidRepository; import com.ddang.ddang.image.domain.AuctionImage; import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.notification.domain.NotificationStatus; @@ -30,7 +30,7 @@ public class BidServiceFixture { private AuctionRepository auctionRepository; @Autowired - private JpaBidRepository bidRepository; + private BidRepository bidRepository; protected NotificationStatus 알림_성공 = NotificationStatus.SUCCESS; protected String 이미지_절대_url = "https://3-ddang.store/auctions/images"; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/bid/infrastructure/persistence/BidRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/bid/infrastructure/persistence/BidRepositoryImplTest.java new file mode 100644 index 000000000..d49dc0faa --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/bid/infrastructure/persistence/BidRepositoryImplTest.java @@ -0,0 +1,68 @@ +package com.ddang.ddang.bid.infrastructure.persistence; + +import com.ddang.ddang.bid.domain.Bid; +import com.ddang.ddang.bid.domain.repository.BidRepository; +import com.ddang.ddang.bid.infrastructure.persistence.fixture.BidRepositoryImplFixture; +import com.ddang.ddang.configuration.JpaConfiguration; +import com.ddang.ddang.configuration.QuerydslConfiguration; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@Import({JpaConfiguration.class, QuerydslConfiguration.class}) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class BidRepositoryImplTest extends BidRepositoryImplFixture { + + BidRepository bidRepository; + + @BeforeEach + void setUp(@Autowired final JpaBidRepository jpaBidRepository) { + bidRepository = new BidRepositoryImpl(jpaBidRepository); + } + + @Test + void 입찰을_저장한다() { + // given + final Bid bid = new Bid(경매1, 입찰자1, 입찰액); + + // when + final Bid actual = bidRepository.save(bid); + + // then + assertThat(actual.getId()).isPositive(); + } + + @Test + void 특정_경매의_입찰을_모두_조회한다() { + // when + final List actual = bidRepository.findAllByAuctionId(경매1.getId()); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).hasSize(2); + softAssertions.assertThat(actual.get(0).getId()).isEqualTo(경매1의_입찰1.getId()); + softAssertions.assertThat(actual.get(1).getId()).isEqualTo(경매1의_입찰2겸_마지막_입찰.getId()); + }); + } + + @Test + void 특정_경매의_마지막_입찰을_조회한다() { + // when + final Optional actual = bidRepository.findLastBidByAuctionId(경매1.getId()); + + // then + assertThat(actual.get().getId()).isEqualTo(경매1의_입찰2겸_마지막_입찰.getId()); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/bid/infrastructure/persistence/JpaBidRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/bid/infrastructure/persistence/JpaBidRepositoryTest.java index ab298d42b..90af22d4c 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/bid/infrastructure/persistence/JpaBidRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/bid/infrastructure/persistence/JpaBidRepositoryTest.java @@ -15,6 +15,7 @@ import org.springframework.context.annotation.Import; import java.util.List; +import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; @@ -45,19 +46,10 @@ class JpaBidRepositoryTest extends JpaBidRepositoryFixture { assertThat(actual.getId()).isPositive(); } - @Test - void 특정_경매에_입찰이_존재하는지_확인한다() { - // when - final boolean actual = bidRepository.existsById(경매1의_입찰1.getId()); - - // then - assertThat(actual).isTrue(); - } - @Test void 특정_경매의_입찰을_모두_조회한다() { // when - final List actual = bidRepository.findByAuctionIdOrderByIdAsc(경매1.getId()); + final List actual = bidRepository.findAllByAuctionIdOrderByIdAsc(경매1.getId()); // then SoftAssertions.assertSoftly(softAssertions -> { @@ -70,9 +62,9 @@ class JpaBidRepositoryTest extends JpaBidRepositoryFixture { @Test void 특정_경매의_마지막_입찰을_조회한다() { // when - final Bid actual = bidRepository.findLastBidByAuctionId(경매1.getId()); + final Optional actual = bidRepository.findLastBidByAuctionId(경매1.getId()); // then - assertThat(actual.getId()).isEqualTo(경매1의_입찰2겸_마지막_입찰.getId()); + assertThat(actual.get().getId()).isEqualTo(경매1의_입찰2겸_마지막_입찰.getId()); } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/bid/infrastructure/persistence/fixture/BidRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/bid/infrastructure/persistence/fixture/BidRepositoryImplFixture.java new file mode 100644 index 000000000..cb36da38a --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/bid/infrastructure/persistence/fixture/BidRepositoryImplFixture.java @@ -0,0 +1,126 @@ +package com.ddang.ddang.bid.infrastructure.persistence.fixture; + +import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.domain.BidUnit; +import com.ddang.ddang.auction.domain.Price; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.AuctionRepositoryImpl; +import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.bid.domain.Bid; +import com.ddang.ddang.bid.domain.BidPrice; +import com.ddang.ddang.bid.domain.repository.BidRepository; +import com.ddang.ddang.bid.infrastructure.persistence.BidRepositoryImpl; +import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; +import com.ddang.ddang.category.domain.Category; +import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; +import com.ddang.ddang.image.domain.AuctionImage; +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.repository.UserRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.infrastructure.persistence.UserRepositoryImpl; +import com.querydsl.jpa.impl.JPAQueryFactory; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +import java.time.LocalDateTime; +import java.util.List; + +@SuppressWarnings("NonAsciiCharacters") +public class BidRepositoryImplFixture { + + @Autowired + private JpaCategoryRepository categoryRepository; + + private UserRepository userRepository; + + private AuctionRepository auctionRepository; + + private BidRepository bidRepository; + + protected User 판매자; + protected Auction 경매1; + protected Auction 경매2; + protected User 입찰자1; + protected BidPrice 입찰액; + protected Bid 경매1의_입찰1; + protected Bid 경매1의_입찰2겸_마지막_입찰; + + @BeforeEach + void fixtureSetUp( + @Autowired final JpaUserRepository jpaUserRepository, + @Autowired final JpaAuctionRepository jpaAuctionRepository, + @Autowired final JPAQueryFactory queryFactory, + @Autowired final JpaBidRepository jpaBidRepository + ) { + userRepository = new UserRepositoryImpl(jpaUserRepository); + auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(queryFactory)); + bidRepository = new BidRepositoryImpl(jpaBidRepository); + + final ProfileImage 프로필_이미지 = new ProfileImage("프로필.jpg", "프로필.jpg"); + 판매자 = User.builder() + .name("판매자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); + + final Category 전자기기_카테고리 = new Category("전자기기"); + final Category 전자기기_서브_노트북_카테고리 = new Category("노트북 카테고리"); + 전자기기_카테고리.addSubCategory(전자기기_서브_노트북_카테고리); + final AuctionImage 경매_이미지 = new AuctionImage("경매이미지.jpg", "경매이미지.jpg"); + 경매1 = Auction.builder() + .seller(판매자) + .title("경매 상품") + .description("이것은 경매 상품입니다.") + .subCategory(전자기기_서브_노트북_카테고리) + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(LocalDateTime.now()) + .build(); + 경매1.addAuctionImages(List.of(경매_이미지)); + 경매2 = Auction.builder() + .seller(판매자) + .title("경매 상품") + .description("이것은 경매 상품입니다.") + .subCategory(전자기기_서브_노트북_카테고리) + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(LocalDateTime.now()) + .build(); + 경매2.addAuctionImages(List.of(경매_이미지)); + + 입찰자1 = User.builder() + .name("입찰자1") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12346") + .build(); + final User 입찰자2 = User.builder() + .name("입찰자2") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12346") + .build(); + + 입찰액 = new BidPrice(10_000); + + 경매1의_입찰1 = new Bid(경매1, 입찰자1, 입찰액); + 경매1의_입찰2겸_마지막_입찰 = new Bid(경매1, 입찰자2, 입찰액); + final Bid 경매2의_입찰1 = new Bid(경매2, 입찰자1, 입찰액); + + userRepository.save(판매자); + userRepository.save(입찰자1); + userRepository.save(입찰자2); + + categoryRepository.saveAll(List.of(전자기기_카테고리, 전자기기_서브_노트북_카테고리)); + auctionRepository.save(경매1); + auctionRepository.save(경매2); + + bidRepository.save(경매1의_입찰1); + bidRepository.save(경매1의_입찰2겸_마지막_입찰); + bidRepository.save(경매2의_입찰1); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java index b7da09ec1..495216c72 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java @@ -8,7 +8,7 @@ import com.ddang.ddang.authentication.domain.dto.AuthenticationUserInfo; import com.ddang.ddang.bid.domain.Bid; import com.ddang.ddang.bid.domain.BidPrice; -import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; +import com.ddang.ddang.bid.domain.repository.BidRepository; import com.ddang.ddang.category.domain.Category; import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; import com.ddang.ddang.chat.application.dto.CreateChatRoomDto; @@ -27,7 +27,6 @@ import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; @@ -47,7 +46,7 @@ public class ChatRoomServiceFixture { private UserRepository userRepository; @Autowired - private JpaBidRepository bidRepository; + private BidRepository bidRepository; @Autowired private ChatRoomRepository chatRoomRepository; @@ -206,7 +205,9 @@ void setUp() { final Bid 채팅방_없는_경매_입찰 = new Bid(채팅방이_없는_경매, 구매자, new BidPrice(15_000)); final Bid 지토가_엔초_경매에_입찰 = new Bid(판매자_엔초_구매자_지토_경매, 지토, new BidPrice(15_000)); final Bid 엔초가_제이미_경매에_입찰 = new Bid(판매자_제이미_구매자_엔초_경매, 엔초, new BidPrice(15_000)); - bidRepository.saveAll(List.of(채팅방_없는_경매_입찰, 지토가_엔초_경매에_입찰, 엔초가_제이미_경매에_입찰)); + bidRepository.save(채팅방_없는_경매_입찰); + bidRepository.save(지토가_엔초_경매에_입찰); + bidRepository.save(엔초가_제이미_경매에_입찰); 채팅방이_없는_경매.updateLastBid(채팅방_없는_경매_입찰); 판매자_엔초_구매자_지토_경매.updateLastBid(지토가_엔초_경매에_입찰); 판매자_제이미_구매자_엔초_경매.updateLastBid(엔초가_제이미_경매에_입찰); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndImageRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndImageRepositoryImplFixture.java index 238f76175..9ffbf0839 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndImageRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndImageRepositoryImplFixture.java @@ -9,6 +9,8 @@ import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; import com.ddang.ddang.bid.domain.Bid; import com.ddang.ddang.bid.domain.BidPrice; +import com.ddang.ddang.bid.domain.repository.BidRepository; +import com.ddang.ddang.bid.infrastructure.persistence.BidRepositoryImpl; import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; import com.ddang.ddang.category.domain.Category; import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; @@ -40,8 +42,7 @@ public class ChatRoomAndImageRepositoryImplFixture { private UserRepository userRepository; - @Autowired - private JpaBidRepository bidRepository; + private BidRepository bidRepository; private ChatRoomRepository chatRoomRepository; @@ -53,10 +54,13 @@ void fixtureSetUp( @Autowired final JPAQueryFactory jpaQueryFactory, @Autowired final JpaAuctionRepository jpaAuctionRepository, @Autowired final JpaUserRepository jpaUserRepository, - @Autowired final JpaChatRoomRepository jpaChatRoomRepository) { + @Autowired final JpaChatRoomRepository jpaChatRoomRepository, + @Autowired final JpaBidRepository jpaBidRepository + ) { auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(jpaQueryFactory)); userRepository = new UserRepositoryImpl(jpaUserRepository); chatRoomRepository = new ChatRoomRepositoryImpl(jpaChatRoomRepository); + bidRepository = new BidRepositoryImpl(jpaBidRepository); final Category 전자기기_카테고리 = new Category("전자기기"); final Category 전자기기_서브_노트북_카테고리 = new Category("노트북 카테고리"); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndMessageAndImageRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndMessageAndImageRepositoryImplFixture.java index 910a036b0..d776c4829 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndMessageAndImageRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndMessageAndImageRepositoryImplFixture.java @@ -9,6 +9,8 @@ import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; import com.ddang.ddang.bid.domain.Bid; import com.ddang.ddang.bid.domain.BidPrice; +import com.ddang.ddang.bid.domain.repository.BidRepository; +import com.ddang.ddang.bid.infrastructure.persistence.BidRepositoryImpl; import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; import com.ddang.ddang.category.domain.Category; import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; @@ -42,8 +44,7 @@ public class ChatRoomAndMessageAndImageRepositoryImplFixture { private UserRepository userRepository; - @Autowired - private JpaBidRepository bidRepository; + private BidRepository bidRepository; private ChatRoomRepository chatRoomRepository; @@ -66,11 +67,13 @@ void fixtureSetUp( @Autowired final JPAQueryFactory jpaQueryFactory, @Autowired final JpaAuctionRepository jpaAuctionRepository, @Autowired final JpaUserRepository jpaUserRepository, - @Autowired final JpaChatRoomRepository jpaChatRoomRepository + @Autowired final JpaChatRoomRepository jpaChatRoomRepository, + @Autowired final JpaBidRepository jpaBidRepository ) { auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(jpaQueryFactory)); userRepository = new UserRepositoryImpl(jpaUserRepository); chatRoomRepository = new ChatRoomRepositoryImpl(jpaChatRoomRepository); + bidRepository = new BidRepositoryImpl(jpaBidRepository); final Category 전자기기_카테고리 = new Category("전자기기"); final Category 전자기기_서브_노트북_카테고리 = new Category("노트북 카테고리"); @@ -195,7 +198,9 @@ void fixtureSetUp( auctionRepository.save(엔초의_경매); auctionRepository.save(제이미의_경매); - bidRepository.saveAll(List.of(엔초가_메리_경매에_입찰, 지토가_엔초_경매에_입찰, 엔초가_제이미_경매에_입찰)); + bidRepository.save(엔초가_메리_경매에_입찰); + bidRepository.save(지토가_엔초_경매에_입찰); + bidRepository.save(엔초가_제이미_경매에_입찰); 메리의_경매.updateLastBid(엔초가_메리_경매에_입찰); 엔초의_경매.updateLastBid(지토가_엔초_경매에_입찰); 제이미의_경매.updateLastBid(엔초가_제이미_경매에_입찰); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomRepositoryImplFixture.java index 54d23f007..9eb5becd0 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomRepositoryImplFixture.java @@ -9,6 +9,8 @@ import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; import com.ddang.ddang.bid.domain.Bid; import com.ddang.ddang.bid.domain.BidPrice; +import com.ddang.ddang.bid.domain.repository.BidRepository; +import com.ddang.ddang.bid.infrastructure.persistence.BidRepositoryImpl; import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; import com.ddang.ddang.category.domain.Category; import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; @@ -40,8 +42,7 @@ public class ChatRoomRepositoryImplFixture { private AuctionRepository auctionRepository; - @Autowired - private JpaBidRepository bidRepository; + private BidRepository bidRepository; private ChatRoomRepository chatRoomRepository; @@ -57,11 +58,13 @@ void fixtureSetUp( @Autowired final JPAQueryFactory queryFactory, @Autowired final JpaAuctionRepository jpaAuctionRepository, @Autowired final JpaUserRepository jpaUserRepository, - @Autowired final JpaChatRoomRepository jpaChatRoomRepository + @Autowired final JpaChatRoomRepository jpaChatRoomRepository, + @Autowired final JpaBidRepository jpaBidRepository ) { auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(queryFactory)); userRepository = new UserRepositoryImpl(jpaUserRepository); chatRoomRepository = new ChatRoomRepositoryImpl(jpaChatRoomRepository); + bidRepository = new BidRepositoryImpl(jpaBidRepository); final Category 전자기기_카테고리 = new Category("전자기기"); final Category 전자기기_서브_노트북_카테고리 = new Category("노트북 카테고리"); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java index 083220f23..30c073a00 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java @@ -6,7 +6,7 @@ import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.bid.domain.Bid; import com.ddang.ddang.bid.domain.BidPrice; -import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; +import com.ddang.ddang.bid.domain.repository.BidRepository; import com.ddang.ddang.chat.domain.ChatRoom; import com.ddang.ddang.chat.domain.Message; import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; @@ -46,7 +46,7 @@ public class FcmNotificationServiceFixture { private AuctionRepository auctionRepository; @Autowired - private JpaBidRepository bidRepository; + private BidRepository bidRepository; @Autowired private JpaAuctionImageRepository auctionImageRepository; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java index 81fb61456..04323da66 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java @@ -10,7 +10,7 @@ import com.ddang.ddang.bid.application.event.BidNotificationEvent; import com.ddang.ddang.bid.domain.Bid; import com.ddang.ddang.bid.domain.BidPrice; -import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; +import com.ddang.ddang.bid.domain.repository.BidRepository; import com.ddang.ddang.chat.application.dto.CreateMessageDto; import com.ddang.ddang.chat.application.event.MessageNotificationEvent; import com.ddang.ddang.chat.domain.ChatRoom; @@ -49,7 +49,7 @@ public class NotificationEventListenerFixture { private JpaAuctionImageRepository auctionImageRepository; @Autowired - private JpaBidRepository bidRepository; + private BidRepository bidRepository; @Autowired private JpaMessageRepository messageRepository; @@ -64,7 +64,7 @@ public class NotificationEventListenerFixture { protected String 이미지_절대_경로 = "/imageUrl"; @BeforeEach - void setUp() { + void setUpFixture() { final User 발신자_겸_판매자 = User.builder() .name("발신자 겸 판매자") .profileImage(new ProfileImage("upload.png", "store.png")) From ca3b225fa0e3eae7f67589ef8605168bc706e763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=9C=EC=9D=B4=EB=AF=B8?= <63184334+JJ503@users.noreply.github.com> Date: Sun, 15 Oct 2023 15:56:27 +0900 Subject: [PATCH 25/37] =?UTF-8?q?refactor:=20#672=20Report=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=9D=B8=ED=94=84=EB=9D=BC=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81=20(#685)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 도메인 영역에 경매 신고 repository 추가 * refactor: EntityGraph를 jpql로 변경 * refactor: EntityGraph를 jpql로 변경 * feat: 도메인 영역에 경매 신고 repository 구현체 추가 * refactor: service에서 도메인 영역의 경매 신고 repository를 사용하도록 변경 * test: 테스트에서 도메인 영역의 경매 신고 repository를 사용하도록 변경 * feat: 도메인 영역에 채팅방 신고 repository 추가 * refactor: EntityGraph를 jpql로 변경 * feat: 도메인 영역에 쪽지방 신고 repository 구현체 추가 * test: 테스트 실패 해결 * test: 픽스처 클래스 네이밍 수정 * feat: 도메인 영역에 질문 신고 repository 추가 * refactor: EntityGraph를 jpql로 변경 * test: 테스트에서 도메인 영역의 질문 신고 repository를 사용하도록 변경 * refactor: service에서 도메인 영역의 쪽지방 신고 repository를 사용하도록 변경 * refactor: service에서 도메인 영역의 질문 신고 repository를 사용하도록 변경 * refactor: import 와일드카드 제거 * refactor: EntityGraph를 jpql로 변경 * feat: 도메인 영역에 답변 신고 repository 추가 * feat: 도메인 영역에 답변 신고 repository 구현체 추가 * refactor: service에서 도메인 영역의 답변 신고 repository를 사용하도록 변경 * test: 테스트에서 도메인 영역의 신고관련 repository를 사용하도록 변경 * refactor: import 와일드카드 제거 * test: 테스트 실패 문제 해결 * test: final 추가 * refactor: 쿼리문 명령어를 대문자로 수정 * refactor: 클래스명 수정 * refactor: 필드 순서 변경 및 불필효한 필드 제거 * test: 테스트 영역에서 도메인 영역의 repository를 사용하도록 변경 --- .../application/AnswerReportService.java | 6 +- .../application/AuctionReportService.java | 6 +- .../application/ChatRoomReportService.java | 6 +- .../application/QuestionReportService.java | 6 +- .../repository/AnswerReportRepository.java | 14 ++ .../repository/AuctionReportRepository.java | 14 ++ .../repository/ChatRoomReportRepository.java | 14 ++ .../repository/QuestionReportRepository.java | 14 ++ .../AnswerReportRepositoryImpl.java | 30 ++++ .../AuctionReportRepositoryImpl.java | 30 ++++ .../ChatRoomReportRepositoryImpl.java | 30 ++++ .../JpaAnswerReportRepository.java | 17 +- .../JpaAuctionReportRepository.java | 13 +- .../JpaChatRoomReportRepository.java | 15 +- .../JpaQuestionReportRepository.java | 12 +- .../QuestionReportRepositoryImpl.java | 30 ++++ ...QuerydslAuctionAndImageRepositoryTest.java | 2 +- .../BlackListTokenRepositoryImplTest.java | 2 +- .../CategoryRepositoryImplTest.java | 2 +- .../fixture/AnswerReportServiceFixture.java | 8 +- .../fixture/AuctionReportServiceFixture.java | 9 +- .../fixture/ChatRoomReportServiceFixture.java | 9 +- .../fixture/QuestionReportServiceFixture.java | 8 +- .../AnswerReportRepositoryImplTest.java | 78 ++++++++ .../AuctionReportRepositoryImplTest.java | 80 +++++++++ .../ChatRoomReportRepositoryImplTest.java | 79 ++++++++ .../JpaAnswerReportRepositoryTest.java | 2 +- .../JpaAuctionReportRepositoryTest.java | 10 +- .../JpaChatRoomReportRepositoryTest.java | 10 +- ... JpaQuestionReportRepositoryImplTest.java} | 6 +- .../QuestionReportRepositoryImplImplTest.java | 78 ++++++++ .../AnswerReportRepositoryImplFixture.java | 156 ++++++++++++++++ .../AuctionReportRepositoryImplFixture.java | 130 ++++++++++++++ .../ChatRoomReportRepositoryImplFixture.java | 168 ++++++++++++++++++ ...aQuestionReportRepositoryImplFixture.java} | 42 +++-- .../QuestionReportRepositoryImplFixture.java | 144 +++++++++++++++ 36 files changed, 1206 insertions(+), 74 deletions(-) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/report/domain/repository/AnswerReportRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/report/domain/repository/AuctionReportRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/report/domain/repository/ChatRoomReportRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/report/domain/repository/QuestionReportRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/AnswerReportRepositoryImpl.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/AuctionReportRepositoryImpl.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/ChatRoomReportRepositoryImpl.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/QuestionReportRepositoryImpl.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/AnswerReportRepositoryImplTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/AuctionReportRepositoryImplTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/ChatRoomReportRepositoryImplTest.java rename backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/{JpaQuestionReportRepositoryTest.java => JpaQuestionReportRepositoryImplTest.java} (94%) create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/QuestionReportRepositoryImplImplTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/AnswerReportRepositoryImplFixture.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/AuctionReportRepositoryImplFixture.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/ChatRoomReportRepositoryImplFixture.java rename backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/{JpaQuestionReportRepositoryFixture.java => JpaQuestionReportRepositoryImplFixture.java} (75%) create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/QuestionReportRepositoryImplFixture.java diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/application/AnswerReportService.java b/backend/ddang/src/main/java/com/ddang/ddang/report/application/AnswerReportService.java index c2151c209..77e48aa98 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/report/application/AnswerReportService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/application/AnswerReportService.java @@ -7,7 +7,7 @@ import com.ddang.ddang.report.application.dto.ReadAnswerReportDto; import com.ddang.ddang.report.application.exception.InvalidAnswererReportException; import com.ddang.ddang.report.domain.AnswerReport; -import com.ddang.ddang.report.infrastructure.persistence.JpaAnswerReportRepository; +import com.ddang.ddang.report.domain.repository.AnswerReportRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -24,7 +24,7 @@ public class AnswerReportService { private final JpaAnswerRepository answerRepository; private final UserRepository userRepository; - private final JpaAnswerReportRepository answerReportRepository; + private final AnswerReportRepository answerReportRepository; @Transactional public Long create(final CreateAnswerReportDto answerReportDto) { @@ -52,7 +52,7 @@ private void checkInvalidAnswerReport(final User reporter, final Answer answer) } public List readAll() { - final List answerReports = answerReportRepository.findAllByOrderByIdAsc(); + final List answerReports = answerReportRepository.findAll(); return answerReports.stream() .map(ReadAnswerReportDto::from) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/application/AuctionReportService.java b/backend/ddang/src/main/java/com/ddang/ddang/report/application/AuctionReportService.java index 4bd7bfffb..5660f96f6 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/report/application/AuctionReportService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/application/AuctionReportService.java @@ -8,7 +8,7 @@ import com.ddang.ddang.report.application.exception.AlreadyReportAuctionException; import com.ddang.ddang.report.application.exception.InvalidReporterToAuctionException; import com.ddang.ddang.report.domain.AuctionReport; -import com.ddang.ddang.report.infrastructure.persistence.JpaAuctionReportRepository; +import com.ddang.ddang.report.domain.repository.AuctionReportRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -25,7 +25,7 @@ public class AuctionReportService { private final AuctionRepository auctionRepository; private final UserRepository userRepository; - private final JpaAuctionReportRepository auctionReportRepository; + private final AuctionReportRepository auctionReportRepository; @Transactional public Long create(final CreateAuctionReportDto auctionReportDto) { @@ -51,7 +51,7 @@ private void checkInvalidAuctionReport(final User reporter, final Auction auctio } public List readAll() { - final List auctionReports = auctionReportRepository.findAllByOrderByIdAsc(); + final List auctionReports = auctionReportRepository.findAll(); return auctionReports.stream() .map(ReadAuctionReportDto::from) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/application/ChatRoomReportService.java b/backend/ddang/src/main/java/com/ddang/ddang/report/application/ChatRoomReportService.java index 11b3c3ed9..186f6ce5f 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/report/application/ChatRoomReportService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/application/ChatRoomReportService.java @@ -8,7 +8,7 @@ import com.ddang.ddang.report.application.exception.AlreadyReportChatRoomException; import com.ddang.ddang.report.application.exception.InvalidChatRoomReportException; import com.ddang.ddang.report.domain.ChatRoomReport; -import com.ddang.ddang.report.infrastructure.persistence.JpaChatRoomReportRepository; +import com.ddang.ddang.report.domain.repository.ChatRoomReportRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -25,7 +25,7 @@ public class ChatRoomReportService { private final UserRepository userRepository; private final ChatRoomRepository chatRoomRepository; - private final JpaChatRoomReportRepository chatRoomReportRepository; + private final ChatRoomReportRepository chatRoomReportRepository; @Transactional public Long create(final CreateChatRoomReportDto chatRoomReportDto) { @@ -52,7 +52,7 @@ private void checkInvalidChatRoomReport(final User reporter, final ChatRoom chat } public List readAll() { - final List auctionReports = chatRoomReportRepository.findAllByOrderByIdAsc(); + final List auctionReports = chatRoomReportRepository.findAll(); return auctionReports.stream() .map(ReadChatRoomReportDto::from) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/application/QuestionReportService.java b/backend/ddang/src/main/java/com/ddang/ddang/report/application/QuestionReportService.java index 4c85f2b87..e9194ea4a 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/report/application/QuestionReportService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/application/QuestionReportService.java @@ -7,7 +7,7 @@ import com.ddang.ddang.report.application.dto.ReadQuestionReportDto; import com.ddang.ddang.report.application.exception.InvalidQuestionReportException; import com.ddang.ddang.report.domain.QuestionReport; -import com.ddang.ddang.report.infrastructure.persistence.JpaQuestionReportRepository; +import com.ddang.ddang.report.domain.repository.QuestionReportRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -24,7 +24,7 @@ public class QuestionReportService { private final JpaQuestionRepository questionRepository; private final UserRepository userRepository; - private final JpaQuestionReportRepository questionReportRepository; + private final QuestionReportRepository questionReportRepository; @Transactional public Long create(final CreateQuestionReportDto questionReportDto) { @@ -52,7 +52,7 @@ private void checkInvalidQuestionReport(final User reporter, final Question ques } public List readAll() { - final List questionReports = questionReportRepository.findAllByOrderByIdAsc(); + final List questionReports = questionReportRepository.findAll(); return questionReports.stream() .map(ReadQuestionReportDto::from) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/domain/repository/AnswerReportRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/report/domain/repository/AnswerReportRepository.java new file mode 100644 index 000000000..be7c7a79a --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/domain/repository/AnswerReportRepository.java @@ -0,0 +1,14 @@ +package com.ddang.ddang.report.domain.repository; + +import com.ddang.ddang.report.domain.AnswerReport; + +import java.util.List; + +public interface AnswerReportRepository { + + AnswerReport save(final AnswerReport answerReport); + + boolean existsByAnswerIdAndReporterId(final Long answerId, final Long reportId); + + List findAll(); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/domain/repository/AuctionReportRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/report/domain/repository/AuctionReportRepository.java new file mode 100644 index 000000000..5584de605 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/domain/repository/AuctionReportRepository.java @@ -0,0 +1,14 @@ +package com.ddang.ddang.report.domain.repository; + +import com.ddang.ddang.report.domain.AuctionReport; + +import java.util.List; + +public interface AuctionReportRepository { + + AuctionReport save(final AuctionReport auctionReport); + + boolean existsByAuctionIdAndReporterId(final Long auctionId, final Long reporterId); + + List findAll(); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/domain/repository/ChatRoomReportRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/report/domain/repository/ChatRoomReportRepository.java new file mode 100644 index 000000000..20f4425e9 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/domain/repository/ChatRoomReportRepository.java @@ -0,0 +1,14 @@ +package com.ddang.ddang.report.domain.repository; + +import com.ddang.ddang.report.domain.ChatRoomReport; + +import java.util.List; + +public interface ChatRoomReportRepository { + + ChatRoomReport save(final ChatRoomReport chatRoomReport); + + boolean existsByChatRoomIdAndReporterId(final Long chatRoomId, final Long reporterId); + + List findAll(); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/domain/repository/QuestionReportRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/report/domain/repository/QuestionReportRepository.java new file mode 100644 index 000000000..d13618d6e --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/domain/repository/QuestionReportRepository.java @@ -0,0 +1,14 @@ +package com.ddang.ddang.report.domain.repository; + +import com.ddang.ddang.report.domain.QuestionReport; + +import java.util.List; + +public interface QuestionReportRepository { + + QuestionReport save(final QuestionReport questionReport); + + boolean existsByQuestionIdAndReporterId(final Long questionId, final Long reporterId); + + List findAll(); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/AnswerReportRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/AnswerReportRepositoryImpl.java new file mode 100644 index 000000000..c65ef0d32 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/AnswerReportRepositoryImpl.java @@ -0,0 +1,30 @@ +package com.ddang.ddang.report.infrastructure.persistence; + +import com.ddang.ddang.report.domain.AnswerReport; +import com.ddang.ddang.report.domain.repository.AnswerReportRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +@RequiredArgsConstructor +public class AnswerReportRepositoryImpl implements AnswerReportRepository { + + private final JpaAnswerReportRepository jpaAnswerReportRepository; + + @Override + public AnswerReport save(final AnswerReport answerReport) { + return jpaAnswerReportRepository.save(answerReport); + } + + @Override + public boolean existsByAnswerIdAndReporterId(final Long answerId, final Long reportId) { + return jpaAnswerReportRepository.existsByAnswerIdAndReporterId(answerId, reportId); + } + + @Override + public List findAll() { + return jpaAnswerReportRepository.findAll(); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/AuctionReportRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/AuctionReportRepositoryImpl.java new file mode 100644 index 000000000..994363702 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/AuctionReportRepositoryImpl.java @@ -0,0 +1,30 @@ +package com.ddang.ddang.report.infrastructure.persistence; + +import com.ddang.ddang.report.domain.AuctionReport; +import com.ddang.ddang.report.domain.repository.AuctionReportRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +@RequiredArgsConstructor +public class AuctionReportRepositoryImpl implements AuctionReportRepository { + + private final JpaAuctionReportRepository jpaAuctionReportRepository; + + @Override + public AuctionReport save(final AuctionReport auctionReport) { + return jpaAuctionReportRepository.save(auctionReport); + } + + @Override + public boolean existsByAuctionIdAndReporterId(final Long auctionId, final Long reporterId) { + return jpaAuctionReportRepository.existsByAuctionIdAndReporterId(auctionId, reporterId); + } + + @Override + public List findAll() { + return jpaAuctionReportRepository.findAll(); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/ChatRoomReportRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/ChatRoomReportRepositoryImpl.java new file mode 100644 index 000000000..8212f3249 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/ChatRoomReportRepositoryImpl.java @@ -0,0 +1,30 @@ +package com.ddang.ddang.report.infrastructure.persistence; + +import com.ddang.ddang.report.domain.ChatRoomReport; +import com.ddang.ddang.report.domain.repository.ChatRoomReportRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +@RequiredArgsConstructor +public class ChatRoomReportRepositoryImpl implements ChatRoomReportRepository { + + private final JpaChatRoomReportRepository jpaChatRoomReportRepository; + + @Override + public ChatRoomReport save(final ChatRoomReport chatRoomReport) { + return jpaChatRoomReportRepository.save(chatRoomReport); + } + + @Override + public boolean existsByChatRoomIdAndReporterId(final Long chatRoomId, final Long reporterId) { + return jpaChatRoomReportRepository.existsByChatRoomIdAndReporterId(chatRoomId, reporterId); + } + + @Override + public List findAll() { + return jpaChatRoomReportRepository.findAll(); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/JpaAnswerReportRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/JpaAnswerReportRepository.java index 46dcac184..2be18d491 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/JpaAnswerReportRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/JpaAnswerReportRepository.java @@ -1,15 +1,24 @@ package com.ddang.ddang.report.infrastructure.persistence; import com.ddang.ddang.report.domain.AnswerReport; -import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import java.util.List; public interface JpaAnswerReportRepository extends JpaRepository { - boolean existsByAnswerIdAndReporterId(final Long answerId, final Long ReporterId); + boolean existsByAnswerIdAndReporterId(final Long answerId, final Long reportId); - @EntityGraph(attributePaths = {"reporter", "answer", "answer.question", "answer.question.auction", "answer.question.auction.seller"}) - List findAllByOrderByIdAsc(); + @Query(""" + SELECT ar + FROM AnswerReport ar + JOIN FETCH ar.reporter + JOIN FETCH ar.answer an + JOIN FETCH an.question q + JOIN FETCH q.auction a + JOIN FETCH a.seller + ORDER BY ar.id ASC + """) + List findAll(); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/JpaAuctionReportRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/JpaAuctionReportRepository.java index c426a4051..5fa4e4186 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/JpaAuctionReportRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/JpaAuctionReportRepository.java @@ -1,8 +1,8 @@ package com.ddang.ddang.report.infrastructure.persistence; import com.ddang.ddang.report.domain.AuctionReport; -import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import java.util.List; @@ -10,6 +10,13 @@ public interface JpaAuctionReportRepository extends JpaRepository findAllByOrderByIdAsc(); + @Query(""" + SELECT ar + FROM AuctionReport ar + JOIN FETCH ar.reporter + JOIN FETCH ar.auction a + JOIN FETCH a.seller + ORDER BY ar.id ASC + """) + List findAll(); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/JpaChatRoomReportRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/JpaChatRoomReportRepository.java index d6965e7df..c41258456 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/JpaChatRoomReportRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/JpaChatRoomReportRepository.java @@ -1,8 +1,8 @@ package com.ddang.ddang.report.infrastructure.persistence; import com.ddang.ddang.report.domain.ChatRoomReport; -import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import java.util.List; @@ -10,6 +10,15 @@ public interface JpaChatRoomReportRepository extends JpaRepository findAllByOrderByIdAsc(); + @Query(""" + SELECT crr + FROM ChatRoomReport crr + JOIN FETCH crr.reporter + JOIN FETCH crr.chatRoom cr + JOIN FETCH cr.buyer + JOIN FETCH cr.auction a + JOIN FETCH a.seller + ORDER BY crr.id ASC + """) + List findAll(); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/JpaQuestionReportRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/JpaQuestionReportRepository.java index 6f5e7006a..deaf6e349 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/JpaQuestionReportRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/JpaQuestionReportRepository.java @@ -1,8 +1,8 @@ package com.ddang.ddang.report.infrastructure.persistence; import com.ddang.ddang.report.domain.QuestionReport; -import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import java.util.List; @@ -10,6 +10,12 @@ public interface JpaQuestionReportRepository extends JpaRepository findAllByOrderByIdAsc(); + @Query(""" + SELECT qr + FROM QuestionReport qr + JOIN FETCH qr.reporter + JOIN FETCH qr.question + ORDER BY qr.id ASC + """) + List findAll(); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/QuestionReportRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/QuestionReportRepositoryImpl.java new file mode 100644 index 000000000..d5a7b2802 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/infrastructure/persistence/QuestionReportRepositoryImpl.java @@ -0,0 +1,30 @@ +package com.ddang.ddang.report.infrastructure.persistence; + +import com.ddang.ddang.report.domain.QuestionReport; +import com.ddang.ddang.report.domain.repository.QuestionReportRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +@RequiredArgsConstructor +public class QuestionReportRepositoryImpl implements QuestionReportRepository { + + private final JpaQuestionReportRepository jpaQuestionReportRepository; + + @Override + public QuestionReport save(final QuestionReport questionReport) { + return jpaQuestionReportRepository.save(questionReport); + } + + @Override + public boolean existsByQuestionIdAndReporterId(final Long questionId, final Long reporterId) { + return jpaQuestionReportRepository.existsByQuestionIdAndReporterId(questionId, reporterId); + } + + @Override + public List findAll() { + return jpaQuestionReportRepository.findAll(); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionAndImageRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionAndImageRepositoryTest.java index 7ac95a9b1..2adf85696 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionAndImageRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionAndImageRepositoryTest.java @@ -24,7 +24,7 @@ class QuerydslAuctionAndImageRepositoryTest extends QuerydslAuctionAndImageRepos QuerydslAuctionAndImageRepository querydslAuctionAndImageRepository; @BeforeEach - void setUp(@Autowired JPAQueryFactory queryFactory) { + void setUp(@Autowired final JPAQueryFactory queryFactory) { querydslAuctionAndImageRepository = new QuerydslAuctionAndImageRepository(queryFactory); } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/infrastructure/persistence/BlackListTokenRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/infrastructure/persistence/BlackListTokenRepositoryImplTest.java index 2fb557928..33c24b852 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/infrastructure/persistence/BlackListTokenRepositoryImplTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/infrastructure/persistence/BlackListTokenRepositoryImplTest.java @@ -26,7 +26,7 @@ class BlackListTokenRepositoryImplTest extends BlackListTokenRepositoryFixture { BlackListTokenRepository blackListTokenRepository; @BeforeEach - void setUp(@Autowired JpaBlackListTokenRepository jpaBlackListTokenRepository) { + void setUp(@Autowired final JpaBlackListTokenRepository jpaBlackListTokenRepository) { blackListTokenRepository = new BlackListTokenRepositoryImpl(jpaBlackListTokenRepository); } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/category/infrastructure/persistence/CategoryRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/category/infrastructure/persistence/CategoryRepositoryImplTest.java index 19feb7c34..11a2b389a 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/category/infrastructure/persistence/CategoryRepositoryImplTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/category/infrastructure/persistence/CategoryRepositoryImplTest.java @@ -26,7 +26,7 @@ class CategoryRepositoryImplTest extends CategoryRepositoryFixture { CategoryRepository categoryRepository; @BeforeEach - void setUp(@Autowired JpaCategoryRepository jpaCategoryRepository) { + void setUp(@Autowired final JpaCategoryRepository jpaCategoryRepository) { categoryRepository = new CategoryRepositoryImpl(jpaCategoryRepository); } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AnswerReportServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AnswerReportServiceFixture.java index 9e067fed2..dfdd32d84 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AnswerReportServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AnswerReportServiceFixture.java @@ -14,7 +14,7 @@ import com.ddang.ddang.qna.infrastructure.JpaQuestionRepository; import com.ddang.ddang.report.application.dto.CreateAnswerReportDto; import com.ddang.ddang.report.domain.AnswerReport; -import com.ddang.ddang.report.infrastructure.persistence.JpaAnswerReportRepository; +import com.ddang.ddang.report.domain.repository.AnswerReportRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -43,7 +43,7 @@ public class AnswerReportServiceFixture { private JpaAnswerRepository answerRepository; @Autowired - private JpaAnswerReportRepository answerReportRepository; + private AnswerReportRepository answerReportRepository; protected User 신고자; protected User 이미_신고한_신고자1; @@ -137,7 +137,9 @@ void setUp() { auctionRepository.save(경매); questionRepository.save(질문); answerRepository.save(답변); - answerReportRepository.saveAll(List.of(답변_신고1, 답변_신고2, 답변_신고3)); + answerReportRepository.save(답변_신고1); + answerReportRepository.save(답변_신고2); + answerReportRepository.save(답변_신고3); 답변_신고_요청_dto = new CreateAnswerReportDto(답변.getId(), "신고합니다.", 신고자.getId()); 존재하지_않는_답변_신고_요청_dto = new CreateAnswerReportDto(존재하지_않는_답변_아이디, "신고합니다.", 신고자.getId()); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AuctionReportServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AuctionReportServiceFixture.java index 162d68ba1..caedb9689 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AuctionReportServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AuctionReportServiceFixture.java @@ -12,7 +12,7 @@ import com.ddang.ddang.image.infrastructure.persistence.JpaProfileImageRepository; import com.ddang.ddang.report.application.dto.CreateAuctionReportDto; import com.ddang.ddang.report.domain.AuctionReport; -import com.ddang.ddang.report.infrastructure.persistence.JpaAuctionReportRepository; +import com.ddang.ddang.report.domain.repository.AuctionReportRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -41,7 +41,7 @@ public class AuctionReportServiceFixture { private AuctionRepository auctionRepository; @Autowired - private JpaAuctionReportRepository auctionReportRepository; + private AuctionReportRepository auctionReportRepository; protected User 이미_신고한_신고자1; protected User 이미_신고한_신고자2; @@ -136,8 +136,9 @@ void setUp() { auctionRepository.save(경매); auctionRepository.save(삭제된_경매); - - auctionReportRepository.saveAll(List.of(경매_신고1, 경매_신고2, 경매_신고3)); + auctionReportRepository.save(경매_신고1); + auctionReportRepository.save(경매_신고2); + auctionReportRepository.save(경매_신고3); 새로운_경매_신고_요청_dto = new CreateAuctionReportDto( 경매.getId(), diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/ChatRoomReportServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/ChatRoomReportServiceFixture.java index 56e34897d..e6be807e4 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/ChatRoomReportServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/ChatRoomReportServiceFixture.java @@ -14,11 +14,10 @@ import com.ddang.ddang.image.infrastructure.persistence.JpaProfileImageRepository; import com.ddang.ddang.report.application.dto.CreateChatRoomReportDto; import com.ddang.ddang.report.domain.ChatRoomReport; -import com.ddang.ddang.report.infrastructure.persistence.JpaChatRoomReportRepository; +import com.ddang.ddang.report.domain.repository.ChatRoomReportRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; -import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; @@ -44,7 +43,7 @@ public class ChatRoomReportServiceFixture { private AuctionRepository auctionRepository; @Autowired - private JpaChatRoomReportRepository chatRoomReportRepository; + private ChatRoomReportRepository chatRoomReportRepository; @Autowired private ChatRoomRepository chatRoomRepository; @@ -161,7 +160,9 @@ void setUp() { chatRoomRepository.save(채팅방2); chatRoomRepository.save(채팅방3); - chatRoomReportRepository.saveAll(List.of(채팅방_신고1, 채팅방_신고2, 채팅방_신고3)); + chatRoomReportRepository.save(채팅방_신고1); + chatRoomReportRepository.save(채팅방_신고2); + chatRoomReportRepository.save(채팅방_신고3); 채팅방_신고_요청_dto = new CreateChatRoomReportDto( 채팅방1.getId(), diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/QuestionReportServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/QuestionReportServiceFixture.java index 087656702..9e671032c 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/QuestionReportServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/QuestionReportServiceFixture.java @@ -12,7 +12,7 @@ import com.ddang.ddang.qna.infrastructure.JpaQuestionRepository; import com.ddang.ddang.report.application.dto.CreateQuestionReportDto; import com.ddang.ddang.report.domain.QuestionReport; -import com.ddang.ddang.report.infrastructure.persistence.JpaQuestionReportRepository; +import com.ddang.ddang.report.domain.repository.QuestionReportRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -38,7 +38,7 @@ public class QuestionReportServiceFixture { private JpaQuestionRepository questionRepository; @Autowired - private JpaQuestionReportRepository questionReportRepository; + private QuestionReportRepository questionReportRepository; protected User 이미_신고한_신고자1; protected User 이미_신고한_신고자2; @@ -126,7 +126,9 @@ void setUp() { categoryRepository.saveAll(List.of(전자기기_카테고리, 전자기기_서브_노트북_카테고리)); auctionRepository.save(경매); questionRepository.save(질문); - questionReportRepository.saveAll(List.of(질문_신고1, 질문_신고2, 질문_신고3)); + questionReportRepository.save(질문_신고1); + questionReportRepository.save(질문_신고2); + questionReportRepository.save(질문_신고3); 질문_신고_요청_dto = new CreateQuestionReportDto(질문.getId(), "신고합니다.", 신고자.getId()); 존재하지_않는_질문_신고_요청_dto = new CreateQuestionReportDto(존재하지_않는_질문_아이디, "신고합니다.", 신고자.getId()); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/AnswerReportRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/AnswerReportRepositoryImplTest.java new file mode 100644 index 000000000..ae270e0e6 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/AnswerReportRepositoryImplTest.java @@ -0,0 +1,78 @@ +package com.ddang.ddang.report.infrastructure.persistence; + +import com.ddang.ddang.configuration.JpaConfiguration; +import com.ddang.ddang.configuration.QuerydslConfiguration; +import com.ddang.ddang.report.domain.AnswerReport; +import com.ddang.ddang.report.domain.repository.AnswerReportRepository; +import com.ddang.ddang.report.infrastructure.persistence.fixture.AnswerReportRepositoryImplFixture; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@Import({JpaConfiguration.class, QuerydslConfiguration.class}) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class AnswerReportRepositoryImplTest extends AnswerReportRepositoryImplFixture { + + AnswerReportRepository answerReportRepository; + + @BeforeEach + void setUp(@Autowired final JpaAnswerReportRepository jpaAnswerReportRepository) { + answerReportRepository = new AnswerReportRepositoryImpl(jpaAnswerReportRepository); + } + + @Test + void 답변을_등록한다() { + // given + final AnswerReport answerReport = new AnswerReport(신고자, 답변, 신고_내용); + + // when + final AnswerReport actual = answerReportRepository.save(answerReport); + + // then + assertThat(actual.getId()).isPositive(); + } + + @Test + void 신고한_답변이라면_참을_반환한다() { + // when + final boolean actual = answerReportRepository.existsByAnswerIdAndReporterId(이미_신고된_답변.getId(), 신고자.getId()); + + // then + assertThat(actual).isTrue(); + } + + @Test + void 신고_전인_답변이라면_거짓을_반환한다() { + // when + final boolean actual = answerReportRepository.existsByAnswerIdAndReporterId(답변.getId(), 신고자.getId()); + + // then + assertThat(actual).isFalse(); + } + + @Test + void 신고된_답변_목록을_조회한다() { + // when + final List actual = answerReportRepository.findAll(); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).hasSize(4); + softAssertions.assertThat(actual.get(0)).isEqualTo(답변_신고1); + softAssertions.assertThat(actual.get(1)).isEqualTo(답변_신고2); + softAssertions.assertThat(actual.get(2)).isEqualTo(답변_신고3); + softAssertions.assertThat(actual.get(3)).isEqualTo(답변_신고4); + }); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/AuctionReportRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/AuctionReportRepositoryImplTest.java new file mode 100644 index 000000000..fd88a30bf --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/AuctionReportRepositoryImplTest.java @@ -0,0 +1,80 @@ +package com.ddang.ddang.report.infrastructure.persistence; + +import com.ddang.ddang.configuration.JpaConfiguration; +import com.ddang.ddang.configuration.QuerydslConfiguration; +import com.ddang.ddang.report.domain.AuctionReport; +import com.ddang.ddang.report.domain.repository.AuctionReportRepository; +import com.ddang.ddang.report.infrastructure.persistence.fixture.AuctionReportRepositoryImplFixture; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@Import({JpaConfiguration.class, QuerydslConfiguration.class}) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class AuctionReportRepositoryImplTest extends AuctionReportRepositoryImplFixture { + + AuctionReportRepository auctionReportRepository; + + @BeforeEach + void setUp(@Autowired final JpaAuctionReportRepository jpaAuctionReportRepository) { + auctionReportRepository = new AuctionReportRepositoryImpl(jpaAuctionReportRepository); + } + + @Test + void 경매_신고를_저장한다() { + // given + final AuctionReport auctionReport = new AuctionReport(판매자, 경매, "신고합니다"); + + // when + final AuctionReport actual = auctionReportRepository.save(auctionReport); + + // then + assertThat(actual.getId()).isPositive(); + } + + @Test + void 특정_경매_아이디와_신고자_아이디가_동일한_레코드가_존재하면_참을_반환한다() { + // when + final boolean actual = auctionReportRepository.existsByAuctionIdAndReporterId(경매.getId(), 신고자1.getId()); + + // then + assertThat(actual).isTrue(); + } + + @Test + void 특정_경매_아이디와_신고자_아이디가_동일한_레코드가_존재하지_않는다면_거짓을_반환한다() { + // when + final boolean actual = auctionReportRepository.existsByAuctionIdAndReporterId( + 존재하지_않는_경매_아이디, + 존재하지_않는_사용자_아이디 + ); + + // then + assertThat(actual).isFalse(); + } + + @Test + void 전체_경매_신고_목록을_조회한다() { + // when + final List actual = auctionReportRepository.findAll(); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).hasSize(3); + softAssertions.assertThat(actual.get(0)).isEqualTo(경매_신고1); + softAssertions.assertThat(actual.get(1)).isEqualTo(경매_신고2); + softAssertions.assertThat(actual.get(2)).isEqualTo(경매_신고3); + }); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/ChatRoomReportRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/ChatRoomReportRepositoryImplTest.java new file mode 100644 index 000000000..01b72d001 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/ChatRoomReportRepositoryImplTest.java @@ -0,0 +1,79 @@ +package com.ddang.ddang.report.infrastructure.persistence; + +import com.ddang.ddang.configuration.JpaConfiguration; +import com.ddang.ddang.configuration.QuerydslConfiguration; +import com.ddang.ddang.report.domain.ChatRoomReport; +import com.ddang.ddang.report.domain.repository.ChatRoomReportRepository; +import com.ddang.ddang.report.infrastructure.persistence.fixture.ChatRoomReportRepositoryImplFixture; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@Import({JpaConfiguration.class, QuerydslConfiguration.class}) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class ChatRoomReportRepositoryImplTest extends ChatRoomReportRepositoryImplFixture { + + ChatRoomReportRepository chatRoomReportRepository; + + @BeforeEach + void setUp(@Autowired final JpaChatRoomReportRepository jpaChatRoomReportRepository) { + chatRoomReportRepository = new ChatRoomReportRepositoryImpl(jpaChatRoomReportRepository); + } + + @Test + void 채팅방_신고를_저장한다() { + final ChatRoomReport chatRoomReport = new ChatRoomReport(구매자1, 채팅방1, "신고합니다."); + + // when + final ChatRoomReport actual = chatRoomReportRepository.save(chatRoomReport); + + // then + assertThat(actual.getId()).isPositive(); + } + + @Test + void 특정_채팅방_아이디와_신고자_아이디가_동일한_레코드가_존재한다면_참을_반환한다() { + // when + final boolean actual = chatRoomReportRepository.existsByChatRoomIdAndReporterId(채팅방1.getId(), 구매자1겸_신고자.getId()); + + // then + assertThat(actual).isTrue(); + } + + @Test + void 특정_채팅방_아이디와_신고자_아이디가_동일한_레코드가_존재하지_않는다면_거짓을_반환한다() { + // when + final boolean actual = chatRoomReportRepository.existsByChatRoomIdAndReporterId( + 존재하지_않는_채팅방_아이디, + 존재하지_않는_사용자_아이디 + ); + + // then + assertThat(actual).isFalse(); + } + + @Test + void 전체_채팅방_신고_목록을_조회한다() { + // when + final List actual = chatRoomReportRepository.findAll(); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).hasSize(3); + softAssertions.assertThat(actual.get(0)).isEqualTo(채팅방_신고1); + softAssertions.assertThat(actual.get(1)).isEqualTo(채팅방_신고2); + softAssertions.assertThat(actual.get(2)).isEqualTo(채팅방_신고3); + }); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/JpaAnswerReportRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/JpaAnswerReportRepositoryTest.java index 4e1a9c379..1606e77e7 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/JpaAnswerReportRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/JpaAnswerReportRepositoryTest.java @@ -58,7 +58,7 @@ class JpaAnswerReportRepositoryTest extends JpaAnswerReportRepositoryFixture { @Test void 신고된_답변_목록을_조회한다() { // when - final List actual = answerReportRepository.findAllByOrderByIdAsc(); + final List actual = answerReportRepository.findAll(); // then SoftAssertions.assertSoftly(softAssertions -> { diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/JpaAuctionReportRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/JpaAuctionReportRepositoryTest.java index 20dd7cfa4..48aff7243 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/JpaAuctionReportRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/JpaAuctionReportRepositoryTest.java @@ -4,8 +4,6 @@ import com.ddang.ddang.configuration.QuerydslConfiguration; import com.ddang.ddang.report.domain.AuctionReport; import com.ddang.ddang.report.infrastructure.persistence.fixture.JpaAuctionReportRepositoryFixture; -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; @@ -24,9 +22,6 @@ @SuppressWarnings("NonAsciiCharacters") class JpaAuctionReportRepositoryTest extends JpaAuctionReportRepositoryFixture { - @PersistenceContext - EntityManager em; - @Autowired JpaAuctionReportRepository auctionReportRepository; @@ -39,9 +34,6 @@ class JpaAuctionReportRepositoryTest extends JpaAuctionReportRepositoryFixture { final AuctionReport actual = auctionReportRepository.save(auctionReport); // then - em.flush(); - em.clear(); - assertThat(actual.getId()).isPositive(); } @@ -69,7 +61,7 @@ class JpaAuctionReportRepositoryTest extends JpaAuctionReportRepositoryFixture { @Test void 전체_경매_신고_목록을_조회한다() { // when - final List actual = auctionReportRepository.findAllByOrderByIdAsc(); + final List actual = auctionReportRepository.findAll(); // then SoftAssertions.assertSoftly(softAssertions -> { diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/JpaChatRoomReportRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/JpaChatRoomReportRepositoryTest.java index 4bd9d2bf1..89ab87322 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/JpaChatRoomReportRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/JpaChatRoomReportRepositoryTest.java @@ -4,8 +4,6 @@ import com.ddang.ddang.configuration.QuerydslConfiguration; import com.ddang.ddang.report.domain.ChatRoomReport; import com.ddang.ddang.report.infrastructure.persistence.fixture.JpaChatRoomReportRepositoryFixture; -import jakarta.persistence.EntityManager; -import jakarta.persistence.PersistenceContext; import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; @@ -24,9 +22,6 @@ @SuppressWarnings("NonAsciiCharacters") class JpaChatRoomReportRepositoryTest extends JpaChatRoomReportRepositoryFixture { - @PersistenceContext - EntityManager em; - @Autowired JpaChatRoomReportRepository chatRoomReportRepository; @@ -38,9 +33,6 @@ class JpaChatRoomReportRepositoryTest extends JpaChatRoomReportRepositoryFixture final ChatRoomReport actual = chatRoomReportRepository.save(chatRoomReport); // then - em.flush(); - em.clear(); - assertThat(actual.getId()).isPositive(); } @@ -68,7 +60,7 @@ class JpaChatRoomReportRepositoryTest extends JpaChatRoomReportRepositoryFixture @Test void 전체_채팅방_신고_목록을_조회한다() { // when - final List actual = chatRoomReportRepository.findAllByOrderByIdAsc(); + final List actual = chatRoomReportRepository.findAll(); // then SoftAssertions.assertSoftly(softAssertions -> { diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/JpaQuestionReportRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/JpaQuestionReportRepositoryImplTest.java similarity index 94% rename from backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/JpaQuestionReportRepositoryTest.java rename to backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/JpaQuestionReportRepositoryImplTest.java index 7c85405e7..c26823861 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/JpaQuestionReportRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/JpaQuestionReportRepositoryImplTest.java @@ -3,7 +3,7 @@ import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; import com.ddang.ddang.report.domain.QuestionReport; -import com.ddang.ddang.report.infrastructure.persistence.fixture.JpaQuestionReportRepositoryFixture; +import com.ddang.ddang.report.infrastructure.persistence.fixture.JpaQuestionReportRepositoryImplFixture; import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; @@ -20,7 +20,7 @@ @Import({JpaConfiguration.class, QuerydslConfiguration.class}) @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @SuppressWarnings("NonAsciiCharacters") -class JpaQuestionReportRepositoryTest extends JpaQuestionReportRepositoryFixture { +class JpaQuestionReportRepositoryImplTest extends JpaQuestionReportRepositoryImplFixture { @Autowired JpaQuestionReportRepository questionReportRepository; @@ -58,7 +58,7 @@ class JpaQuestionReportRepositoryTest extends JpaQuestionReportRepositoryFixture @Test void 신고된_질문_목록을_조회한다() { // when - final List actual = questionReportRepository.findAllByOrderByIdAsc(); + final List actual = questionReportRepository.findAll(); // then SoftAssertions.assertSoftly(softAssertions -> { diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/QuestionReportRepositoryImplImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/QuestionReportRepositoryImplImplTest.java new file mode 100644 index 000000000..92697fa61 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/QuestionReportRepositoryImplImplTest.java @@ -0,0 +1,78 @@ +package com.ddang.ddang.report.infrastructure.persistence; + +import com.ddang.ddang.configuration.JpaConfiguration; +import com.ddang.ddang.configuration.QuerydslConfiguration; +import com.ddang.ddang.report.domain.QuestionReport; +import com.ddang.ddang.report.domain.repository.QuestionReportRepository; +import com.ddang.ddang.report.infrastructure.persistence.fixture.QuestionReportRepositoryImplFixture; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@Import({JpaConfiguration.class, QuerydslConfiguration.class}) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class QuestionReportRepositoryImplTest extends QuestionReportRepositoryImplFixture { + + QuestionReportRepository questionReportRepository; + + @BeforeEach + void setUp(@Autowired final JpaQuestionReportRepository jpaQuestionReportRepository) { + questionReportRepository = new QuestionReportRepositoryImpl(jpaQuestionReportRepository); + } + + @Test + void 질문_신고를_등록한다() { + // given + final QuestionReport questionReport = new QuestionReport(신고자, 질문, 신고_내용); + + // when + final QuestionReport actual = questionReportRepository.save(questionReport); + + // then + assertThat(actual.getId()).isPositive(); + } + + @Test + void 신고한_질문이라면_참을_반환한다() { + // when + final boolean actual = questionReportRepository.existsByQuestionIdAndReporterId(이미_신고한_질문.getId(), 신고자.getId()); + + // then + assertThat(actual).isTrue(); + } + + @Test + void 신고_전인_질문이라면_거짓을_반환한다() { + // when + final boolean actual = questionReportRepository.existsByQuestionIdAndReporterId(질문.getId(), 신고자.getId()); + + // then + assertThat(actual).isFalse(); + } + + @Test + void 신고된_질문_목록을_조회한다() { + // when + final List actual = questionReportRepository.findAll(); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).hasSize(4); + softAssertions.assertThat(actual.get(0)).isEqualTo(질문_신고1); + softAssertions.assertThat(actual.get(1)).isEqualTo(질문_신고2); + softAssertions.assertThat(actual.get(2)).isEqualTo(질문_신고3); + softAssertions.assertThat(actual.get(3)).isEqualTo(질문_신고4); + }); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/AnswerReportRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/AnswerReportRepositoryImplFixture.java new file mode 100644 index 000000000..786a8a97e --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/AnswerReportRepositoryImplFixture.java @@ -0,0 +1,156 @@ +package com.ddang.ddang.report.infrastructure.persistence.fixture; + +import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.domain.BidUnit; +import com.ddang.ddang.auction.domain.Price; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.AuctionRepositoryImpl; +import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.category.domain.Category; +import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; +import com.ddang.ddang.image.domain.AuctionImage; +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.qna.domain.Answer; +import com.ddang.ddang.qna.domain.Question; +import com.ddang.ddang.qna.infrastructure.JpaAnswerRepository; +import com.ddang.ddang.qna.infrastructure.JpaQuestionRepository; +import com.ddang.ddang.report.domain.AnswerReport; +import com.ddang.ddang.report.domain.repository.AnswerReportRepository; +import com.ddang.ddang.report.infrastructure.persistence.AnswerReportRepositoryImpl; +import com.ddang.ddang.report.infrastructure.persistence.JpaAnswerReportRepository; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.repository.UserRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.infrastructure.persistence.UserRepositoryImpl; +import com.querydsl.jpa.impl.JPAQueryFactory; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +import java.time.LocalDateTime; +import java.util.List; + +@SuppressWarnings("NonAsciiCharacters") +public class AnswerReportRepositoryImplFixture { + + @Autowired + private JpaCategoryRepository categoryRepository; + + @Autowired + private JpaQuestionRepository questionRepository; + + @Autowired + private JpaAnswerRepository answerRepository; + + private UserRepository userRepository; + + private AuctionRepository auctionRepository; + + private AnswerReportRepository answerReportRepository; + + protected User 신고자; + protected Answer 답변; + protected String 신고_내용 = "신고합니다."; + protected Answer 이미_신고된_답변; + protected AnswerReport 답변_신고1; + protected AnswerReport 답변_신고2; + protected AnswerReport 답변_신고3; + protected AnswerReport 답변_신고4; + + @BeforeEach + void setUpFixture( + @Autowired final JpaUserRepository jpaUserRepository, + @Autowired final JpaAuctionRepository jpaAuctionRepository, + @Autowired final JPAQueryFactory queryFactory, + @Autowired final JpaAnswerReportRepository jpaAnswerReportRepository + ) { + userRepository = new UserRepositoryImpl(jpaUserRepository); + auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(queryFactory)); + answerReportRepository = new AnswerReportRepositoryImpl(jpaAnswerReportRepository); + + + final ProfileImage 프로필_이미지 = new ProfileImage("프로필.jpg", "프로필.jpg"); + final User 판매자 = User.builder() + .name("판매자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); + final User 질문자 = User.builder() + .name("질문자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12346") + .build(); + 신고자 = User.builder() + .name("신고자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12347") + .build(); + final User 신고자2 = User.builder() + .name("신고자2") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12348") + .build(); + final User 신고자3 = User.builder() + .name("신고자3") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12349") + .build(); + final User 신고자4 = User.builder() + .name("신고자4") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12350") + .build(); + + final Category 전자기기_카테고리 = new Category("전자기기"); + final Category 전자기기_서브_노트북_카테고리 = new Category("노트북 카테고리"); + 전자기기_카테고리.addSubCategory(전자기기_서브_노트북_카테고리); + final AuctionImage 경매_이미지 = new AuctionImage("경매이미지.jpg", "경매이미지.jpg"); + final Auction 경매 = Auction.builder() + .seller(판매자) + .title("경매 상품") + .description("이것은 경매 상품입니다.") + .subCategory(전자기기_서브_노트북_카테고리) + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(LocalDateTime.now()) + .build(); + 경매.addAuctionImages(List.of(경매_이미지)); + + final Question 질문1 = new Question(경매, 질문자, "질문드립니다."); + final Question 질문2 = new Question(경매, 질문자, "질문드립니다."); + 답변 = new Answer("답변드립니다."); + 이미_신고된_답변 = new Answer("답변드립니다."); + 질문1.addAnswer(답변); + 질문2.addAnswer(이미_신고된_답변); + + 답변_신고1 = new AnswerReport(신고자, 이미_신고된_답변, "신고합니다."); + 답변_신고2 = new AnswerReport(신고자2, 이미_신고된_답변, "신고합니다."); + 답변_신고3 = new AnswerReport(신고자3, 이미_신고된_답변, "신고합니다."); + 답변_신고4 = new AnswerReport(신고자4, 이미_신고된_답변, "신고합니다."); + + userRepository.save(판매자); + userRepository.save(질문자); + userRepository.save(신고자); + userRepository.save(신고자2); + userRepository.save(신고자3); + userRepository.save(신고자4); + + + categoryRepository.saveAll(List.of(전자기기_카테고리, 전자기기_서브_노트북_카테고리)); + auctionRepository.save(경매); + + questionRepository.saveAll(List.of(질문1, 질문2)); + answerRepository.saveAll(List.of(답변, 이미_신고된_답변)); + answerReportRepository.save(답변_신고1); + answerReportRepository.save(답변_신고2); + answerReportRepository.save(답변_신고3); + answerReportRepository.save(답변_신고4); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/AuctionReportRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/AuctionReportRepositoryImplFixture.java new file mode 100644 index 000000000..ff317c0a3 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/AuctionReportRepositoryImplFixture.java @@ -0,0 +1,130 @@ +package com.ddang.ddang.report.infrastructure.persistence.fixture; + +import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.domain.BidUnit; +import com.ddang.ddang.auction.domain.Price; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.AuctionRepositoryImpl; +import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.category.domain.Category; +import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; +import com.ddang.ddang.image.domain.AuctionImage; +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.image.infrastructure.persistence.JpaAuctionImageRepository; +import com.ddang.ddang.image.infrastructure.persistence.JpaProfileImageRepository; +import com.ddang.ddang.report.domain.AuctionReport; +import com.ddang.ddang.report.domain.repository.AuctionReportRepository; +import com.ddang.ddang.report.infrastructure.persistence.AuctionReportRepositoryImpl; +import com.ddang.ddang.report.infrastructure.persistence.JpaAuctionReportRepository; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.repository.UserRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.infrastructure.persistence.UserRepositoryImpl; +import com.querydsl.jpa.impl.JPAQueryFactory; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +import java.time.LocalDateTime; +import java.util.List; + +@SuppressWarnings("NonAsciiCharacters") +public class AuctionReportRepositoryImplFixture { + + @Autowired + private JpaCategoryRepository categoryRepository; + + @Autowired + private JpaProfileImageRepository profileImageRepository; + + @Autowired + private JpaAuctionImageRepository auctionImageRepository; + + private UserRepository userRepository; + + private AuctionRepository auctionRepository; + + private AuctionReportRepository auctionReportRepository; + + protected Long 존재하지_않는_경매_아이디 = -9999L; + protected Long 존재하지_않는_사용자_아이디 = -9999L; + protected User 판매자; + protected User 신고자1; + protected Auction 경매; + protected AuctionReport 경매_신고1; + protected AuctionReport 경매_신고2; + protected AuctionReport 경매_신고3; + + @BeforeEach + void setUpFixture( + @Autowired final JpaUserRepository jpaUserRepository, + @Autowired final JpaAuctionRepository jpaAuctionRepository, + @Autowired final JPAQueryFactory queryFactory, + @Autowired final JpaAuctionReportRepository jpaAuctionReportRepository + ) { + userRepository = new UserRepositoryImpl(jpaUserRepository); + auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(queryFactory)); + auctionReportRepository = new AuctionReportRepositoryImpl(jpaAuctionReportRepository); + + final ProfileImage 프로필_이미지 = new ProfileImage("프로필.jpg", "프로필.jpg"); + 판매자 = User.builder() + .name("판매자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); + 신고자1 = User.builder() + .name("신고자1") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12346") + .build(); + final User 신고자2 = User.builder() + .name("신고자2") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12347") + .build(); + final User 신고자3 = User.builder() + .name("신고자3") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12348") + .build(); + + final Category 전자기기_카테고리 = new Category("전자기기"); + final Category 전자기기_서브_노트북_카테고리 = new Category("노트북 카테고리"); + 전자기기_카테고리.addSubCategory(전자기기_서브_노트북_카테고리); + final AuctionImage 경매_이미지 = new AuctionImage("경매이미지.jpg", "경매이미지.jpg"); + 경매 = Auction.builder() + .seller(판매자) + .title("경매 상품") + .description("이것은 경매 상품입니다.") + .subCategory(전자기기_서브_노트북_카테고리) + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(LocalDateTime.now()) + .build(); + 경매.addAuctionImages(List.of(경매_이미지)); + + 경매_신고1 = new AuctionReport(신고자1, 경매, "신고합니다"); + 경매_신고2 = new AuctionReport(신고자2, 경매, "신고합니다"); + 경매_신고3 = new AuctionReport(신고자3, 경매, "신고합니다"); + + + profileImageRepository.save(프로필_이미지); + userRepository.save(판매자); + userRepository.save(신고자1); + userRepository.save(신고자2); + userRepository.save(신고자3); + + categoryRepository.saveAll(List.of(전자기기_카테고리, 전자기기_서브_노트북_카테고리)); + auctionImageRepository.save(경매_이미지); + auctionRepository.save(경매); + + auctionReportRepository.save(경매_신고1); + auctionReportRepository.save(경매_신고2); + auctionReportRepository.save(경매_신고3); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/ChatRoomReportRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/ChatRoomReportRepositoryImplFixture.java new file mode 100644 index 000000000..c86fcc029 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/ChatRoomReportRepositoryImplFixture.java @@ -0,0 +1,168 @@ +package com.ddang.ddang.report.infrastructure.persistence.fixture; + +import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.domain.BidUnit; +import com.ddang.ddang.auction.domain.Price; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.AuctionRepositoryImpl; +import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.category.domain.Category; +import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; +import com.ddang.ddang.chat.domain.ChatRoom; +import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; +import com.ddang.ddang.chat.infrastructure.persistence.ChatRoomRepositoryImpl; +import com.ddang.ddang.chat.infrastructure.persistence.JpaChatRoomRepository; +import com.ddang.ddang.image.domain.AuctionImage; +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.image.infrastructure.persistence.JpaAuctionImageRepository; +import com.ddang.ddang.image.infrastructure.persistence.JpaProfileImageRepository; +import com.ddang.ddang.report.domain.ChatRoomReport; +import com.ddang.ddang.report.domain.repository.ChatRoomReportRepository; +import com.ddang.ddang.report.infrastructure.persistence.ChatRoomReportRepositoryImpl; +import com.ddang.ddang.report.infrastructure.persistence.JpaChatRoomReportRepository; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.repository.UserRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.infrastructure.persistence.UserRepositoryImpl; +import com.querydsl.jpa.impl.JPAQueryFactory; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +import java.time.LocalDateTime; +import java.util.List; + +@SuppressWarnings("NonAsciiCharacters") +public class ChatRoomReportRepositoryImplFixture { + + @Autowired + private JpaCategoryRepository categoryRepository; + + @Autowired + private JpaProfileImageRepository profileImageRepository; + + @Autowired + private JpaAuctionImageRepository auctionImageRepository; + + private UserRepository userRepository; + + private AuctionRepository auctionRepository; + + private ChatRoomRepository chatRoomRepository; + + private ChatRoomReportRepository chatRoomReportRepository; + + protected Long 존재하지_않는_채팅방_아이디 = -9999L; + protected Long 존재하지_않는_사용자_아이디 = -9999L; + protected User 구매자1; + protected User 구매자1겸_신고자; + protected ChatRoom 채팅방1; + protected ChatRoomReport 채팅방_신고1; + protected ChatRoomReport 채팅방_신고2; + protected ChatRoomReport 채팅방_신고3; + + @BeforeEach + void setUpFixture( + @Autowired final JpaUserRepository jpaUserRepository, + @Autowired final JpaAuctionRepository jpaAuctionRepository, + @Autowired final JPAQueryFactory queryFactory, + @Autowired final JpaChatRoomRepository jpaChatRoomRepository, + @Autowired final JpaChatRoomReportRepository jpaChatRoomReportRepository + ) { + userRepository = new UserRepositoryImpl(jpaUserRepository); + auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(queryFactory)); + chatRoomRepository = new ChatRoomRepositoryImpl(jpaChatRoomRepository); + chatRoomReportRepository = new ChatRoomReportRepositoryImpl(jpaChatRoomReportRepository); + + final ProfileImage 프로필_이미지 = new ProfileImage("프로필.jpg", "프로필.jpg"); + final User 판매자 = User.builder() + .name("판매자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); + 구매자1 = User.builder() + .name("구매자1") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12346") + .build(); + final User 구매자2겸_신고자 = User.builder() + .name("구매자2") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12347") + .build(); + final User 구매자3겸_신고자 = User.builder() + .name("구매자3") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12348") + .build(); + 구매자1겸_신고자 = 구매자1; + + final Category 전자기기_카테고리 = new Category("전자기기"); + final Category 전자기기_서브_노트북_카테고리 = new Category("노트북 카테고리"); + 전자기기_카테고리.addSubCategory(전자기기_서브_노트북_카테고리); + final AuctionImage 경매_이미지 = new AuctionImage("경매이미지.jpg", "경매이미지.jpg"); + final Auction 경매1 = Auction.builder() + .seller(판매자) + .title("경매 상품") + .description("이것은 경매 상품입니다.") + .subCategory(전자기기_서브_노트북_카테고리) + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(LocalDateTime.now()) + .build(); + 경매1.addAuctionImages(List.of(경매_이미지)); + final Auction 경매2 = Auction.builder() + .seller(판매자) + .title("경매 상품") + .description("이것은 경매 상품입니다.") + .subCategory(전자기기_서브_노트북_카테고리) + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(LocalDateTime.now()) + .build(); + 경매2.addAuctionImages(List.of(경매_이미지)); + final Auction 경매3 = Auction.builder() + .seller(판매자) + .title("경매 상품") + .description("이것은 경매 상품입니다.") + .subCategory(전자기기_서브_노트북_카테고리) + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(LocalDateTime.now()) + .build(); + 경매3.addAuctionImages(List.of(경매_이미지)); + + 채팅방1 = new ChatRoom(경매1, 구매자1); + final ChatRoom 채팅방2 = new ChatRoom(경매2, 구매자2겸_신고자); + final ChatRoom 채팅방3 = new ChatRoom(경매3, 구매자3겸_신고자); + + 채팅방_신고1 = new ChatRoomReport(구매자1겸_신고자, 채팅방1, "신고합니다."); + 채팅방_신고2 = new ChatRoomReport(구매자2겸_신고자, 채팅방2, "신고합니다."); + 채팅방_신고3 = new ChatRoomReport(구매자3겸_신고자, 채팅방3, "신고합니다."); + + profileImageRepository.save(프로필_이미지); + userRepository.save(판매자); + userRepository.save(구매자1); + userRepository.save(구매자2겸_신고자); + userRepository.save(구매자3겸_신고자); + + categoryRepository.saveAll(List.of(전자기기_카테고리, 전자기기_서브_노트북_카테고리)); + auctionImageRepository.save(경매_이미지); + auctionRepository.save(경매1); + auctionRepository.save(경매2); + auctionRepository.save(경매3); + + chatRoomRepository.save(채팅방1); + chatRoomRepository.save(채팅방2); + chatRoomRepository.save(채팅방3); + + chatRoomReportRepository.save(채팅방_신고1); + chatRoomReportRepository.save(채팅방_신고2); + chatRoomReportRepository.save(채팅방_신고3); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/JpaQuestionReportRepositoryFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/JpaQuestionReportRepositoryImplFixture.java similarity index 75% rename from backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/JpaQuestionReportRepositoryFixture.java rename to backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/JpaQuestionReportRepositoryImplFixture.java index cae501164..1c975e1d0 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/JpaQuestionReportRepositoryFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/JpaQuestionReportRepositoryImplFixture.java @@ -3,7 +3,10 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.AuctionRepositoryImpl; import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; import com.ddang.ddang.category.domain.Category; import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; import com.ddang.ddang.image.domain.AuctionImage; @@ -11,10 +14,15 @@ import com.ddang.ddang.qna.domain.Question; import com.ddang.ddang.qna.infrastructure.JpaQuestionRepository; import com.ddang.ddang.report.domain.QuestionReport; +import com.ddang.ddang.report.domain.repository.QuestionReportRepository; import com.ddang.ddang.report.infrastructure.persistence.JpaQuestionReportRepository; +import com.ddang.ddang.report.infrastructure.persistence.QuestionReportRepositoryImpl; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.repository.UserRepository; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.infrastructure.persistence.UserRepositoryImpl; +import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; import org.junit.jupiter.api.BeforeEach; @@ -24,25 +32,22 @@ import java.util.List; @SuppressWarnings("NonAsciiCharacters") -public class JpaQuestionReportRepositoryFixture { +public class JpaQuestionReportRepositoryImplFixture { @PersistenceContext private EntityManager em; - @Autowired - private JpaUserRepository userRepository; + private UserRepository userRepository; @Autowired private JpaCategoryRepository categoryRepository; - @Autowired - private JpaAuctionRepository auctionRepository; + private AuctionRepository auctionRepository; @Autowired private JpaQuestionRepository questionRepository; - @Autowired - private JpaQuestionReportRepository questionReportRepository; + private QuestionReportRepository questionReportRepository; protected User 신고자; protected Question 질문; @@ -54,7 +59,16 @@ public class JpaQuestionReportRepositoryFixture { protected QuestionReport 질문_신고4; @BeforeEach - void setUp() { + void setUpFixture( + @Autowired final JpaUserRepository jpaUserRepository, + @Autowired final JpaAuctionRepository jpaAuctionRepository, + @Autowired final JPAQueryFactory queryFactory, + @Autowired final JpaQuestionReportRepository jpaQuestionReportRepository + ) { + userRepository = new UserRepositoryImpl(jpaUserRepository); + auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(queryFactory)); + questionReportRepository = new QuestionReportRepositoryImpl(jpaQuestionReportRepository); + final ProfileImage 프로필_이미지 = new ProfileImage("프로필.jpg", "프로필.jpg"); final User 판매자 = User.builder() .name("판매자") @@ -116,13 +130,21 @@ void setUp() { 질문_신고3 = new QuestionReport(신고자3, 이미_신고한_질문, "신고합니다"); 질문_신고4 = new QuestionReport(신고자4, 이미_신고한_질문, "신고합니다"); - userRepository.saveAll(List.of(판매자, 질문자, 신고자, 신고자2, 신고자3, 신고자4)); + userRepository.save(판매자); + userRepository.save(질문자); + userRepository.save(신고자); + userRepository.save(신고자2); + userRepository.save(신고자3); + userRepository.save(신고자4); categoryRepository.saveAll(List.of(전자기기_카테고리, 전자기기_서브_노트북_카테고리)); auctionRepository.save(경매); questionRepository.saveAll(List.of(질문, 이미_신고한_질문)); - questionReportRepository.saveAll(List.of(질문_신고1, 질문_신고2, 질문_신고3, 질문_신고4)); + questionReportRepository.save(질문_신고1); + questionReportRepository.save(질문_신고2); + questionReportRepository.save(질문_신고3); + questionReportRepository.save(질문_신고4); em.flush(); em.clear(); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/QuestionReportRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/QuestionReportRepositoryImplFixture.java new file mode 100644 index 000000000..1e820ddcc --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/QuestionReportRepositoryImplFixture.java @@ -0,0 +1,144 @@ +package com.ddang.ddang.report.infrastructure.persistence.fixture; + +import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.domain.BidUnit; +import com.ddang.ddang.auction.domain.Price; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.AuctionRepositoryImpl; +import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.category.domain.Category; +import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; +import com.ddang.ddang.image.domain.AuctionImage; +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.qna.domain.Question; +import com.ddang.ddang.qna.infrastructure.JpaQuestionRepository; +import com.ddang.ddang.report.domain.QuestionReport; +import com.ddang.ddang.report.domain.repository.QuestionReportRepository; +import com.ddang.ddang.report.infrastructure.persistence.JpaQuestionReportRepository; +import com.ddang.ddang.report.infrastructure.persistence.QuestionReportRepositoryImpl; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.repository.UserRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.infrastructure.persistence.UserRepositoryImpl; +import com.querydsl.jpa.impl.JPAQueryFactory; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +import java.time.LocalDateTime; +import java.util.List; + +@SuppressWarnings("NonAsciiCharacters") +public class QuestionReportRepositoryImplFixture { + + @Autowired + private JpaCategoryRepository categoryRepository; + + @Autowired + private JpaQuestionRepository questionRepository; + + private UserRepository userRepository; + + private AuctionRepository auctionRepository; + + private QuestionReportRepository questionReportRepository; + + protected User 신고자; + protected Question 질문; + protected Question 이미_신고한_질문; + protected String 신고_내용 = "신고합니다."; + protected QuestionReport 질문_신고1; + protected QuestionReport 질문_신고2; + protected QuestionReport 질문_신고3; + protected QuestionReport 질문_신고4; + + @BeforeEach + void setUpFixture( + @Autowired final JpaUserRepository jpaUserRepository, + @Autowired final JpaAuctionRepository jpaAuctionRepository, + @Autowired final JPAQueryFactory queryFactory, + @Autowired final JpaQuestionReportRepository jpaQuestionReportRepository + ) { + userRepository = new UserRepositoryImpl(jpaUserRepository); + auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(queryFactory)); + questionReportRepository = new QuestionReportRepositoryImpl(jpaQuestionReportRepository); + + final ProfileImage 프로필_이미지 = new ProfileImage("프로필.jpg", "프로필.jpg"); + final User 판매자 = User.builder() + .name("판매자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); + final User 질문자 = User.builder() + .name("질문자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12346") + .build(); + 신고자 = User.builder() + .name("신고자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12347") + .build(); + final User 신고자2 = User.builder() + .name("신고자2") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12348") + .build(); + final User 신고자3 = User.builder() + .name("신고자3") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12349") + .build(); + final User 신고자4 = User.builder() + .name("신고자4") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12350") + .build(); + + final Category 전자기기_카테고리 = new Category("전자기기"); + final Category 전자기기_서브_노트북_카테고리 = new Category("노트북 카테고리"); + 전자기기_카테고리.addSubCategory(전자기기_서브_노트북_카테고리); + final AuctionImage 경매_이미지 = new AuctionImage("경매이미지.jpg", "경매이미지.jpg"); + final Auction 경매 = Auction.builder() + .seller(판매자) + .title("경매 상품") + .description("이것은 경매 상품입니다.") + .subCategory(전자기기_서브_노트북_카테고리) + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(LocalDateTime.now()) + .build(); + 경매.addAuctionImages(List.of(경매_이미지)); + + 질문 = new Question(경매, 질문자, "질문드립니다."); + 이미_신고한_질문 = new Question(경매, 질문자, "질문드립니다."); + + 질문_신고1 = new QuestionReport(신고자, 이미_신고한_질문, "신고합니다"); + 질문_신고2 = new QuestionReport(신고자2, 이미_신고한_질문, "신고합니다"); + 질문_신고3 = new QuestionReport(신고자3, 이미_신고한_질문, "신고합니다"); + 질문_신고4 = new QuestionReport(신고자4, 이미_신고한_질문, "신고합니다"); + + userRepository.save(판매자); + userRepository.save(질문자); + userRepository.save(신고자); + userRepository.save(신고자2); + userRepository.save(신고자3); + userRepository.save(신고자4); + + categoryRepository.saveAll(List.of(전자기기_카테고리, 전자기기_서브_노트북_카테고리)); + auctionRepository.save(경매); + + questionRepository.saveAll(List.of(질문, 이미_신고한_질문)); + questionReportRepository.save(질문_신고1); + questionReportRepository.save(질문_신고2); + questionReportRepository.save(질문_신고3); + questionReportRepository.save(질문_신고4); + } +} From 6351bee17c8675f2b6486d1cc7ace958aaed0b93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=9C=EC=9D=B4=EB=AF=B8?= <63184334+JJ503@users.noreply.github.com> Date: Sun, 15 Oct 2023 16:02:50 +0900 Subject: [PATCH 26/37] =?UTF-8?q?refactor:=20#673=20Q&A=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=9D=B8=ED=94=84=EB=9D=BC=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81=20(#686)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 도메인 영역에 질문 repository 추가 * refactor: EntityGraph를 jpql로 변경 * refactor: 사용하지 않는 클래스 제거 * refactor: 잘못된 쿼리문 수정 * feat: 도메인 영역에 질문 repository 구현체 추가 * refactor: service에서 도메인 영역의 질문 repository를 사용하도록 변경 * test: 테스트에서 도메인 영역의 질문 repository를 사용하도록 변경 * refactor: 사용하지 않는 메서드 제거 * refactor: 쿼리문 명령는 대문자로 수정 * feat: 도메인 영역에 답변 repository 추가 * feat: 도메인 영역에 답변 repository 구현체 추가 * test: 테스트에서 도메인 영역의 답변 repository를 사용하도록 변경 * test: 테스트 실패 문제 해결 * fix: 잘못된 쿼리 조건 수정 * test: 불필요한 로직 제거 * refactor: final 누락 추가 --- .../ddang/qna/application/AnswerService.java | 10 +- .../qna/application/QuestionService.java | 6 +- .../qna/application/dto/QuestionDto.java | 20 --- .../domain/repository/AnswerRepository.java | 14 +++ .../domain/repository/QuestionRepository.java | 15 +++ .../infrastructure/AnswerRepositoryImpl.java | 30 +++++ .../infrastructure/JpaAnswerRepository.java | 11 +- .../infrastructure/JpaQuestionRepository.java | 12 +- .../QuestionRepositoryImpl.java | 31 +++++ .../application/AnswerReportService.java | 6 +- .../application/QuestionReportService.java | 6 +- .../fixture/AnswerServiceFixture.java | 12 +- .../fixture/QuestionServiceFixture.java | 16 +-- .../AnswerRepositoryImplTest.java | 81 ++++++++++++ .../QuestionRepositoryImplTest.java | 81 ++++++++++++ .../fixture/AnswerRepositoryImplFixture.java | 102 +++++++++++++++ .../QuestionRepositoryImplFixture.java | 117 ++++++++++++++++++ .../fixture/AnswerReportServiceFixture.java | 8 +- .../fixture/QuestionReportServiceFixture.java | 4 +- 19 files changed, 525 insertions(+), 57 deletions(-) delete mode 100644 backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/QuestionDto.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/qna/domain/repository/AnswerRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/qna/domain/repository/QuestionRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/qna/infrastructure/AnswerRepositoryImpl.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/qna/infrastructure/QuestionRepositoryImpl.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/AnswerRepositoryImplTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/QuestionRepositoryImplTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/AnswerRepositoryImplFixture.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/QuestionRepositoryImplFixture.java diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/AnswerService.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/AnswerService.java index 2ef0967d4..17c39fdc9 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/AnswerService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/AnswerService.java @@ -9,8 +9,8 @@ import com.ddang.ddang.qna.application.exception.QuestionNotFoundException; import com.ddang.ddang.qna.domain.Answer; import com.ddang.ddang.qna.domain.Question; -import com.ddang.ddang.qna.infrastructure.JpaAnswerRepository; -import com.ddang.ddang.qna.infrastructure.JpaQuestionRepository; +import com.ddang.ddang.qna.domain.repository.AnswerRepository; +import com.ddang.ddang.qna.domain.repository.QuestionRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -26,8 +26,8 @@ public class AnswerService { private final ApplicationEventPublisher answerEventPublisher; private final UserRepository userRepository; - private final JpaQuestionRepository questionRepository; - private final JpaAnswerRepository answerRepository; + private final QuestionRepository questionRepository; + private final AnswerRepository answerRepository; @Transactional public Long create(final CreateAnswerDto answerDto, final String absoluteImageUrl) { @@ -65,7 +65,7 @@ private void checkAlreadyAnswered(final Question question) { @Transactional public void deleteById(final Long answerId, final Long userId) { - final Answer answer = answerRepository.findByIdAndDeletedIsFalse(answerId) + final Answer answer = answerRepository.findById(answerId) .orElseThrow(() -> new AnswerNotFoundException("해당 답변을 찾을 수 없습니다.")); final User user = userRepository.findById(userId) .orElseThrow(() -> new UserNotFoundException("해당 사용자를 찾을 수 없습니다.")); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java index 49a758758..1fb03bbf3 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/QuestionService.java @@ -11,11 +11,11 @@ import com.ddang.ddang.qna.application.exception.InvalidQuestionerException; import com.ddang.ddang.qna.application.exception.QuestionNotFoundException; import com.ddang.ddang.qna.domain.Question; -import com.ddang.ddang.qna.infrastructure.JpaQuestionRepository; +import com.ddang.ddang.qna.domain.repository.QuestionRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; -import lombok.RequiredArgsConstructor; import com.ddang.ddang.user.domain.repository.UserRepository; +import lombok.RequiredArgsConstructor; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -31,7 +31,7 @@ public class QuestionService { private final ApplicationEventPublisher questionEventPublisher; private final AuctionRepository auctionRepository; private final UserRepository userRepository; - private final JpaQuestionRepository questionRepository; + private final QuestionRepository questionRepository; @Transactional public Long create(final CreateQuestionDto questionDto, final String absoluteImageUrl) { diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/QuestionDto.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/QuestionDto.java deleted file mode 100644 index 6e5eb7224..000000000 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/QuestionDto.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.ddang.ddang.qna.application.dto; - -import com.ddang.ddang.auction.domain.Auction; -import com.ddang.ddang.qna.domain.Answer; -import com.ddang.ddang.qna.domain.Question; -import com.ddang.ddang.user.domain.User; - -public record QuestionDto(Auction auction, User writer, String content, Answer answer, boolean deleted, String auctionImageAbsoluteUrl){ - - public static QuestionDto from(final Question question, String auctionImageAbsoluteUrl) { - return new QuestionDto( - question.getAuction(), - question.getWriter(), - question.getContent(), - question.getAnswer(), - question.isDeleted(), - auctionImageAbsoluteUrl - ); - } -} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/domain/repository/AnswerRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/domain/repository/AnswerRepository.java new file mode 100644 index 000000000..67adf0c12 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/domain/repository/AnswerRepository.java @@ -0,0 +1,14 @@ +package com.ddang.ddang.qna.domain.repository; + +import com.ddang.ddang.qna.domain.Answer; + +import java.util.Optional; + +public interface AnswerRepository { + + Answer save(final Answer answer); + + boolean existsByQuestionId(final Long questionId); + + Optional findById(final Long id); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/domain/repository/QuestionRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/domain/repository/QuestionRepository.java new file mode 100644 index 000000000..6da4f42bd --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/domain/repository/QuestionRepository.java @@ -0,0 +1,15 @@ +package com.ddang.ddang.qna.domain.repository; + +import com.ddang.ddang.qna.domain.Question; + +import java.util.List; +import java.util.Optional; + +public interface QuestionRepository { + + Question save(final Question question); + + Optional findById(final Long id); + + List findAllByAuctionId(final Long auctionId); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/infrastructure/AnswerRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/infrastructure/AnswerRepositoryImpl.java new file mode 100644 index 000000000..ed8069bfd --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/infrastructure/AnswerRepositoryImpl.java @@ -0,0 +1,30 @@ +package com.ddang.ddang.qna.infrastructure; + +import com.ddang.ddang.qna.domain.Answer; +import com.ddang.ddang.qna.domain.repository.AnswerRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +@RequiredArgsConstructor +public class AnswerRepositoryImpl implements AnswerRepository { + + private final JpaAnswerRepository jpaAnswerRepository; + + @Override + public Answer save(final Answer answer) { + return jpaAnswerRepository.save(answer); + } + + @Override + public boolean existsByQuestionId(final Long questionId) { + return jpaAnswerRepository.existsByQuestionId(questionId); + } + + @Override + public Optional findById(final Long id) { + return jpaAnswerRepository.findByIdAndDeletedIsFalse(id); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/infrastructure/JpaAnswerRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/infrastructure/JpaAnswerRepository.java index eea851954..ffd0167ca 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/infrastructure/JpaAnswerRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/infrastructure/JpaAnswerRepository.java @@ -1,8 +1,8 @@ package com.ddang.ddang.qna.infrastructure; import com.ddang.ddang.qna.domain.Answer; -import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import java.util.Optional; @@ -10,6 +10,13 @@ public interface JpaAnswerRepository extends JpaRepository { boolean existsByQuestionId(Long questionId); - @EntityGraph(attributePaths = {"question", "question.auction", "question.auction.seller"}) + @Query(""" + SELECT an + FROM Answer an + JOIN FETCH an.question q + JOIN FETCH q.auction a + JOIN FETCH a.seller + WHERE an.deleted = false AND an.id = :answerId + """) Optional findByIdAndDeletedIsFalse(final Long answerId); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/infrastructure/JpaQuestionRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/infrastructure/JpaQuestionRepository.java index 615e04d2b..11de78514 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/infrastructure/JpaQuestionRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/infrastructure/JpaQuestionRepository.java @@ -1,8 +1,8 @@ package com.ddang.ddang.qna.infrastructure; import com.ddang.ddang.qna.domain.Question; -import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import java.util.List; import java.util.Optional; @@ -11,6 +11,14 @@ public interface JpaQuestionRepository extends JpaRepository { Optional findByIdAndDeletedIsFalse(final Long id); - @EntityGraph(attributePaths = {"writer", "answer", "auction", "auction.seller"}) + @Query(""" + SELECT q + FROM Question q + JOIN FETCH q.writer + LEFT JOIN FETCH q.answer + JOIN FETCH q.auction a + JOIN FETCH a.seller + WHERE q.deleted = false AND a.id = :auctionId + """) List findAllByAuctionId(final Long auctionId); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/infrastructure/QuestionRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/infrastructure/QuestionRepositoryImpl.java new file mode 100644 index 000000000..fd107d99a --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/infrastructure/QuestionRepositoryImpl.java @@ -0,0 +1,31 @@ +package com.ddang.ddang.qna.infrastructure; + +import com.ddang.ddang.qna.domain.Question; +import com.ddang.ddang.qna.domain.repository.QuestionRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +@RequiredArgsConstructor +public class QuestionRepositoryImpl implements QuestionRepository { + + private final JpaQuestionRepository jpaQuestionRepository; + + @Override + public Question save(final Question question) { + return jpaQuestionRepository.save(question); + } + + @Override + public Optional findById(final Long id) { + return jpaQuestionRepository.findByIdAndDeletedIsFalse(id); + } + + @Override + public List findAllByAuctionId(final Long auctionId) { + return jpaQuestionRepository.findAllByAuctionId(auctionId); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/application/AnswerReportService.java b/backend/ddang/src/main/java/com/ddang/ddang/report/application/AnswerReportService.java index 77e48aa98..ed67037e7 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/report/application/AnswerReportService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/application/AnswerReportService.java @@ -2,7 +2,7 @@ import com.ddang.ddang.qna.application.exception.AnswerNotFoundException; import com.ddang.ddang.qna.domain.Answer; -import com.ddang.ddang.qna.infrastructure.JpaAnswerRepository; +import com.ddang.ddang.qna.domain.repository.AnswerRepository; import com.ddang.ddang.report.application.dto.CreateAnswerReportDto; import com.ddang.ddang.report.application.dto.ReadAnswerReportDto; import com.ddang.ddang.report.application.exception.InvalidAnswererReportException; @@ -22,13 +22,13 @@ @RequiredArgsConstructor public class AnswerReportService { - private final JpaAnswerRepository answerRepository; + private final AnswerRepository answerRepository; private final UserRepository userRepository; private final AnswerReportRepository answerReportRepository; @Transactional public Long create(final CreateAnswerReportDto answerReportDto) { - final Answer answer = answerRepository.findByIdAndDeletedIsFalse(answerReportDto.answerId()) + final Answer answer = answerRepository.findById(answerReportDto.answerId()) .orElseThrow(() -> new AnswerNotFoundException("해당 답변을 찾을 수 없습니다.") ); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/application/QuestionReportService.java b/backend/ddang/src/main/java/com/ddang/ddang/report/application/QuestionReportService.java index e9194ea4a..f47825c45 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/report/application/QuestionReportService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/application/QuestionReportService.java @@ -2,7 +2,7 @@ import com.ddang.ddang.qna.application.exception.QuestionNotFoundException; import com.ddang.ddang.qna.domain.Question; -import com.ddang.ddang.qna.infrastructure.JpaQuestionRepository; +import com.ddang.ddang.qna.domain.repository.QuestionRepository; import com.ddang.ddang.report.application.dto.CreateQuestionReportDto; import com.ddang.ddang.report.application.dto.ReadQuestionReportDto; import com.ddang.ddang.report.application.exception.InvalidQuestionReportException; @@ -22,13 +22,13 @@ @RequiredArgsConstructor public class QuestionReportService { - private final JpaQuestionRepository questionRepository; + private final QuestionRepository questionRepository; private final UserRepository userRepository; private final QuestionReportRepository questionReportRepository; @Transactional public Long create(final CreateQuestionReportDto questionReportDto) { - final Question question = questionRepository.findByIdAndDeletedIsFalse(questionReportDto.questionId()) + final Question question = questionRepository.findById(questionReportDto.questionId()) .orElseThrow(() -> new QuestionNotFoundException("해당 질문을 찾을 수 없습니다.") ); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/AnswerServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/AnswerServiceFixture.java index 0cb19e684..11ac6f45c 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/AnswerServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/AnswerServiceFixture.java @@ -8,8 +8,8 @@ import com.ddang.ddang.qna.application.dto.CreateAnswerDto; import com.ddang.ddang.qna.domain.Answer; import com.ddang.ddang.qna.domain.Question; -import com.ddang.ddang.qna.infrastructure.JpaAnswerRepository; -import com.ddang.ddang.qna.infrastructure.JpaQuestionRepository; +import com.ddang.ddang.qna.domain.repository.AnswerRepository; +import com.ddang.ddang.qna.domain.repository.QuestionRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -17,7 +17,6 @@ import org.springframework.beans.factory.annotation.Autowired; import java.time.LocalDateTime; -import java.util.List; @SuppressWarnings("NonAsciiCharacters") public class AnswerServiceFixture { @@ -29,10 +28,10 @@ public class AnswerServiceFixture { private UserRepository userRepository; @Autowired - private JpaQuestionRepository questionRepository; + private QuestionRepository questionRepository; @Autowired - private JpaAnswerRepository answerRepository; + private AnswerRepository answerRepository; protected Long 존재하지_않는_답변_아이디 = -999L; protected Long 존재하지_않는_사용자_아이디 = -999L; @@ -87,7 +86,8 @@ void setUp() { userRepository.save(판매자가_아닌_사용자); auctionRepository.save(경매); - questionRepository.saveAll(List.of(질문, 답변한_질문)); + questionRepository.save(질문); + questionRepository.save(답변한_질문); answerRepository.save(답변); 답변_등록_요청_dto = new CreateAnswerDto(질문.getId(), "답변 드립니다.", 판매자.getId()); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java index 63818f386..ac73432f8 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java @@ -13,8 +13,8 @@ import com.ddang.ddang.qna.application.dto.ReadUserInQnaDto; import com.ddang.ddang.qna.domain.Answer; import com.ddang.ddang.qna.domain.Question; -import com.ddang.ddang.qna.infrastructure.JpaAnswerRepository; -import com.ddang.ddang.qna.infrastructure.JpaQuestionRepository; +import com.ddang.ddang.qna.domain.repository.AnswerRepository; +import com.ddang.ddang.qna.domain.repository.QuestionRepository; import com.ddang.ddang.region.domain.Region; import com.ddang.ddang.region.domain.repository.RegionRepository; import com.ddang.ddang.user.domain.Reliability; @@ -24,7 +24,6 @@ import org.springframework.beans.factory.annotation.Autowired; import java.time.LocalDateTime; -import java.util.List; @SuppressWarnings("NonAsciiCharacters") public class QuestionServiceFixture { @@ -36,10 +35,10 @@ public class QuestionServiceFixture { private AuctionRepository auctionRepository; @Autowired - private JpaQuestionRepository questionRepository; + private QuestionRepository questionRepository; @Autowired - private JpaAnswerRepository answerRepository; + private AnswerRepository answerRepository; @Autowired private RegionRepository regionRepository; @@ -166,8 +165,11 @@ void setUp() { auctionRepository.save(질문과_답변이_존재하는_경매); auctionRepository.save(종료된_경매); auctionRepository.save(삭제된_경매); - questionRepository.saveAll(List.of(질문, 질문2, 질문3)); - answerRepository.saveAll(List.of(답변1, 답변2)); + questionRepository.save(질문); + questionRepository.save(질문2); + questionRepository.save(질문3); + answerRepository.save(답변1); + answerRepository.save(답변2); 질문_3개_답변_2개가_존재하는_경매_아이디 = 질문과_답변이_존재하는_경매.getId(); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/AnswerRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/AnswerRepositoryImplTest.java new file mode 100644 index 000000000..8d516216b --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/AnswerRepositoryImplTest.java @@ -0,0 +1,81 @@ +package com.ddang.ddang.qna.infrastructure; + +import com.ddang.ddang.configuration.JpaConfiguration; +import com.ddang.ddang.configuration.QuerydslConfiguration; +import com.ddang.ddang.qna.domain.Answer; +import com.ddang.ddang.qna.domain.repository.AnswerRepository; +import com.ddang.ddang.qna.infrastructure.fixture.AnswerRepositoryImplFixture; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@Import({JpaConfiguration.class, QuerydslConfiguration.class}) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class AnswerRepositoryImplTest extends AnswerRepositoryImplFixture { + + AnswerRepository answerRepository; + + @BeforeEach + void setUp(@Autowired final JpaAnswerRepository jpaAnswerRepository) { + answerRepository = new AnswerRepositoryImpl(jpaAnswerRepository); + } + + @Test + void 답변을_저장한다() { + // given + final Answer answer = new Answer(답변_내용); + 질문.addAnswer(answer); + + // when + final Answer actual = answerRepository.save(answer); + + // then + assertThat(actual.getId()).isPositive(); + } + + @Test + void 이미_질문에_대한_답변이_존재한다면_참을_반환한다() { + // when + final boolean actual = answerRepository.existsByQuestionId(답변이_존재하는_질문.getId()); + + // then + assertThat(actual).isTrue(); + } + + @Test + void 이미_질문에_대한_답변이_존재하지_않는다면_거짓을_반환한다() { + // when + final boolean actual = answerRepository.existsByQuestionId(답변이_존재하지_않는_질문.getId()); + + // then + assertThat(actual).isFalse(); + } + + @Test + void 삭제된_답변은_조회되지_않는다() { + // when + final Optional actual = answerRepository.findById(삭제된_답변.getId()); + + // then + assertThat(actual).isEmpty(); + } + + @Test + void 삭제되지_않은_답변은_조회된다() { + // when + final Optional actual = answerRepository.findById(답변.getId()); + + // then + assertThat(actual).contains(답변); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/QuestionRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/QuestionRepositoryImplTest.java new file mode 100644 index 000000000..f3522af97 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/QuestionRepositoryImplTest.java @@ -0,0 +1,81 @@ +package com.ddang.ddang.qna.infrastructure; + +import com.ddang.ddang.configuration.JpaConfiguration; +import com.ddang.ddang.configuration.QuerydslConfiguration; +import com.ddang.ddang.qna.domain.Question; +import com.ddang.ddang.qna.domain.repository.QuestionRepository; +import com.ddang.ddang.qna.infrastructure.fixture.QuestionRepositoryImplFixture; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@Import({JpaConfiguration.class, QuerydslConfiguration.class}) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +class QuestionRepositoryImplTest extends QuestionRepositoryImplFixture { + + QuestionRepository questionRepository; + + @BeforeEach + void setUp(@Autowired final JpaQuestionRepository jpaQuestionRepository) { + questionRepository = new QuestionRepositoryImpl(jpaQuestionRepository); + } + + @Test + void 질문을_저장한다() { + // given + final Question question = new Question(경매, 질문자, 질문_내용); + + // when + final Question actual = questionRepository.save(question); + + // then + assertThat(actual.getId()).isPositive(); + } + + @Test + void 삭제된_질문은_조회되지_않는다() { + // when + final Optional actual = questionRepository.findById(삭제된_질문.getId()); + + // then + assertThat(actual).isEmpty(); + } + + @Test + void 삭제되지_않은_질문은_조회된다() { + // when + final Optional actual = questionRepository.findById(질문1.getId()); + + // then + assertThat(actual).contains(질문1); + } + + @Test + void 경매_아이디를_통해_질문과_답변들을_모두_조회한다() { + // when + final List actual = questionRepository.findAllByAuctionId(질문이_3개_답변이_2개인_경매.getId()); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).hasSize(3); + softAssertions.assertThat(actual.get(0)).isEqualTo(질문1); + softAssertions.assertThat(actual.get(0).getAnswer()).isEqualTo(답변1); + softAssertions.assertThat(actual.get(1)).isEqualTo(질문2); + softAssertions.assertThat(actual.get(1).getAnswer()).isEqualTo(답변2); + softAssertions.assertThat(actual.get(2)).isEqualTo(질문3); + softAssertions.assertThat(actual.get(2).getAnswer()).isNull(); + }); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/AnswerRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/AnswerRepositoryImplFixture.java new file mode 100644 index 000000000..44cac6457 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/AnswerRepositoryImplFixture.java @@ -0,0 +1,102 @@ +package com.ddang.ddang.qna.infrastructure.fixture; + +import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.domain.BidUnit; +import com.ddang.ddang.auction.domain.Price; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.AuctionRepositoryImpl; +import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.qna.domain.Answer; +import com.ddang.ddang.qna.domain.Question; +import com.ddang.ddang.qna.domain.repository.AnswerRepository; +import com.ddang.ddang.qna.domain.repository.QuestionRepository; +import com.ddang.ddang.qna.infrastructure.AnswerRepositoryImpl; +import com.ddang.ddang.qna.infrastructure.JpaAnswerRepository; +import com.ddang.ddang.qna.infrastructure.JpaQuestionRepository; +import com.ddang.ddang.qna.infrastructure.QuestionRepositoryImpl; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.repository.UserRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.infrastructure.persistence.UserRepositoryImpl; +import com.querydsl.jpa.impl.JPAQueryFactory; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +import java.time.LocalDateTime; + +@SuppressWarnings("NonAsciiCharacters") +public class AnswerRepositoryImplFixture { + + private UserRepository userRepository; + + private AuctionRepository auctionRepository; + + private QuestionRepository questionRepository; + + private AnswerRepository answerRepository; + + protected Question 질문; + protected Question 답변이_존재하는_질문; + protected Question 답변이_존재하지_않는_질문; + protected String 답변_내용 = "답변드립니다."; + protected Answer 답변; + protected Answer 삭제된_답변; + + @BeforeEach + void setUpFixture( + @Autowired final JpaUserRepository jpaUserRepository, + @Autowired final JpaAuctionRepository jpaAuctionRepository, + @Autowired final JPAQueryFactory queryFactory, + @Autowired final JpaQuestionRepository jpaQuestionRepository, + @Autowired final JpaAnswerRepository jpaAnswerRepository + ) { + userRepository = new UserRepositoryImpl(jpaUserRepository); + auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(queryFactory)); + questionRepository = new QuestionRepositoryImpl(jpaQuestionRepository); + answerRepository = new AnswerRepositoryImpl(jpaAnswerRepository); + + final ProfileImage 프로필_이미지 = new ProfileImage("프로필.jpg", "프로필.jpg"); + final User 판매자 = User.builder() + .name("판매자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); + final Auction 경매 = Auction.builder() + .seller(판매자) + .title("경매 상품 1") + .description("이것은 경매 상품 1 입니다.") + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(LocalDateTime.now()) + .build(); + final User 질문자 = User.builder() + .name("질문자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12346") + .build(); + 질문 = new Question(경매, 질문자, "궁금한 점이 있어요."); + 답변이_존재하는_질문 = new Question(경매, 질문자, "궁금한 점이 있어요."); + 답변이_존재하지_않는_질문 = 질문; + final Question 답변이_삭제된_질문 = new Question(경매, 질문자, "궁금한 점이 있어요."); + + 답변 = new Answer("답변드립니다."); + 답변이_존재하는_질문.addAnswer(답변); + 삭제된_답변 = new Answer("답변드립니다."); + 답변이_삭제된_질문.addAnswer(삭제된_답변); + 삭제된_답변.delete(); + + userRepository.save(판매자); + userRepository.save(질문자); + auctionRepository.save(경매); + questionRepository.save(질문); + questionRepository.save(답변이_존재하는_질문); + questionRepository.save(답변이_삭제된_질문); + answerRepository.save(답변); + answerRepository.save(삭제된_답변); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/QuestionRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/QuestionRepositoryImplFixture.java new file mode 100644 index 000000000..f0bb5e568 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/QuestionRepositoryImplFixture.java @@ -0,0 +1,117 @@ +package com.ddang.ddang.qna.infrastructure.fixture; + +import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.domain.BidUnit; +import com.ddang.ddang.auction.domain.Price; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.AuctionRepositoryImpl; +import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.qna.domain.Answer; +import com.ddang.ddang.qna.domain.Question; +import com.ddang.ddang.qna.domain.repository.AnswerRepository; +import com.ddang.ddang.qna.domain.repository.QuestionRepository; +import com.ddang.ddang.qna.infrastructure.AnswerRepositoryImpl; +import com.ddang.ddang.qna.infrastructure.JpaAnswerRepository; +import com.ddang.ddang.qna.infrastructure.JpaQuestionRepository; +import com.ddang.ddang.qna.infrastructure.QuestionRepositoryImpl; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.repository.UserRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.infrastructure.persistence.UserRepositoryImpl; +import com.querydsl.jpa.impl.JPAQueryFactory; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +import java.time.LocalDateTime; + +@SuppressWarnings("NonAsciiCharacters") +public class QuestionRepositoryImplFixture { + + private AuctionRepository auctionRepository; + + private UserRepository userRepository; + + private QuestionRepository questionRepository; + + private AnswerRepository answerRepository; + + protected Auction 경매; + protected Auction 질문이_3개_답변이_2개인_경매; + protected User 질문자; + protected String 질문_내용 = "궁금한 점이 있어요."; + protected Question 질문1; + protected Question 질문2; + protected Question 질문3; + protected Question 삭제된_질문; + protected Answer 답변1; + protected Answer 답변2; + + @BeforeEach + void setUpFixture( + @Autowired final JpaAuctionRepository jpaAuctionRepository, + @Autowired final JPAQueryFactory queryFactory, + @Autowired final JpaUserRepository jpaUserRepository, + @Autowired final JpaQuestionRepository jpaQuestionRepository, + @Autowired final JpaAnswerRepository jpaAnswerRepository + ) { + auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(queryFactory)); + userRepository = new UserRepositoryImpl(jpaUserRepository); + questionRepository = new QuestionRepositoryImpl(jpaQuestionRepository); + answerRepository = new AnswerRepositoryImpl(jpaAnswerRepository); + + final ProfileImage 프로필_이미지 = new ProfileImage("프로필.jpg", "프로필.jpg"); + final User 판매자 = User.builder() + .name("판매자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); + 경매 = Auction.builder() + .seller(판매자) + .title("경매 상품") + .description("이것은 경매 상품입니다.") + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(LocalDateTime.now()) + .build(); + 질문이_3개_답변이_2개인_경매 = Auction.builder() + .seller(판매자) + .title("경매 상품") + .description("이것은 경매 상품입니다.") + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(LocalDateTime.now()) + .build(); + 질문자 = User.builder() + .name("질문자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12346") + .build(); + + 질문1 = new Question(질문이_3개_답변이_2개인_경매, 질문자, "질문1"); + 질문2 = new Question(질문이_3개_답변이_2개인_경매, 질문자, "질문2"); + 질문3 = new Question(질문이_3개_답변이_2개인_경매, 질문자, "질문3"); + 답변1 = new Answer("답변1"); + 답변2 = new Answer("답변2"); + 질문1.addAnswer(답변1); + 질문2.addAnswer(답변2); + + 삭제된_질문 = new Question(경매, 질문자, "질문3"); + 삭제된_질문.delete(); + + userRepository.save(판매자); + userRepository.save(질문자); + auctionRepository.save(경매); + auctionRepository.save(질문이_3개_답변이_2개인_경매); + questionRepository.save(질문1); + questionRepository.save(질문2); + questionRepository.save(질문3); + questionRepository.save(삭제된_질문); + answerRepository.save(답변1); + answerRepository.save(답변2); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AnswerReportServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AnswerReportServiceFixture.java index dfdd32d84..dbb98a243 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AnswerReportServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AnswerReportServiceFixture.java @@ -10,8 +10,8 @@ import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.qna.domain.Answer; import com.ddang.ddang.qna.domain.Question; -import com.ddang.ddang.qna.infrastructure.JpaAnswerRepository; -import com.ddang.ddang.qna.infrastructure.JpaQuestionRepository; +import com.ddang.ddang.qna.domain.repository.AnswerRepository; +import com.ddang.ddang.qna.domain.repository.QuestionRepository; import com.ddang.ddang.report.application.dto.CreateAnswerReportDto; import com.ddang.ddang.report.domain.AnswerReport; import com.ddang.ddang.report.domain.repository.AnswerReportRepository; @@ -37,10 +37,10 @@ public class AnswerReportServiceFixture { private AuctionRepository auctionRepository; @Autowired - private JpaQuestionRepository questionRepository; + private QuestionRepository questionRepository; @Autowired - private JpaAnswerRepository answerRepository; + private AnswerRepository answerRepository; @Autowired private AnswerReportRepository answerReportRepository; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/QuestionReportServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/QuestionReportServiceFixture.java index 9e671032c..7e7bb9d8e 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/QuestionReportServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/QuestionReportServiceFixture.java @@ -9,7 +9,7 @@ import com.ddang.ddang.image.domain.AuctionImage; import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.qna.domain.Question; -import com.ddang.ddang.qna.infrastructure.JpaQuestionRepository; +import com.ddang.ddang.qna.domain.repository.QuestionRepository; import com.ddang.ddang.report.application.dto.CreateQuestionReportDto; import com.ddang.ddang.report.domain.QuestionReport; import com.ddang.ddang.report.domain.repository.QuestionReportRepository; @@ -35,7 +35,7 @@ public class QuestionReportServiceFixture { private AuctionRepository auctionRepository; @Autowired - private JpaQuestionRepository questionRepository; + private QuestionRepository questionRepository; @Autowired private QuestionReportRepository questionReportRepository; From d139814011e7cffdc5c1d78ba865042b12ebd77c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=9C=EC=9D=B4=EB=AF=B8?= <63184334+JJ503@users.noreply.github.com> Date: Sun, 15 Oct 2023 16:44:01 +0900 Subject: [PATCH 27/37] =?UTF-8?q?feat:=20#687=20=EB=8B=89=EB=84=A4?= =?UTF-8?q?=EC=9E=84=20=EC=88=98=EC=A0=95=20=EC=8B=9C=20=EC=A4=91=EB=B3=B5?= =?UTF-8?q?=20=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20(#688)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 이름 수정시 이미 존재하는 이름에 대한 예외처리 추가 * feat: 예외 처리 추가 --- .../exception/GlobalExceptionHandler.java | 9 ++++ .../ddang/user/application/UserService.java | 8 ++++ .../exception/AlreadyExistsNameException.java | 8 ++++ .../domain/repository/UserRepository.java | 2 + .../persistence/JpaUserRepository.java | 2 + .../persistence/UserRepositoryImpl.java | 5 +++ .../user/application/UserServiceTest.java | 9 ++++ .../fixture/UserServiceFixture.java | 12 ++++- .../persistence/JpaUserRepositoryTest.java | 22 ++++++++- .../persistence/UserRepositoryImplTest.java | 22 ++++++++- .../fixture/JpaUserRepositoryFixture.java | 6 ++- .../fixture/UserRepositoryImplFixture.java | 6 ++- .../user/presentation/UserControllerTest.java | 45 +++++++++++++++++-- .../fixture/UserControllerFixture.java | 1 + 14 files changed, 145 insertions(+), 12 deletions(-) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/user/application/exception/AlreadyExistsNameException.java diff --git a/backend/ddang/src/main/java/com/ddang/ddang/exception/GlobalExceptionHandler.java b/backend/ddang/src/main/java/com/ddang/ddang/exception/GlobalExceptionHandler.java index 9438d22e0..9cfdd446e 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/exception/GlobalExceptionHandler.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/exception/GlobalExceptionHandler.java @@ -38,6 +38,7 @@ import com.ddang.ddang.report.application.exception.InvalidReporterToAuctionException; import com.ddang.ddang.review.application.exception.AlreadyReviewException; import com.ddang.ddang.review.application.exception.ReviewNotFoundException; +import com.ddang.ddang.user.application.exception.AlreadyExistsNameException; import com.ddang.ddang.user.application.exception.UserNotFoundException; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -409,6 +410,14 @@ public ResponseEntity handleAlreadyAnsweredException(final Al .body(new ExceptionResponse(ex.getMessage())); } + @ExceptionHandler(AlreadyExistsNameException.class) + public ResponseEntity handleAlreadyExistsNameException(final AlreadyExistsNameException ex) { + logger.warn(String.format(LOG_MESSAGE_FORMAT, ex.getClass().getSimpleName(), ex.getMessage())); + + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ExceptionResponse(ex.getMessage())); + } + @Override protected ResponseEntity handleMethodArgumentNotValid( final MethodArgumentNotValidException ex, diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/application/UserService.java b/backend/ddang/src/main/java/com/ddang/ddang/user/application/UserService.java index be8daa106..c0cc24705 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/user/application/UserService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/application/UserService.java @@ -4,6 +4,7 @@ import com.ddang.ddang.image.domain.dto.StoreImageDto; import com.ddang.ddang.user.application.dto.ReadUserDto; import com.ddang.ddang.user.application.dto.UpdateUserDto; +import com.ddang.ddang.user.application.exception.AlreadyExistsNameException; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -42,7 +43,14 @@ private void updateUserByRequest(final UpdateUserDto userDto, final User user) { user.updateProfileImage(storeImageDto.toProfileImageEntity()); } if (userDto.name() != null) { + validateAvailableName(userDto.name()); user.updateName(userDto.name()); } } + + private void validateAvailableName(final String name) { + if (userRepository.existsByName(name)) { + throw new AlreadyExistsNameException("이미 존재하는 닉네임입니다."); + } + } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/application/exception/AlreadyExistsNameException.java b/backend/ddang/src/main/java/com/ddang/ddang/user/application/exception/AlreadyExistsNameException.java new file mode 100644 index 000000000..a5e0a9332 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/application/exception/AlreadyExistsNameException.java @@ -0,0 +1,8 @@ +package com.ddang.ddang.user.application.exception; + +public class AlreadyExistsNameException extends IllegalArgumentException { + + public AlreadyExistsNameException(final String message) { + super(message); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/repository/UserRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/repository/UserRepository.java index 6fac305ab..6f1b7fdfc 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/repository/UserRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/repository/UserRepository.java @@ -17,4 +17,6 @@ public interface UserRepository { boolean existsByIdAndDeletedIsTrue(final Long id); boolean existsByNameEndingWith(final String name); + + boolean existsByName(final String name); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepository.java index 1d0b949c7..a703d934b 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepository.java @@ -25,4 +25,6 @@ public interface JpaUserRepository extends JpaRepository { boolean existsByIdAndDeletedIsTrue(final Long id); boolean existsByNameEndingWith(final String name); + + boolean existsByName(final String name); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/UserRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/UserRepositoryImpl.java index 4b0dc0d85..5a5e3fac6 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/UserRepositoryImpl.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/infrastructure/persistence/UserRepositoryImpl.java @@ -42,4 +42,9 @@ public boolean existsByIdAndDeletedIsTrue(final Long id) { public boolean existsByNameEndingWith(final String name) { return jpaUserRepository.existsByNameEndingWith(name); } + + @Override + public boolean existsByName(final String name) { + return jpaUserRepository.existsByName(name); + } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/application/UserServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/user/application/UserServiceTest.java index 6db02f940..c68ffc576 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/application/UserServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/application/UserServiceTest.java @@ -3,6 +3,7 @@ import com.ddang.ddang.configuration.IsolateDatabase; import com.ddang.ddang.image.domain.StoreImageProcessor; import com.ddang.ddang.user.application.dto.ReadUserDto; +import com.ddang.ddang.user.application.exception.AlreadyExistsNameException; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.application.fixture.UserServiceFixture; import org.assertj.core.api.SoftAssertions; @@ -78,6 +79,14 @@ class UserServiceTest extends UserServiceFixture { }); } + @Test + void 사용자_정보_수정시_동일한_이름이_이미_존재한다_예외가_발생한다() { + // when & then + assertThatThrownBy(() -> userService.updateById(사용자.getId(), 이미_존재하는_사용자_이름으로_수정_요청_dto)) + .isInstanceOf(AlreadyExistsNameException.class) + .hasMessage("이미 존재하는 닉네임입니다."); + } + @Test void 사용자_정보를_수정시_이미지만_수정한다() { // given diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/application/fixture/UserServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/user/application/fixture/UserServiceFixture.java index 6df4ff59c..c62e5bb4d 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/application/fixture/UserServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/application/fixture/UserServiceFixture.java @@ -25,18 +25,27 @@ public class UserServiceFixture { protected StoreImageDto 새로운_프로필_이미지_dto; protected UpdateUserDto 사용자_정보_수정_요청_dto; protected UpdateUserDto 사용자_이름만_수정_요청_dto; + protected UpdateUserDto 이미_존재하는_사용자_이름으로_수정_요청_dto; protected UpdateUserDto 사용자_이미지만_수정_요청_dto; @BeforeEach void setUp() { 프로필_이미지 = new ProfileImage("upload.png", "store.png"); + final String 이미_존재하는_사용자_이름 = "중복되는 이름"; + final User 이미_저장된_사용자 = User.builder() + .name(이미_존재하는_사용자_이름) + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); 사용자 = User.builder() .name(사용자_이름) .profileImage(프로필_이미지) .reliability(new Reliability(4.7d)) - .oauthId("12345") + .oauthId("12346") .build(); + userRepository.save(이미_저장된_사용자); userRepository.save(사용자); final MockMultipartFile 새로운_이미지_파일 = new MockMultipartFile( @@ -49,6 +58,7 @@ void setUp() { 사용자_정보_수정_요청_dto = new UpdateUserDto("updateName", 새로운_이미지_파일); 사용자_이름만_수정_요청_dto = new UpdateUserDto("updateName", null); + 이미_존재하는_사용자_이름으로_수정_요청_dto = new UpdateUserDto(이미_존재하는_사용자_이름, null); 사용자_이미지만_수정_요청_dto = new UpdateUserDto(null, 새로운_이미지_파일); } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepositoryTest.java index cb3a10d56..d907a04fd 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/JpaUserRepositoryTest.java @@ -106,7 +106,7 @@ class JpaUserRepositoryTest extends JpaUserRepositoryFixture { } @Test - void 이름이_아직_없다면_거짓을_반환한다() { + void 마지막_이름이_동일한_이름이_아직_없다면_거짓을_반환한다() { // when final boolean actual = userRepository.existsByNameEndingWith(존재하지_않는_사용자_이름); @@ -114,12 +114,30 @@ class JpaUserRepositoryTest extends JpaUserRepositoryFixture { assertThat(actual).isFalse(); } + @Test + void 마지막_이름이_동일한_이름이_있다면_참을_반환한다() { + // when + final boolean actual = userRepository.existsByNameEndingWith(끝이_동일한_이름); + + // then + assertThat(actual).isTrue(); + } + @Test void 이름이_있다면_참을_반환한다() { // when - final boolean actual = userRepository.existsByNameEndingWith(존재하는_사용자_이름); + final boolean actual = userRepository.existsByName(존재하는_사용자_이름); // then assertThat(actual).isTrue(); } + + @Test + void 이름이_없다면_거짓을_반환한다() { + // when + final boolean actual = userRepository.existsByName(존재하지_않는_사용자_이름); + + // then + assertThat(actual).isFalse(); + } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/UserRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/UserRepositoryImplTest.java index a7fac4bb8..775126096 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/UserRepositoryImplTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/UserRepositoryImplTest.java @@ -112,7 +112,7 @@ void setUp(@Autowired final JpaUserRepository jpaUserRepository) { } @Test - void 이름이_아직_없다면_거짓을_반환한다() { + void 마지막_이름이_동일한_이름이_아직_없다면_거짓을_반환한다() { // when final boolean actual = userRepository.existsByNameEndingWith(존재하지_않는_사용자_이름); @@ -120,12 +120,30 @@ void setUp(@Autowired final JpaUserRepository jpaUserRepository) { assertThat(actual).isFalse(); } + @Test + void 마지막_이름이_동일한_이름이_있다면_참을_반환한다() { + // when + final boolean actual = userRepository.existsByNameEndingWith(끝이_동일한_이름); + + // then + assertThat(actual).isTrue(); + } + @Test void 이름이_있다면_참을_반환한다() { // when - final boolean actual = userRepository.existsByNameEndingWith(존재하는_사용자_이름); + final boolean actual = userRepository.existsByName(존재하는_사용자_이름); // then assertThat(actual).isTrue(); } + + @Test + void 이름이_없다면_거짓을_반환한다() { + // when + final boolean actual = userRepository.existsByName(존재하지_않는_사용자_이름); + + // then + assertThat(actual).isFalse(); + } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/JpaUserRepositoryFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/JpaUserRepositoryFixture.java index 437b21aef..c6c9be071 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/JpaUserRepositoryFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/JpaUserRepositoryFixture.java @@ -23,7 +23,8 @@ public class JpaUserRepositoryFixture { protected ProfileImage 프로필_이미지 = new ProfileImage("upload.png", "store.png"); protected String 존재하지_않는_oauth_아이디 = "invalidOauthId"; protected Long 존재하지_않는_사용자_아이디 = -999L; - protected String 존재하지_않는_사용자_이름 = "새로운 이름"; + protected String 존재하지_않는_사용자_이름 = "67890"; + protected String 끝이_동일한_이름; protected String 존재하는_사용자_이름; protected User 사용자; protected User 탈퇴한_사용자; @@ -32,7 +33,7 @@ public class JpaUserRepositoryFixture { void setUp() { final ProfileImage 사용자_프로필_이미지 = new ProfileImage("upload.png", "store.png"); 사용자 = User.builder() - .name("사용자") + .name("kakao12345") .profileImage(사용자_프로필_이미지) .reliability(new Reliability(4.7d)) .oauthId("12345") @@ -48,6 +49,7 @@ void setUp() { userRepository.saveAll(List.of(사용자, 탈퇴한_사용자)); + 끝이_동일한_이름 = "12345"; 존재하는_사용자_이름 = 사용자.getName(); em.flush(); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/UserRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/UserRepositoryImplFixture.java index bf9345fa1..0d6b25d93 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/UserRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/infrastructure/persistence/fixture/UserRepositoryImplFixture.java @@ -17,7 +17,8 @@ public class UserRepositoryImplFixture { protected ProfileImage 프로필_이미지 = new ProfileImage("upload.png", "store.png"); protected String 존재하지_않는_oauth_아이디 = "invalidOauthId"; protected Long 존재하지_않는_사용자_아이디 = -999L; - protected String 존재하지_않는_사용자_이름 = "새로운 이름"; + protected String 존재하지_않는_사용자_이름 = "67890"; + protected String 끝이_동일한_이름; protected String 존재하는_사용자_이름; protected User 사용자; protected User 탈퇴한_사용자; @@ -28,7 +29,7 @@ void fixtureSetUp(@Autowired final JpaUserRepository jpaUserRepository) { final ProfileImage 사용자_프로필_이미지 = new ProfileImage("upload.png", "store.png"); 사용자 = User.builder() - .name("사용자") + .name("kakao12345") .profileImage(사용자_프로필_이미지) .reliability(new Reliability(4.7d)) .oauthId("12345") @@ -45,6 +46,7 @@ void fixtureSetUp(@Autowired final JpaUserRepository jpaUserRepository) { userRepository.save(사용자); userRepository.save(탈퇴한_사용자); + 끝이_동일한_이름 = "12345"; 존재하는_사용자_이름 = 사용자.getName(); } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/presentation/UserControllerTest.java b/backend/ddang/src/test/java/com/ddang/ddang/user/presentation/UserControllerTest.java index 83ca223a7..12f0cdff7 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/presentation/UserControllerTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/presentation/UserControllerTest.java @@ -6,6 +6,7 @@ import com.ddang.ddang.authentication.domain.TokenType; import com.ddang.ddang.authentication.domain.dto.AuthenticationStore; import com.ddang.ddang.exception.GlobalExceptionHandler; +import com.ddang.ddang.user.application.exception.AlreadyExistsNameException; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.presentation.fixture.UserControllerFixture; import org.junit.jupiter.api.BeforeEach; @@ -108,6 +109,22 @@ void setUp() { ); } + @Test + void 존재하지_않는_사용자_정보_조회시_404를_반환한다() throws Exception { + // given + given(tokenDecoder.decode(eq(TokenType.ACCESS), anyString())).willReturn(Optional.of(존재하지_않는_사용자_ID_클레임)); + given(userService.readById(anyLong())).willThrow(new UserNotFoundException("사용자 정보를 사용할 수 없습니다.")); + + // when & then + mockMvc.perform(get("/users") + .header(HttpHeaders.AUTHORIZATION, 액세스_토큰_값) + ) + .andExpectAll( + status().isNotFound(), + jsonPath("$.message").exists() + ); + } + @Test void 사용자_정보를_모두_수정한다() throws Exception { // given @@ -174,13 +191,35 @@ void setUp() { } @Test - void 존재하지_않는_사용자_정보_조회시_404를_반환한다() throws Exception { + void 이미_존재하는_이름으로_수정할시_400_예외를_반환한다() throws Exception { // given given(tokenDecoder.decode(eq(TokenType.ACCESS), anyString())).willReturn(Optional.of(사용자_ID_클레임)); - given(userService.readById(anyLong())).willThrow(new UserNotFoundException("사용자 정보를 사용할 수 없습니다.")); + given(userService.updateById(anyLong(), any())).willThrow(new AlreadyExistsNameException("이미 존재하는 닉네임입니다.")); // when & then - mockMvc.perform(get("/users") + mockMvc.perform(multipart(HttpMethod.PATCH, "/users") + .file(수정할_이름) + .file(프로필_이미지가_없는_경우_파일) + .contentType(MediaType.MULTIPART_FORM_DATA_VALUE) + .header(HttpHeaders.AUTHORIZATION, 액세스_토큰_값) + ) + .andExpectAll( + status().isBadRequest(), + jsonPath("$.message").exists() + ); + } + + @Test + void 존재하지_않는_사용자_정보를_수정하면_404를_반환한다() throws Exception { + // given + given(tokenDecoder.decode(eq(TokenType.ACCESS), anyString())).willReturn(Optional.of(존재하지_않는_사용자_ID_클레임)); + given(userService.updateById(anyLong(), any())).willThrow(new UserNotFoundException("사용자 정보를 사용할 수 없습니다.")); + + // when & then + mockMvc.perform(multipart(HttpMethod.PATCH, "/users") + .file(수정할_이름) + .file(프로필_이미지가_없는_경우_파일) + .contentType(MediaType.MULTIPART_FORM_DATA_VALUE) .header(HttpHeaders.AUTHORIZATION, 액세스_토큰_값) ) .andExpectAll( diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/presentation/fixture/UserControllerFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/user/presentation/fixture/UserControllerFixture.java index 7d63d3ad5..fa46afbd5 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/presentation/fixture/UserControllerFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/presentation/fixture/UserControllerFixture.java @@ -14,6 +14,7 @@ public class UserControllerFixture extends CommonControllerSliceTest { protected String 액세스_토큰_값 = "Bearer accessToken"; protected PrivateClaims 사용자_ID_클레임 = new PrivateClaims(1L); + protected PrivateClaims 존재하지_않는_사용자_ID_클레임 = new PrivateClaims(999L); protected String 탈퇴한_사용자_이름 = "알 수 없음"; protected ReadUserDto 사용자_정보_조회_dto = new ReadUserDto(1L, "사용자1", 1L, 4.6d, "12345", false); From fa8e2967e914240ed153e74ad048d329e93334ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=8A=B9=EC=9B=90=20Merry?= Date: Sun, 15 Oct 2023 22:34:43 +0900 Subject: [PATCH 28/37] =?UTF-8?q?refactor:=20#689=20Message=20=EC=9D=B8?= =?UTF-8?q?=ED=94=84=EB=9D=BC=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81=20(#6?= =?UTF-8?q?94)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 도메인 영역에 메시지 레포지토리 추가 * refactor: 메서드명에서 레포지토리명과 중복되는 부분 제거 * fix: 불필요한 메서드 제거 * refactor: 도메인 메시지 레포지토의 구현체 추가 * refactor: 서비스에서 도메인 레포지토리 사용하도록 변경 * refactor: 클래스명 변경에 따른 테스트 네이밍 변경 * test: 도메인 메시지 레포지토리 구현체 테스트 추가 * refactor: 변수명 명확하게 변경 * refactor: 누락된 then절 추가 * test: 테스트에서 도메인 영역의 메시지 레포지토리 사용하도록 수정 * refactor: 테스트 픽스처에서 도메인 영역의 메시지 레포지토리를 사용하도록 변경 * refactor: 불필요한 주석 삭제 * refactor: 누락된 SuppressWarnings 어노테이션 추가 * refactor: 불필요한 import문 삭제 및 사용되지 않는 필드 지역변수로 변경 * style: 불필요한 개행 제거 --- .../chat/application/MessageService.java | 6 +- .../domain/repository/MessageRepository.java | 14 ++ .../persistence/JpaMessageRepository.java | 2 +- .../persistence/MessageRepositoryImpl.java | 35 ++++ .../QuerydslMessageRepository.java | 36 +++- .../QuerydslMessageRepositoryImpl.java | 43 ----- .../fixture/ChatRoomServiceFixture.java | 157 +++++++++--------- .../fixture/MessageServiceFixture.java | 4 +- .../ChatRoomRepositoryImplTest.java | 1 + .../MessageRepositoryImplTest.java | 75 +++++++++ ...ava => QuerydslMessageRepositoryTest.java} | 14 +- ...dMessageAndImageRepositoryImplFixture.java | 28 ++-- .../fixture/MessageRepositoryImplFixture.java | 128 ++++++++++++++ ... => QuerydslMessageRepositoryFixture.java} | 42 +++-- .../NotificationEventListenerTest.java | 6 +- .../FcmNotificationServiceFixture.java | 37 ++--- 16 files changed, 437 insertions(+), 191 deletions(-) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/MessageRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/MessageRepositoryImpl.java delete mode 100644 backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslMessageRepositoryImpl.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/MessageRepositoryImplTest.java rename backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/{QuerydslMessageRepositoryImplTest.java => QuerydslMessageRepositoryTest.java} (92%) create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/MessageRepositoryImplFixture.java rename backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/{QuerydslMessageRepositoryImplFixture.java => QuerydslMessageRepositoryFixture.java} (80%) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java index 72c9947e0..35493d0f5 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java @@ -9,7 +9,7 @@ import com.ddang.ddang.chat.domain.ChatRoom; import com.ddang.ddang.chat.domain.Message; import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; -import com.ddang.ddang.chat.infrastructure.persistence.JpaMessageRepository; +import com.ddang.ddang.chat.domain.repository.MessageRepository; import com.ddang.ddang.chat.presentation.dto.request.ReadMessageRequest; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; @@ -29,7 +29,7 @@ public class MessageService { private final ApplicationEventPublisher messageEventPublisher; - private final JpaMessageRepository messageRepository; + private final MessageRepository messageRepository; private final ChatRoomRepository chatRoomRepository; private final UserRepository userRepository; @@ -71,7 +71,7 @@ public List readAllByLastMessageId(final ReadMessageRequest requ validateLastMessageId(request.lastMessageId()); } - final List readMessages = messageRepository.findMessagesAllByLastMessageId( + final List readMessages = messageRepository.findAllByLastMessageId( request.messageReaderId(), chatRoom.getId(), request.lastMessageId() diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/MessageRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/MessageRepository.java new file mode 100644 index 000000000..9bcf77d43 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/repository/MessageRepository.java @@ -0,0 +1,14 @@ +package com.ddang.ddang.chat.domain.repository; + +import com.ddang.ddang.chat.domain.Message; + +import java.util.List; + +public interface MessageRepository { + + Message save(final Message message); + + boolean existsById(final Long lastMessageId); + + List findAllByLastMessageId(final Long messageReaderId, final Long chatRoomId, final Long lastMessageId); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaMessageRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaMessageRepository.java index ebd827adf..d28ed0cf6 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaMessageRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/JpaMessageRepository.java @@ -3,5 +3,5 @@ import com.ddang.ddang.chat.domain.Message; import org.springframework.data.jpa.repository.JpaRepository; -public interface JpaMessageRepository extends JpaRepository, QuerydslMessageRepository { +public interface JpaMessageRepository extends JpaRepository { } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/MessageRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/MessageRepositoryImpl.java new file mode 100644 index 000000000..758d8c9bd --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/MessageRepositoryImpl.java @@ -0,0 +1,35 @@ +package com.ddang.ddang.chat.infrastructure.persistence; + +import com.ddang.ddang.chat.domain.Message; +import com.ddang.ddang.chat.domain.repository.MessageRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +@RequiredArgsConstructor +public class MessageRepositoryImpl implements MessageRepository { + + private final JpaMessageRepository jpaMessageRepository; + private final QuerydslMessageRepository querydslMessageRepository; + + @Override + public Message save(final Message message) { + return jpaMessageRepository.save(message); + } + + @Override + public boolean existsById(final Long lastMessageId) { + return jpaMessageRepository.existsById(lastMessageId); + } + + @Override + public List findAllByLastMessageId( + final Long messageReaderId, + final Long chatRoomId, + final Long lastMessageId + ) { + return querydslMessageRepository.findAllByLastMessageId(messageReaderId, chatRoomId, lastMessageId); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslMessageRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslMessageRepository.java index ad979d450..3115e135b 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslMessageRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslMessageRepository.java @@ -1,13 +1,43 @@ package com.ddang.ddang.chat.infrastructure.persistence; import com.ddang.ddang.chat.domain.Message; +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; import java.util.List; -public interface QuerydslMessageRepository { +import static com.ddang.ddang.chat.domain.QMessage.message; - List findMessagesAllByLastMessageId( +@Repository +@RequiredArgsConstructor +public class QuerydslMessageRepository { + + private final JPAQueryFactory queryFactory; + + public List findAllByLastMessageId( final Long messageReaderId, final Long chatRoomId, - final Long lastMessageId); + final Long lastMessageId + ) { + return queryFactory + .selectFrom(message) + .where( + message.writer.id.eq(messageReaderId) + .or(message.receiver.id.eq(messageReaderId)), + message.chatRoom.id.eq(chatRoomId), + isGreaterThanLastId(lastMessageId) + ) + .orderBy(message.id.asc()) + .fetch(); + } + + private BooleanExpression isGreaterThanLastId(final Long lastMessageId) { + if (lastMessageId == null) { + return null; + } + + return message.id.gt(lastMessageId); + } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslMessageRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslMessageRepositoryImpl.java deleted file mode 100644 index 65b9cfd90..000000000 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslMessageRepositoryImpl.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.ddang.ddang.chat.infrastructure.persistence; - -import com.ddang.ddang.chat.domain.Message; -import com.querydsl.core.types.dsl.BooleanExpression; -import com.querydsl.jpa.impl.JPAQueryFactory; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Repository; - -import java.util.List; - -import static com.ddang.ddang.chat.domain.QMessage.message; - -@Repository -@RequiredArgsConstructor -public class QuerydslMessageRepositoryImpl implements QuerydslMessageRepository { - - private final JPAQueryFactory queryFactory; - - public List findMessagesAllByLastMessageId( - final Long messageReaderId, - final Long chatRoomId, - final Long lastMessageId - ) { - return queryFactory - .selectFrom(message) - .where( - message.writer.id.eq(messageReaderId) - .or(message.receiver.id.eq(messageReaderId)), - message.chatRoom.id.eq(chatRoomId), - isGreaterThanLastId(lastMessageId) - ) - .orderBy(message.id.asc()) - .fetch(); - } - - private BooleanExpression isGreaterThanLastId(final Long lastMessageId) { - if (lastMessageId == null) { - return null; - } - - return message.id.gt(lastMessageId); - } -} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java index 495216c72..234913411 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/ChatRoomServiceFixture.java @@ -21,7 +21,7 @@ import com.ddang.ddang.chat.domain.Message; import com.ddang.ddang.chat.domain.dto.ChatRoomAndImageDto; import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; -import com.ddang.ddang.chat.infrastructure.persistence.JpaMessageRepository; +import com.ddang.ddang.chat.domain.repository.MessageRepository; import com.ddang.ddang.image.domain.AuctionImage; import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.user.domain.Reliability; @@ -52,7 +52,7 @@ public class ChatRoomServiceFixture { private ChatRoomRepository chatRoomRepository; @Autowired - private JpaMessageRepository messageRepository; + private MessageRepository messageRepository; protected User 판매자; protected User 구매자; @@ -105,41 +105,41 @@ void setUp() { new AuctionImage("제이미의_대표 이미지가_아닌_경매_이미지.png", "제이미의_대표 이미지가_아닌_경매_이미지.png"); 판매자 = User.builder() - .name("판매자") - .profileImage(프로필_이미지) - .reliability(new Reliability(4.7d)) - .oauthId("12345") - .build(); + .name("판매자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); 구매자 = User.builder() - .name("구매자") - .profileImage(프로필_이미지) - .reliability(new Reliability(4.7d)) - .oauthId("12346") - .build(); - 엔초 = User.builder() - .name("엔초") + .name("구매자") .profileImage(프로필_이미지) .reliability(new Reliability(4.7d)) .oauthId("12346") .build(); + 엔초 = User.builder() + .name("엔초") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12346") + .build(); 제이미 = User.builder() - .name("제이미") - .profileImage(프로필_이미지) - .reliability(new Reliability(4.7d)) - .oauthId("12347") - .build(); - 지토 = User.builder() - .name("지토") + .name("제이미") .profileImage(프로필_이미지) .reliability(new Reliability(4.7d)) - .oauthId("12348") + .oauthId("12347") .build(); + 지토 = User.builder() + .name("지토") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12348") + .build(); 경매에_참여한_적_없는_사용자 = User.builder() - .name("외부인") - .profileImage(프로필_이미지) - .reliability(new Reliability(4.7d)) - .oauthId("12349") - .build(); + .name("외부인") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12349") + .build(); userRepository.save(판매자); userRepository.save(구매자); userRepository.save(엔초); @@ -148,50 +148,50 @@ void setUp() { userRepository.save(경매에_참여한_적_없는_사용자); 채팅방이_없는_경매 = Auction.builder() - .seller(판매자) - .title("맥북") - .description("맥북 팔아요") - .subCategory(전자기기_서브_노트북_카테고리) - .startPrice(new Price(10_000)) - .bidUnit(new BidUnit(1_000)) - .closingTime(LocalDateTime.now()) - .build(); + .seller(판매자) + .title("맥북") + .description("맥북 팔아요") + .subCategory(전자기기_서브_노트북_카테고리) + .startPrice(new Price(10_000)) + .bidUnit(new BidUnit(1_000)) + .closingTime(LocalDateTime.now()) + .build(); final Auction 종료되지_않은_경매 = Auction.builder() - .seller(판매자) - .title("맥북") - .description("맥북 팔아요") - .subCategory(전자기기_서브_노트북_카테고리) - .startPrice(new Price(10_000)) - .bidUnit(new BidUnit(1_000)) - .closingTime(LocalDateTime.now().plusDays(10L)) - .build(); + .seller(판매자) + .title("맥북") + .description("맥북 팔아요") + .subCategory(전자기기_서브_노트북_카테고리) + .startPrice(new Price(10_000)) + .bidUnit(new BidUnit(1_000)) + .closingTime(LocalDateTime.now().plusDays(10L)) + .build(); final Auction 낙찰자가_없는_경매 = Auction.builder() - .seller(판매자) - .title("맥북") - .description("맥북 팔아요") - .subCategory(전자기기_서브_노트북_카테고리) - .startPrice(new Price(10_000)) - .bidUnit(new BidUnit(1_000)) - .closingTime(LocalDateTime.now()) - .build(); + .seller(판매자) + .title("맥북") + .description("맥북 팔아요") + .subCategory(전자기기_서브_노트북_카테고리) + .startPrice(new Price(10_000)) + .bidUnit(new BidUnit(1_000)) + .closingTime(LocalDateTime.now()) + .build(); 판매자_엔초_구매자_지토_경매 = Auction.builder() - .seller(엔초) - .title("엔초 맥북") - .description("엔초 맥북 팔아요") - .subCategory(전자기기_서브_노트북_카테고리) - .startPrice(new Price(10_000)) - .bidUnit(new BidUnit(1_000)) - .closingTime(LocalDateTime.now()) - .build(); + .seller(엔초) + .title("엔초 맥북") + .description("엔초 맥북 팔아요") + .subCategory(전자기기_서브_노트북_카테고리) + .startPrice(new Price(10_000)) + .bidUnit(new BidUnit(1_000)) + .closingTime(LocalDateTime.now()) + .build(); final Auction 판매자_제이미_구매자_엔초_경매 = Auction.builder() - .seller(제이미) - .title("제이미 맥북") - .description("제이미 맥북 팔아요") - .subCategory(전자기기_서브_노트북_카테고리) - .startPrice(new Price(10_000)) - .bidUnit(new BidUnit(1_000)) - .closingTime(LocalDateTime.now()) - .build(); + .seller(제이미) + .title("제이미 맥북") + .description("제이미 맥북 팔아요") + .subCategory(전자기기_서브_노트북_카테고리) + .startPrice(new Price(10_000)) + .bidUnit(new BidUnit(1_000)) + .closingTime(LocalDateTime.now()) + .build(); 채팅방이_없는_경매.addAuctionImages(List.of(경매_대표_이미지, 대표_이미지가_아닌_경매_이미지)); 판매자_엔초_구매자_지토_경매.addAuctionImages(List.of(엔초의_경매_대표_이미지, 엔초의_대표_이미지가_아닌_경매_이미지)); 판매자_제이미_구매자_엔초_경매.addAuctionImages(List.of(제이미의_경매_대표_이미지, 제이미의_대표_이미지가_아닌_경매_이미지)); @@ -219,18 +219,19 @@ void setUp() { chatRoomRepository.save(제이미_엔초_채팅방); 엔초가_지토에게_1시에_보낸_쪽지 = Message.builder() - .chatRoom(엔초_지토_채팅방) - .contents("엔초가 지토에게 1시애 보낸 쪽지") - .writer(엔초) - .receiver(지토) - .build(); + .chatRoom(엔초_지토_채팅방) + .contents("엔초가 지토에게 1시애 보낸 쪽지") + .writer(엔초) + .receiver(지토) + .build(); 제이미가_엔초에게_2시에_보낸_쪽지 = Message.builder() - .chatRoom(제이미_엔초_채팅방) - .contents("제이미가 엔초에게 2시애 보낸 쪽지") - .writer(제이미) - .receiver(엔초) - .build(); - messageRepository.saveAll(List.of(엔초가_지토에게_1시에_보낸_쪽지, 제이미가_엔초에게_2시에_보낸_쪽지)); + .chatRoom(제이미_엔초_채팅방) + .contents("제이미가 엔초에게 2시애 보낸 쪽지") + .writer(제이미) + .receiver(엔초) + .build(); + messageRepository.save(엔초가_지토에게_1시에_보낸_쪽지); + messageRepository.save(제이미가_엔초에게_2시에_보낸_쪽지); final ChatRoomAndImageDto 엔초_지토_채팅방_정보 = new ChatRoomAndImageDto(엔초_지토_채팅방, 엔초의_경매_대표_이미지); 엔초_회원_정보 = new AuthenticationUserInfo(엔초.getId()); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java index 185fc5783..892695e39 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/application/fixture/MessageServiceFixture.java @@ -10,7 +10,7 @@ import com.ddang.ddang.chat.domain.ChatRoom; import com.ddang.ddang.chat.domain.Message; import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; -import com.ddang.ddang.chat.infrastructure.persistence.JpaMessageRepository; +import com.ddang.ddang.chat.domain.repository.MessageRepository; import com.ddang.ddang.chat.presentation.dto.request.ReadMessageRequest; import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.user.domain.Reliability; @@ -30,7 +30,7 @@ public class MessageServiceFixture { private AuctionRepository auctionRepository; @Autowired - private JpaMessageRepository messageRepository; + private MessageRepository messageRepository; @Autowired private UserRepository userRepository; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomRepositoryImplTest.java index 51b38d031..33520e3e1 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomRepositoryImplTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/ChatRoomRepositoryImplTest.java @@ -38,6 +38,7 @@ void setUp(@Autowired final JpaChatRoomRepository jpaChatRoomRepository) { // when chatRoomRepository.save(chatRoom); + // then assertThat(chatRoom.getId()).isPositive(); } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/MessageRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/MessageRepositoryImplTest.java new file mode 100644 index 000000000..adef04b97 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/MessageRepositoryImplTest.java @@ -0,0 +1,75 @@ +package com.ddang.ddang.chat.infrastructure.persistence; + +import com.ddang.ddang.chat.domain.Message; +import com.ddang.ddang.chat.domain.repository.MessageRepository; +import com.ddang.ddang.chat.infrastructure.persistence.fixture.MessageRepositoryImplFixture; +import com.ddang.ddang.configuration.JpaConfiguration; +import com.ddang.ddang.configuration.QuerydslConfiguration; +import com.querydsl.jpa.impl.JPAQueryFactory; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@Import({JpaConfiguration.class, QuerydslConfiguration.class}) +@SuppressWarnings("NonAsciiCharacters") +public class MessageRepositoryImplTest extends MessageRepositoryImplFixture { + + MessageRepository messageRepository; + + @BeforeEach + void setUp( + @Autowired final JPAQueryFactory queryFactory, + @Autowired final JpaMessageRepository jpaMessageRepository + ) { + messageRepository = new MessageRepositoryImpl(jpaMessageRepository, new QuerydslMessageRepository(queryFactory)); + } + + @Test + void 메시지를_저장한다() { + // when + messageRepository.save(저장할_메시지); + + // then + assertThat(저장할_메시지.getId()).isPositive(); + } + + @Test + void 메시지_아이디에_해당하는_메시지가_존재하면_true를_반환한다() { + // when + final boolean actual = messageRepository.existsById(저장된_메시지.getId()); + + // then + assertThat(actual).isTrue(); + } + + @Test + void 메시지_아이디에_해당하는_메시지가_존재하지_않으면_false를_반환한다() { + // when + final boolean actual = messageRepository.existsById(존재하지_않는_메시지_아이디); + + // then + assertThat(actual).isFalse(); + } + + @Test + void 마지막_메시지_이후에_저장된_모든_메시지를_조회한다() { + // when + final List actual = messageRepository.findAllByLastMessageId(구매자_겸_수신자.getId(), 메시지가_5개인_채팅방.getId(), 두_번째_메시지_아이디); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).hasSize(3); + softAssertions.assertThat(actual.get(0)).isEqualTo(세_번째_메시지); + softAssertions.assertThat(actual.get(1)).isEqualTo(네_번째_메시지); + softAssertions.assertThat(actual.get(2)).isEqualTo(다섯_번째_메시지); + }); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslMessageRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslMessageRepositoryTest.java similarity index 92% rename from backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslMessageRepositoryImplTest.java rename to backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslMessageRepositoryTest.java index bcf573dc7..282385a11 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslMessageRepositoryImplTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslMessageRepositoryTest.java @@ -1,7 +1,7 @@ package com.ddang.ddang.chat.infrastructure.persistence; import com.ddang.ddang.chat.domain.Message; -import com.ddang.ddang.chat.infrastructure.persistence.fixture.QuerydslMessageRepositoryImplFixture; +import com.ddang.ddang.chat.infrastructure.persistence.fixture.QuerydslMessageRepositoryFixture; import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; import com.querydsl.jpa.impl.JPAQueryFactory; @@ -22,19 +22,19 @@ @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @SuppressWarnings("NonAsciiCharacters") @Import({JpaConfiguration.class, QuerydslConfiguration.class}) -class QuerydslMessageRepositoryImplTest extends QuerydslMessageRepositoryImplFixture { +class QuerydslMessageRepositoryTest extends QuerydslMessageRepositoryFixture { - QuerydslMessageRepositoryImpl querydslMessageRepository; + QuerydslMessageRepository querydslMessageRepository; @BeforeEach void setUp(@Autowired final JPAQueryFactory queryFactory) { - querydslMessageRepository = new QuerydslMessageRepositoryImpl(queryFactory); + querydslMessageRepository = new QuerydslMessageRepository(queryFactory); } @Test void 마지막으로_읽은_메시지_이후에_추가된_메시지를_조회한다() { // when - final List actual = querydslMessageRepository.findMessagesAllByLastMessageId( + final List actual = querydslMessageRepository.findAllByLastMessageId( 판매자.getId(), 채팅방.getId(), 세_번째_메시지.getId() @@ -56,7 +56,7 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { @Test void 상대방이_메시지를_추가한_경우_마지막으로_읽은_메시지_이후의_메시지를_조회한다() { // when - final List actual = querydslMessageRepository.findMessagesAllByLastMessageId( + final List actual = querydslMessageRepository.findAllByLastMessageId( 구매자.getId(), 채팅방.getId(), 세_번째_메시지.getId() @@ -78,7 +78,7 @@ void setUp(@Autowired final JPAQueryFactory queryFactory) { @Test void 마지막으로_읽은_메시지_이후의_메시지가_없는_경우_빈_리스트를_반환한다() { // when - final List actual = querydslMessageRepository.findMessagesAllByLastMessageId( + final List actual = querydslMessageRepository.findAllByLastMessageId( 구매자.getId(), 채팅방.getId(), 열_번째_메시지.getId() diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndMessageAndImageRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndMessageAndImageRepositoryImplFixture.java index d776c4829..79bdacb98 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndMessageAndImageRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndMessageAndImageRepositoryImplFixture.java @@ -17,9 +17,12 @@ import com.ddang.ddang.chat.domain.ChatRoom; import com.ddang.ddang.chat.domain.Message; import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; +import com.ddang.ddang.chat.domain.repository.MessageRepository; import com.ddang.ddang.chat.infrastructure.persistence.ChatRoomRepositoryImpl; import com.ddang.ddang.chat.infrastructure.persistence.JpaChatRoomRepository; import com.ddang.ddang.chat.infrastructure.persistence.JpaMessageRepository; +import com.ddang.ddang.chat.infrastructure.persistence.MessageRepositoryImpl; +import com.ddang.ddang.chat.infrastructure.persistence.QuerydslMessageRepository; import com.ddang.ddang.image.domain.AuctionImage; import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.user.domain.Reliability; @@ -37,19 +40,18 @@ @SuppressWarnings("NonAsciiCharacters") public class ChatRoomAndMessageAndImageRepositoryImplFixture { - private AuctionRepository auctionRepository; - @Autowired private JpaCategoryRepository categoryRepository; + private AuctionRepository auctionRepository; + private UserRepository userRepository; private BidRepository bidRepository; private ChatRoomRepository chatRoomRepository; - @Autowired - private JpaMessageRepository messageRepository; + private MessageRepository messageRepository; protected User 엔초; protected AuctionImage 메리의_경매_대표_이미지; @@ -68,12 +70,14 @@ void fixtureSetUp( @Autowired final JpaAuctionRepository jpaAuctionRepository, @Autowired final JpaUserRepository jpaUserRepository, @Autowired final JpaChatRoomRepository jpaChatRoomRepository, - @Autowired final JpaBidRepository jpaBidRepository + @Autowired final JpaBidRepository jpaBidRepository, + @Autowired final JpaMessageRepository jpaMessageRepository ) { auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(jpaQueryFactory)); userRepository = new UserRepositoryImpl(jpaUserRepository); chatRoomRepository = new ChatRoomRepositoryImpl(jpaChatRoomRepository); bidRepository = new BidRepositoryImpl(jpaBidRepository); + messageRepository = new MessageRepositoryImpl(jpaMessageRepository, new QuerydslMessageRepository(jpaQueryFactory)); final Category 전자기기_카테고리 = new Category("전자기기"); final Category 전자기기_서브_노트북_카테고리 = new Category("노트북 카테고리"); @@ -209,14 +213,10 @@ void fixtureSetUp( chatRoomRepository.save(엔초_지토_채팅방); chatRoomRepository.save(제이미_엔초_채팅방); - messageRepository.saveAll( - List.of( - 제이미가_엔초에게_1시에_보낸_쪽지, - 엔초가_지토에게_2시에_보낸_쪽지, - 메리가_엔초에게_3시에_보낸_쪽지, - 제이미가_엔초에게_4시에_보낸_쪽지, - 엔초가_지토에게_5시에_보낸_쪽지 - ) - ); + messageRepository.save(제이미가_엔초에게_1시에_보낸_쪽지); + messageRepository.save(엔초가_지토에게_2시에_보낸_쪽지); + messageRepository.save(메리가_엔초에게_3시에_보낸_쪽지); + messageRepository.save(제이미가_엔초에게_4시에_보낸_쪽지); + messageRepository.save(엔초가_지토에게_5시에_보낸_쪽지); } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/MessageRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/MessageRepositoryImplFixture.java new file mode 100644 index 000000000..105997c3d --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/MessageRepositoryImplFixture.java @@ -0,0 +1,128 @@ +package com.ddang.ddang.chat.infrastructure.persistence.fixture; + +import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.AuctionRepositoryImpl; +import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; +import com.ddang.ddang.chat.domain.ChatRoom; +import com.ddang.ddang.chat.domain.Message; +import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; +import com.ddang.ddang.chat.domain.repository.MessageRepository; +import com.ddang.ddang.chat.infrastructure.persistence.ChatRoomRepositoryImpl; +import com.ddang.ddang.chat.infrastructure.persistence.JpaChatRoomRepository; +import com.ddang.ddang.chat.infrastructure.persistence.JpaMessageRepository; +import com.ddang.ddang.chat.infrastructure.persistence.MessageRepositoryImpl; +import com.ddang.ddang.chat.infrastructure.persistence.QuerydslMessageRepository; +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.repository.UserRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.infrastructure.persistence.UserRepositoryImpl; +import com.querydsl.jpa.impl.JPAQueryFactory; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.ArrayList; +import java.util.List; + +@SuppressWarnings("NonAsciiCharacters") +public class MessageRepositoryImplFixture { + + private MessageRepository messageRepository; + private UserRepository userRepository; + private AuctionRepository auctionRepository; + private ChatRoomRepository chatRoomRepository; + + protected User 판매자_겸_발신자; + protected User 구매자_겸_수신자; + protected Auction 경매; + protected Auction 메시지가_5개인_경매; + protected ChatRoom 채팅방; + protected ChatRoom 메시지가_5개인_채팅방; + protected Message 저장할_메시지; + protected Message 저장된_메시지; + protected Message 세_번째_메시지; + protected Message 네_번째_메시지; + protected Message 다섯_번째_메시지; + protected long 두_번째_메시지_아이디; + + protected String 메시지_내용 = "메시지 내용"; + protected long 존재하지_않는_메시지_아이디 = -999L; + + @BeforeEach + void fixtureSetUp( + @Autowired final JPAQueryFactory queryFactory, + @Autowired final JpaMessageRepository jpaMessageRepository, + @Autowired final JpaUserRepository jpaUserRepository, + @Autowired final JpaAuctionRepository jpaAuctionRepository, + @Autowired final JpaChatRoomRepository jpaChatRoomRepository + ) { + messageRepository = new MessageRepositoryImpl(jpaMessageRepository, new QuerydslMessageRepository(queryFactory)); + userRepository = new UserRepositoryImpl(jpaUserRepository); + auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository((queryFactory))); + chatRoomRepository = new ChatRoomRepositoryImpl(jpaChatRoomRepository); + + 판매자_겸_발신자 = User.builder() + .name("판매자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("78923") + .build(); + 구매자_겸_수신자 = User.builder() + .name("구매자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); + userRepository.save(판매자_겸_발신자); + userRepository.save(구매자_겸_수신자); + + 경매 = Auction.builder() + .title("title") + .build(); + 메시지가_5개인_경매 = Auction.builder() + .title("메시지가_5개인_경매") + .build(); + auctionRepository.save(경매); + auctionRepository.save(메시지가_5개인_경매); + + 채팅방 = new ChatRoom(경매, 구매자_겸_수신자); + 메시지가_5개인_채팅방 = new ChatRoom(메시지가_5개인_경매, 구매자_겸_수신자); + chatRoomRepository.save(채팅방); + chatRoomRepository.save(메시지가_5개인_채팅방); + + 저장할_메시지 = Message.builder() + .chatRoom(채팅방) + .writer(판매자_겸_발신자) + .receiver(구매자_겸_수신자) + .contents(메시지_내용) + .build(); + 저장된_메시지 = Message.builder() + .chatRoom(채팅방) + .writer(판매자_겸_발신자) + .receiver(구매자_겸_수신자) + .contents("레포지토리에 저장된 메시지") + .build(); + messageRepository.save(저장된_메시지); + + int 메시지_총_개수 = 5; + List 저장된_메시지들 = new ArrayList<>(); + for (int count = 0; count < 메시지_총_개수; count++) { + final Message 메시지 = Message.builder() + .chatRoom(메시지가_5개인_채팅방) + .writer(판매자_겸_발신자) + .receiver(구매자_겸_수신자) + .contents("안녕하세요") + .build(); + 저장된_메시지들.add(메시지); + messageRepository.save(메시지); + } + + 두_번째_메시지_아이디 = 저장된_메시지들.get(1).getId(); + 세_번째_메시지 = 저장된_메시지들.get(2); + 네_번째_메시지 = 저장된_메시지들.get(3); + 다섯_번째_메시지 = 저장된_메시지들.get(4); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslMessageRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslMessageRepositoryFixture.java similarity index 80% rename from backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslMessageRepositoryImplFixture.java rename to backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslMessageRepositoryFixture.java index ca6a05285..916829582 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslMessageRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/QuerydslMessageRepositoryFixture.java @@ -7,8 +7,11 @@ import com.ddang.ddang.auction.infrastructure.persistence.QuerydslAuctionRepository; import com.ddang.ddang.chat.domain.ChatRoom; import com.ddang.ddang.chat.domain.Message; +import com.ddang.ddang.chat.domain.repository.MessageRepository; import com.ddang.ddang.chat.infrastructure.persistence.JpaChatRoomRepository; import com.ddang.ddang.chat.infrastructure.persistence.JpaMessageRepository; +import com.ddang.ddang.chat.infrastructure.persistence.MessageRepositoryImpl; +import com.ddang.ddang.chat.infrastructure.persistence.QuerydslMessageRepository; import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; @@ -16,13 +19,14 @@ import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; -import java.util.ArrayList; -import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; +import java.util.ArrayList; +import java.util.List; + @SuppressWarnings("NonAsciiCharacters") -public class QuerydslMessageRepositoryImplFixture { +public class QuerydslMessageRepositoryFixture { @PersistenceContext private EntityManager em; @@ -40,7 +44,7 @@ public class QuerydslMessageRepositoryImplFixture { private JpaChatRoomRepository chatRoomRepository; @Autowired - private JpaMessageRepository messageRepository; + private JpaMessageRepository jpaMessageRepository; protected User 판매자; protected User 구매자; @@ -59,6 +63,15 @@ public class QuerydslMessageRepositoryImplFixture { @BeforeEach void setUp() { + final AuctionRepository auctionRepository = new AuctionRepositoryImpl( + jpaAuctionRepository, + new QuerydslAuctionRepository(queryFactory) + ); + final MessageRepository messageRepository = new MessageRepositoryImpl( + jpaMessageRepository, + new QuerydslMessageRepository(queryFactory) + ); + 판매자 = User.builder() .name("판매자") .profileImage(new ProfileImage("upload.png", "store.png")) @@ -79,11 +92,6 @@ void setUp() { .title("title") .build(); - final AuctionRepository auctionRepository = new AuctionRepositoryImpl( - jpaAuctionRepository, - new QuerydslAuctionRepository(queryFactory) - ); - auctionRepository.save(경매); 채팅방 = new ChatRoom(경매, 구매자); @@ -93,15 +101,15 @@ void setUp() { 메시지_총_개수 = 10; 저장된_메시지들 = new ArrayList<>(); for (int count = 0; count < 메시지_총_개수; count++) { - final Message message = Message.builder() - .chatRoom(채팅방) - .writer(판매자) - .receiver(구매자) - .contents("안녕하세요") - .build(); - 저장된_메시지들.add(message); + final Message 메시지 = Message.builder() + .chatRoom(채팅방) + .writer(판매자) + .receiver(구매자) + .contents("안녕하세요") + .build(); + 저장된_메시지들.add(메시지); + messageRepository.save(메시지); } - messageRepository.saveAll(저장된_메시지들); 세_번째_메시지 = 저장된_메시지들.get(2); 네_번째_메시지 = 저장된_메시지들.get(3); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/NotificationEventListenerTest.java b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/NotificationEventListenerTest.java index a7f2d15ab..661f705a6 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/NotificationEventListenerTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/NotificationEventListenerTest.java @@ -5,7 +5,7 @@ import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; import com.ddang.ddang.chat.application.MessageService; import com.ddang.ddang.chat.application.event.MessageNotificationEvent; -import com.ddang.ddang.chat.infrastructure.persistence.JpaMessageRepository; +import com.ddang.ddang.chat.domain.repository.MessageRepository; import com.ddang.ddang.configuration.IsolateDatabase; import com.ddang.ddang.notification.application.fixture.NotificationEventListenerFixture; import com.ddang.ddang.notification.domain.NotificationStatus; @@ -47,7 +47,7 @@ class NotificationEventListenerTest extends NotificationEventListenerFixture { MessageService messageService; @Autowired - JpaMessageRepository messageRepository; + MessageRepository messageRepository; @Autowired JpaBidRepository bidRepository; @@ -85,7 +85,7 @@ class NotificationEventListenerTest extends NotificationEventListenerFixture { // then SoftAssertions.assertSoftly(softAssertions -> { - softAssertions.assertThat(messageRepository.findById(actualSavedMessageId)).isPresent(); + softAssertions.assertThat(messageRepository.existsById(actualSavedMessageId)).isTrue(); final long actual = events.stream(MessageNotificationEvent.class).count(); softAssertions.assertThat(actual).isEqualTo(1); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java index 30c073a00..686c9b2a4 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java @@ -10,7 +10,7 @@ import com.ddang.ddang.chat.domain.ChatRoom; import com.ddang.ddang.chat.domain.Message; import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; -import com.ddang.ddang.chat.infrastructure.persistence.JpaMessageRepository; +import com.ddang.ddang.chat.domain.repository.MessageRepository; import com.ddang.ddang.device.domain.DeviceToken; import com.ddang.ddang.device.infrastructure.persistence.JpaDeviceTokenRepository; import com.ddang.ddang.image.domain.AuctionImage; @@ -34,7 +34,7 @@ public class FcmNotificationServiceFixture { private UserRepository userRepository; @Autowired - private JpaMessageRepository messageRepository; + private MessageRepository messageRepository; @Autowired private ChatRoomRepository chatRoomRepository; @@ -52,9 +52,6 @@ public class FcmNotificationServiceFixture { private JpaAuctionImageRepository auctionImageRepository; protected User 메시지_조회자_겸_발신자; - private User 메시지_수신자; - private User 새로운_입찰자; - private User 기기토큰이_없는_사용자; protected DeviceToken 기기토큰; protected CreateNotificationDto 기기토큰이_없는_사용자의_알림_생성_DTO; protected CreateNotificationDto 알림_생성_DTO; @@ -69,24 +66,24 @@ void setUp() { .reliability(new Reliability(4.7d)) .oauthId("12345") .build(); - 메시지_수신자 = User.builder() - .name("메시지_수신자") - .profileImage(new ProfileImage("upload.png", "store.png")) - .reliability(new Reliability(4.7d)) - .oauthId("12347") - .build(); - 새로운_입찰자 = User.builder() - .name("입찰자1") - .profileImage(new ProfileImage("upload.png", "store.png")) - .reliability(new Reliability(4.7d)) - .oauthId("56789") - .build(); - 기기토큰이_없는_사용자 = User.builder() - .name("기기토큰이 없는 사용자") + final User 메시지_수신자 = User.builder() + .name("메시지_수신자") .profileImage(new ProfileImage("upload.png", "store.png")) .reliability(new Reliability(4.7d)) - .oauthId("12234") + .oauthId("12347") .build(); + final User 새로운_입찰자 = User.builder() + .name("입찰자1") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("56789") + .build(); + final User 기기토큰이_없는_사용자 = User.builder() + .name("기기토큰이 없는 사용자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12234") + .build(); userRepository.save(메시지_조회자_겸_발신자); userRepository.save(메시지_수신자); From a58f961f1b4aded1cb6caf195232c3c4a5771278 Mon Sep 17 00:00:00 2001 From: apptie <57691173+apptie@users.noreply.github.com> Date: Mon, 16 Oct 2023 00:06:02 +0900 Subject: [PATCH 29/37] =?UTF-8?q?refactor:=20#692=20=EA=B2=BD=EB=A7=A4=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=20=EC=A1=B0=ED=9A=8C=20=EC=8B=9C=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=ED=95=9C=20=EC=82=AC=EC=9A=A9=EC=9E=90?= =?UTF-8?q?=EA=B0=80=20=ED=95=B4=EB=8B=B9=20=EA=B2=BD=EB=A7=A4=EC=9D=98=20?= =?UTF-8?q?=EC=B5=9C=EA=B3=A0=20=EC=9E=85=EC=B0=B0=EC=9E=90=EC=9D=B8?= =?UTF-8?q?=EC=A7=80=20=EC=97=AC=EB=B6=80=EB=A5=BC=20=EB=B0=98=ED=99=98?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=9D=91=EB=8B=B5=20=ED=98=95?= =?UTF-8?q?=EC=8B=9D=20=EB=B3=80=EA=B2=BD=20(#695)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 경매 상세 조회 api 요청 시 로그인한 사용자가 해당 경매의 최종 입찰자인지 여부를 반환하도록 변경 * docs: 문서 최신화 * style: 개행 변경 --- .../application/dto/ReadAuctionDto.java | 14 +- .../response/ReadAuctionDetailResponse.java | 10 +- .../src/main/resources/static/docs/docs.html | 125 +++++++++--------- .../presentation/AuctionControllerTest.java | 43 ++++-- .../fixture/AuctionControllerFixture.java | 9 +- .../fixture/UserAuctionControllerFixture.java | 6 +- 6 files changed, 120 insertions(+), 87 deletions(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/application/dto/ReadAuctionDto.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/application/dto/ReadAuctionDto.java index 6f9677172..d5be76317 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/application/dto/ReadAuctionDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/application/dto/ReadAuctionDto.java @@ -29,7 +29,8 @@ public record ReadAuctionDto( String sellerName, double sellerReliability, boolean isSellerDeleted, - AuctionStatus auctionStatus + AuctionStatus auctionStatus, + Long lastBidderId ) { public static ReadAuctionDto of(final Auction auction, final LocalDateTime targetTime) { @@ -53,7 +54,8 @@ public static ReadAuctionDto of(final Auction auction, final LocalDateTime targe auction.getSeller().getName(), auction.getSeller().getReliability().getValue(), auction.getSeller().isDeleted(), - auction.findAuctionStatus(targetTime) + auction.findAuctionStatus(targetTime), + convertLastBidderId(auction) ); } @@ -79,4 +81,12 @@ private static List convertReadRegionsDto(final Auction auction) .map(ReadRegionsDto::from) .toList(); } + + private static Long convertLastBidderId(final Auction auction) { + if (auction.getLastBid() == null) { + return null; + } + + return auction.getLastBid().getBidder().getId(); + } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadAuctionDetailResponse.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadAuctionDetailResponse.java index 318daccce..3baa08f29 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadAuctionDetailResponse.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadAuctionDetailResponse.java @@ -8,7 +8,8 @@ public record ReadAuctionDetailResponse( AuctionDetailResponse auction, SellerResponse seller, ChatRoomInAuctionResponse chat, - boolean isOwner + boolean isOwner, + boolean isLastBidder ) { public static ReadAuctionDetailResponse of( @@ -24,11 +25,16 @@ public static ReadAuctionDetailResponse of( auctionDetailResponse, sellerResponse, chatRoomResponse, - isOwner(auctionDto, userInfo) + isOwner(auctionDto, userInfo), + isLastBidder(auctionDto, userInfo) ); } private static boolean isOwner(final ReadAuctionDto auctionDto, final AuthenticationUserInfo userInfo) { return auctionDto.sellerId().equals(userInfo.userId()); } + + private static boolean isLastBidder(final ReadAuctionDto auctionDto, final AuthenticationUserInfo userInfo) { + return userInfo.userId().equals(auctionDto.lastBidderId()); + } } diff --git a/backend/ddang/src/main/resources/static/docs/docs.html b/backend/ddang/src/main/resources/static/docs/docs.html index fe00d2198..bf5f56834 100644 --- a/backend/ddang/src/main/resources/static/docs/docs.html +++ b/backend/ddang/src/main/resources/static/docs/docs.html @@ -913,25 +913,9 @@

요청

} -

bids.[]

[]

Array

특정 경매의 모든 입찰 목록

bids.[].name

[].name

String

입찰한 사용자의 닉네임

bids.[].profileImage

[].profileImage

String

입찰한 사용자의 프로필 이미지 URL

bids.[].price

[].price

Number

입찰한 금액

bids.[].bidTime

[].bidTime

String

입찰한 시간

- ---- - - - - - - - - - - - - -
Table 2. /oauth2/withdrawal/{oauth2Type}
ParameterDescription

oauth2Type

소셜 로그인을 할 서비스 선택(kakao로 고정)

+
+

Unresolved directive in docs.adoc - include::/Users/labtop/intellij/test-ddang/2023-3-ddang/backend/ddang/build/generated-snippets/authentication-controller-test/ouath2-type과_access-token과_refresh-token을_전달하면_탈퇴한다/path-parameters.adoc[]

+
@@ -1294,7 +1278,7 @@

요청

- +@@ -1373,7 +1357,7 @@

요청

Table 3. /regions/{firstId}Table 2. /regions/{firstId}
- +@@ -1469,7 +1453,7 @@

요청

Content-Disposition: form-data; name=request; filename=request Content-Type: application/json -{"title":"제목","description":"내용","bidUnit":1000,"startPrice":1000,"closingTime":"2023-10-18T00:23:05.544558","subCategoryId":2,"thirdRegionIds":[3]} +{"title":"제목","description":"내용","bidUnit":1000,"startPrice":1000,"closingTime":"2023-10-18T21:12:06.450773","subCategoryId":2,"thirdRegionIds":[3]} --6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm-- @@ -2018,7 +2002,7 @@

요청

Table 4. /regions/{firstId}/{secondId}Table 3. /regions/{firstId}/{secondId}
- +@@ -2050,7 +2034,7 @@

요청

- +
Table 5. /auctions/{auctionId}Table 4. /auctions/{auctionId}

Authorization

회원 Bearer 인증 정보

사용자 Bearer 인증 정보

@@ -2076,8 +2060,8 @@

응답

"lastBidPrice" : null, "status" : "UNBIDDEN", "bidUnit" : 1000, - "registerTime" : "2023-10-15T00:23:05", - "closingTime" : "2023-10-15T00:23:05", + "registerTime" : "2023-10-15T21:12:06", + "closingTime" : "2023-10-15T21:12:06", "directRegions" : [ { "first" : "서울특별시", "second" : "강서구", @@ -2095,7 +2079,8 @@

응답

"id" : 1, "isChatParticipant" : true }, - "isOwner" : true + "isOwner" : true, + "isLastBidder" : false } @@ -2241,12 +2226,17 @@

응답

chat.isChatParticipant

Boolean

-

채팅방을 생성 가능 유저 여부

+

로그인한 사용자가 채팅방 생성이 가능한 사용자인지에 대한 여부

isOwner

Boolean

-

유저가 해당 경매 글을 작성한 유저인지에 대한 여부

+

로그인한 사용자가 해당 경매 글을 작성한 사용자인지에 대한 여부

+ + +

isLastBidder

+

Boolean

+

로그인한 사용자가 해당 경매의 최고 입찰자인지에 대한 여부

@@ -2264,7 +2254,7 @@

요청

- +@@ -2415,7 +2405,7 @@

요청

Table 6. /auctions/{auctionId}Table 5. /auctions/{auctionId}
- +@@ -2543,7 +2533,7 @@

요청

Table 7. /questions/{questionId}Table 6. /questions/{questionId}
- +@@ -2599,8 +2589,9 @@

응답

"name" : "질문자", "image" : "http://localhost:8080/users/images/1" }, - "createdTime" : "2023-10-15T00:23:05", - "content" : "질문1" + "createdTime" : "2023-10-15T21:12:06", + "content" : "질문1", + "isQuestioner" : false }, "answer" : { "id" : 1, @@ -2609,7 +2600,7 @@

응답

"name" : "판매자", "image" : "http://localhost:8080/users/images/2" }, - "createdTime" : "2023-10-15T00:23:05", + "createdTime" : "2023-10-15T21:12:06", "content" : "답변1" } }, { @@ -2620,8 +2611,9 @@

응답

"name" : "질문자", "image" : "http://localhost:8080/users/images/1" }, - "createdTime" : "2023-10-15T00:23:05", - "content" : "질문2" + "createdTime" : "2023-10-15T21:12:06", + "content" : "질문2", + "isQuestioner" : false }, "answer" : { "id" : 2, @@ -2630,7 +2622,7 @@

응답

"name" : "판매자", "image" : "http://localhost:8080/users/images/2" }, - "createdTime" : "2023-10-15T00:23:05", + "createdTime" : "2023-10-15T21:12:06", "content" : "답변1" } } ] @@ -2697,6 +2689,11 @@

응답

+ + + + + @@ -2838,12 +2835,12 @@

응답

"name" : "사용자1", "profileImage" : "http://localhost:8080/users/images/1", "price" : 10000, - "bidTime" : "2023-10-15T00:23:10" + "bidTime" : "2023-10-15T21:12:13" }, { "name" : "사용자2", "profileImage" : "http://localhost:8080/users/images/2", "price" : 12000, - "bidTime" : "2023-10-15T00:23:10" + "bidTime" : "2023-10-15T21:12:13" } ] @@ -3037,7 +3034,7 @@

응답

"price" : 10000 }, "lastMessage" : { - "createdAt" : "2023-10-15T00:23:11", + "createdAt" : "2023-10-15T21:12:16", "contents" : "메시지1" }, "isChatAvailable" : true @@ -3055,7 +3052,7 @@

응답

"price" : 20000 }, "lastMessage" : { - "createdAt" : "2023-10-15T00:23:11", + "createdAt" : "2023-10-15T21:12:16", "contents" : "메시지2" }, "isChatAvailable" : true @@ -3167,7 +3164,7 @@

요청

Table 8. /questions/answers/{answerId}Table 7. /questions/answers/{answerId}

질문 내용

qnas.[].question.isQuestioner

Boolean

질문 작성자 여부 확인

qnas.[].answer

Object

답변 정보 JSON

- +@@ -3318,7 +3315,7 @@

요청

Table 9. /chattings/{chatRoomId}Table 8. /chattings/{chatRoomId}
- +@@ -3429,7 +3426,7 @@

요청

Table 10. /chattings/{chatRoomId}/messagesTable 9. /chattings/{chatRoomId}/messages
- +@@ -3493,7 +3490,7 @@

응답

[ { "id" : 1, - "createdAt" : "2023-10-15T00:23:11", + "createdAt" : "2023-10-15T21:12:16", "isMyMessage" : true, "contents" : "메시지내용" } ] @@ -3643,7 +3640,7 @@

응답

"id" : 2, "name" : "회원1" }, - "createdTime" : "2023-10-15T00:23:18", + "createdTime" : "2023-10-15T21:12:26", "auction" : { "id" : 1, "title" : "제목" @@ -3655,7 +3652,7 @@

응답

"id" : 3, "name" : "회원2" }, - "createdTime" : "2023-10-15T00:23:18", + "createdTime" : "2023-10-15T21:12:26", "auction" : { "id" : 1, "title" : "제목" @@ -3667,7 +3664,7 @@

응답

"id" : 4, "name" : "회원3" }, - "createdTime" : "2023-10-15T00:23:18", + "createdTime" : "2023-10-15T21:12:26", "auction" : { "id" : 1, "title" : "제목" @@ -3831,7 +3828,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-15T00:23:18", + "createdTime" : "2023-10-15T21:12:27", "chatRoom" : { "id" : 1 }, @@ -3842,7 +3839,7 @@

응답

"id" : 3, "name" : "구매자2" }, - "createdTime" : "2023-10-15T00:23:18", + "createdTime" : "2023-10-15T21:12:27", "chatRoom" : { "id" : 1 }, @@ -3853,7 +3850,7 @@

응답

"id" : 3, "name" : "구매자2" }, - "createdTime" : "2023-10-15T00:23:18", + "createdTime" : "2023-10-15T21:12:27", "chatRoom" : { "id" : 1 }, @@ -4017,7 +4014,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-15T00:23:18", + "createdTime" : "2023-10-15T21:12:27", "question" : { "id" : 1 }, @@ -4028,7 +4025,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-15T00:23:18", + "createdTime" : "2023-10-15T21:12:27", "question" : { "id" : 2 }, @@ -4039,7 +4036,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-15T00:23:18", + "createdTime" : "2023-10-15T21:12:27", "question" : { "id" : 3 }, @@ -4203,7 +4200,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-15T00:23:18", + "createdTime" : "2023-10-15T21:12:27", "answer" : { "id" : 1 }, @@ -4214,7 +4211,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-15T00:23:18", + "createdTime" : "2023-10-15T21:12:27", "answer" : { "id" : 2 }, @@ -4225,7 +4222,7 @@

응답

"id" : 2, "name" : "구매자1" }, - "createdTime" : "2023-10-15T00:23:18", + "createdTime" : "2023-10-15T21:12:27", "answer" : { "id" : 3 }, @@ -4455,7 +4452,7 @@

요청

Table 11. /chattings/{chatRoomId}/messagesTable 10. /chattings/{chatRoomId}/messages
- +@@ -4526,7 +4523,7 @@

요청

Table 12. /reviews/{reviewId}Table 11. /reviews/{reviewId}
- +@@ -4561,7 +4558,7 @@

응답

}, "content" : "친절하다.", "score" : 5.0, - "createdTime" : "2023-10-15T00:23:19" + "createdTime" : "2023-10-15T21:12:29" }, { "id" : 2, "writer" : { @@ -4571,7 +4568,7 @@

응답

}, "content" : "친절하다.", "score" : 5.0, - "createdTime" : "2023-10-15T00:23:19" + "createdTime" : "2023-10-15T21:12:29" } ] @@ -4645,7 +4642,7 @@

요청

Table 13. /reviews/users/{userId}Table 12. /reviews/users/{userId}
- +@@ -4729,7 +4726,7 @@

응답

diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/presentation/AuctionControllerTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/presentation/AuctionControllerTest.java index cc415afe8..56b5b9669 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/presentation/AuctionControllerTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/presentation/AuctionControllerTest.java @@ -266,13 +266,17 @@ void setUp() { jsonPath("$.auction.bidUnit", is(경매_조회_dto.bidUnit())), jsonPath("$.auction.registerTime").exists(), jsonPath("$.auction.closingTime").exists(), - jsonPath("$.auction.directRegions[0].first", is(경매_조회_dto.auctionRegions().get(0).firstRegionDto().regionName())), - jsonPath("$.auction.directRegions[0].second", is(경매_조회_dto.auctionRegions().get(0).secondRegionDto().regionName())), - jsonPath("$.auction.directRegions[0].third", is(경매_조회_dto.auctionRegions().get(0).thirdRegionDto().regionName())), + jsonPath("$.auction.directRegions[0].first", + is(경매_조회_dto.auctionRegions().get(0).firstRegionDto().regionName())), + jsonPath("$.auction.directRegions[0].second", + is(경매_조회_dto.auctionRegions().get(0).secondRegionDto().regionName())), + jsonPath("$.auction.directRegions[0].third", + is(경매_조회_dto.auctionRegions().get(0).thirdRegionDto().regionName())), jsonPath("$.auction.auctioneerCount", is(경매_조회_dto.auctioneerCount())), jsonPath("$.chat.id").exists(), jsonPath("$.chat.isChatParticipant", is(true)), jsonPath("$.isOwner", is(true)), + jsonPath("$.isLastBidder", is(false)), jsonPath("$.seller.nickname", is(경매_조회_dto.sellerName())), jsonPath("$.seller.id", is(경매_조회_dto.sellerId()), Long.class), jsonPath("$.seller.image", containsString(프로필_이미지_상대_주소)) @@ -313,18 +317,26 @@ void setUp() { ) .andExpectAll( status().isOk(), - jsonPath("$.auctions.[0].id", is(두번째_경매_조회_dto.id()), Long.class), + jsonPath("$.auctions.[0].id", is(두번째_경매_조회_dto.id()), + Long.class), jsonPath("$.auctions.[0].title", is(두번째_경매_조회_dto.title())), - jsonPath("$.auctions.[0].image", containsString(경매_이미지_상대_주소)), - jsonPath("$.auctions.[0].auctionPrice", is(두번째_경매_조회_dto.startPrice())), + jsonPath("$.auctions.[0].image", + containsString(경매_이미지_상대_주소)), + jsonPath("$.auctions.[0].auctionPrice", + is(두번째_경매_조회_dto.startPrice())), jsonPath("$.auctions.[0].status").exists(), - jsonPath("$.auctions.[0].auctioneerCount", is(두번째_경매_조회_dto.auctioneerCount())), - jsonPath("$.auctions.[1].id", is(첫번째_경매_조회_dto.id()), Long.class), + jsonPath("$.auctions.[0].auctioneerCount", + is(두번째_경매_조회_dto.auctioneerCount())), + jsonPath("$.auctions.[1].id", is(첫번째_경매_조회_dto.id()), + Long.class), jsonPath("$.auctions.[1].title", is(첫번째_경매_조회_dto.title())), - jsonPath("$.auctions.[1].image", containsString(경매_이미지_상대_주소)), - jsonPath("$.auctions.[1].auctionPrice", is(첫번째_경매_조회_dto.startPrice())), + jsonPath("$.auctions.[1].image", + containsString(경매_이미지_상대_주소)), + jsonPath("$.auctions.[1].auctionPrice", + is(첫번째_경매_조회_dto.startPrice())), jsonPath("$.auctions.[1].status").exists(), - jsonPath("$.auctions.[1].auctioneerCount", is(첫번째_경매_조회_dto.auctioneerCount())), + jsonPath("$.auctions.[1].auctioneerCount", + is(첫번째_경매_조회_dto.auctioneerCount())), jsonPath("$.isLast").exists() ); @@ -410,7 +422,7 @@ void setUp() { resultActions.andDo( restDocs.document( requestHeaders( - headerWithName("Authorization").description("회원 Bearer 인증 정보") + headerWithName("Authorization").description("사용자 Bearer 인증 정보") ), pathParameters( parameterWithName("auctionId").description("조회하고자 하는 경매 ID") @@ -458,9 +470,12 @@ void setUp() { .description("판매자 신뢰도"), fieldWithPath("chat.id").type(JsonFieldType.NUMBER).description("채팅방 ID"), fieldWithPath("chat.isChatParticipant").type(JsonFieldType.BOOLEAN) - .description("채팅방을 생성 가능 유저 여부"), + .description( + "로그인한 사용자가 채팅방 생성이 가능한 사용자인지에 대한 여부"), fieldWithPath("isOwner").type(JsonFieldType.BOOLEAN) - .description("유저가 해당 경매 글을 작성한 유저인지에 대한 여부") + .description("로그인한 사용자가 해당 경매 글을 작성한 사용자인지에 대한 여부"), + fieldWithPath("isLastBidder").type(JsonFieldType.BOOLEAN) + .description("로그인한 사용자가 해당 경매의 최고 입찰자인지에 대한 여부") ) ) ); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/presentation/fixture/AuctionControllerFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/presentation/fixture/AuctionControllerFixture.java index 804f0e3ec..b92c77e17 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/presentation/fixture/AuctionControllerFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/presentation/fixture/AuctionControllerFixture.java @@ -157,7 +157,8 @@ void fixtureSetUp() throws JsonProcessingException { "판매자", 3.5d, false, - AuctionStatus.UNBIDDEN + AuctionStatus.UNBIDDEN, + null ); 첫번째_경매_조회_dto = new ReadAuctionDto( @@ -180,7 +181,8 @@ void fixtureSetUp() throws JsonProcessingException { "판매자", 3.5d, false, - AuctionStatus.UNBIDDEN + AuctionStatus.UNBIDDEN, + null ); 두번째_경매_조회_dto = new ReadAuctionDto( @@ -203,7 +205,8 @@ void fixtureSetUp() throws JsonProcessingException { "판매자", 3.5d, false, - AuctionStatus.UNBIDDEN + AuctionStatus.UNBIDDEN, + null ); 경매_목록_조회_dto = new ReadAuctionsDto(List.of(두번째_경매_조회_dto, 첫번째_경매_조회_dto), true); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/presentation/fixture/UserAuctionControllerFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/user/presentation/fixture/UserAuctionControllerFixture.java index 506a674df..eb2731dc4 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/presentation/fixture/UserAuctionControllerFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/presentation/fixture/UserAuctionControllerFixture.java @@ -44,7 +44,8 @@ public class UserAuctionControllerFixture extends CommonControllerSliceTest { "판매자", 3.5d, false, - AuctionStatus.UNBIDDEN + AuctionStatus.UNBIDDEN, + null ); protected ReadAuctionDto 경매_정보_dto2 = new ReadAuctionDto( 2L, @@ -66,7 +67,8 @@ public class UserAuctionControllerFixture extends CommonControllerSliceTest { "판매자", 3.5d, false, - AuctionStatus.UNBIDDEN + AuctionStatus.UNBIDDEN, + null ); protected ReadAuctionsDto 사용자의_경매들_정보_dto = new ReadAuctionsDto(List.of(경매_정보_dto2, 경매_정보_dto1), true); protected ReadAuctionsDto 사용자가_참여한_경매들_정보_dto = new ReadAuctionsDto(List.of(경매_정보_dto2, 경매_정보_dto1), true); From 75071162053e5577c522be3c7c6cbc7ef75a38cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=8A=B9=EC=9B=90=20Merry?= Date: Mon, 16 Oct 2023 01:12:46 +0900 Subject: [PATCH 30/37] =?UTF-8?q?refactor:=20#690=20Device=20=EC=9D=B8?= =?UTF-8?q?=ED=94=84=EB=9D=BC=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81=20=20?= =?UTF-8?q?(#696)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 도메인 영역 기기토큰 레포지토리 추가 * feat: 도메인 기기토큰 레포지토리의 구현체 추가 * feat: 기기토큰 레포지토리 메서드 중 누락된 메서드 추가 * refactor: 서비스 레이어에서 도메인 영역 기기토큰 레포지토리 사용하도록 변경 * refactor: 누락된 final 추가 * test: 테스트에서 도메인 영역의 기기토큰 레포지토리 사용하도록 변경 * refactor: 레포지토리명에 맞춰 변수명 변경 * refactor: 테스트 픽스처에서 도메인 영역의 사용자 레포지토리 사용하도록 변경 * test: 기기토큰 레포지토리 구현체 테스트 추가 * chore: 질문에 대한 todo 주석 추가 * style: 개행 추가 * refactor: jpaQueryFactory 파라미터명 통일 * refactor: 필드 순서 변경 * refactor: given절 추가 * refactor: jpa 레포지토리 저장 테스트 메서드에서 엔티티 매니저 사용하는 코드 삭제 * refactor: 불필요한 필드 삭제 * refactor: 테스트에서 도메인 레포지토리 사용하도록 변경 * refactor: 불필요한 todo 삭제 --- .../application/AuthenticationService.java | 15 +++-- .../application/DeviceTokenService.java | 4 +- .../repository/DeviceTokenRepository.java | 14 ++++ .../DeviceTokenRepositoryImpl.java | 30 +++++++++ .../persistence/JpaDeviceTokenRepository.java | 2 +- .../application/FcmNotificationService.java | 4 +- .../AuctionRepositoryImplTest.java | 14 ++-- .../persistence/JpaAuctionRepositoryTest.java | 1 + ...QuerydslAuctionAndImageRepositoryTest.java | 4 +- .../fixture/AuctionRepositoryImplFixture.java | 6 +- ...rydslAuctionAndImageRepositoryFixture.java | 34 +++++----- .../AuthenticationServiceTest.java | 22 ++++--- .../fixture/AuthenticationServiceFixture.java | 9 ++- .../persistence/JpaBidRepositoryTest.java | 6 -- .../fixture/BidRepositoryImplFixture.java | 4 +- .../JpaChatRoomRepositoryTest.java | 18 ++---- .../persistence/JpaMessageRepositoryTest.java | 6 -- .../QuerydslMessageRepositoryTest.java | 4 +- ...ChatRoomAndImageRepositoryImplFixture.java | 4 +- .../ChatRoomRepositoryImplFixture.java | 4 +- .../application/DeviceTokenServiceTest.java | 4 +- .../fixture/DeviceTokenServiceFixture.java | 5 +- .../DeviceTokenRepositoryImplTest.java | 63 ++++++++++++++++++ .../JpaDeviceTokenRepositoryTest.java | 4 +- .../DeviceTokenRepositoryImplFixture.java | 64 +++++++++++++++++++ .../JpaDeviceTokenRepositoryFixture.java | 23 ++++--- .../FcmNotificationServiceFixture.java | 4 +- .../fixture/AnswerRepositoryImplFixture.java | 4 +- .../ChatRoomReportRepositoryImplTest.java | 1 + .../JpaChatRoomReportRepositoryTest.java | 1 + ... => QuestionReportRepositoryImplTest.java} | 0 .../AuctionReportRepositoryImplFixture.java | 4 +- ...paQuestionReportRepositoryImplFixture.java | 12 ++-- .../QuestionReportRepositoryImplFixture.java | 4 +- .../persistence/JpaReviewRepositoryTest.java | 22 +++---- .../fixture/JpaReviewRepositoryFixture.java | 1 - 36 files changed, 293 insertions(+), 128 deletions(-) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/device/domain/repository/DeviceTokenRepository.java create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/device/infrastructure/persistence/DeviceTokenRepositoryImpl.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/device/infrastructure/persistence/DeviceTokenRepositoryImplTest.java create mode 100644 backend/ddang/src/test/java/com/ddang/ddang/device/infrastructure/persistence/fixture/DeviceTokenRepositoryImplFixture.java rename backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/{QuestionReportRepositoryImplImplTest.java => QuestionReportRepositoryImplTest.java} (100%) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java index c3a2d41b7..47df37458 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java @@ -1,7 +1,5 @@ package com.ddang.ddang.authentication.application; -import static com.ddang.ddang.image.domain.ProfileImage.DEFAULT_PROFILE_IMAGE_STORE_NAME; - import com.ddang.ddang.authentication.application.dto.LoginInformationDto; import com.ddang.ddang.authentication.application.dto.LoginUserInformationDto; import com.ddang.ddang.authentication.application.dto.TokenDto; @@ -18,20 +16,23 @@ import com.ddang.ddang.authentication.infrastructure.oauth2.Oauth2Type; import com.ddang.ddang.device.application.DeviceTokenService; import com.ddang.ddang.device.application.dto.PersistDeviceTokenDto; -import com.ddang.ddang.device.infrastructure.persistence.JpaDeviceTokenRepository; +import com.ddang.ddang.device.domain.repository.DeviceTokenRepository; import com.ddang.ddang.image.application.exception.ImageNotFoundException; import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.image.domain.repository.ProfileImageRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; -import java.time.LocalDateTime; -import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import static com.ddang.ddang.image.domain.ProfileImage.DEFAULT_PROFILE_IMAGE_STORE_NAME; + @Service @Transactional(readOnly = true) @RequiredArgsConstructor @@ -47,7 +48,7 @@ public class AuthenticationService { private final TokenEncoder tokenEncoder; private final TokenDecoder tokenDecoder; private final BlackListTokenService blackListTokenService; - private final JpaDeviceTokenRepository deviceTokenRepository; + private final DeviceTokenRepository deviceTokenRepository; @Transactional public LoginInformationDto login( diff --git a/backend/ddang/src/main/java/com/ddang/ddang/device/application/DeviceTokenService.java b/backend/ddang/src/main/java/com/ddang/ddang/device/application/DeviceTokenService.java index 0733c5731..3377accda 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/device/application/DeviceTokenService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/device/application/DeviceTokenService.java @@ -2,7 +2,7 @@ import com.ddang.ddang.device.application.dto.PersistDeviceTokenDto; import com.ddang.ddang.device.domain.DeviceToken; -import com.ddang.ddang.device.infrastructure.persistence.JpaDeviceTokenRepository; +import com.ddang.ddang.device.domain.repository.DeviceTokenRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -15,7 +15,7 @@ @RequiredArgsConstructor public class DeviceTokenService { - private final JpaDeviceTokenRepository deviceTokenRepository; + private final DeviceTokenRepository deviceTokenRepository; private final UserRepository userRepository; @Transactional diff --git a/backend/ddang/src/main/java/com/ddang/ddang/device/domain/repository/DeviceTokenRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/device/domain/repository/DeviceTokenRepository.java new file mode 100644 index 000000000..02ce0b505 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/device/domain/repository/DeviceTokenRepository.java @@ -0,0 +1,14 @@ +package com.ddang.ddang.device.domain.repository; + +import com.ddang.ddang.device.domain.DeviceToken; + +import java.util.Optional; + +public interface DeviceTokenRepository { + + DeviceToken save(final DeviceToken deviceToken); + + Optional findByUserId(final Long userId); + + void deleteByUserId(final Long id); +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/device/infrastructure/persistence/DeviceTokenRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/device/infrastructure/persistence/DeviceTokenRepositoryImpl.java new file mode 100644 index 000000000..c9e5248d5 --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/device/infrastructure/persistence/DeviceTokenRepositoryImpl.java @@ -0,0 +1,30 @@ +package com.ddang.ddang.device.infrastructure.persistence; + +import com.ddang.ddang.device.domain.DeviceToken; +import com.ddang.ddang.device.domain.repository.DeviceTokenRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +@RequiredArgsConstructor +public class DeviceTokenRepositoryImpl implements DeviceTokenRepository { + + private final JpaDeviceTokenRepository jpaDeviceTokenRepository; + + @Override + public DeviceToken save(final DeviceToken deviceToken) { + return jpaDeviceTokenRepository.save(deviceToken); + } + + @Override + public Optional findByUserId(final Long userId) { + return jpaDeviceTokenRepository.findByUserId(userId); + } + + @Override + public void deleteByUserId(final Long id) { + jpaDeviceTokenRepository.deleteByUserId(id); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/device/infrastructure/persistence/JpaDeviceTokenRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/device/infrastructure/persistence/JpaDeviceTokenRepository.java index 13fc6f49b..f58182fde 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/device/infrastructure/persistence/JpaDeviceTokenRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/device/infrastructure/persistence/JpaDeviceTokenRepository.java @@ -9,5 +9,5 @@ public interface JpaDeviceTokenRepository extends JpaRepository findByUserId(final Long userId); - void deleteByUserId(Long id); + void deleteByUserId(final Long id); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/notification/application/FcmNotificationService.java b/backend/ddang/src/main/java/com/ddang/ddang/notification/application/FcmNotificationService.java index 8eeb9b6ef..78c8068c4 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/notification/application/FcmNotificationService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/notification/application/FcmNotificationService.java @@ -2,7 +2,7 @@ import com.ddang.ddang.device.application.exception.DeviceTokenNotFoundException; import com.ddang.ddang.device.domain.DeviceToken; -import com.ddang.ddang.device.infrastructure.persistence.JpaDeviceTokenRepository; +import com.ddang.ddang.device.domain.repository.DeviceTokenRepository; import com.ddang.ddang.notification.application.dto.CreateNotificationDto; import com.ddang.ddang.notification.domain.NotificationStatus; import com.google.firebase.messaging.AndroidConfig; @@ -27,7 +27,7 @@ public class FcmNotificationService implements NotificationService { private final FirebaseMessaging firebaseMessaging; - private final JpaDeviceTokenRepository deviceTokenRepository; + private final DeviceTokenRepository deviceTokenRepository; @Override public NotificationStatus send(final CreateNotificationDto createNotificationDto) throws FirebaseMessagingException { diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionRepositoryImplTest.java index 0486386bd..5275f26b6 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionRepositoryImplTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionRepositoryImplTest.java @@ -1,14 +1,11 @@ package com.ddang.ddang.auction.infrastructure.persistence; -import static org.assertj.core.api.Assertions.assertThat; - import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.auction.infrastructure.persistence.fixture.AuctionRepositoryImplFixture; import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; import com.querydsl.jpa.impl.JPAQueryFactory; -import java.util.Optional; import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayNameGeneration; @@ -20,6 +17,10 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Slice; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + @DataJpaTest @Import({JpaConfiguration.class, QuerydslConfiguration.class}) @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @@ -29,16 +30,13 @@ class AuctionRepositoryImplTest extends AuctionRepositoryImplFixture { @Autowired JpaAuctionRepository jpaAuctionRepository; - @Autowired - JPAQueryFactory queryFactory; - AuctionRepository auctionRepository; @BeforeEach - void setUp() { + void setUp(@Autowired final JPAQueryFactory jpaQueryFactory) { auctionRepository = new AuctionRepositoryImpl( jpaAuctionRepository, - new QuerydslAuctionRepository(queryFactory) + new QuerydslAuctionRepository(jpaQueryFactory) ); } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepositoryTest.java index d8b992ae6..915dc19f7 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepositoryTest.java @@ -29,6 +29,7 @@ class JpaAuctionRepositoryTest extends JpaAuctionRepositoryFixture { // when final Auction actual = auctionRepository.save(저장하기_전_경매_엔티티); + // then assertThat(actual.getId()).isPositive(); } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionAndImageRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionAndImageRepositoryTest.java index 2adf85696..eb4847e87 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionAndImageRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionAndImageRepositoryTest.java @@ -24,8 +24,8 @@ class QuerydslAuctionAndImageRepositoryTest extends QuerydslAuctionAndImageRepos QuerydslAuctionAndImageRepository querydslAuctionAndImageRepository; @BeforeEach - void setUp(@Autowired final JPAQueryFactory queryFactory) { - querydslAuctionAndImageRepository = new QuerydslAuctionAndImageRepository(queryFactory); + void setUp(@Autowired final JPAQueryFactory jpaQueryFactory) { + querydslAuctionAndImageRepository = new QuerydslAuctionAndImageRepository(jpaQueryFactory); } @Test diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java index f6e039530..dac3a5df0 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java @@ -38,15 +38,15 @@ @SuppressWarnings("NonAsciiCharacters") public class AuctionRepositoryImplFixture { + @Autowired + private JpaCategoryRepository categoryRepository; + private AuctionRepository auctionRepository; private UserRepository userRepository; private RegionRepository regionRepository; - @Autowired - private JpaCategoryRepository categoryRepository; - private BidRepository bidRepository; private Instant 시간 = Instant.parse("2023-07-08T22:21:20Z"); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionAndImageRepositoryFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionAndImageRepositoryFixture.java index 170011312..949634098 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionAndImageRepositoryFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/QuerydslAuctionAndImageRepositoryFixture.java @@ -12,39 +12,47 @@ import com.ddang.ddang.image.infrastructure.persistence.JpaAuctionImageRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.repository.UserRepository; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.infrastructure.persistence.UserRepositoryImpl; import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; -import java.time.LocalDateTime; -import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; +import java.time.LocalDateTime; +import java.util.List; + @SuppressWarnings("NonAsciiCharacters") public class QuerydslAuctionAndImageRepositoryFixture { @PersistenceContext private EntityManager em; - @Autowired - private JPAQueryFactory queryFactory; - - @Autowired - private JpaAuctionRepository jpaAuctionRepository; - @Autowired private JpaAuctionImageRepository auctionImageRepository; + + private UserRepository userRepository; - @Autowired - private JpaUserRepository userRepository; + private AuctionRepository auctionRepository; private User 사용자; protected Auction 경매; protected AuctionImage 경매_이미지; @BeforeEach - void setUp() { + void fixtureSetUp( + @Autowired JPAQueryFactory jpaQueryFactory, + @Autowired JpaAuctionRepository jpaAuctionRepository, + @Autowired JpaUserRepository jpaUserRepository + ) { + auctionRepository = new AuctionRepositoryImpl( + jpaAuctionRepository, + new QuerydslAuctionRepository(jpaQueryFactory) + ); + userRepository = new UserRepositoryImpl(jpaUserRepository); + 경매 = Auction.builder() .title("경매 상품 1") .description("이것은 경매 상품 1 입니다.") @@ -63,10 +71,6 @@ void setUp() { .oauthId("12345") .build(); - final AuctionRepository auctionRepository = new AuctionRepositoryImpl( - jpaAuctionRepository, - new QuerydslAuctionRepository(queryFactory) - ); auctionRepository.save(경매); userRepository.save(사용자); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java index cc952942b..5ad2d9bf6 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java @@ -1,10 +1,5 @@ package com.ddang.ddang.authentication.application; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.BDDMockito.given; - import com.ddang.ddang.authentication.application.dto.LoginInformationDto; import com.ddang.ddang.authentication.application.dto.TokenDto; import com.ddang.ddang.authentication.application.exception.InvalidWithdrawalException; @@ -17,6 +12,8 @@ import com.ddang.ddang.authentication.infrastructure.oauth2.OAuth2UserInformationProvider; import com.ddang.ddang.configuration.IsolateDatabase; import com.ddang.ddang.device.application.DeviceTokenService; +import com.ddang.ddang.device.domain.repository.DeviceTokenRepository; +import com.ddang.ddang.device.infrastructure.persistence.DeviceTokenRepositoryImpl; import com.ddang.ddang.device.infrastructure.persistence.JpaDeviceTokenRepository; import com.ddang.ddang.image.application.exception.ImageNotFoundException; import com.ddang.ddang.image.domain.repository.ProfileImageRepository; @@ -32,6 +29,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.MockBean; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; + @IsolateDatabase @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @SuppressWarnings("NonAsciiCharacters") @@ -63,15 +65,19 @@ class AuthenticationServiceTest extends AuthenticationServiceFixture { @Autowired BlackListTokenService blackListTokenService; - @Autowired - JpaDeviceTokenRepository deviceTokenRepository; + DeviceTokenRepository deviceTokenRepository; AuthenticationService authenticationService; + AuthenticationService profileImageNotFoundAuthenticationService; @BeforeEach - void fixtureSetUp(@Autowired final JpaProfileImageRepository jpaProfileImageRepository) { + void fixtureSetUp( + @Autowired final JpaProfileImageRepository jpaProfileImageRepository, + @Autowired final JpaDeviceTokenRepository jpaDeviceTokenRepository + ) { profileImageRepository = new ProfileImageRepositoryImpl(jpaProfileImageRepository); + deviceTokenRepository = new DeviceTokenRepositoryImpl(jpaDeviceTokenRepository); authenticationService = new AuthenticationService( deviceTokenService, diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java index d5e7457b1..743f83d72 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java @@ -6,6 +6,8 @@ import com.ddang.ddang.authentication.infrastructure.jwt.PrivateClaims; import com.ddang.ddang.authentication.infrastructure.oauth2.Oauth2Type; import com.ddang.ddang.device.domain.DeviceToken; +import com.ddang.ddang.device.domain.repository.DeviceTokenRepository; +import com.ddang.ddang.device.infrastructure.persistence.DeviceTokenRepositoryImpl; import com.ddang.ddang.device.infrastructure.persistence.JpaDeviceTokenRepository; import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.image.infrastructure.persistence.JpaProfileImageRepository; @@ -58,11 +60,12 @@ public class AuthenticationServiceFixture { @Autowired private TokenEncoder tokenEncoder; - @Autowired - private JpaDeviceTokenRepository deviceTokenRepository; + private DeviceTokenRepository deviceTokenRepository; @BeforeEach - void fixtureSetUp() { + void fixtureSetUp(@Autowired final JpaDeviceTokenRepository jpaDeviceTokenRepository) { + deviceTokenRepository = new DeviceTokenRepositoryImpl(jpaDeviceTokenRepository); + profileImageRepository.save(new ProfileImage("default_profile_image.png", "default_profile_image.png")); 사용자 = User.builder() diff --git a/backend/ddang/src/test/java/com/ddang/ddang/bid/infrastructure/persistence/JpaBidRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/bid/infrastructure/persistence/JpaBidRepositoryTest.java index 90af22d4c..5aafd4ece 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/bid/infrastructure/persistence/JpaBidRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/bid/infrastructure/persistence/JpaBidRepositoryTest.java @@ -25,9 +25,6 @@ @SuppressWarnings("NonAsciiCharacters") class JpaBidRepositoryTest extends JpaBidRepositoryFixture { - @PersistenceContext - EntityManager em; - @Autowired JpaBidRepository bidRepository; @@ -40,9 +37,6 @@ class JpaBidRepositoryTest extends JpaBidRepositoryFixture { final Bid actual = bidRepository.save(bid); // then - em.flush(); - em.clear(); - assertThat(actual.getId()).isPositive(); } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/bid/infrastructure/persistence/fixture/BidRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/bid/infrastructure/persistence/fixture/BidRepositoryImplFixture.java index cb36da38a..fbab9a1b0 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/bid/infrastructure/persistence/fixture/BidRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/bid/infrastructure/persistence/fixture/BidRepositoryImplFixture.java @@ -50,13 +50,13 @@ public class BidRepositoryImplFixture { @BeforeEach void fixtureSetUp( + @Autowired final JPAQueryFactory jpaQueryFactory, @Autowired final JpaUserRepository jpaUserRepository, @Autowired final JpaAuctionRepository jpaAuctionRepository, - @Autowired final JPAQueryFactory queryFactory, @Autowired final JpaBidRepository jpaBidRepository ) { userRepository = new UserRepositoryImpl(jpaUserRepository); - auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(queryFactory)); + auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(jpaQueryFactory)); bidRepository = new BidRepositoryImpl(jpaBidRepository); final ProfileImage 프로필_이미지 = new ProfileImage("프로필.jpg", "프로필.jpg"); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/JpaChatRoomRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/JpaChatRoomRepositoryTest.java index 5e5d0da01..18e656f27 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/JpaChatRoomRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/JpaChatRoomRepositoryTest.java @@ -23,11 +23,8 @@ @SuppressWarnings("NonAsciiCharacters") class JpaChatRoomRepositoryTest extends JpaChatRoomRepositoryFixture { - @PersistenceContext - EntityManager em; - @Autowired - JpaChatRoomRepository chatRoomRepository; + JpaChatRoomRepository jpaChatRoomRepository; @Test void 채팅방을_저장한다() { @@ -35,19 +32,16 @@ class JpaChatRoomRepositoryTest extends JpaChatRoomRepositoryFixture { final ChatRoom chatRoom = new ChatRoom(경매, 구매자); // when - chatRoomRepository.save(chatRoom); + jpaChatRoomRepository.save(chatRoom); // then - em.flush(); - em.clear(); - assertThat(chatRoom.getId()).isPositive(); } @Test void 지정한_아이디에_대한_채팅방을_조회한다() { // when - final Optional actual = chatRoomRepository.findById(채팅방.getId()); + final Optional actual = jpaChatRoomRepository.findById(채팅방.getId()); // then assertThat(actual).contains(채팅방); @@ -56,7 +50,7 @@ class JpaChatRoomRepositoryTest extends JpaChatRoomRepositoryFixture { @Test void 지정한_경매_아이디가_포함된_채팅방의_아이디를_조회한다() { // when - final Optional actual = chatRoomRepository.findChatRoomIdByAuctionId(경매.getId()); + final Optional actual = jpaChatRoomRepository.findChatRoomIdByAuctionId(경매.getId()); // then assertThat(actual).contains(채팅방.getId()); @@ -65,7 +59,7 @@ class JpaChatRoomRepositoryTest extends JpaChatRoomRepositoryFixture { @Test void 지정한_경매_아이디가_포함된_채팅방이_존재한다면_참을_반환한다() { // when - final boolean actual = chatRoomRepository.existsByAuctionId(경매.getId()); + final boolean actual = jpaChatRoomRepository.existsByAuctionId(경매.getId()); // then assertThat(actual).isTrue(); @@ -74,7 +68,7 @@ class JpaChatRoomRepositoryTest extends JpaChatRoomRepositoryFixture { @Test void 지정한_경매_아이디가_포함된_채팅방이_존재하지_않는다면_거짓을_반환한다() { // when - final boolean actual = chatRoomRepository.existsByAuctionId(존재하지_않는_채팅방_아이디); + final boolean actual = jpaChatRoomRepository.existsByAuctionId(존재하지_않는_채팅방_아이디); // then assertThat(actual).isFalse(); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/JpaMessageRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/JpaMessageRepositoryTest.java index c6e8cb278..0cb97b3e3 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/JpaMessageRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/JpaMessageRepositoryTest.java @@ -21,9 +21,6 @@ @SuppressWarnings("NonAsciiCharacters") class JpaMessageRepositoryTest extends JpaMessageRepositoryFixture { - @PersistenceContext - EntityManager em; - @Autowired JpaMessageRepository messageRepository; @@ -32,9 +29,6 @@ class JpaMessageRepositoryTest extends JpaMessageRepositoryFixture { // when final Message actual = messageRepository.save(메시지); - em.flush(); - em.clear(); - // then assertThat(actual.getId()).isPositive(); } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslMessageRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslMessageRepositoryTest.java index 282385a11..2c29b2691 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslMessageRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/QuerydslMessageRepositoryTest.java @@ -27,8 +27,8 @@ class QuerydslMessageRepositoryTest extends QuerydslMessageRepositoryFixture { QuerydslMessageRepository querydslMessageRepository; @BeforeEach - void setUp(@Autowired final JPAQueryFactory queryFactory) { - querydslMessageRepository = new QuerydslMessageRepository(queryFactory); + void setUp(@Autowired final JPAQueryFactory jpaQueryFactory) { + querydslMessageRepository = new QuerydslMessageRepository(jpaQueryFactory); } @Test diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndImageRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndImageRepositoryImplFixture.java index 9ffbf0839..651a16e8d 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndImageRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomAndImageRepositoryImplFixture.java @@ -35,11 +35,11 @@ @SuppressWarnings("NonAsciiCharacters") public class ChatRoomAndImageRepositoryImplFixture { - private AuctionRepository auctionRepository; - @Autowired private JpaCategoryRepository categoryRepository; + private AuctionRepository auctionRepository; + private UserRepository userRepository; private BidRepository bidRepository; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomRepositoryImplFixture.java index 9eb5becd0..826573910 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/chat/infrastructure/persistence/fixture/ChatRoomRepositoryImplFixture.java @@ -55,13 +55,13 @@ public class ChatRoomRepositoryImplFixture { @BeforeEach void fixtureSetUp( - @Autowired final JPAQueryFactory queryFactory, + @Autowired final JPAQueryFactory jpaQueryFactory, @Autowired final JpaAuctionRepository jpaAuctionRepository, @Autowired final JpaUserRepository jpaUserRepository, @Autowired final JpaChatRoomRepository jpaChatRoomRepository, @Autowired final JpaBidRepository jpaBidRepository ) { - auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(queryFactory)); + auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(jpaQueryFactory)); userRepository = new UserRepositoryImpl(jpaUserRepository); chatRoomRepository = new ChatRoomRepositoryImpl(jpaChatRoomRepository); bidRepository = new BidRepositoryImpl(jpaBidRepository); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/device/application/DeviceTokenServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/device/application/DeviceTokenServiceTest.java index 8d3b0e484..15187cd40 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/device/application/DeviceTokenServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/device/application/DeviceTokenServiceTest.java @@ -3,7 +3,7 @@ import com.ddang.ddang.configuration.IsolateDatabase; import com.ddang.ddang.device.application.fixture.DeviceTokenServiceFixture; import com.ddang.ddang.device.domain.DeviceToken; -import com.ddang.ddang.device.infrastructure.persistence.JpaDeviceTokenRepository; +import com.ddang.ddang.device.domain.repository.DeviceTokenRepository; import com.ddang.ddang.user.application.exception.UserNotFoundException; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; @@ -25,7 +25,7 @@ class DeviceTokenServiceTest extends DeviceTokenServiceFixture { DeviceTokenService deviceTokenService; @Autowired - JpaDeviceTokenRepository deviceTokenRepository; + DeviceTokenRepository deviceTokenRepository; @Test void 사용자의_디바이스_토큰이_존재하지_않는다면_저장한다() { diff --git a/backend/ddang/src/test/java/com/ddang/ddang/device/application/fixture/DeviceTokenServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/device/application/fixture/DeviceTokenServiceFixture.java index 243208fc7..e7f5a01eb 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/device/application/fixture/DeviceTokenServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/device/application/fixture/DeviceTokenServiceFixture.java @@ -2,7 +2,7 @@ import com.ddang.ddang.device.application.dto.PersistDeviceTokenDto; import com.ddang.ddang.device.domain.DeviceToken; -import com.ddang.ddang.device.infrastructure.persistence.JpaDeviceTokenRepository; +import com.ddang.ddang.device.domain.repository.DeviceTokenRepository; import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; @@ -14,10 +14,11 @@ public class DeviceTokenServiceFixture { @Autowired - private JpaDeviceTokenRepository deviceTokenRepository; + private DeviceTokenRepository deviceTokenRepository; @Autowired private UserRepository userRepository; + private String 초기_디바이스_토큰_값 = "initialDeviceToken"; private DeviceToken 사용자의_디바이스_토큰; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/device/infrastructure/persistence/DeviceTokenRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/device/infrastructure/persistence/DeviceTokenRepositoryImplTest.java new file mode 100644 index 000000000..89b3f23de --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/device/infrastructure/persistence/DeviceTokenRepositoryImplTest.java @@ -0,0 +1,63 @@ +package com.ddang.ddang.device.infrastructure.persistence; + +import com.ddang.ddang.configuration.JpaConfiguration; +import com.ddang.ddang.configuration.QuerydslConfiguration; +import com.ddang.ddang.device.domain.DeviceToken; +import com.ddang.ddang.device.domain.repository.DeviceTokenRepository; +import com.ddang.ddang.device.infrastructure.persistence.fixture.DeviceTokenRepositoryImplFixture; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@DataJpaTest +@Import({JpaConfiguration.class, QuerydslConfiguration.class}) +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +@SuppressWarnings("NonAsciiCharacters") +public class DeviceTokenRepositoryImplTest extends DeviceTokenRepositoryImplFixture { + + DeviceTokenRepository deviceTokenRepository; + + @BeforeEach + void setUp(@Autowired final JpaDeviceTokenRepository jpaDeviceTokenRepository) { + deviceTokenRepository = new DeviceTokenRepositoryImpl(jpaDeviceTokenRepository); + } + + @Test + void 기기토큰을_저장한다() { + // when + deviceTokenRepository.save(아이디가_없는_기기토큰); + + // then + assertThat(아이디가_없는_기기토큰.getId()).isPositive(); + } + + @Test + void 사용자_아이디에_해당하는_기기토큰을_조회한다() { + // when + final Optional actual = deviceTokenRepository.findByUserId(아이디가_있는_기기토큰_사용자.getId()); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).isPresent(); + softAssertions.assertThat(actual.get()).isEqualTo(아이디가_있는_기기토큰); + }); + } + + @Test + void 사용자_아이디에_해당하는_기기토큰을_삭제한다() { + // when + deviceTokenRepository.deleteByUserId(삭제할_기기토큰_사용자.getId()); + + // then + assertThat(deviceTokenRepository.findByUserId(삭제할_기기토큰_사용자.getId())).isEmpty(); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/device/infrastructure/persistence/JpaDeviceTokenRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/device/infrastructure/persistence/JpaDeviceTokenRepositoryTest.java index 06dbc3a7a..44df2f70f 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/device/infrastructure/persistence/JpaDeviceTokenRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/device/infrastructure/persistence/JpaDeviceTokenRepositoryTest.java @@ -22,12 +22,12 @@ class JpaDeviceTokenRepositoryTest extends JpaDeviceTokenRepositoryFixture { @Autowired - JpaDeviceTokenRepository userDeviceTokenRepository; + JpaDeviceTokenRepository jpaDeviceTokenRepository; @Test void 주어진_사용자_아이디에_해당하는_기기토큰을_조회한다() { // when - final Optional actual = userDeviceTokenRepository.findByUserId(사용자.getId()); + final Optional actual = jpaDeviceTokenRepository.findByUserId(사용자.getId()); // then assertThat(actual).contains(사용자의_디바이스_토큰); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/device/infrastructure/persistence/fixture/DeviceTokenRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/device/infrastructure/persistence/fixture/DeviceTokenRepositoryImplFixture.java new file mode 100644 index 000000000..d4e4e5728 --- /dev/null +++ b/backend/ddang/src/test/java/com/ddang/ddang/device/infrastructure/persistence/fixture/DeviceTokenRepositoryImplFixture.java @@ -0,0 +1,64 @@ +package com.ddang.ddang.device.infrastructure.persistence.fixture; + +import com.ddang.ddang.device.domain.DeviceToken; +import com.ddang.ddang.device.domain.repository.DeviceTokenRepository; +import com.ddang.ddang.device.infrastructure.persistence.DeviceTokenRepositoryImpl; +import com.ddang.ddang.device.infrastructure.persistence.JpaDeviceTokenRepository; +import com.ddang.ddang.image.domain.ProfileImage; +import com.ddang.ddang.user.domain.Reliability; +import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.repository.UserRepository; +import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.infrastructure.persistence.UserRepositoryImpl; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; + +@SuppressWarnings("NonAsciiCharacters") +public class DeviceTokenRepositoryImplFixture { + + private UserRepository userRepository; + private DeviceTokenRepository deviceTokenRepository; + + protected DeviceToken 아이디가_없는_기기토큰; + protected DeviceToken 아이디가_있는_기기토큰; + protected DeviceToken 삭제할_기기토큰; + protected User 아이디가_있는_기기토큰_사용자; + protected User 삭제할_기기토큰_사용자; + + @BeforeEach + void fixtureSetUp( + @Autowired final JpaUserRepository jpaUserRepository, + @Autowired final JpaDeviceTokenRepository jpaDeviceTokenRepository + ) { + userRepository = new UserRepositoryImpl(jpaUserRepository); + deviceTokenRepository = new DeviceTokenRepositoryImpl(jpaDeviceTokenRepository); + + final User 아이디가_없는_기기토큰_사용자 = User.builder() + .name("저장하지 않은 기기토큰 사용자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("98765") + .build(); + 아이디가_있는_기기토큰_사용자 = User.builder() + .name("기기토큰_사용자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); + 삭제할_기기토큰_사용자 = User.builder() + .name("삭제할 기기토큰_사용자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("14392") + .build(); + userRepository.save(아이디가_없는_기기토큰_사용자); + userRepository.save(아이디가_있는_기기토큰_사용자); + userRepository.save(삭제할_기기토큰_사용자); + + 아이디가_없는_기기토큰 = new DeviceToken(아이디가_없는_기기토큰_사용자, "아이디가 없는 기기토큰"); + 아이디가_있는_기기토큰 = new DeviceToken(아이디가_있는_기기토큰_사용자, "아이디가_있는_기기토큰"); + 삭제할_기기토큰 = new DeviceToken(삭제할_기기토큰_사용자, "삭제할_기기토큰"); + deviceTokenRepository.save(아이디가_있는_기기토큰); + deviceTokenRepository.save(삭제할_기기토큰); + } +} diff --git a/backend/ddang/src/test/java/com/ddang/ddang/device/infrastructure/persistence/fixture/JpaDeviceTokenRepositoryFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/device/infrastructure/persistence/fixture/JpaDeviceTokenRepositoryFixture.java index 128847999..1c578b432 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/device/infrastructure/persistence/fixture/JpaDeviceTokenRepositoryFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/device/infrastructure/persistence/fixture/JpaDeviceTokenRepositoryFixture.java @@ -5,7 +5,9 @@ import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; +import com.ddang.ddang.user.domain.repository.UserRepository; import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; +import com.ddang.ddang.user.infrastructure.persistence.UserRepositoryImpl; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; import org.junit.jupiter.api.BeforeEach; @@ -17,28 +19,29 @@ public class JpaDeviceTokenRepositoryFixture { @PersistenceContext private EntityManager em; - @Autowired - private JpaUserRepository userRepository; + private UserRepository userRepository; @Autowired - private JpaDeviceTokenRepository deviceTokenRepository; + private JpaDeviceTokenRepository jpaDeviceTokenRepository; protected User 사용자; protected DeviceToken 사용자의_디바이스_토큰; @BeforeEach - void setUp() { + void setUp(@Autowired final JpaUserRepository jpaUserRepository) { + userRepository = new UserRepositoryImpl(jpaUserRepository); + 사용자 = User.builder() - .name("사용자") - .profileImage(new ProfileImage("upload.png", "store.png")) - .reliability(new Reliability(4.7d)) - .oauthId("12345") - .build(); + .name("사용자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); 사용자의_디바이스_토큰 = new DeviceToken(사용자, "deviceToken"); userRepository.save(사용자); - deviceTokenRepository.save(사용자의_디바이스_토큰); + jpaDeviceTokenRepository.save(사용자의_디바이스_토큰); em.flush(); em.clear(); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java index 686c9b2a4..5d3a217b8 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/FcmNotificationServiceFixture.java @@ -12,7 +12,7 @@ import com.ddang.ddang.chat.domain.repository.ChatRoomRepository; import com.ddang.ddang.chat.domain.repository.MessageRepository; import com.ddang.ddang.device.domain.DeviceToken; -import com.ddang.ddang.device.infrastructure.persistence.JpaDeviceTokenRepository; +import com.ddang.ddang.device.domain.repository.DeviceTokenRepository; import com.ddang.ddang.image.domain.AuctionImage; import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.image.infrastructure.persistence.JpaAuctionImageRepository; @@ -40,7 +40,7 @@ public class FcmNotificationServiceFixture { private ChatRoomRepository chatRoomRepository; @Autowired - private JpaDeviceTokenRepository deviceTokenRepository; + private DeviceTokenRepository deviceTokenRepository; @Autowired private AuctionRepository auctionRepository; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/AnswerRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/AnswerRepositoryImplFixture.java index 44cac6457..8ad80f28d 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/AnswerRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/AnswerRepositoryImplFixture.java @@ -47,14 +47,14 @@ public class AnswerRepositoryImplFixture { @BeforeEach void setUpFixture( + @Autowired final JPAQueryFactory jpaQueryFactory, @Autowired final JpaUserRepository jpaUserRepository, @Autowired final JpaAuctionRepository jpaAuctionRepository, - @Autowired final JPAQueryFactory queryFactory, @Autowired final JpaQuestionRepository jpaQuestionRepository, @Autowired final JpaAnswerRepository jpaAnswerRepository ) { userRepository = new UserRepositoryImpl(jpaUserRepository); - auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(queryFactory)); + auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(jpaQueryFactory)); questionRepository = new QuestionRepositoryImpl(jpaQuestionRepository); answerRepository = new AnswerRepositoryImpl(jpaAnswerRepository); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/ChatRoomReportRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/ChatRoomReportRepositoryImplTest.java index 01b72d001..8b76d3c3d 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/ChatRoomReportRepositoryImplTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/ChatRoomReportRepositoryImplTest.java @@ -33,6 +33,7 @@ void setUp(@Autowired final JpaChatRoomReportRepository jpaChatRoomReportReposit @Test void 채팅방_신고를_저장한다() { + // given final ChatRoomReport chatRoomReport = new ChatRoomReport(구매자1, 채팅방1, "신고합니다."); // when diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/JpaChatRoomReportRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/JpaChatRoomReportRepositoryTest.java index 89ab87322..8030b4a76 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/JpaChatRoomReportRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/JpaChatRoomReportRepositoryTest.java @@ -27,6 +27,7 @@ class JpaChatRoomReportRepositoryTest extends JpaChatRoomReportRepositoryFixture @Test void 채팅방_신고를_저장한다() { + // given final ChatRoomReport chatRoomReport = new ChatRoomReport(구매자1, 채팅방1, "신고합니다."); // when diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/QuestionReportRepositoryImplImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/QuestionReportRepositoryImplTest.java similarity index 100% rename from backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/QuestionReportRepositoryImplImplTest.java rename to backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/QuestionReportRepositoryImplTest.java diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/AuctionReportRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/AuctionReportRepositoryImplFixture.java index ff317c0a3..89b9153b6 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/AuctionReportRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/AuctionReportRepositoryImplFixture.java @@ -58,13 +58,13 @@ public class AuctionReportRepositoryImplFixture { @BeforeEach void setUpFixture( + @Autowired final JPAQueryFactory jpaQueryFactory, @Autowired final JpaUserRepository jpaUserRepository, @Autowired final JpaAuctionRepository jpaAuctionRepository, - @Autowired final JPAQueryFactory queryFactory, @Autowired final JpaAuctionReportRepository jpaAuctionReportRepository ) { userRepository = new UserRepositoryImpl(jpaUserRepository); - auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(queryFactory)); + auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(jpaQueryFactory)); auctionReportRepository = new AuctionReportRepositoryImpl(jpaAuctionReportRepository); final ProfileImage 프로필_이미지 = new ProfileImage("프로필.jpg", "프로필.jpg"); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/JpaQuestionReportRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/JpaQuestionReportRepositoryImplFixture.java index 1c975e1d0..06f52d338 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/JpaQuestionReportRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/JpaQuestionReportRepositoryImplFixture.java @@ -37,16 +37,16 @@ public class JpaQuestionReportRepositoryImplFixture { @PersistenceContext private EntityManager em; - private UserRepository userRepository; - @Autowired private JpaCategoryRepository categoryRepository; - private AuctionRepository auctionRepository; - @Autowired private JpaQuestionRepository questionRepository; + private UserRepository userRepository; + + private AuctionRepository auctionRepository; + private QuestionReportRepository questionReportRepository; protected User 신고자; @@ -60,13 +60,13 @@ public class JpaQuestionReportRepositoryImplFixture { @BeforeEach void setUpFixture( + @Autowired final JPAQueryFactory jpaQueryFactory, @Autowired final JpaUserRepository jpaUserRepository, @Autowired final JpaAuctionRepository jpaAuctionRepository, - @Autowired final JPAQueryFactory queryFactory, @Autowired final JpaQuestionReportRepository jpaQuestionReportRepository ) { userRepository = new UserRepositoryImpl(jpaUserRepository); - auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(queryFactory)); + auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(jpaQueryFactory)); questionReportRepository = new QuestionReportRepositoryImpl(jpaQuestionReportRepository); final ProfileImage 프로필_이미지 = new ProfileImage("프로필.jpg", "프로필.jpg"); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/QuestionReportRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/QuestionReportRepositoryImplFixture.java index 1e820ddcc..458fe7f2e 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/QuestionReportRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/QuestionReportRepositoryImplFixture.java @@ -55,13 +55,13 @@ public class QuestionReportRepositoryImplFixture { @BeforeEach void setUpFixture( + @Autowired final JPAQueryFactory jpaQueryFactory, @Autowired final JpaUserRepository jpaUserRepository, @Autowired final JpaAuctionRepository jpaAuctionRepository, - @Autowired final JPAQueryFactory queryFactory, @Autowired final JpaQuestionReportRepository jpaQuestionReportRepository ) { userRepository = new UserRepositoryImpl(jpaUserRepository); - auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(queryFactory)); + auctionRepository = new AuctionRepositoryImpl(jpaAuctionRepository, new QuerydslAuctionRepository(jpaQueryFactory)); questionReportRepository = new QuestionReportRepositoryImpl(jpaQuestionReportRepository); final ProfileImage 프로필_이미지 = new ProfileImage("프로필.jpg", "프로필.jpg"); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/review/infrastructure/persistence/JpaReviewRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/review/infrastructure/persistence/JpaReviewRepositoryTest.java index d48cd257d..a4f86c7d3 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/review/infrastructure/persistence/JpaReviewRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/review/infrastructure/persistence/JpaReviewRepositoryTest.java @@ -25,28 +25,22 @@ @SuppressWarnings("NonAsciiCharacters") class JpaReviewRepositoryTest extends JpaReviewRepositoryFixture { - @PersistenceContext - EntityManager em; - @Autowired - JpaReviewRepository reviewRepository; + JpaReviewRepository jpaReviewRepository; @Test void 평가를_저장한다() { // when - reviewRepository.save(저장하려는_평가); + jpaReviewRepository.save(저장하려는_평가); // then - em.flush(); - em.clear(); - assertThat(저장하려는_평가.getId()).isPositive(); } @Test void 지정한_경매_아이디와_작성자_아이디를_포함하는_평가가_존재하면_참을_반환한다() { // when - final boolean actual = reviewRepository.existsByAuctionIdAndWriterId(판매자1이_평가한_경매.getId(), 판매자1.getId()); + final boolean actual = jpaReviewRepository.existsByAuctionIdAndWriterId(판매자1이_평가한_경매.getId(), 판매자1.getId()); // then assertThat(actual).isTrue(); @@ -55,7 +49,7 @@ class JpaReviewRepositoryTest extends JpaReviewRepositoryFixture { @Test void 지정한_채팅방_아이디를_포함하는_평가가_존재하지_않는다면_거짓을_반환한다() { // when - final boolean actual = reviewRepository.existsByAuctionIdAndWriterId(평가_안한_경매.getId(), 평가_안한_경매_판매자.getId()); + final boolean actual = jpaReviewRepository.existsByAuctionIdAndWriterId(평가_안한_경매.getId(), 평가_안한_경매_판매자.getId()); // then assertThat(actual).isFalse(); @@ -64,7 +58,7 @@ class JpaReviewRepositoryTest extends JpaReviewRepositoryFixture { @Test void 지정한_아이디가_평가_대상_아이디에_해당하는_평가_목록을_최신순으로_조회한다() { // when - final List actual = reviewRepository.findAllByTargetId(구매자.getId()); + final List actual = jpaReviewRepository.findAllByTargetId(구매자.getId()); // then SoftAssertions.assertSoftly(softAssertions -> { @@ -78,7 +72,7 @@ class JpaReviewRepositoryTest extends JpaReviewRepositoryFixture { void 지정한_경매_아이디와_작성자_아이디가_해당하는_평가가_존재한다면_optional에_넣어_반환한다() { // when final Optional actual = - reviewRepository.findByAuctionIdAndWriterId(판매자1이_평가한_경매.getId(), 판매자1.getId()); + jpaReviewRepository.findByAuctionIdAndWriterId(판매자1이_평가한_경매.getId(), 판매자1.getId()); // then assertThat(actual).contains(구매자가_판매자1에게_받은_평가); @@ -88,7 +82,7 @@ class JpaReviewRepositoryTest extends JpaReviewRepositoryFixture { void 지정한_경매_아이디와_작성자_아이디가_해당하는_평가가_존재하지_않는다면_빈_optional을_반환한다() { // when final Optional actual = - reviewRepository.findByAuctionIdAndWriterId(평가_안한_경매.getId(), 평가_안한_경매_판매자.getId()); + jpaReviewRepository.findByAuctionIdAndWriterId(평가_안한_경매.getId(), 평가_안한_경매_판매자.getId()); // then assertThat(actual).isEmpty(); @@ -97,7 +91,7 @@ class JpaReviewRepositoryTest extends JpaReviewRepositoryFixture { @Test void 지정한_평가_아이디보다_아이디가_큰_평가_목록을_조회한다() { // when - final List actual = reviewRepository.findAllByIdGreaterThan(구매자가_판매자1에게_받은_평가.getId()); + final List actual = jpaReviewRepository.findAllByIdGreaterThan(구매자가_판매자1에게_받은_평가.getId()); // then SoftAssertions.assertSoftly(softAssertions -> { diff --git a/backend/ddang/src/test/java/com/ddang/ddang/review/infrastructure/persistence/fixture/JpaReviewRepositoryFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/review/infrastructure/persistence/fixture/JpaReviewRepositoryFixture.java index fae340ff0..214a2ac84 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/review/infrastructure/persistence/fixture/JpaReviewRepositoryFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/review/infrastructure/persistence/fixture/JpaReviewRepositoryFixture.java @@ -40,7 +40,6 @@ public class JpaReviewRepositoryFixture { @Autowired private JpaReviewRepository reviewRepository; - protected User 판매자1; protected User 판매자2; protected User 평가_안한_경매_판매자; From d8096cfe03ca0447d87dbd2169f60b2f8b728a63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=9C=EC=9D=B4=EB=AF=B8?= <63184334+JJ503@users.noreply.github.com> Date: Mon, 16 Oct 2023 01:57:55 +0900 Subject: [PATCH 31/37] =?UTF-8?q?refactor:=20#697=20=EC=A7=88=EB=AC=B8?= =?UTF-8?q?=EA=B3=BC=20=EB=8B=B5=EB=B3=80=20=EC=A1=B0=ED=9A=8C=20=EC=8B=9C?= =?UTF-8?q?=20=EC=82=AD=EC=A0=9C=EB=90=9C=20=EB=8B=B5=EB=B3=80=EC=9D=80=20?= =?UTF-8?q?=EB=B3=B4=EC=9D=B4=EC=A7=80=20=EC=95=8A=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#698)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test: 질문이 삭제된 경우 조회되지 않음을 나타내는 테스트 추가 * refactor: 답변이 삭제된 경우 null이 반환되도록 수정 --- .../dto/response/ReadQnaResponse.java | 2 +- .../qna/application/dto/ReadAnswerDto.java | 7 +++- .../qna/application/dto/ReadQuestionDto.java | 2 + .../AuctionQuestionControllerFixture.java | 8 ++-- .../fixture/QuestionServiceFixture.java | 10 ++--- .../JpaQuestionRepositoryTest.java | 15 ++++++++ .../fixture/JpaQuestionRepositoryFixture.java | 38 +++++++++++++++++-- 7 files changed, 67 insertions(+), 15 deletions(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadQnaResponse.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadQnaResponse.java index dd71a5eca..c5d2d82e3 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadQnaResponse.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadQnaResponse.java @@ -16,7 +16,7 @@ public static ReadQnaResponse from(final ReadQnaDto readQnaDto) { } private static ReadAnswerResponse processReadAnswerResponse(final ReadAnswerDto readAnswerDto) { - if (readAnswerDto == null) { + if (readAnswerDto.isDeleted()) { return null; } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadAnswerDto.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadAnswerDto.java index d7739bf11..01b576735 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadAnswerDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadAnswerDto.java @@ -9,14 +9,17 @@ public record ReadAnswerDto( Long id, ReadUserInQnaDto writerDto, String content, - LocalDateTime createdTime + LocalDateTime createdTime, + boolean isDeleted ) { + public static ReadAnswerDto from(final Answer answer, final User writer) { return new ReadAnswerDto( answer.getId(), ReadUserInQnaDto.from(writer), answer.getContent(), - answer.getCreatedTime() + answer.getCreatedTime(), + answer.isDeleted() ); } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadQuestionDto.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadQuestionDto.java index 07123720f..6f13fe347 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadQuestionDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/ReadQuestionDto.java @@ -10,6 +10,7 @@ public record ReadQuestionDto( ReadUserInQnaDto readUserInQnaDto, String content, LocalDateTime createdTime, + boolean isDeleted, boolean isQuestioner ) { @@ -21,6 +22,7 @@ public static ReadQuestionDto of(final Question question, final User user) { ReadUserInQnaDto.from(question.getWriter()), question.getContent(), question.getCreatedTime(), + question.isDeleted(), isWriter(question, user) ); } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/presentation/fixture/AuctionQuestionControllerFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/presentation/fixture/AuctionQuestionControllerFixture.java index 19f240ede..588ae7036 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/presentation/fixture/AuctionQuestionControllerFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/presentation/fixture/AuctionQuestionControllerFixture.java @@ -34,10 +34,10 @@ public class AuctionQuestionControllerFixture extends CommonControllerSliceTest "12346", false ); - protected ReadQuestionDto 질문_정보_dto1 = new ReadQuestionDto(1L, 질문자_정보_dto, "질문1", LocalDateTime.now(), false); - protected ReadQuestionDto 질문_정보_dto2 = new ReadQuestionDto(2L, 질문자_정보_dto, "질문2", LocalDateTime.now(), false); - protected ReadAnswerDto 답변_정보_dto1 = new ReadAnswerDto(1L, 판매자_정보_dto, "답변1", LocalDateTime.now()); - protected ReadAnswerDto 답변_정보_dto2 = new ReadAnswerDto(2L, 판매자_정보_dto, "답변1", LocalDateTime.now()); + protected ReadQuestionDto 질문_정보_dto1 = new ReadQuestionDto(1L, 질문자_정보_dto, "질문1", LocalDateTime.now(), false, false); + protected ReadQuestionDto 질문_정보_dto2 = new ReadQuestionDto(2L, 질문자_정보_dto, "질문2", LocalDateTime.now(), false, false); + protected ReadAnswerDto 답변_정보_dto1 = new ReadAnswerDto(1L, 판매자_정보_dto, "답변1", LocalDateTime.now(), false); + protected ReadAnswerDto 답변_정보_dto2 = new ReadAnswerDto(2L, 판매자_정보_dto, "답변1", LocalDateTime.now(), false); private ReadQnaDto 질문과_답변_정보_dto1 = new ReadQnaDto(질문_정보_dto1, 답변_정보_dto1); private ReadQnaDto 질문과_답변_정보_dto2 = new ReadQnaDto(질문_정보_dto2, 답변_정보_dto2); protected ReadQnasDto 질문과_답변_정보들_dto = diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java index ac73432f8..8f5ff4471 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java @@ -183,10 +183,10 @@ void setUp() { final ReadUserInQnaDto 판매자_정보_dto = ReadUserInQnaDto.from(판매자); final ReadUserInQnaDto 질문자_정보_dto = ReadUserInQnaDto.from(질문자); final ReadUserInQnaDto 두번째_질문자_정보_dto = ReadUserInQnaDto.from(두번째_질문을_작성한_사용자); - 질문_정보_dto1 = new ReadQuestionDto(질문.getId(), 질문자_정보_dto, 질문.getContent(), 질문.getCreatedTime(), false); - 질문_정보_dto2 = new ReadQuestionDto(질문2.getId(), 두번째_질문자_정보_dto, 질문2.getContent(), 질문2.getCreatedTime(), true); - 질문_정보_dto3 = new ReadQuestionDto(질문3.getId(), 질문자_정보_dto, 질문3.getContent(), 질문3.getCreatedTime(), false); - 답변_정보_dto1 = new ReadAnswerDto(답변1.getId(), 판매자_정보_dto, 답변1.getContent(), 답변1.getCreatedTime()); - 답변_정보_dto2 = new ReadAnswerDto(답변2.getId(), 판매자_정보_dto, 답변2.getContent(), 답변2.getCreatedTime()); + 질문_정보_dto1 = new ReadQuestionDto(질문.getId(), 질문자_정보_dto, 질문.getContent(), 질문.getCreatedTime(), false, false); + 질문_정보_dto2 = new ReadQuestionDto(질문2.getId(), 두번째_질문자_정보_dto, 질문2.getContent(), 질문2.getCreatedTime(), false, true); + 질문_정보_dto3 = new ReadQuestionDto(질문3.getId(), 질문자_정보_dto, 질문3.getContent(), 질문3.getCreatedTime(), false, false); + 답변_정보_dto1 = new ReadAnswerDto(답변1.getId(), 판매자_정보_dto, 답변1.getContent(), 답변1.getCreatedTime(), false); + 답변_정보_dto2 = new ReadAnswerDto(답변2.getId(), 판매자_정보_dto, 답변2.getContent(), 답변2.getCreatedTime(), false); } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/JpaQuestionRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/JpaQuestionRepositoryTest.java index f3ff3c557..ee99840a2 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/JpaQuestionRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/JpaQuestionRepositoryTest.java @@ -72,4 +72,19 @@ class JpaQuestionRepositoryTest extends JpaQuestionRepositoryFixture { softAssertions.assertThat(actual.get(2).getAnswer()).isNull(); }); } + + @Test + void 경매_아이디를_통해_질문과_답변_조회시_질문이_삭제된_경우_답변이_있더라도_함꼐_조회되지_않는다() { + // when + final List actual = questionRepository.findAllByAuctionId(질문이_3개_답변이_2개중_첫번째_질문이_삭제된_경매.getId()); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual).hasSize(2); + softAssertions.assertThat(actual.get(0)).isEqualTo(삭제되지_않은_질문2); + softAssertions.assertThat(actual.get(0).getAnswer()).isEqualTo(삭제되지_않은_질문의_답변2); + softAssertions.assertThat(actual.get(1)).isEqualTo(답변이_없는_질문3); + softAssertions.assertThat(actual.get(1).getAnswer()).isNull(); + }); + } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/JpaQuestionRepositoryFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/JpaQuestionRepositoryFixture.java index 40a7ceeda..584541f92 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/JpaQuestionRepositoryFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/JpaQuestionRepositoryFixture.java @@ -40,14 +40,21 @@ public class JpaQuestionRepositoryFixture { protected Auction 경매; protected Auction 질문이_3개_답변이_2개인_경매; + protected Auction 질문이_3개_답변이_2개중_첫번째_질문이_삭제된_경매; + protected Auction 질문이_3개_답변이_2개중_첫번째_답변이_삭제된_경매; protected User 질문자; protected String 질문_내용 = "궁금한 점이 있어요."; protected Question 질문1; protected Question 질문2; protected Question 질문3; + protected Question 삭제된_질문1; + protected Question 삭제되지_않은_질문2; + protected Question 답변이_없는_질문3; protected Question 삭제된_질문; protected Answer 답변1; protected Answer 답변2; + protected Answer 삭제된_질문의_답변1; + protected Answer 삭제되지_않은_질문의_답변2; @BeforeEach void setUp() { @@ -74,6 +81,22 @@ void setUp() { .startPrice(new Price(1_000)) .closingTime(LocalDateTime.now()) .build(); + 질문이_3개_답변이_2개중_첫번째_질문이_삭제된_경매 = Auction.builder() + .seller(판매자) + .title("경매 상품") + .description("이것은 경매 상품입니다.") + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(LocalDateTime.now()) + .build(); + 질문이_3개_답변이_2개중_첫번째_답변이_삭제된_경매 = Auction.builder() + .seller(판매자) + .title("경매 상품") + .description("이것은 경매 상품입니다.") + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(LocalDateTime.now()) + .build(); 질문자 = User.builder() .name("질문자") .profileImage(프로필_이미지) @@ -89,13 +112,22 @@ void setUp() { 질문1.addAnswer(답변1); 질문2.addAnswer(답변2); + 삭제된_질문1 = new Question(질문이_3개_답변이_2개중_첫번째_질문이_삭제된_경매, 질문자, "질문1"); + 삭제되지_않은_질문2 = new Question(질문이_3개_답변이_2개중_첫번째_질문이_삭제된_경매, 질문자, "질문2"); + 답변이_없는_질문3 = new Question(질문이_3개_답변이_2개중_첫번째_질문이_삭제된_경매, 질문자, "질문3"); + 삭제된_질문의_답변1 = new Answer("삭제된 질문의 답변"); + 삭제되지_않은_질문의_답변2 = new Answer("삭제되지 않은 질문의 답변2"); + 삭제된_질문1.addAnswer(삭제된_질문의_답변1); + 삭제된_질문1.delete(); + 삭제되지_않은_질문2.addAnswer(삭제되지_않은_질문의_답변2); + 삭제된_질문 = new Question(경매, 질문자, "질문3"); 삭제된_질문.delete(); userRepository.saveAll(List.of(판매자, 질문자)); - auctionRepository.saveAll(List.of(경매, 질문이_3개_답변이_2개인_경매)); - questionRepository.saveAll(List.of(질문1, 질문2, 질문3, 삭제된_질문)); - answerRepository.saveAll(List.of(답변1, 답변2)); + auctionRepository.saveAll(List.of(경매, 질문이_3개_답변이_2개인_경매, 질문이_3개_답변이_2개중_첫번째_질문이_삭제된_경매, 질문이_3개_답변이_2개중_첫번째_답변이_삭제된_경매)); + questionRepository.saveAll(List.of(질문1, 질문2, 질문3, 삭제된_질문, 삭제된_질문1, 삭제되지_않은_질문2, 답변이_없는_질문3)); + answerRepository.saveAll(List.of(답변1, 답변2, 삭제된_질문의_답변1, 삭제되지_않은_질문의_답변2)); em.flush(); em.clear(); From 937b365a2240b8b1e19c89f674358c4581fbf969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=9C=EC=9D=B4=EB=AF=B8?= <63184334+JJ503@users.noreply.github.com> Date: Mon, 16 Oct 2023 15:57:57 +0900 Subject: [PATCH 32/37] =?UTF-8?q?fix:=20=EB=8B=B5=EB=B3=80=EC=9D=B4=20null?= =?UTF-8?q?=EC=9D=B8=20=EA=B2=BD=EC=9A=B0=EC=97=90=20=EB=8C=80=ED=95=9C=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80=20(#700)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auction/presentation/dto/response/ReadQnaResponse.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadQnaResponse.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadQnaResponse.java index c5d2d82e3..25a6ae9a1 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadQnaResponse.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadQnaResponse.java @@ -16,7 +16,7 @@ public static ReadQnaResponse from(final ReadQnaDto readQnaDto) { } private static ReadAnswerResponse processReadAnswerResponse(final ReadAnswerDto readAnswerDto) { - if (readAnswerDto.isDeleted()) { + if (readAnswerDto == null || readAnswerDto.isDeleted()) { return null; } From 19520512eecbaa70af5e47f6b5cd96e664a93181 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=9C=EC=9D=B4=EB=AF=B8?= <63184334+JJ503@users.noreply.github.com> Date: Mon, 16 Oct 2023 19:11:56 +0900 Subject: [PATCH 33/37] =?UTF-8?q?feat:=20#573=20=ED=83=88=ED=87=B4=20?= =?UTF-8?q?=EC=8B=9C=20=EC=82=AC=EC=9A=A9=EC=9E=90=20=EB=8B=89=EB=84=A4?= =?UTF-8?q?=EC=9E=84=20=EB=9E=9C=EB=8D=A4=20=EA=B0=92=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#606)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 탈퇴 시 닉네임을 랜덤 UUID로 변경하는 로직 추가 * feat: 탈퇴 시 프로필 이미지 삭제 기능 추가 * refactor: 가입 시 이미지를 기본 이미지가 아닌 null로 전달 * feat: 프로필 이미지 아이디가 null이라면 기본 이미지 url을 반환 기능 추가 * refactor: import 와일드카드 제거 * feat: 이미지가 null인 경우 기본 이미지를 반환하는 기능 추가 * test: 픽스처 네이밍을 명확하게 수정 * fix: 충돌 문제 해결 --- .../presentation/AuctionController.java | 6 +-- .../application/AuthenticationService.java | 12 ------ .../ddang/image/domain/ProfileImage.java | 2 + .../presentation/util/ImageRelativeUrl.java | 4 ++ .../presentation/util/ImageUrlCalculator.java | 11 ++++- .../com/ddang/ddang/user/domain/User.java | 7 +++- .../db/migration/V19__alter_user_tables.sql | 1 + .../AuthenticationServiceTest.java | 38 +++-------------- .../fixture/AuthenticationServiceFixture.java | 2 + .../util/ImageUrlCalculatorTest.java | 42 ++++++++++++++++++- .../fixture/ImageUrlCalculatorFixture.java | 13 ++++-- .../com/ddang/ddang/user/domain/UserTest.java | 9 +++- 12 files changed, 91 insertions(+), 56 deletions(-) create mode 100644 backend/ddang/src/main/resources/db/migration/V19__alter_user_tables.sql diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/AuctionController.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/AuctionController.java index fa3dad2fd..fa69bc062 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/AuctionController.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/AuctionController.java @@ -16,8 +16,6 @@ import com.ddang.ddang.authentication.domain.dto.AuthenticationUserInfo; import com.ddang.ddang.chat.application.ChatRoomService; import jakarta.validation.Valid; -import java.net.URI; -import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; @@ -29,7 +27,9 @@ import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; -import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import java.net.URI; +import java.util.List; @RestController @RequestMapping("/auctions") diff --git a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java index 47df37458..81daab852 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java @@ -17,9 +17,6 @@ import com.ddang.ddang.device.application.DeviceTokenService; import com.ddang.ddang.device.application.dto.PersistDeviceTokenDto; import com.ddang.ddang.device.domain.repository.DeviceTokenRepository; -import com.ddang.ddang.image.application.exception.ImageNotFoundException; -import com.ddang.ddang.image.domain.ProfileImage; -import com.ddang.ddang.image.domain.repository.ProfileImageRepository; import com.ddang.ddang.user.domain.Reliability; import com.ddang.ddang.user.domain.User; import com.ddang.ddang.user.domain.repository.UserRepository; @@ -31,8 +28,6 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; -import static com.ddang.ddang.image.domain.ProfileImage.DEFAULT_PROFILE_IMAGE_STORE_NAME; - @Service @Transactional(readOnly = true) @RequiredArgsConstructor @@ -44,7 +39,6 @@ public class AuthenticationService { private final DeviceTokenService deviceTokenService; private final Oauth2UserInformationProviderComposite providerComposite; private final UserRepository userRepository; - private final ProfileImageRepository profileImageRepository; private final TokenEncoder tokenEncoder; private final TokenDecoder tokenDecoder; private final BlackListTokenService blackListTokenService; @@ -83,7 +77,6 @@ private LoginUserInformationDto findOrPersistUser( .name(oauth2Type.calculateNickname( calculateRandomNumber()) ) - .profileImage(findDefaultProfileImage()) .reliability(INITIALIZE_USER_RELIABILITY) .oauthId(userInformationDto.findUserId()) .oauth2Type(oauth2Type) @@ -96,11 +89,6 @@ private LoginUserInformationDto findOrPersistUser( return new LoginUserInformationDto(signInUser, isSignUpUser.get()); } - private ProfileImage findDefaultProfileImage() { - return profileImageRepository.findByStoreName(DEFAULT_PROFILE_IMAGE_STORE_NAME) - .orElseThrow(() -> new ImageNotFoundException("기본 이미지를 찾을 수 없습니다.")); - } - private String calculateRandomNumber() { String name = RandomNameGenerator.generate(); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/image/domain/ProfileImage.java b/backend/ddang/src/main/java/com/ddang/ddang/image/domain/ProfileImage.java index e45936a8c..d85c01c1e 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/image/domain/ProfileImage.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/image/domain/ProfileImage.java @@ -19,6 +19,8 @@ public class ProfileImage { public static final String DEFAULT_PROFILE_IMAGE_STORE_NAME = "default_profile_image.png"; + // TODO: 10/13/23 앞으로 id가 아닌 store name으로 진행하기로 했는데, 임시로 해둡니다. 추후 삭제해주시면 감사하겠습니다. + public static final String DEFAULT_PROFILE_IMAGE_ID = "1"; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/backend/ddang/src/main/java/com/ddang/ddang/image/presentation/util/ImageRelativeUrl.java b/backend/ddang/src/main/java/com/ddang/ddang/image/presentation/util/ImageRelativeUrl.java index 7fa5603ea..854b6f813 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/image/presentation/util/ImageRelativeUrl.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/image/presentation/util/ImageRelativeUrl.java @@ -20,4 +20,8 @@ public String calculateAbsoluteUrl() { return imageBaseUrl + value; } + + public String getValue() { + return value; + } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/image/presentation/util/ImageUrlCalculator.java b/backend/ddang/src/main/java/com/ddang/ddang/image/presentation/util/ImageUrlCalculator.java index f2a0b8759..374a03459 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/image/presentation/util/ImageUrlCalculator.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/image/presentation/util/ImageUrlCalculator.java @@ -1,18 +1,27 @@ package com.ddang.ddang.image.presentation.util; +import com.ddang.ddang.image.domain.ProfileImage; + public final class ImageUrlCalculator { private ImageUrlCalculator() { } - // TODO: 9/29/23 id 타입을 long으로 변경 및 이미지는 null이 되는 경우가 없도록 할 것 public static String calculateBy(final ImageRelativeUrl imageRelativeUrl, final Long id) { final String absoluteUrl = imageRelativeUrl.calculateAbsoluteUrl(); + if (id == null && imageRelativeUrl == ImageRelativeUrl.USER) { + return absoluteUrl + ProfileImage.DEFAULT_PROFILE_IMAGE_ID; + } + return absoluteUrl + id; } public static String calculateBy(final String imageAbsoluteUrl, final Long id) { + if (id == null && imageAbsoluteUrl.contains(ImageRelativeUrl.USER.getValue())) { + return imageAbsoluteUrl + ProfileImage.DEFAULT_PROFILE_IMAGE_ID; + } + return imageAbsoluteUrl + id; } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/User.java b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/User.java index 629a87a69..c6fe79755 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/User.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/User.java @@ -23,6 +23,9 @@ import lombok.NoArgsConstructor; import lombok.ToString; +import java.util.List; +import java.util.UUID; + @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter @@ -43,7 +46,7 @@ public class User extends BaseTimeEntity { private String name; @OneToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.REMOVE}) - @JoinColumn(name = "profile_image_id", foreignKey = @ForeignKey(name = "fk_user_profile_image"), nullable = false) + @JoinColumn(name = "profile_image_id", foreignKey = @ForeignKey(name = "fk_user_profile_image")) private ProfileImage profileImage; @Embedded @@ -88,6 +91,8 @@ public void updateProfileImage(final ProfileImage profileImage) { public void withdrawal() { this.deleted = DELETED_STATUS; + this.name = UUID.randomUUID().toString(); + this.profileImage = null; } public void updateReliability(final Reliability reliability) { diff --git a/backend/ddang/src/main/resources/db/migration/V19__alter_user_tables.sql b/backend/ddang/src/main/resources/db/migration/V19__alter_user_tables.sql new file mode 100644 index 000000000..1a844adae --- /dev/null +++ b/backend/ddang/src/main/resources/db/migration/V19__alter_user_tables.sql @@ -0,0 +1 @@ +ALTER TABLE users MODIFY profile_image_id bigint; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java index 5ad2d9bf6..a038bb3d5 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java @@ -15,17 +15,15 @@ import com.ddang.ddang.device.domain.repository.DeviceTokenRepository; import com.ddang.ddang.device.infrastructure.persistence.DeviceTokenRepositoryImpl; import com.ddang.ddang.device.infrastructure.persistence.JpaDeviceTokenRepository; -import com.ddang.ddang.image.application.exception.ImageNotFoundException; import com.ddang.ddang.image.domain.repository.ProfileImageRepository; import com.ddang.ddang.image.infrastructure.persistence.JpaProfileImageRepository; import com.ddang.ddang.image.infrastructure.persistence.ProfileImageRepositoryImpl; import com.ddang.ddang.user.domain.repository.UserRepository; -import org.assertj.core.api.SoftAssertions; +import org.assertj.core.api.*; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; -import org.mockito.Mock; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.MockBean; @@ -39,9 +37,6 @@ @SuppressWarnings("NonAsciiCharacters") class AuthenticationServiceTest extends AuthenticationServiceFixture { - @Mock - ProfileImageRepository defaultProfileImageRepository; - @MockBean Oauth2UserInformationProviderComposite providerComposite; @@ -69,8 +64,6 @@ class AuthenticationServiceTest extends AuthenticationServiceFixture { AuthenticationService authenticationService; - AuthenticationService profileImageNotFoundAuthenticationService; - @BeforeEach void fixtureSetUp( @Autowired final JpaProfileImageRepository jpaProfileImageRepository, @@ -83,17 +76,6 @@ void fixtureSetUp( deviceTokenService, providerComposite, userRepository, - profileImageRepository, - tokenEncoder, - tokenDecoder, - blackListTokenService, - deviceTokenRepository - ); - profileImageNotFoundAuthenticationService = new AuthenticationService( - deviceTokenService, - providerComposite, - userRepository, - defaultProfileImageRepository, tokenEncoder, tokenDecoder, blackListTokenService, @@ -142,18 +124,6 @@ void fixtureSetUp( }); } - @Test - void 가입하지_않은_회원이_소셜_로그인을_할_때_기본_프로필_이미지를_찾을_수_없으면_예외가_발생한다() { - // given - given(providerComposite.findProvider(지원하는_소셜_로그인_타입)).willReturn(userInfoProvider); - given(userInfoProvider.findUserInformation(anyString())).willReturn(가입하지_않은_사용자_회원_정보); - - // when & then - assertThatThrownBy(() -> profileImageNotFoundAuthenticationService.login(지원하는_소셜_로그인_타입, 유효한_소셜_로그인_토큰, 디바이스_토큰)) - .isInstanceOf(ImageNotFoundException.class) - .hasMessage("기본 이미지를 찾을 수 없습니다."); - } - @Test void 가입하지_않은_사용자가_소셜_로그인을_할_경우_accessToken과_refreshToken을_반환한다() { // given @@ -244,7 +214,11 @@ void fixtureSetUp( authenticationService.withdrawal(유효한_액세스_토큰, 유효한_리프레시_토큰); // then - assertThat(사용자.isDeleted()).isTrue(); + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(사용자.isDeleted()).isTrue(); + softAssertions.assertThat(사용자.getName()).isNotEqualTo(사용자_이름); + softAssertions.assertThat(사용자.getProfileImage()).isNull(); + }); } @Test diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java index 743f83d72..608389528 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java @@ -33,6 +33,7 @@ public class AuthenticationServiceFixture { protected String 디바이스_토큰 = "deviceToken"; + protected String 사용자_이름; protected User 사용자; protected User 탈퇴한_사용자; @@ -75,6 +76,7 @@ void fixtureSetUp(@Autowired final JpaDeviceTokenRepository jpaDeviceTokenReposi .oauthId("12345") .oauth2Type(Oauth2Type.KAKAO) .build(); + 사용자_이름 = 사용자.getName(); 탈퇴한_사용자 = User.builder() .name("kakao12346") diff --git a/backend/ddang/src/test/java/com/ddang/ddang/image/presentation/util/ImageUrlCalculatorTest.java b/backend/ddang/src/test/java/com/ddang/ddang/image/presentation/util/ImageUrlCalculatorTest.java index 741e064d2..491761182 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/image/presentation/util/ImageUrlCalculatorTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/image/presentation/util/ImageUrlCalculatorTest.java @@ -4,15 +4,44 @@ import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; import static org.assertj.core.api.Assertions.assertThat; @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @SuppressWarnings("NonAsciiCharacters") +@SpringBootTest class ImageUrlCalculatorTest extends ImageUrlCalculatorFixture { @Test - void 프로필_사진의_URL을_계산한다() { + void 프로필_사진의_상대_URL로_절대_경로를_계산한다() { + // when + final String actual = ImageUrlCalculator.calculateBy(프로필_이미지_상대_URL, 프로필_이미지_아이디); + + // then + assertThat(actual).contains(프로필_이미지_전체_URL); + } + + @Test + void 프로필_사진의_아이디가_null인_경우_기본_이미지의_상대_URL로_절대_경로를_계산한다() { + // when + final String actual = ImageUrlCalculator.calculateBy(프로필_이미지_상대_URL, 프로필_이미지_아이디가_null); + + // then + assertThat(actual).contains(프로필_기본_이미지_전체_URL); + } + + @Test + void 경매_대표_이미지의_상대_URL로_절대_경로를_계산한다() { + // when + final String actual = ImageUrlCalculator.calculateBy(경매_이미지_상대_URL, 경매_이미지_아이디); + + // then + assertThat(actual).contains(경매_이미지_전체_URL); + } + + @Test + void 프로필_사진의_절대_URL로_절대_경로를_계산한다() { // when final String actual = ImageUrlCalculator.calculateBy(프로필_이미지_절대_URL, 프로필_이미지_아이디); @@ -21,7 +50,16 @@ class ImageUrlCalculatorTest extends ImageUrlCalculatorFixture { } @Test - void 경매_대표_이미지의_URL을_계산한다() { + void 프로필_사진의_아이디가_null인_경우_기본_이미지의_절대_URL로_절대_경로를_계산한다() { + // when + final String actual = ImageUrlCalculator.calculateBy(프로필_이미지_절대_URL, 프로필_이미지_아이디가_null); + + // then + assertThat(actual).isEqualTo(프로필_기본_이미지_전체_URL); + } + + @Test + void 경매_대표_이미지의_절대_URL로_절대_경로를_계산한다() { // when final String actual = ImageUrlCalculator.calculateBy(경매_이미지_절대_URL, 경매_이미지_아이디); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/image/presentation/util/fixture/ImageUrlCalculatorFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/image/presentation/util/fixture/ImageUrlCalculatorFixture.java index d817dd3a2..abdeaf933 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/image/presentation/util/fixture/ImageUrlCalculatorFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/image/presentation/util/fixture/ImageUrlCalculatorFixture.java @@ -1,12 +1,19 @@ package com.ddang.ddang.image.presentation.util.fixture; +import com.ddang.ddang.image.presentation.util.ImageRelativeUrl; + @SuppressWarnings("NonAsciiCharacters") public class ImageUrlCalculatorFixture { - protected String 프로필_이미지_절대_URL = "http://3-ddang.store/users/images/"; - protected Long 프로필_이미지_아이디 = 1L; + protected ImageRelativeUrl 프로필_이미지_상대_URL = ImageRelativeUrl.USER; + protected ImageRelativeUrl 경매_이미지_상대_URL = ImageRelativeUrl.AUCTION; + + protected String 프로필_이미지_절대_URL = "/users/images/"; + protected Long 프로필_이미지_아이디 = 2L; + protected Long 프로필_이미지_아이디가_null = null; protected String 프로필_이미지_전체_URL = 프로필_이미지_절대_URL + 프로필_이미지_아이디; - protected String 경매_이미지_절대_URL = "http://3-ddang.store/auctions/images/"; + protected String 프로필_기본_이미지_전체_URL = 프로필_이미지_절대_URL + "1"; + protected String 경매_이미지_절대_URL = "/auctions/images/"; protected Long 경매_이미지_아이디 = 1L; protected String 경매_이미지_전체_URL = 경매_이미지_절대_URL + 경매_이미지_아이디; } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/user/domain/UserTest.java b/backend/ddang/src/test/java/com/ddang/ddang/user/domain/UserTest.java index 6d47960c8..aea916432 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/user/domain/UserTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/user/domain/UserTest.java @@ -93,8 +93,9 @@ class UserTest extends UserFixture { @Test void 회원_탈퇴한다() { // given + final String userName = "kakao12345"; final User user = User.builder() - .name("kakao12345") + .name(userName) .profileImage(new ProfileImage("upload.png", "store.png")) .reliability(new Reliability(5.0d)) .oauthId("12345") @@ -104,7 +105,11 @@ class UserTest extends UserFixture { user.withdrawal(); // then - assertThat(user.isDeleted()).isTrue(); + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(user.isDeleted()).isTrue(); + softAssertions.assertThat(user.getName()).isNotEqualTo(userName); + softAssertions.assertThat(user.getProfileImage()).isNull(); + }); } @Test From ec335a1c121a6465dc0d06535f2b4bee954b0cbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=9C=EC=9D=B4=EB=AF=B8?= <63184334+JJ503@users.noreply.github.com> Date: Tue, 17 Oct 2023 13:52:46 +0900 Subject: [PATCH 34/37] =?UTF-8?q?fix:=20#701=20=EB=8B=B5=EB=B3=80=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=EC=8B=9C=20=EB=8B=A4=EC=8B=9C=20=EB=8B=B5?= =?UTF-8?q?=EB=B3=80=EC=9D=84=20=EB=8B=AC=EC=A7=80=20=EB=AA=BB=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0=20(#704)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 답변에 작성자 필드 추가 * feat: 필드 추가에 대한 flyway 스크립트 추가 * feat: 답변 삭제 시 질문과의 연관관계 끊기 기능 추가 * refactor: 문자열 상수 처리 * test: import 와일드카드 제거 * fix: 문제가 발생할 flyway 스크립트 수정 --- .../ddang/qna/application/AnswerService.java | 2 +- .../qna/application/dto/CreateAnswerDto.java | 5 +++-- .../com/ddang/ddang/qna/domain/Answer.java | 18 +++++++++++++----- .../com/ddang/ddang/qna/domain/Question.java | 5 +++++ .../db/migration/V20__alter_answer_tables.sql | 2 ++ .../AuthenticationServiceTest.java | 2 +- .../NotificationEventListenerFixture.java | 2 +- .../qna/application/AnswerServiceTest.java | 16 +++++++++++++++- .../fixture/AnswerServiceFixture.java | 16 ++++++++++++++-- .../fixture/QuestionServiceFixture.java | 4 ++-- .../ddang/ddang/qna/domain/AnswerTest.java | 16 +++++++++++++++- .../qna/domain/fixture/AnswerFixture.java | 8 +++++--- .../qna/domain/fixture/QuestionFixture.java | 2 +- .../AnswerRepositoryImplTest.java | 2 +- .../JpaAnswerRepositoryTest.java | 2 +- .../fixture/AnswerRepositoryImplFixture.java | 17 +++++++++-------- .../fixture/JpaAnswerRepositoryFixture.java | 19 ++++++++++--------- .../fixture/JpaQuestionRepositoryFixture.java | 8 ++++---- .../QuestionRepositoryImplFixture.java | 4 ++-- .../fixture/AnswerReportServiceFixture.java | 2 +- .../AnswerReportRepositoryImplFixture.java | 4 ++-- .../JpaAnswerReportRepositoryFixture.java | 4 ++-- 22 files changed, 110 insertions(+), 50 deletions(-) create mode 100644 backend/ddang/src/main/resources/db/migration/V20__alter_answer_tables.sql diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/AnswerService.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/AnswerService.java index 17c39fdc9..c52939eb6 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/AnswerService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/AnswerService.java @@ -41,7 +41,7 @@ public Long create(final CreateAnswerDto answerDto, final String absoluteImageUr checkInvalidAnswerer(question, writer); checkAlreadyAnswered(question); - final Answer answer = answerDto.toEntity(); + final Answer answer = answerDto.toEntity(writer); question.addAnswer(answer); final Answer persistAnswer = answerRepository.save(answer); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/CreateAnswerDto.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/CreateAnswerDto.java index 79bf745ba..ec0188c58 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/CreateAnswerDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/application/dto/CreateAnswerDto.java @@ -2,6 +2,7 @@ import com.ddang.ddang.qna.presentation.dto.request.CreateAnswerRequest; import com.ddang.ddang.qna.domain.Answer; +import com.ddang.ddang.user.domain.User; public record CreateAnswerDto(Long questionId, String content, Long userId) { @@ -9,7 +10,7 @@ public static CreateAnswerDto of(final Long questionId, final CreateAnswerReques return new CreateAnswerDto(questionId, answerRequest.content(), userId); } - public Answer toEntity() { - return new Answer(content); + public Answer toEntity(final User writer) { + return new Answer(writer, content); } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/domain/Answer.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/domain/Answer.java index d21924f5a..d22dadec0 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/domain/Answer.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/domain/Answer.java @@ -10,6 +10,7 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToOne; import lombok.AccessLevel; import lombok.EqualsAndHashCode; @@ -25,11 +26,16 @@ public class Answer extends BaseCreateTimeEntity { private static final boolean DELETED_STATUS = true; + private static final Question EMPTY_QUESTION = null; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "writer_id", foreignKey = @ForeignKey(name = "fk_answer_writer")) + private User writer; + @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "question_id", foreignKey = @ForeignKey(name = "fk_answer_question")) private Question question; @@ -40,7 +46,8 @@ public class Answer extends BaseCreateTimeEntity { @Column(name = "is_deleted") private boolean deleted = false; - public Answer(final String content) { + public Answer(final User writer, final String content) { + this.writer = writer; this.content = content; } @@ -49,14 +56,15 @@ public void initQuestion(final Question question) { } public boolean isWriter(final User user) { - return question.getAuction().isOwner(user); + return writer.equals(user); } public void delete() { deleted = DELETED_STATUS; - } - public User getWriter() { - return question.getAuction().getSeller(); + if (question != EMPTY_QUESTION) { + question.deleteAnswer(); + question = EMPTY_QUESTION; + } } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/qna/domain/Question.java b/backend/ddang/src/main/java/com/ddang/ddang/qna/domain/Question.java index 6043ff435..36ceb9a88 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/qna/domain/Question.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/qna/domain/Question.java @@ -27,6 +27,7 @@ public class Question extends BaseCreateTimeEntity { private static final boolean DELETED_STATUS = true; + private static final Answer EMPTY_ANSWER = null; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -71,4 +72,8 @@ public boolean isWriter(final User user) { public void delete() { deleted = DELETED_STATUS; } + + public void deleteAnswer() { + answer = EMPTY_ANSWER; + } } diff --git a/backend/ddang/src/main/resources/db/migration/V20__alter_answer_tables.sql b/backend/ddang/src/main/resources/db/migration/V20__alter_answer_tables.sql new file mode 100644 index 000000000..a00161dec --- /dev/null +++ b/backend/ddang/src/main/resources/db/migration/V20__alter_answer_tables.sql @@ -0,0 +1,2 @@ +alter table answer add writer_id bigint; +alter table answer add constraint fk_answer_writer foreign key (writer_id) references writer (id); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java index a038bb3d5..d367f7ad3 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java @@ -19,7 +19,7 @@ import com.ddang.ddang.image.infrastructure.persistence.JpaProfileImageRepository; import com.ddang.ddang.image.infrastructure.persistence.ProfileImageRepositoryImpl; import com.ddang.ddang.user.domain.repository.UserRepository; -import org.assertj.core.api.*; +import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; diff --git a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java index 04323da66..3f7f9c0f2 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/notification/application/fixture/NotificationEventListenerFixture.java @@ -132,7 +132,7 @@ void setUpFixture() { 입찰_알림_이벤트 = new BidNotificationEvent(입찰_DTO); final Question 질문 = new Question(경매, 질문자, "질문 내용"); - final Answer 답변 = new Answer("응답 내용"); + final Answer 답변 = new Answer(발신자_겸_판매자, "응답 내용"); 질문.addAnswer(답변); 질문_알림_이벤트 = new QuestionNotificationEvent(질문, 이미지_절대_경로); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/AnswerServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/AnswerServiceTest.java index feac87d7a..1c92a75e8 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/AnswerServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/AnswerServiceTest.java @@ -9,6 +9,7 @@ import com.ddang.ddang.qna.application.exception.QuestionNotFoundException; import com.ddang.ddang.qna.application.fixture.AnswerServiceFixture; import com.ddang.ddang.user.application.exception.UserNotFoundException; +import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; @@ -40,6 +41,15 @@ class AnswerServiceTest extends AnswerServiceFixture { assertThat(actual).isPositive(); } + @Test + void 답변을_삭제한_질문에_다시_답변을_달_수_있다() { + // when + final Long actual = answerService.create(답변이_삭제된_질문에_답변_등록_요청_dto, 이미지_절대_경로); + + // then + assertThat(actual).isPositive(); + } + @Test void 존재하지_않는_사용자가_질문에_답하는_경우_예외가_발생한다() { // when & then @@ -78,7 +88,11 @@ class AnswerServiceTest extends AnswerServiceFixture { answerService.deleteById(답변.getId(), 판매자.getId()); // then - assertThat(답변.isDeleted()).isTrue(); + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(답변.isDeleted()).isTrue(); + softAssertions.assertThat(답변.getQuestion()).isNull(); + softAssertions.assertThat(답변한_질문.getAnswer()).isNull(); + }); } @Test diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/AnswerServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/AnswerServiceFixture.java index 11ac6f45c..f950e072d 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/AnswerServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/AnswerServiceFixture.java @@ -37,6 +37,7 @@ public class AnswerServiceFixture { protected Long 존재하지_않는_사용자_아이디 = -999L; protected String 이미지_절대_경로 = "/imageUrl"; + protected Question 답변한_질문; protected Answer 답변; protected User 판매자; protected User 판매자가_아닌_사용자; @@ -46,6 +47,7 @@ public class AnswerServiceFixture { protected CreateAnswerDto 존재하지_않는_질문에_답변_등록_요청_dto; protected CreateAnswerDto 판매자가_아닌_사용자가_질문에_답변_등록_요청_dto; protected CreateAnswerDto 이미_답변한_질문에_답변_등록_요청_dto; + protected CreateAnswerDto 답변이_삭제된_질문에_답변_등록_요청_dto; @BeforeEach void setUp() { @@ -77,23 +79,33 @@ void setUp() { .oauthId("12347") .build(); final Question 질문 = new Question(경매, 질문자, "궁금한 점이 있습니다."); - final Question 답변한_질문 = new Question(경매, 질문자, "궁금한 점이 있습니다."); - 답변 = new Answer("답변드립니다."); + final Question 삭제된_답변이_있는_질문 = new Question(경매, 질문자, "궁금한 점이 있습니다."); + 답변한_질문 = new Question(경매, 질문자, "궁금한 점이 있습니다."); + 답변 = new Answer(판매자, "답변드립니다."); 답변한_질문.addAnswer(답변); + final Answer 삭제된_답변 = new Answer(판매자, "삭제할 답변입니다"); + userRepository.save(판매자); userRepository.save(질문자); userRepository.save(판매자가_아닌_사용자); auctionRepository.save(경매); + questionRepository.save(질문); questionRepository.save(답변한_질문); + questionRepository.save(삭제된_답변이_있는_질문); + answerRepository.save(답변); + answerRepository.save(삭제된_답변); + + 삭제된_답변.delete(); 답변_등록_요청_dto = new CreateAnswerDto(질문.getId(), "답변 드립니다.", 판매자.getId()); 존재하지_않는_사용자의_답변_등록_요청_dto = new CreateAnswerDto(질문.getId(), "답변 드립니다.", -999L); 존재하지_않는_질문에_답변_등록_요청_dto = new CreateAnswerDto(-999L, "답변 드립니다.", 판매자.getId()); 판매자가_아닌_사용자가_질문에_답변_등록_요청_dto = new CreateAnswerDto(질문.getId(), "답변 드립니다.", 질문자.getId()); 이미_답변한_질문에_답변_등록_요청_dto = new CreateAnswerDto(답변한_질문.getId(), "답변 드립니다.", 판매자.getId()); + 답변이_삭제된_질문에_답변_등록_요청_dto = new CreateAnswerDto(삭제된_답변이_있는_질문.getId(), "답변드립니다", 판매자.getId()); } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java index 8f5ff4471..b9577e3a8 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/application/fixture/QuestionServiceFixture.java @@ -151,8 +151,8 @@ void setUp() { 질문 = new Question(질문과_답변이_존재하는_경매, 질문자, "질문1"); final Question 질문2 = new Question(질문과_답변이_존재하는_경매, 두번째_질문을_작성한_사용자, "질문2"); final Question 질문3 = new Question(질문과_답변이_존재하는_경매, 질문자, "질문3"); - final Answer 답변1 = new Answer("답변1"); - final Answer 답변2 = new Answer("답변2"); + final Answer 답변1 = new Answer(판매자, "답변1"); + final Answer 답변2 = new Answer(판매자, "답변2"); 질문.addAnswer(답변1); 질문2.addAnswer(답변2); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/domain/AnswerTest.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/domain/AnswerTest.java index a6d4228e4..5cb8a6c6c 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/domain/AnswerTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/domain/AnswerTest.java @@ -2,6 +2,7 @@ import com.ddang.ddang.qna.domain.fixture.AnswerFixture; import com.ddang.ddang.user.domain.User; +import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; @@ -15,7 +16,7 @@ class AnswerTest extends AnswerFixture { @Test void 답변과_질문의_연관관계를_세팅한다() { // given - final Answer answer = new Answer("답변드립니다."); + final Answer answer = new Answer(판매자, "답변드립니다."); // when answer.initQuestion(질문); @@ -68,4 +69,17 @@ class AnswerTest extends AnswerFixture { // then assertThat(actual).isEqualTo(판매자); } + + @Test + void 답변_삭제시_삭제_상태를_참으로_변경하고_질문과의_연관관계를_끊는다() { + // when + 답변.delete(); + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(답변.isDeleted()).isTrue(); + softAssertions.assertThat(답변.getQuestion()).isNull(); + softAssertions.assertThat(답변이_있는_질문.getAnswer()).isNull(); + }); + } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/domain/fixture/AnswerFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/domain/fixture/AnswerFixture.java index 0099a5a5f..a465f0039 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/domain/fixture/AnswerFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/domain/fixture/AnswerFixture.java @@ -36,9 +36,10 @@ public class AnswerFixture { protected User 답변_작성자가_아닌_사용자 = 질문_작성자; protected Question 질문 = new Question(경매, 질문_작성자, "궁금한 점이 있어요."); - private Question 답변이_있는_질문 = new Question(경매, 질문_작성자, "궁금한 점이 있어요."); - protected Answer 답변 = new Answer("답변드립니다."); - protected Answer 삭제된_답변 = new Answer("답변드립니다."); + protected Question 답변이_있는_질문 = new Question(경매, 질문_작성자, "궁금한 점이 있어요."); + private Question 삭제된_답변이_있는_질문 = new Question(경매, 질문_작성자, "궁금한 점이 있어요."); + protected Answer 답변 = new Answer(판매자, "답변드립니다."); + protected Answer 삭제된_답변 = new Answer(판매자, "답변드립니다."); @BeforeEach void setUp() { @@ -49,6 +50,7 @@ void setUp() { ReflectionTestUtils.setField(삭제된_답변, "id", 1L); 답변이_있는_질문.addAnswer(답변); + 삭제된_답변이_있는_질문.addAnswer(삭제된_답변); 삭제된_답변.delete(); } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/domain/fixture/QuestionFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/domain/fixture/QuestionFixture.java index deee8b3eb..cfbc61889 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/domain/fixture/QuestionFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/domain/fixture/QuestionFixture.java @@ -42,7 +42,7 @@ public class QuestionFixture { protected Question 질문 = new Question(경매, 질문_작성자, 질문_내용); protected Question 삭제된_질문 = new Question(경매, 질문_작성자, 질문_내용); - protected Answer 답변 = new Answer("답변드립니다."); + protected Answer 답변 = new Answer(판매자, "답변드립니다."); @BeforeEach void setUp() { diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/AnswerRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/AnswerRepositoryImplTest.java index 8d516216b..c44cea576 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/AnswerRepositoryImplTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/AnswerRepositoryImplTest.java @@ -33,7 +33,7 @@ void setUp(@Autowired final JpaAnswerRepository jpaAnswerRepository) { @Test void 답변을_저장한다() { // given - final Answer answer = new Answer(답변_내용); + final Answer answer = new Answer(판매자, 답변_내용); 질문.addAnswer(answer); // when diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/JpaAnswerRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/JpaAnswerRepositoryTest.java index bd3a53533..6b77da6c9 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/JpaAnswerRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/JpaAnswerRepositoryTest.java @@ -27,7 +27,7 @@ class JpaAnswerRepositoryTest extends JpaAnswerRepositoryFixture { @Test void 답변을_저장한다() { // given - final Answer answer = new Answer(답변_내용); + final Answer answer = new Answer(판매자, 답변_내용); 질문.addAnswer(answer); // when diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/AnswerRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/AnswerRepositoryImplFixture.java index 8ad80f28d..9a829351c 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/AnswerRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/AnswerRepositoryImplFixture.java @@ -38,6 +38,7 @@ public class AnswerRepositoryImplFixture { private AnswerRepository answerRepository; + protected User 판매자; protected Question 질문; protected Question 답변이_존재하는_질문; protected Question 답변이_존재하지_않는_질문; @@ -59,12 +60,12 @@ void setUpFixture( answerRepository = new AnswerRepositoryImpl(jpaAnswerRepository); final ProfileImage 프로필_이미지 = new ProfileImage("프로필.jpg", "프로필.jpg"); - final User 판매자 = User.builder() - .name("판매자") - .profileImage(프로필_이미지) - .reliability(new Reliability(4.7d)) - .oauthId("12345") - .build(); + 판매자 = User.builder() + .name("판매자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); final Auction 경매 = Auction.builder() .seller(판매자) .title("경매 상품 1") @@ -84,9 +85,9 @@ void setUpFixture( 답변이_존재하지_않는_질문 = 질문; final Question 답변이_삭제된_질문 = new Question(경매, 질문자, "궁금한 점이 있어요."); - 답변 = new Answer("답변드립니다."); + 답변 = new Answer(판매자, "답변드립니다."); 답변이_존재하는_질문.addAnswer(답변); - 삭제된_답변 = new Answer("답변드립니다."); + 삭제된_답변 = new Answer(판매자, "답변드립니다."); 답변이_삭제된_질문.addAnswer(삭제된_답변); 삭제된_답변.delete(); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/JpaAnswerRepositoryFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/JpaAnswerRepositoryFixture.java index 524ef1cae..9bf067ef2 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/JpaAnswerRepositoryFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/JpaAnswerRepositoryFixture.java @@ -36,8 +36,9 @@ public class JpaAnswerRepositoryFixture { private JpaQuestionRepository questionRepository; @Autowired - private JpaAnswerRepository answerRepository; + private JpaAnswerRepository answerRepository; + protected User 판매자; protected Question 질문; protected Question 답변이_존재하는_질문; protected Question 답변이_존재하지_않는_질문; @@ -48,12 +49,12 @@ public class JpaAnswerRepositoryFixture { @BeforeEach void setUp() { final ProfileImage 프로필_이미지 = new ProfileImage("프로필.jpg", "프로필.jpg"); - final User 판매자 = User.builder() - .name("판매자") - .profileImage(프로필_이미지) - .reliability(new Reliability(4.7d)) - .oauthId("12345") - .build(); + 판매자 = User.builder() + .name("판매자") + .profileImage(프로필_이미지) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); final Auction 경매 = Auction.builder() .seller(판매자) .title("경매 상품 1") @@ -73,9 +74,9 @@ void setUp() { 답변이_존재하지_않는_질문 = 질문; final Question 답변이_삭제된_질문 = new Question(경매, 질문자, "궁금한 점이 있어요."); - 답변 = new Answer("답변드립니다."); + 답변 = new Answer(판매자, "답변드립니다."); 답변이_존재하는_질문.addAnswer(답변); - 삭제된_답변 = new Answer("답변드립니다."); + 삭제된_답변 = new Answer(판매자, "답변드립니다."); 답변이_삭제된_질문.addAnswer(삭제된_답변); 삭제된_답변.delete(); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/JpaQuestionRepositoryFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/JpaQuestionRepositoryFixture.java index 584541f92..3baac995b 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/JpaQuestionRepositoryFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/JpaQuestionRepositoryFixture.java @@ -107,16 +107,16 @@ void setUp() { 질문1 = new Question(질문이_3개_답변이_2개인_경매, 질문자, "질문1"); 질문2 = new Question(질문이_3개_답변이_2개인_경매, 질문자, "질문2"); 질문3 = new Question(질문이_3개_답변이_2개인_경매, 질문자, "질문3"); - 답변1 = new Answer("답변1"); - 답변2 = new Answer("답변2"); + 답변1 = new Answer(판매자, "답변1"); + 답변2 = new Answer(판매자, "답변2"); 질문1.addAnswer(답변1); 질문2.addAnswer(답변2); 삭제된_질문1 = new Question(질문이_3개_답변이_2개중_첫번째_질문이_삭제된_경매, 질문자, "질문1"); 삭제되지_않은_질문2 = new Question(질문이_3개_답변이_2개중_첫번째_질문이_삭제된_경매, 질문자, "질문2"); 답변이_없는_질문3 = new Question(질문이_3개_답변이_2개중_첫번째_질문이_삭제된_경매, 질문자, "질문3"); - 삭제된_질문의_답변1 = new Answer("삭제된 질문의 답변"); - 삭제되지_않은_질문의_답변2 = new Answer("삭제되지 않은 질문의 답변2"); + 삭제된_질문의_답변1 = new Answer(판매자, "삭제된 질문의 답변"); + 삭제되지_않은_질문의_답변2 = new Answer(판매자, "삭제되지 않은 질문의 답변2"); 삭제된_질문1.addAnswer(삭제된_질문의_답변1); 삭제된_질문1.delete(); 삭제되지_않은_질문2.addAnswer(삭제되지_않은_질문의_답변2); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/QuestionRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/QuestionRepositoryImplFixture.java index f0bb5e568..2bea362bd 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/QuestionRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/qna/infrastructure/fixture/QuestionRepositoryImplFixture.java @@ -95,8 +95,8 @@ void setUpFixture( 질문1 = new Question(질문이_3개_답변이_2개인_경매, 질문자, "질문1"); 질문2 = new Question(질문이_3개_답변이_2개인_경매, 질문자, "질문2"); 질문3 = new Question(질문이_3개_답변이_2개인_경매, 질문자, "질문3"); - 답변1 = new Answer("답변1"); - 답변2 = new Answer("답변2"); + 답변1 = new Answer(판매자, "답변1"); + 답변2 = new Answer(판매자, "답변2"); 질문1.addAnswer(답변1); 질문2.addAnswer(답변2); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AnswerReportServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AnswerReportServiceFixture.java index dbb98a243..7d5fabb84 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AnswerReportServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/application/fixture/AnswerReportServiceFixture.java @@ -119,7 +119,7 @@ void setUp() { 경매.addAuctionImages(List.of(경매_이미지)); final Question 질문 = new Question(경매, 질문자, "질문드립니다."); - 답변 = new Answer("답변드립니다."); + 답변 = new Answer(판매자, "답변드립니다."); 질문.addAnswer(답변); 답변_신고1 = new AnswerReport(이미_신고한_신고자1, 답변, "신고합니다."); 답변_신고2 = new AnswerReport(이미_신고한_신고자2, 답변, "신고합니다."); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/AnswerReportRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/AnswerReportRepositoryImplFixture.java index 786a8a97e..bd09d169b 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/AnswerReportRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/AnswerReportRepositoryImplFixture.java @@ -125,8 +125,8 @@ void setUpFixture( final Question 질문1 = new Question(경매, 질문자, "질문드립니다."); final Question 질문2 = new Question(경매, 질문자, "질문드립니다."); - 답변 = new Answer("답변드립니다."); - 이미_신고된_답변 = new Answer("답변드립니다."); + 답변 = new Answer(판매자, "답변드립니다."); + 이미_신고된_답변 = new Answer(판매자, "답변드립니다."); 질문1.addAnswer(답변); 질문2.addAnswer(이미_신고된_답변); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/JpaAnswerReportRepositoryFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/JpaAnswerReportRepositoryFixture.java index dd47fd348..d3f880bd1 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/JpaAnswerReportRepositoryFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/report/infrastructure/persistence/fixture/JpaAnswerReportRepositoryFixture.java @@ -115,8 +115,8 @@ void setUp() { final Question 질문1 = new Question(경매, 질문자, "질문드립니다."); final Question 질문2 = new Question(경매, 질문자, "질문드립니다."); - 답변 = new Answer("답변드립니다."); - 이미_신고된_답변 = new Answer("답변드립니다."); + 답변 = new Answer(판매자, "답변드립니다."); + 이미_신고된_답변 = new Answer(판매자, "답변드립니다."); 질문1.addAnswer(답변); 질문2.addAnswer(이미_신고된_답변); From 87e42e12207ab6f1ce31b22515e6a2034835f1dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=9C=EC=9D=B4=EB=AF=B8?= <63184334+JJ503@users.noreply.github.com> Date: Tue, 17 Oct 2023 14:05:01 +0900 Subject: [PATCH 35/37] =?UTF-8?q?fix:=20flyway=20=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A6=BD=ED=8A=B8=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0=20?= =?UTF-8?q?(#706)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/resources/db/migration/V20__alter_answer_tables.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/ddang/src/main/resources/db/migration/V20__alter_answer_tables.sql b/backend/ddang/src/main/resources/db/migration/V20__alter_answer_tables.sql index a00161dec..b5da309ae 100644 --- a/backend/ddang/src/main/resources/db/migration/V20__alter_answer_tables.sql +++ b/backend/ddang/src/main/resources/db/migration/V20__alter_answer_tables.sql @@ -1,2 +1,2 @@ alter table answer add writer_id bigint; -alter table answer add constraint fk_answer_writer foreign key (writer_id) references writer (id); +alter table answer add constraint fk_answer_writer foreign key (writer_id) references users (id); From 55c844bd1f6effa1aecdfb610b5803933987c450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=9C=EC=9D=B4=EB=AF=B8?= <63184334+JJ503@users.noreply.github.com> Date: Wed, 18 Oct 2023 17:34:01 +0900 Subject: [PATCH 36/37] =?UTF-8?q?feat:=20#705=20=EA=B2=BD=EB=A7=A4=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=ED=83=88=ED=87=B4=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#710)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 경매 상세 조회 시 탈퇴한 사용자라면 알 수 없음으로 출력되도록 수정 * refactor: ToString과 EqualsAndHashCode 설정 수정 * feat: 사용자가 등록한 경매, 마지막인 경매 중 현재 진행 중인 경매가 있는지 확인하는 기능 레파지토리에 추가 * feat: 사용자가 등록한 경매, 마지막인 경매 중 현재 진행 중인 경매가 있는지 확인하는 기능 서비스에 추가 * refactor: jpql에서 querydsl로 변경 * test: 컨트롤러 테스트 추가 * test: import 와일드카드 제거 * refactor: querydsl을 jpa 레파지토리로 이동 --- .../domain/repository/AuctionRepository.java | 6 ++ .../persistence/AuctionRepositoryImpl.java | 15 ++++ .../persistence/JpaAuctionRepository.java | 13 ++- .../QuerydslAuctionRepository.java | 23 +++--- .../response/ReadReviewDetailResponse.java | 2 +- .../ReadUserInAuctionQuestionResponse.java | 3 +- .../dto/response/SellerResponse.java | 3 +- .../application/AuthenticationService.java | 24 ++++-- .../WithdrawalNotAllowedException.java | 8 ++ .../java/com/ddang/ddang/bid/domain/Bid.java | 4 +- .../exception/GlobalExceptionHandler.java | 9 +++ .../ddang/report/domain/QuestionReport.java | 2 +- .../com/ddang/ddang/user/domain/User.java | 4 +- .../AuctionRepositoryImplTest.java | 72 +++++++++++++++++ .../persistence/JpaAuctionRepositoryTest.java | 80 ++++++++++++++++++- .../fixture/AuctionRepositoryImplFixture.java | 38 ++++++++- .../fixture/JpaAuctionRepositoryFixture.java | 73 ++++++++++++++--- .../AuthenticationServiceTest.java | 62 +++++++++----- .../fixture/AuthenticationServiceFixture.java | 80 ++++++++++++++++++- .../AuthenticationControllerTest.java | 43 +++++++++- 20 files changed, 493 insertions(+), 71 deletions(-) create mode 100644 backend/ddang/src/main/java/com/ddang/ddang/authentication/application/exception/WithdrawalNotAllowedException.java diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/domain/repository/AuctionRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/domain/repository/AuctionRepository.java index a175eac29..1d8be6dbc 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/domain/repository/AuctionRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/domain/repository/AuctionRepository.java @@ -2,6 +2,8 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.presentation.dto.request.ReadAuctionSearchCondition; + +import java.time.LocalDateTime; import java.util.Optional; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; @@ -24,4 +26,8 @@ Slice findAuctionsAllByCondition( Slice findAuctionsAllByUserId(final Long userId, final Pageable pageable); Slice findAuctionsAllByBidderId(final Long bidderId, final Pageable pageable); + + boolean existsBySellerIdAndAuctionStatusIsOngoing(final Long userId, final LocalDateTime now); + + boolean existsLastBidByUserIdAndAuctionStatusIsOngoing(final Long userId, final LocalDateTime now); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionRepositoryImpl.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionRepositoryImpl.java index 1f67b0ac1..8064ae926 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionRepositoryImpl.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionRepositoryImpl.java @@ -3,6 +3,8 @@ import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.auction.presentation.dto.request.ReadAuctionSearchCondition; + +import java.time.LocalDateTime; import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; @@ -53,4 +55,17 @@ public Slice findAuctionsAllByUserId(final Long userId, final Pageable public Slice findAuctionsAllByBidderId(final Long bidderId, final Pageable pageable) { return querydslAuctionRepository.findAuctionsAllByBidderId(bidderId, pageable); } + + @Override + public boolean existsBySellerIdAndAuctionStatusIsOngoing(final Long userId, final LocalDateTime now) { + return jpaAuctionRepository.existsBySellerIdAndDeletedIsFalseAndClosingTimeGreaterThanEqual(userId, now); + } + + @Override + public boolean existsLastBidByUserIdAndAuctionStatusIsOngoing(final Long userId, final LocalDateTime now) { + return jpaAuctionRepository.existsByLastBidBidderIdAndDeletedIsFalseAndClosingTimeGreaterThanEqual( + userId, + now + ); + } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepository.java index 9e37a0e75..8ccb8660f 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepository.java @@ -2,9 +2,10 @@ import com.ddang.ddang.auction.domain.Auction; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import java.time.LocalDateTime; import java.util.Optional; -import org.springframework.data.jpa.repository.Query; public interface JpaAuctionRepository extends JpaRepository { @@ -25,4 +26,14 @@ public interface JpaAuctionRepository extends JpaRepository { @Query("SELECT a FROM Auction a WHERE a.deleted = false AND a.id = :id") Optional findPureAuctionById(final Long id); + + boolean existsBySellerIdAndDeletedIsFalseAndClosingTimeGreaterThanEqual( + final Long userId, + final LocalDateTime now + ); + + boolean existsByLastBidBidderIdAndDeletedIsFalseAndClosingTimeGreaterThanEqual( + final Long userId, + final LocalDateTime now + ); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepository.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepository.java index 306aa2603..4ef4f2d15 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepository.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/infrastructure/persistence/QuerydslAuctionRepository.java @@ -1,11 +1,5 @@ package com.ddang.ddang.auction.infrastructure.persistence; -import static com.ddang.ddang.auction.domain.QAuction.auction; -import static com.ddang.ddang.bid.domain.QBid.bid; -import static com.ddang.ddang.category.domain.QCategory.category; -import static com.ddang.ddang.region.domain.QAuctionRegion.auctionRegion; -import static com.ddang.ddang.region.domain.QRegion.region; - import com.ddang.ddang.auction.configuration.util.AuctionSortConditionConsts; import com.ddang.ddang.auction.domain.Auction; import com.ddang.ddang.auction.infrastructure.persistence.exception.UnsupportedSortConditionException; @@ -15,10 +9,6 @@ import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.core.types.dsl.CaseBuilder; import com.querydsl.jpa.impl.JPAQueryFactory; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; @@ -26,6 +16,17 @@ import org.springframework.data.domain.Sort.Order; import org.springframework.stereotype.Repository; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static com.ddang.ddang.auction.domain.QAuction.auction; +import static com.ddang.ddang.bid.domain.QBid.bid; +import static com.ddang.ddang.category.domain.QCategory.category; +import static com.ddang.ddang.region.domain.QAuctionRegion.auctionRegion; +import static com.ddang.ddang.region.domain.QRegion.region; + @Repository @RequiredArgsConstructor public class QuerydslAuctionRepository { @@ -83,7 +84,7 @@ private OrderSpecifier processOrderSpecifierByCondition(final Order order) { if (AuctionSortConditionConsts.CLOSING_TINE.equals(order.getProperty())) { return auction.closingTime.asc(); } - + throw new UnsupportedSortConditionException("지원하지 않는 정렬 방식입니다."); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadReviewDetailResponse.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadReviewDetailResponse.java index b50f0e3f1..85aee0385 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadReviewDetailResponse.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadReviewDetailResponse.java @@ -7,7 +7,7 @@ public record ReadReviewDetailResponse(@Nullable Float score, @Nullable String c public static ReadReviewDetailResponse from(final ReadReviewDetailDto readReviewDetailDto) { final Double nullableScore = readReviewDetailDto.score(); - if(nullableScore == null) { + if (nullableScore == null) { return new ReadReviewDetailResponse(null, readReviewDetailDto.content()); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadUserInAuctionQuestionResponse.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadUserInAuctionQuestionResponse.java index 96691511a..336306eb2 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadUserInAuctionQuestionResponse.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/ReadUserInAuctionQuestionResponse.java @@ -3,13 +3,14 @@ import com.ddang.ddang.image.presentation.util.ImageRelativeUrl; import com.ddang.ddang.image.presentation.util.ImageUrlCalculator; import com.ddang.ddang.qna.application.dto.ReadUserInQnaDto; +import com.ddang.ddang.user.presentation.util.NameProcessor; public record ReadUserInAuctionQuestionResponse(Long id, String name, String image) { public static ReadUserInAuctionQuestionResponse from(final ReadUserInQnaDto writerDto) { return new ReadUserInAuctionQuestionResponse( writerDto.id(), - writerDto.name(), + NameProcessor.process(writerDto.isDeleted(), writerDto.name()), ImageUrlCalculator.calculateBy(ImageRelativeUrl.USER, writerDto.profileImageId()) ); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/SellerResponse.java b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/SellerResponse.java index 37ebc7804..994fa91ac 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/SellerResponse.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/auction/presentation/dto/response/SellerResponse.java @@ -3,6 +3,7 @@ import com.ddang.ddang.auction.application.dto.ReadAuctionDto; import com.ddang.ddang.image.presentation.util.ImageRelativeUrl; import com.ddang.ddang.image.presentation.util.ImageUrlCalculator; +import com.ddang.ddang.user.presentation.util.NameProcessor; public record SellerResponse( Long id, @@ -17,7 +18,7 @@ public static SellerResponse from(final ReadAuctionDto auctionDto) { return new SellerResponse( auctionDto.sellerId(), ImageUrlCalculator.calculateBy(ImageRelativeUrl.USER, auctionDto.sellerProfileId()), - auctionDto.sellerName(), + NameProcessor.process(auctionDto.isSellerDeleted(), auctionDto.sellerName()), floatReliability ); } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java index 81daab852..21b8dee8b 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/AuthenticationService.java @@ -1,9 +1,11 @@ package com.ddang.ddang.authentication.application; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.authentication.application.dto.LoginInformationDto; import com.ddang.ddang.authentication.application.dto.LoginUserInformationDto; import com.ddang.ddang.authentication.application.dto.TokenDto; import com.ddang.ddang.authentication.application.exception.InvalidWithdrawalException; +import com.ddang.ddang.authentication.application.exception.WithdrawalNotAllowedException; import com.ddang.ddang.authentication.application.util.RandomNameGenerator; import com.ddang.ddang.authentication.domain.Oauth2UserInformationProviderComposite; import com.ddang.ddang.authentication.domain.TokenDecoder; @@ -39,6 +41,7 @@ public class AuthenticationService { private final DeviceTokenService deviceTokenService; private final Oauth2UserInformationProviderComposite providerComposite; private final UserRepository userRepository; + private final AuctionRepository auctionRepository; private final TokenEncoder tokenEncoder; private final TokenDecoder tokenDecoder; private final BlackListTokenService blackListTokenService; @@ -151,17 +154,28 @@ public void withdrawal( final String refreshToken ) throws InvalidWithdrawalException { final PrivateClaims privateClaims = tokenDecoder.decode(TokenType.ACCESS, accessToken) - .orElseThrow(() -> - new InvalidTokenException("유효한 토큰이 아닙니다.") - ); + .orElseThrow(() -> new InvalidTokenException("유효한 토큰이 아닙니다.")); final User user = userRepository.findById(privateClaims.userId()) .orElseThrow(() -> new InvalidWithdrawalException("탈퇴에 대한 권한이 없습니다.")); - final OAuth2UserInformationProvider provider = providerComposite.findProvider(user.getOauthInformation() - .getOauth2Type()); + final OAuth2UserInformationProvider provider = + providerComposite.findProvider(user.getOauthInformation().getOauth2Type()); + + validateCanWithdrawal(user); user.withdrawal(); blackListTokenService.registerBlackListToken(accessToken, refreshToken); deviceTokenRepository.deleteByUserId(user.getId()); provider.unlinkUserBy(user.getOauthInformation().getOauthId()); } + + private void validateCanWithdrawal(final User user) { + final LocalDateTime now = LocalDateTime.now(); + + if (auctionRepository.existsBySellerIdAndAuctionStatusIsOngoing(user.getId(), now)) { + throw new WithdrawalNotAllowedException("등록한 경매 중 현재 진행 중인 것이 있기에 탈퇴할 수 없습니다."); + } + if (auctionRepository.existsLastBidByUserIdAndAuctionStatusIsOngoing(user.getId(), now)) { + throw new WithdrawalNotAllowedException("마지막 입찰자로 등록되어 있는 것이 있기에 탈퇴할 수 없습니다."); + } + } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/exception/WithdrawalNotAllowedException.java b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/exception/WithdrawalNotAllowedException.java new file mode 100644 index 000000000..e534213de --- /dev/null +++ b/backend/ddang/src/main/java/com/ddang/ddang/authentication/application/exception/WithdrawalNotAllowedException.java @@ -0,0 +1,8 @@ +package com.ddang.ddang.authentication.application.exception; + +public class WithdrawalNotAllowedException extends IllegalArgumentException { + + public WithdrawalNotAllowedException(final String message) { + super(message); + } +} diff --git a/backend/ddang/src/main/java/com/ddang/ddang/bid/domain/Bid.java b/backend/ddang/src/main/java/com/ddang/ddang/bid/domain/Bid.java index db4d6d0fe..be5bcf03d 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/bid/domain/Bid.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/bid/domain/Bid.java @@ -23,8 +23,8 @@ @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter -@EqualsAndHashCode(of = "id") -@ToString(of = {"id", "bidPrice"}) +@EqualsAndHashCode(of = "id", callSuper = false) +@ToString(of = {"id", "price"}) public class Bid extends BaseCreateTimeEntity { @Id diff --git a/backend/ddang/src/main/java/com/ddang/ddang/exception/GlobalExceptionHandler.java b/backend/ddang/src/main/java/com/ddang/ddang/exception/GlobalExceptionHandler.java index 9cfdd446e..e3c7b2ea0 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/exception/GlobalExceptionHandler.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/exception/GlobalExceptionHandler.java @@ -6,6 +6,7 @@ import com.ddang.ddang.auction.domain.exception.InvalidPriceValueException; import com.ddang.ddang.auction.domain.exception.WinnerNotFoundException; import com.ddang.ddang.authentication.application.exception.InvalidWithdrawalException; +import com.ddang.ddang.authentication.application.exception.WithdrawalNotAllowedException; import com.ddang.ddang.authentication.configuration.exception.UserUnauthorizedException; import com.ddang.ddang.authentication.domain.exception.InvalidTokenException; import com.ddang.ddang.authentication.domain.exception.UnsupportedSocialLoginException; @@ -418,6 +419,14 @@ public ResponseEntity handleAlreadyExistsNameException(final .body(new ExceptionResponse(ex.getMessage())); } + @ExceptionHandler(WithdrawalNotAllowedException.class) + public ResponseEntity handleWithdrawalNotAllowedException(final WithdrawalNotAllowedException ex) { + logger.warn(String.format(LOG_MESSAGE_FORMAT, ex.getClass().getSimpleName(), ex.getMessage())); + + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ExceptionResponse(ex.getMessage())); + } + @Override protected ResponseEntity handleMethodArgumentNotValid( final MethodArgumentNotValidException ex, diff --git a/backend/ddang/src/main/java/com/ddang/ddang/report/domain/QuestionReport.java b/backend/ddang/src/main/java/com/ddang/ddang/report/domain/QuestionReport.java index 1feea6a4a..c0abc9ad2 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/report/domain/QuestionReport.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/report/domain/QuestionReport.java @@ -21,7 +21,7 @@ @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter -@EqualsAndHashCode(of = "id") +@EqualsAndHashCode(of = "id", callSuper = false) @ToString(of = {"id", "description"}) public class QuestionReport extends BaseCreateTimeEntity { diff --git a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/User.java b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/User.java index c6fe79755..75f9072a9 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/user/domain/User.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/user/domain/User.java @@ -23,20 +23,18 @@ import lombok.NoArgsConstructor; import lombok.ToString; -import java.util.List; import java.util.UUID; @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter @EqualsAndHashCode(of = "id", callSuper = false) -@ToString(of = {"id", "name", "reliability", "oauthId", "deleted", "oauthInformation"}) +@ToString(of = {"id", "name", "reliability", "deleted", "oauthInformation"}) @Table(name = "users") public class User extends BaseTimeEntity { public static final User EMPTY_USER = null; private static final boolean DELETED_STATUS = true; - private static final String UNKNOWN_NAME = "알 수 없음"; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionRepositoryImplTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionRepositoryImplTest.java index 5275f26b6..e170dd59a 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionRepositoryImplTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/AuctionRepositoryImplTest.java @@ -167,4 +167,76 @@ void setUp(@Autowired final JPAQueryFactory jpaQueryFactory) { assertThat(actual.hasNext()).isFalse(); }); } + + @Test + void 특정_사용자가_판매자인_경매중_현재_진행_중인_경매가_있다면_참을_반환한다() { + // when + final boolean actual = auctionRepository.existsBySellerIdAndAuctionStatusIsOngoing( + 판매자.getId(), + 저장된_경매_엔티티.getClosingTime().minusDays(1) + ); + + // then + assertThat(actual).isTrue(); + } + + @Test + void 특정_사용자가_판매자인_경매중_현재_진행_중인_경매가_없다면_거짓을_반환한다() { + // when + final boolean actual = auctionRepository.existsBySellerIdAndAuctionStatusIsOngoing( + 판매자.getId(), + 저장된_경매_엔티티.getClosingTime().plusDays(1) + ); + + // then + assertThat(actual).isFalse(); + } + + @Test + void 특정_사용자가_판매자인_경매중_현재_진행_중인_경매가_있지만_해당_경매가_삭제_됐다면_거짓을_반환한다() { + // when + final boolean actual = auctionRepository.existsBySellerIdAndAuctionStatusIsOngoing( + 삭제한_경매를_갖고_있는_판매자.getId(), + 삭제된_경매만_있는_사용자의_삭제된_경매_엔티티.getClosingTime().minusDays(1) + ); + + // then + assertThat(actual).isFalse(); + } + + @Test + void 특정_사용자가_마지막_입찰자인_경매중_현재_진행_중인_경매가_있다면_참을_반환한다() { + // when + final boolean actual = auctionRepository.existsLastBidByUserIdAndAuctionStatusIsOngoing( + 구매자.getId(), + 저장된_경매_엔티티.getClosingTime().minusDays(1) + ); + + // then + assertThat(actual).isTrue(); + } + + @Test + void 특정_사용자가_마지막_입찰자인_경매중_현재_진행_중인_경매가_없다면_거짓을_반환한다() { + // when + final boolean actual = auctionRepository.existsLastBidByUserIdAndAuctionStatusIsOngoing( + 구매자.getId(), + 저장된_경매_엔티티.getClosingTime().plusDays(1) + ); + + // then + assertThat(actual).isFalse(); + } + + @Test + void 특정_사용자가_마지막_입찰자인_경매중_현재_진행_중인_경매가_없지만_삭제_됐다면_거짓을_반환한다() { + // when + final boolean actual = auctionRepository.existsLastBidByUserIdAndAuctionStatusIsOngoing( + 삭제된_경매의_마지막_입찰자.getId(), + 삭제된_경매_엔티티.getClosingTime().minusDays(1) + ); + + // then + assertThat(actual).isFalse(); + } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepositoryTest.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepositoryTest.java index 915dc19f7..30ab5239e 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepositoryTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/JpaAuctionRepositoryTest.java @@ -6,7 +6,9 @@ import com.ddang.ddang.auction.infrastructure.persistence.fixture.JpaAuctionRepositoryFixture; import com.ddang.ddang.configuration.JpaConfiguration; import com.ddang.ddang.configuration.QuerydslConfiguration; + import java.util.Optional; + import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; @@ -68,8 +70,10 @@ class JpaAuctionRepositoryTest extends JpaAuctionRepositoryFixture { softAssertions.assertThat(actual.get().getAuctionRegions()).isNotNull(); softAssertions.assertThat(actual.get().getAuctionRegions().get(0)).isNotNull(); softAssertions.assertThat(actual.get().getAuctionRegions().get(0).getThirdRegion()).isNotNull(); - softAssertions.assertThat(actual.get().getAuctionRegions().get(0).getThirdRegion().getFirstRegion()).isNotNull(); - softAssertions.assertThat(actual.get().getAuctionRegions().get(0).getThirdRegion().getSecondRegion()).isNotNull(); + softAssertions.assertThat(actual.get().getAuctionRegions().get(0).getThirdRegion().getFirstRegion()) + .isNotNull(); + softAssertions.assertThat(actual.get().getAuctionRegions().get(0).getThirdRegion().getSecondRegion()) + .isNotNull(); softAssertions.assertThat(actual.get().getSubCategory()).isNotNull(); softAssertions.assertThat(actual.get().getSubCategory().getMainCategory()).isNotNull(); softAssertions.assertThat(actual.get().getSeller()).isNotNull(); @@ -101,4 +105,76 @@ class JpaAuctionRepositoryTest extends JpaAuctionRepositoryFixture { // then assertThat(actual).isEmpty(); } + + @Test + void 특정_사용자가_판매자인_경매중_현재_진행_중인_경매가_있다면_참을_반환한다() { + // when + final boolean actual = auctionRepository.existsBySellerIdAndDeletedIsFalseAndClosingTimeGreaterThanEqual( + 판매자.getId(), + 저장된_경매_엔티티.getClosingTime().minusDays(1) + ); + + // then + assertThat(actual).isTrue(); + } + + @Test + void 특정_사용자가_판매자인_경매중_현재_진행_중인_경매가_없다면_거짓을_반환한다() { + // when + final boolean actual = auctionRepository.existsBySellerIdAndDeletedIsFalseAndClosingTimeGreaterThanEqual( + 판매자.getId(), + 저장된_경매_엔티티.getClosingTime().plusDays(1) + ); + + // then + assertThat(actual).isFalse(); + } + + @Test + void 특정_사용자가_판매자인_경매중_현재_진행_중인_경매가_있지만_해당_경매가_삭제_됐다면_거짓을_반환한다() { + // when + final boolean actual = auctionRepository.existsBySellerIdAndDeletedIsFalseAndClosingTimeGreaterThanEqual( + 삭제한_경매를_갖고_있는_판매자.getId(), + 삭제된_경매만_있는_사용자의_삭제된_경매_엔티티.getClosingTime().minusDays(1) + ); + + // then + assertThat(actual).isFalse(); + } + + @Test + void 특정_사용자가_마지막_입찰자인_경매중_현재_진행_중인_경매가_있다면_참을_반환한다() { + // when + final boolean actual = auctionRepository.existsByLastBidBidderIdAndDeletedIsFalseAndClosingTimeGreaterThanEqual( + 입찰자.getId(), + 저장된_경매_엔티티.getClosingTime().minusDays(1) + ); + + // then + assertThat(actual).isTrue(); + } + + @Test + void 특정_사용자가_마지막_입찰자인_경매중_현재_진행_중인_경매가_없다면_거짓을_반환한다() { + // when + final boolean actual = auctionRepository.existsByLastBidBidderIdAndDeletedIsFalseAndClosingTimeGreaterThanEqual( + 입찰자.getId(), + 저장된_경매_엔티티.getClosingTime().plusDays(1) + ); + + // then + assertThat(actual).isFalse(); + } + + @Test + void 특정_사용자가_마지막_입찰자인_경매중_현재_진행_중인_경매가_없지만_삭제_됐다면_거짓을_반환한다() { + // when + final boolean actual = auctionRepository.existsByLastBidBidderIdAndDeletedIsFalseAndClosingTimeGreaterThanEqual( + 삭제된_경매의_마지막_입찰자.getId(), + 삭제된_경매_엔티티.getClosingTime().minusDays(1) + ); + + // then + assertThat(actual).isFalse(); + } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java index dac3a5df0..1709f9a71 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/AuctionRepositoryImplFixture.java @@ -65,8 +65,12 @@ public class AuctionRepositoryImplFixture { .build(); protected Auction 저장된_경매_엔티티; protected Auction 삭제된_경매_엔티티; + protected Auction 삭제된_경매만_있는_사용자의_삭제된_경매_엔티티; protected User 판매자; + protected User 삭제한_경매를_갖고_있는_판매자; protected User 구매자; + protected User 삭제된_경매의_마지막_입찰자; + protected Bid 입찰; @BeforeEach void fixtureSetUp( @@ -103,6 +107,12 @@ void fixtureSetUp( .reliability(new Reliability(4.7d)) .oauthId("12345") .build(); + 삭제한_경매를_갖고_있는_판매자 = User.builder() + .name("판매자2") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12346") + .build(); 구매자 = User.builder() .name("구매자") @@ -110,9 +120,17 @@ void fixtureSetUp( .reliability(new Reliability(2.7d)) .oauthId("54321") .build(); + 삭제된_경매의_마지막_입찰자 = User.builder() + .name("삭제된 경매의 마지막 입찰자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(2.7d)) + .oauthId("54322") + .build(); userRepository.save(판매자); + userRepository.save(삭제한_경매를_갖고_있는_판매자); userRepository.save(구매자); + userRepository.save(삭제된_경매의_마지막_입찰자); 저장된_경매_엔티티 = Auction.builder() .title("경매 상품 1") @@ -132,15 +150,29 @@ void fixtureSetUp( .subCategory(가구_서브_의자_카테고리) .seller(판매자) .build(); + 삭제된_경매만_있는_사용자의_삭제된_경매_엔티티 = Auction.builder() + .title("경매 상품 1") + .description("이것은 경매 상품 1 입니다.") + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(시간.atZone(위치).toLocalDateTime()) + .subCategory(가구_서브_의자_카테고리) + .seller(삭제한_경매를_갖고_있는_판매자) + .build(); 삭제된_경매_엔티티.addAuctionRegions(List.of(new AuctionRegion(역삼동))); 저장된_경매_엔티티.addAuctionRegions(List.of(new AuctionRegion(역삼동))); 삭제된_경매_엔티티.delete(); + 삭제된_경매만_있는_사용자의_삭제된_경매_엔티티.addAuctionRegions(List.of(new AuctionRegion(역삼동))); + 삭제된_경매만_있는_사용자의_삭제된_경매_엔티티.delete(); bidding(저장된_경매_엔티티, 구매자); - addAuctioneerCount(저장된_경매_엔티티, 1); + addAuctioneerCount(저장된_경매_엔티티, 구매자, 1); + bidding(삭제된_경매_엔티티, 삭제된_경매의_마지막_입찰자); + addAuctioneerCount(삭제된_경매_엔티티, 삭제된_경매의_마지막_입찰자, 1); auctionRepository.save(삭제된_경매_엔티티); auctionRepository.save(저장된_경매_엔티티); + auctionRepository.save(삭제된_경매만_있는_사용자의_삭제된_경매_엔티티); } private void bidding(final Auction targetAuction, final User bidder) { @@ -151,8 +183,8 @@ private void bidding(final Auction targetAuction, final User bidder) { targetAuction.updateLastBid(lastBid); } - private void addAuctioneerCount(final Auction targetAuction, final int count) { - final Bid lastBid = new Bid(targetAuction, targetAuction.getSeller(), new BidPrice(1)); + private void addAuctioneerCount(final Auction targetAuction, final User bidder, final int count) { + final Bid lastBid = new Bid(targetAuction, bidder, new BidPrice(1)); bidRepository.save(lastBid); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/JpaAuctionRepositoryFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/JpaAuctionRepositoryFixture.java index 5505f822e..2eb4f60ac 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/JpaAuctionRepositoryFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/auction/infrastructure/persistence/fixture/JpaAuctionRepositoryFixture.java @@ -4,6 +4,9 @@ import com.ddang.ddang.auction.domain.BidUnit; import com.ddang.ddang.auction.domain.Price; import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; +import com.ddang.ddang.bid.domain.Bid; +import com.ddang.ddang.bid.domain.BidPrice; +import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; import com.ddang.ddang.category.domain.Category; import com.ddang.ddang.category.infrastructure.persistence.JpaCategoryRepository; import com.ddang.ddang.image.domain.ProfileImage; @@ -15,6 +18,7 @@ import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; + import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; @@ -41,10 +45,17 @@ public class JpaAuctionRepositoryFixture { @Autowired private JpaCategoryRepository categoryRepository; + @Autowired + private JpaBidRepository bidRepository; + private Instant 시간 = Instant.parse("2023-07-08T22:21:20Z"); private ZoneId 위치 = ZoneId.of("UTC"); protected Long 존재하지_않는_경매_id = -999L; + protected User 판매자; + protected User 입찰자; + protected User 삭제한_경매를_갖고_있는_판매자; + protected User 삭제된_경매의_마지막_입찰자; protected Auction 저장하기_전_경매_엔티티 = Auction.builder() .title("제목") .description("내용") @@ -54,6 +65,8 @@ public class JpaAuctionRepositoryFixture { .build(); protected Auction 저장된_경매_엔티티; protected Auction 삭제된_경매_엔티티; + protected Auction 삭제된_경매만_있는_사용자의_삭제된_경매_엔티티; + protected Bid 입찰; @BeforeEach void setUp() { @@ -73,39 +86,75 @@ void setUp() { categoryRepository.save(가구_카테고리); - final User 사용자 = User.builder() - .name("사용자") - .profileImage(new ProfileImage("upload.png", "store.png")) - .reliability(new Reliability(4.7d)) - .oauthId("12345") - .build(); - - userRepository.save(사용자); + 판매자 = User.builder() + .name("판매자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12345") + .build(); + 입찰자 = User.builder() + .name("입찰자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12346") + .build(); + 삭제한_경매를_갖고_있는_판매자 = User.builder() + .name("판매자2") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(4.7d)) + .oauthId("12347") + .build(); + 삭제된_경매의_마지막_입찰자 = User.builder() + .name("삭제된 경매의 마지막 입찰자") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(2.7d)) + .oauthId("12348") + .build(); + + userRepository.saveAll(List.of(판매자, 입찰자, 삭제한_경매를_갖고_있는_판매자, 삭제된_경매의_마지막_입찰자)); 저장된_경매_엔티티 = Auction.builder() + .seller(판매자) .title("경매 상품 1") .description("이것은 경매 상품 1 입니다.") .bidUnit(new BidUnit(1_000)) .startPrice(new Price(1_000)) .closingTime(시간.atZone(위치).toLocalDateTime()) .subCategory(가구_서브_의자_카테고리) - .seller(사용자) .build(); 삭제된_경매_엔티티 = Auction.builder() + .seller(판매자) .title("경매 상품 1") .description("이것은 경매 상품 1 입니다.") .bidUnit(new BidUnit(1_000)) .startPrice(new Price(1_000)) .closingTime(시간.atZone(위치).toLocalDateTime()) .subCategory(가구_서브_의자_카테고리) - .seller(사용자) .build(); + 삭제된_경매만_있는_사용자의_삭제된_경매_엔티티 = Auction.builder() + .title("경매 상품 1") + .description("이것은 경매 상품 1 입니다.") + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(시간.atZone(위치).toLocalDateTime()) + .subCategory(가구_서브_의자_카테고리) + .seller(삭제한_경매를_갖고_있는_판매자) + .build(); - 삭제된_경매_엔티티.addAuctionRegions(List.of(new AuctionRegion(역삼동))); 저장된_경매_엔티티.addAuctionRegions(List.of(new AuctionRegion(역삼동))); + 삭제된_경매_엔티티.addAuctionRegions(List.of(new AuctionRegion(역삼동))); 삭제된_경매_엔티티.delete(); + 삭제된_경매만_있는_사용자의_삭제된_경매_엔티티.addAuctionRegions(List.of(new AuctionRegion(역삼동))); + 삭제된_경매만_있는_사용자의_삭제된_경매_엔티티.delete(); + + auctionRepository.saveAll(List.of(저장된_경매_엔티티, 삭제된_경매_엔티티, 삭제된_경매만_있는_사용자의_삭제된_경매_엔티티)); + + final Bid 입찰 = new Bid(저장된_경매_엔티티, 입찰자, new BidPrice(10_000)); + 저장된_경매_엔티티.updateLastBid(입찰); + final Bid 삭제된_경매_입찰 = new Bid(삭제된_경매_엔티티, 삭제된_경매의_마지막_입찰자, new BidPrice(10_000)); + 삭제된_경매_엔티티.updateLastBid(삭제된_경매_입찰); - auctionRepository.saveAll(List.of(저장된_경매_엔티티, 삭제된_경매_엔티티)); + bidRepository.saveAll(List.of(입찰, 삭제된_경매_입찰)); em.flush(); em.clear(); diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java index d367f7ad3..82757e984 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/AuthenticationServiceTest.java @@ -1,8 +1,10 @@ package com.ddang.ddang.authentication.application; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.authentication.application.dto.LoginInformationDto; import com.ddang.ddang.authentication.application.dto.TokenDto; import com.ddang.ddang.authentication.application.exception.InvalidWithdrawalException; +import com.ddang.ddang.authentication.application.exception.WithdrawalNotAllowedException; import com.ddang.ddang.authentication.application.fixture.AuthenticationServiceFixture; import com.ddang.ddang.authentication.domain.Oauth2UserInformationProviderComposite; import com.ddang.ddang.authentication.domain.TokenDecoder; @@ -13,11 +15,6 @@ import com.ddang.ddang.configuration.IsolateDatabase; import com.ddang.ddang.device.application.DeviceTokenService; import com.ddang.ddang.device.domain.repository.DeviceTokenRepository; -import com.ddang.ddang.device.infrastructure.persistence.DeviceTokenRepositoryImpl; -import com.ddang.ddang.device.infrastructure.persistence.JpaDeviceTokenRepository; -import com.ddang.ddang.image.domain.repository.ProfileImageRepository; -import com.ddang.ddang.image.infrastructure.persistence.JpaProfileImageRepository; -import com.ddang.ddang.image.infrastructure.persistence.ProfileImageRepositoryImpl; import com.ddang.ddang.user.domain.repository.UserRepository; import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.BeforeEach; @@ -49,7 +46,8 @@ class AuthenticationServiceTest extends AuthenticationServiceFixture { @Autowired UserRepository userRepository; - ProfileImageRepository profileImageRepository; + @Autowired + AuctionRepository auctionRepository; @Autowired TokenEncoder tokenEncoder; @@ -60,22 +58,18 @@ class AuthenticationServiceTest extends AuthenticationServiceFixture { @Autowired BlackListTokenService blackListTokenService; + @Autowired DeviceTokenRepository deviceTokenRepository; AuthenticationService authenticationService; @BeforeEach - void fixtureSetUp( - @Autowired final JpaProfileImageRepository jpaProfileImageRepository, - @Autowired final JpaDeviceTokenRepository jpaDeviceTokenRepository - ) { - profileImageRepository = new ProfileImageRepositoryImpl(jpaProfileImageRepository); - deviceTokenRepository = new DeviceTokenRepositoryImpl(jpaDeviceTokenRepository); - + void fixtureSetUp() { authenticationService = new AuthenticationService( deviceTokenService, providerComposite, userRepository, + auctionRepository, tokenEncoder, tokenDecoder, blackListTokenService, @@ -83,6 +77,23 @@ void fixtureSetUp( ); } + @Test + void 로그인할_때_가입하지_않은_사용자라면_회원가입을_진행한다() { + // given + given(providerComposite.findProvider(지원하는_소셜_로그인_타입)).willReturn(userInfoProvider); + given(userInfoProvider.findUserInformation(anyString())).willReturn(가입하지_않은_사용자_회원_정보); + + // when + final LoginInformationDto actual = authenticationService.login(지원하는_소셜_로그인_타입, 유효한_소셜_로그인_토큰, 디바이스_토큰); + + + // then + SoftAssertions.assertSoftly(softAssertions -> { + softAssertions.assertThat(actual.tokenDto().accessToken()).isNotEmpty().contains("Bearer "); + softAssertions.assertThat(actual.tokenDto().refreshToken()).isNotEmpty().contains("Bearer "); + }); + } + @Test void 지원하는_소셜_로그인_기능이_아닌_경우_예외가_발생한다() { // given @@ -254,19 +265,26 @@ void fixtureSetUp( } @Test - void 로그인할_때_가입하지_않은_사용자라면_회원가입을_진행한다() { + void 탈퇴할_때_등록한_경매중_진행중인_경매가_있다면_예외가_발생한다() { // given given(providerComposite.findProvider(지원하는_소셜_로그인_타입)).willReturn(userInfoProvider); - given(userInfoProvider.findUserInformation(anyString())).willReturn(가입하지_않은_사용자_회원_정보); + given(userInfoProvider.findUserInformation(anyString())).willReturn(현재_진행중인_경매가_있는_사용자_회원_정보); - // when - final LoginInformationDto actual = authenticationService.login(지원하는_소셜_로그인_타입, 유효한_소셜_로그인_토큰, 디바이스_토큰); + // when & then + assertThatThrownBy(() -> authenticationService.withdrawal(현재_진행중인_경매가_있는_사용자_액세스_토큰, 현재_진행중인_경매가_있는_사용자_리프래시_토큰)) + .isInstanceOf(WithdrawalNotAllowedException.class) + .hasMessage("등록한 경매 중 현재 진행 중인 것이 있기에 탈퇴할 수 없습니다."); + } + @Test + void 탈퇴할_때_등록한_경매중_진행중인_경매의_마지막_입찰자라면_예외가_발생한다() { + // given + given(providerComposite.findProvider(지원하는_소셜_로그인_타입)).willReturn(userInfoProvider); + given(userInfoProvider.findUserInformation(anyString())).willReturn(현재_진행중인_경매가_있는_사용자_회원_정보); - // then - SoftAssertions.assertSoftly(softAssertions -> { - softAssertions.assertThat(actual.tokenDto().accessToken()).isNotEmpty().contains("Bearer "); - softAssertions.assertThat(actual.tokenDto().refreshToken()).isNotEmpty().contains("Bearer "); - }); + // when & then + assertThatThrownBy(() -> authenticationService.withdrawal(현재_진행중인_경매의_마지막_입찰자인_사용자_액세스_토큰, 현재_진행중인_경매의_마지막_입찰자인_사용자_리프래시_토큰)) + .isInstanceOf(WithdrawalNotAllowedException.class) + .hasMessage("마지막 입찰자로 등록되어 있는 것이 있기에 탈퇴할 수 없습니다."); } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java index 608389528..579e50762 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/application/fixture/AuthenticationServiceFixture.java @@ -1,14 +1,21 @@ package com.ddang.ddang.authentication.application.fixture; +import com.ddang.ddang.auction.domain.Auction; +import com.ddang.ddang.auction.domain.BidUnit; +import com.ddang.ddang.auction.domain.Price; +import com.ddang.ddang.auction.domain.repository.AuctionRepository; import com.ddang.ddang.authentication.domain.TokenEncoder; import com.ddang.ddang.authentication.domain.TokenType; import com.ddang.ddang.authentication.domain.dto.UserInformationDto; import com.ddang.ddang.authentication.infrastructure.jwt.PrivateClaims; import com.ddang.ddang.authentication.infrastructure.oauth2.Oauth2Type; +import com.ddang.ddang.bid.domain.Bid; +import com.ddang.ddang.bid.domain.BidPrice; +import com.ddang.ddang.bid.domain.repository.BidRepository; +import com.ddang.ddang.bid.infrastructure.persistence.BidRepositoryImpl; +import com.ddang.ddang.bid.infrastructure.persistence.JpaBidRepository; import com.ddang.ddang.device.domain.DeviceToken; import com.ddang.ddang.device.domain.repository.DeviceTokenRepository; -import com.ddang.ddang.device.infrastructure.persistence.DeviceTokenRepositoryImpl; -import com.ddang.ddang.device.infrastructure.persistence.JpaDeviceTokenRepository; import com.ddang.ddang.image.domain.ProfileImage; import com.ddang.ddang.image.infrastructure.persistence.JpaProfileImageRepository; import com.ddang.ddang.user.domain.Reliability; @@ -42,6 +49,8 @@ public class AuthenticationServiceFixture { protected UserInformationDto 가입한_사용자_회원_정보 = new UserInformationDto(12345L); protected UserInformationDto 탈퇴한_사용자_회원_정보 = new UserInformationDto(54321L); protected UserInformationDto 가입하지_않은_사용자_회원_정보 = new UserInformationDto(-99999L); + protected UserInformationDto 현재_진행중인_경매가_있는_사용자_회원_정보; + protected UserInformationDto 현재_진행중인_경매의_마지막_입찰자인_사용자_회원_정보; protected String 유효한_액세스_토큰; protected String 유효하지_않은_액세스_토큰 = "Bearer invalidAccessToken"; @@ -51,6 +60,10 @@ public class AuthenticationServiceFixture { protected String 유효한_리프레시_토큰; protected String 만료된_리프레시_토큰; protected String 유효하지_않은_타입의_리프레시_토큰 = "invalidRefreshToken"; + protected String 현재_진행중인_경매가_있는_사용자_액세스_토큰; + protected String 현재_진행중인_경매가_있는_사용자_리프래시_토큰; + protected String 현재_진행중인_경매의_마지막_입찰자인_사용자_액세스_토큰; + protected String 현재_진행중인_경매의_마지막_입찰자인_사용자_리프래시_토큰; @Autowired private UserRepository userRepository; @@ -58,14 +71,20 @@ public class AuthenticationServiceFixture { @Autowired private JpaProfileImageRepository profileImageRepository; + @Autowired + private AuctionRepository auctionRepository; + @Autowired private TokenEncoder tokenEncoder; + @Autowired private DeviceTokenRepository deviceTokenRepository; + private BidRepository bidRepository; + @BeforeEach - void fixtureSetUp(@Autowired final JpaDeviceTokenRepository jpaDeviceTokenRepository) { - deviceTokenRepository = new DeviceTokenRepositoryImpl(jpaDeviceTokenRepository); + void fixtureSetUp(@Autowired final JpaBidRepository jpaBidRepository) { + bidRepository = new BidRepositoryImpl(jpaBidRepository); profileImageRepository.save(new ProfileImage("default_profile_image.png", "default_profile_image.png")); @@ -85,14 +104,44 @@ void fixtureSetUp(@Autowired final JpaDeviceTokenRepository jpaDeviceTokenReposi .oauthId("12346") .oauth2Type(Oauth2Type.KAKAO) .build(); + final User 현재_진행중인_경매가_있는_사용자 = User.builder() + .name("kakao12347") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(0.0d)) + .oauthId("12347") + .oauth2Type(Oauth2Type.KAKAO) + .build(); + final User 현재_진행중인_경매의_마지막_입찰자인_사용자 = User.builder() + .name("kakao12348") + .profileImage(new ProfileImage("upload.png", "store.png")) + .reliability(new Reliability(0.0d)) + .oauthId("12348") + .oauth2Type(Oauth2Type.KAKAO) + .build(); userRepository.save(사용자); 탈퇴한_사용자.withdrawal(); userRepository.save(탈퇴한_사용자); + userRepository.save(현재_진행중인_경매가_있는_사용자); + userRepository.save(현재_진행중인_경매의_마지막_입찰자인_사용자); final DeviceToken deviceToken = new DeviceToken(사용자, 디바이스_토큰); deviceTokenRepository.save(deviceToken); + final Auction 진행중인_경매 = Auction.builder() + .seller(현재_진행중인_경매가_있는_사용자) + .title("경매 상품") + .description("이것은 경매 상품입니다.") + .bidUnit(new BidUnit(1_000)) + .startPrice(new Price(1_000)) + .closingTime(LocalDateTime.now().plusDays(7)) + .build(); + final Auction save1 = auctionRepository.save(진행중인_경매); + + final Bid 진행중인_경매의_마지막_입찰 = new Bid(진행중인_경매, 현재_진행중인_경매의_마지막_입찰자인_사용자, new BidPrice(10_000)); + 진행중인_경매.updateLastBid(진행중인_경매의_마지막_입찰); + final Bid save = bidRepository.save(진행중인_경매의_마지막_입찰); + 유효한_리프레시_토큰 = tokenEncoder.encode( LocalDateTime.now(), TokenType.REFRESH, @@ -134,5 +183,28 @@ void fixtureSetUp(@Autowired final JpaDeviceTokenRepository jpaDeviceTokenReposi TokenType.ACCESS, Map.of("userId", -99999L) ); + + 현재_진행중인_경매가_있는_사용자_회원_정보 = new UserInformationDto(현재_진행중인_경매가_있는_사용자.getId()); + 현재_진행중인_경매의_마지막_입찰자인_사용자_회원_정보 = new UserInformationDto(현재_진행중인_경매의_마지막_입찰자인_사용자.getId()); + 현재_진행중인_경매가_있는_사용자_액세스_토큰 = tokenEncoder.encode( + LocalDateTime.now(), + TokenType.ACCESS, + Map.of("userId", 현재_진행중인_경매가_있는_사용자.getId()) + ); + 현재_진행중인_경매가_있는_사용자_리프래시_토큰 = tokenEncoder.encode( + LocalDateTime.now(), + TokenType.REFRESH, + Map.of("userId", 현재_진행중인_경매가_있는_사용자.getId()) + ); + 현재_진행중인_경매의_마지막_입찰자인_사용자_액세스_토큰 = tokenEncoder.encode( + LocalDateTime.now(), + TokenType.ACCESS, + Map.of("userId", 현재_진행중인_경매의_마지막_입찰자인_사용자.getId()) + ); + 현재_진행중인_경매의_마지막_입찰자인_사용자_리프래시_토큰 = tokenEncoder.encode( + LocalDateTime.now(), + TokenType.REFRESH, + Map.of("userId", 현재_진행중인_경매의_마지막_입찰자인_사용자.getId()) + ); } } diff --git a/backend/ddang/src/test/java/com/ddang/ddang/authentication/presentation/AuthenticationControllerTest.java b/backend/ddang/src/test/java/com/ddang/ddang/authentication/presentation/AuthenticationControllerTest.java index 48aea2bae..b0646c46d 100644 --- a/backend/ddang/src/test/java/com/ddang/ddang/authentication/presentation/AuthenticationControllerTest.java +++ b/backend/ddang/src/test/java/com/ddang/ddang/authentication/presentation/AuthenticationControllerTest.java @@ -19,6 +19,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.ddang.ddang.authentication.application.exception.InvalidWithdrawalException; +import com.ddang.ddang.authentication.application.exception.WithdrawalNotAllowedException; import com.ddang.ddang.authentication.configuration.Oauth2TypeConverter; import com.ddang.ddang.authentication.domain.exception.InvalidTokenException; import com.ddang.ddang.authentication.domain.exception.UnsupportedSocialLoginException; @@ -231,7 +232,45 @@ void setUp() { ) .andExpectAll( status().isForbidden(), - jsonPath("$.message").value("탈퇴에 대한 권한 없습니다.") + jsonPath("$.message").exists() + ); + } + + @Test + void ouath2Type과_accessToken과_refreshToken을_전달시_진행중인_경매를_등록한_회원인_경우_400을_반환한다() throws Exception { + // given + willThrow(new WithdrawalNotAllowedException("등록한 경매 중 현재 진행 중인 것이 있기에 탈퇴할 수 없습니다.")) + .given(authenticationService) + .withdrawal(anyString(), anyString()); + + // when & then + mockMvc.perform(RestDocumentationRequestBuilders.post("/oauth2/withdrawal") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(유효한_회원탈퇴_요청)) + .header(HttpHeaders.AUTHORIZATION, 유효한_액세스_토큰_내용) + ) + .andExpectAll( + status().isBadRequest(), + jsonPath("$.message").exists() + ); + } + + @Test + void ouath2Type과_accessToken과_refreshToken을_전달시_진행중인_경매의_마지막_입찰자_회원인_경우_400을_반환한다() throws Exception { + // given + willThrow(new WithdrawalNotAllowedException("마지막 입찰자로 등록되어 있는 것이 있기에 탈퇴할 수 없습니다.")) + .given(authenticationService) + .withdrawal(anyString(), anyString()); + + // when & then + mockMvc.perform(RestDocumentationRequestBuilders.post("/oauth2/withdrawal") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(유효한_회원탈퇴_요청)) + .header(HttpHeaders.AUTHORIZATION, 유효한_액세스_토큰_내용) + ) + .andExpectAll( + status().isBadRequest(), + jsonPath("$.message").exists() ); } @@ -251,7 +290,7 @@ void setUp() { fieldWithPath("refreshToken").type(JsonFieldType.STRING) .description("Refresh Token"), fieldWithPath("isSignUpUser").type(JsonFieldType.BOOLEAN) - .description("최초 로그인 여부(회원가입)") + .description("최초 로그인 여부(회원가입)") ) ) ); From 3647925d6f96bded2b7ee82e97a593e6aa73d35d Mon Sep 17 00:00:00 2001 From: kwonyj1022 Date: Wed, 18 Oct 2023 23:46:06 +0900 Subject: [PATCH 37/37] =?UTF-8?q?remove:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=B4=88=EA=B8=B0=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=84=B8=ED=8C=85=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InitializationUserConfiguration.java | 49 ------------------- .../src/main/resources/application-local.yml | 4 -- 2 files changed, 53 deletions(-) delete mode 100644 backend/ddang/src/main/java/com/ddang/ddang/configuration/initialization/InitializationUserConfiguration.java diff --git a/backend/ddang/src/main/java/com/ddang/ddang/configuration/initialization/InitializationUserConfiguration.java b/backend/ddang/src/main/java/com/ddang/ddang/configuration/initialization/InitializationUserConfiguration.java deleted file mode 100644 index f89bfc8ce..000000000 --- a/backend/ddang/src/main/java/com/ddang/ddang/configuration/initialization/InitializationUserConfiguration.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.ddang.ddang.configuration.initialization; - -import com.ddang.ddang.image.domain.ProfileImage; -import com.ddang.ddang.user.domain.Reliability; -import com.ddang.ddang.user.domain.User; -import com.ddang.ddang.user.domain.repository.UserRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.boot.ApplicationArguments; -import org.springframework.boot.ApplicationRunner; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Configuration; -import org.springframework.transaction.annotation.Transactional; - -@Configuration -@ConditionalOnProperty(name = "data.init.user.enabled", havingValue = "true") -@RequiredArgsConstructor -public class InitializationUserConfiguration implements ApplicationRunner { - - private final UserRepository userRepository; - - @Override - @Transactional - public void run(final ApplicationArguments args) { - final User seller1 = User.builder() - .name("판매자1") - .profileImage(new ProfileImage("upload.png", "updateImage.png")) - .reliability(new Reliability(4.7d)) - .oauthId("12345") - .build(); - - final User buyer1 = User.builder() - .name("구매자1") - .profileImage(new ProfileImage("upload.png", "updateImage.png")) - .reliability(new Reliability(3.0d)) - .oauthId("12346") - .build(); - - final User buyer2 = User.builder() - .name("구매자2") - .profileImage(new ProfileImage("upload.png", "updateImage.png")) - .reliability(new Reliability(0.8d)) - .oauthId("12347") - .build(); - - userRepository.save(seller1); - userRepository.save(buyer1); - userRepository.save(buyer2); - } -} diff --git a/backend/ddang/src/main/resources/application-local.yml b/backend/ddang/src/main/resources/application-local.yml index 2db9e094b..fd586f349 100644 --- a/backend/ddang/src/main/resources/application-local.yml +++ b/backend/ddang/src/main/resources/application-local.yml @@ -29,10 +29,6 @@ data: init: region: enabled: false - auction: - enabled: false - user: - enabled: false image: store:
Table 14. /auctions/{auctionId}/reviewsTable 13. /auctions/{auctionId}/reviews