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/61] =?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/61] =?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/61] =?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 354445aca874cb38c1b84dcccaa721d7c80dcbb1 Mon Sep 17 00:00:00 2001 From: Mendel <67176829+rhthrhrl0@users.noreply.github.com> Date: Thu, 12 Oct 2023 17:44:43 +0900 Subject: [PATCH 04/61] =?UTF-8?q?feat:=20#607=20=EB=A9=94=EC=8B=9C?= =?UTF-8?q?=EC=A7=80=20=EB=B0=A9=20=EB=AA=A9=EB=A1=9D=EC=97=90=20=EB=B8=8C?= =?UTF-8?q?=EB=A1=9C=EB=93=9C=EC=BA=90=EC=8A=A4=ED=8A=B8=20=EB=A6=AC?= =?UTF-8?q?=EC=8B=9C=EB=B2=84=20=EB=93=B1=EB=A1=9D=20=EB=B0=8F=20=ED=95=B4?= =?UTF-8?q?=EC=A0=9C=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80=20(#610)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: MessageFragment에 브로드캐스트 리시버 등록 및 해제 로직 추가 * feat: 로딩 프로퍼티 추가 --- .../feature/message/MessageFragment.kt | 25 +++++++++++++++++-- .../feature/message/MessageViewModel.kt | 5 ++++ ...DdangDdangDdangFirebaseMessagingService.kt | 5 ++-- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/android/app/src/main/java/com/ddangddangddang/android/feature/message/MessageFragment.kt b/android/app/src/main/java/com/ddangddangddang/android/feature/message/MessageFragment.kt index 2b4744688..50d5105c0 100644 --- a/android/app/src/main/java/com/ddangddangddang/android/feature/message/MessageFragment.kt +++ b/android/app/src/main/java/com/ddangddangddang/android/feature/message/MessageFragment.kt @@ -9,6 +9,7 @@ import com.ddangddangddang.android.R import com.ddangddangddang.android.databinding.FragmentMessageBinding import com.ddangddangddang.android.feature.common.notifyFailureMessage import com.ddangddangddang.android.feature.messageRoom.MessageRoomActivity +import com.ddangddangddang.android.reciever.MessageReceiver import com.ddangddangddang.android.util.binding.BindingFragment import dagger.hilt.android.AndroidEntryPoint @@ -19,17 +20,37 @@ class MessageFragment : BindingFragment(R.layout.fragmen viewModel.navigateToMessageRoom(roomId) } + private val messageReceiver: MessageReceiver by lazy { + MessageReceiver { viewModel.loadMessageRooms() } // 필터링 없이 모든 수신을 받아서 처리 한다. + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setupViewModel() setupMessageRoomsRecyclerView() binding.viewModel = viewModel - if (viewModel.messageRooms.value == null) viewModel.loadMessageRooms() + } + + override fun onResume() { + super.onResume() + requireContext().registerReceiver(messageReceiver, MessageReceiver.getIntentFilter()) + viewModel.loadMessageRooms() // 홈 키에서 돌아올 때, 메시지 방에서 돌아올 때 갱신 되도록 하기 위해 여기 배치 + } + + override fun onPause() { + super.onPause() + unregisterMessageReceiver() } override fun onHiddenChanged(hidden: Boolean) { super.onHiddenChanged(hidden) - if (hidden.not()) viewModel.loadMessageRooms() + if (hidden) return unregisterMessageReceiver() + requireContext().registerReceiver(messageReceiver, MessageReceiver.getIntentFilter()) + viewModel.loadMessageRooms() + } + + private fun unregisterMessageReceiver() { + runCatching { requireContext().unregisterReceiver(messageReceiver) } } private fun setupViewModel() { diff --git a/android/app/src/main/java/com/ddangddangddang/android/feature/message/MessageViewModel.kt b/android/app/src/main/java/com/ddangddangddang/android/feature/message/MessageViewModel.kt index a1fd78c6f..e914b386d 100644 --- a/android/app/src/main/java/com/ddangddangddang/android/feature/message/MessageViewModel.kt +++ b/android/app/src/main/java/com/ddangddangddang/android/feature/message/MessageViewModel.kt @@ -12,6 +12,7 @@ import com.ddangddangddang.data.remote.ApiResponse import com.ddangddangddang.data.repository.ChatRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch +import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject @HiltViewModel @@ -26,7 +27,10 @@ class MessageViewModel @Inject constructor( val messageRooms: LiveData> get() = _messageRooms + private var isLoading: AtomicBoolean = AtomicBoolean(false) + fun loadMessageRooms() { + if (isLoading.getAndSet(true)) return viewModelScope.launch { when (val response = repository.getChatRoomPreviews()) { is ApiResponse.Success -> { @@ -46,6 +50,7 @@ class MessageViewModel @Inject constructor( _event.value = MessageEvent.MessageLoadFailure(ErrorType.UNEXPECTED) } } + isLoading.set(false) } } diff --git a/android/app/src/main/java/com/ddangddangddang/android/notification/DdangDdangDdangFirebaseMessagingService.kt b/android/app/src/main/java/com/ddangddangddang/android/notification/DdangDdangDdangFirebaseMessagingService.kt index 590b842d7..d81ceed16 100644 --- a/android/app/src/main/java/com/ddangddangddang/android/notification/DdangDdangDdangFirebaseMessagingService.kt +++ b/android/app/src/main/java/com/ddangddangddang/android/notification/DdangDdangDdangFirebaseMessagingService.kt @@ -66,9 +66,8 @@ class DdangDdangDdangFirebaseMessagingService : FirebaseMessagingService() { when (type) { NotificationType.MESSAGE -> { val activeRoomId = (application as DdangDdangDdang).activeMessageRoomId - if (activeRoomId == id) { - sendBroadcastToMessageReceiver(id) - } else { + sendBroadcastToMessageReceiver(id) // 항상 호출. 이 리시버를 받을지 말지는 거기서 정함. + if (activeRoomId != id) { val notification = createMessageNotification(tag, id, remoteMessage) notificationManager.notify(tag, id.toInt(), notification) } From a3e33f5f13095af152b120b09fd4cb56c5646712 Mon Sep 17 00:00:00 2001 From: Mendel <67176829+rhthrhrl0@users.noreply.github.com> Date: Thu, 12 Oct 2023 17:47:26 +0900 Subject: [PATCH 05/61] =?UTF-8?q?feat:=20#611=20=EA=B2=BD=EB=A7=A4=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=ED=95=84?= =?UTF-8?q?=EC=88=98=20=EC=9E=85=EB=A0=A5=EC=82=AC=ED=95=AD=20=ED=91=9C?= =?UTF-8?q?=EC=8B=9C=EC=99=80=20=ED=9E=8C=ED=8A=B8=20=ED=85=8D=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EB=A7=88=EA=B0=90?= =?UTF-8?q?=20=EC=84=A0=ED=83=9D=20=EB=82=A0=EC=A7=9C=20=EC=A0=9C=ED=95=9C?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80=20(#621)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 캘린더 날짜 선택에서 최소 및 최대 날짜 제한 로직 추가 * feat: 등록 페이지 힌트 수정 및 필수입력 사항 표시 --- .../register/RegisterAuctionActivity.kt | 8 +- .../src/main/res/drawable/ic_necessary_24.xml | 9 ++ .../res/layout/activity_register_auction.xml | 108 +++++++++++++++++- android/app/src/main/res/values/strings.xml | 5 + 4 files changed, 124 insertions(+), 6 deletions(-) create mode 100644 android/app/src/main/res/drawable/ic_necessary_24.xml diff --git a/android/app/src/main/java/com/ddangddangddang/android/feature/register/RegisterAuctionActivity.kt b/android/app/src/main/java/com/ddangddangddang/android/feature/register/RegisterAuctionActivity.kt index c7be9b40b..96c6528bd 100644 --- a/android/app/src/main/java/com/ddangddangddang/android/feature/register/RegisterAuctionActivity.kt +++ b/android/app/src/main/java/com/ddangddangddang/android/feature/register/RegisterAuctionActivity.kt @@ -29,6 +29,7 @@ import com.ddangddangddang.android.util.view.showSnackbar import dagger.hilt.android.AndroidEntryPoint import java.time.LocalDateTime import java.time.LocalTime +import java.util.Calendar @AndroidEntryPoint class RegisterAuctionActivity : @@ -168,7 +169,12 @@ class RegisterAuctionActivity : selectedDateTime.year, selectedDateTime.monthValue - 1, selectedDateTime.dayOfMonth, - ).show() + ).apply { + val calendar: Calendar = Calendar.getInstance() + this.datePicker.minDate = calendar.timeInMillis + calendar.add(Calendar.DATE, 29) + this.datePicker.maxDate = calendar.timeInMillis + }.show() } private fun showTimePicker(selectedTime: LocalTime) { diff --git a/android/app/src/main/res/drawable/ic_necessary_24.xml b/android/app/src/main/res/drawable/ic_necessary_24.xml new file mode 100644 index 000000000..7b4e291aa --- /dev/null +++ b/android/app/src/main/res/drawable/ic_necessary_24.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/layout/activity_register_auction.xml b/android/app/src/main/res/layout/activity_register_auction.xml index b53fb99d3..eacb48cd7 100644 --- a/android/app/src/main/res/layout/activity_register_auction.xml +++ b/android/app/src/main/res/layout/activity_register_auction.xml @@ -68,6 +68,37 @@ android:orientation="vertical" app:layout_constraintGuide_end="@dimen/margin_side_layout" /> + + + + + + + + app:layout_constraintTop_toBottomOf="@id/tv_image"> + + + + + + + + + + + + + 경매 상품 등록 (%d/%d) + * 는 필수입력 사항입니다. + 사진 제목 카테고리 상품 설명 경매 시작가 + 경매 시작가는 0원보다 커야 합니다 경매 마감 시간 + 당일로부터 30일 이내까지 선택 가능합니다 직거래 가능 지역 이미지 주소 경매 입찰 단위 + 100원 이상부터 100원 단위로 입력 가능합니다 채우지 않은 필드가 존재합니다. 필드에 유효하지 않은 값이 존재합니다. 확인 From fc25de8ed6159fe72791dda885b8f7eec9b4cd38 Mon Sep 17 00:00:00 2001 From: Mendel <67176829+rhthrhrl0@users.noreply.github.com> Date: Thu, 12 Oct 2023 17:47:54 +0900 Subject: [PATCH 06/61] =?UTF-8?q?feat:=20#622=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EC=83=81=EC=84=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=ED=99=95=EB=8C=80=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?(#623)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/build.gradle | 3 +++ android/app/src/main/res/layout/item_detail_image.xml | 3 ++- android/settings.gradle | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index c73909063..a4f30b40f 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -110,6 +110,9 @@ dependencies { // app update manager implementation 'com.google.android.play:app-update-ktx:2.1.0' + + // photo view 확대 가능 이미지뷰 라이브러리 + implementation 'com.github.chrisbanes:PhotoView:2.3.0' } kapt { correctErrorTypes true diff --git a/android/app/src/main/res/layout/item_detail_image.xml b/android/app/src/main/res/layout/item_detail_image.xml index 5db0a28e6..666ffd6bb 100644 --- a/android/app/src/main/res/layout/item_detail_image.xml +++ b/android/app/src/main/res/layout/item_detail_image.xml @@ -9,7 +9,8 @@ - Date: Thu, 12 Oct 2023 20:35:31 +0900 Subject: [PATCH 07/61] =?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 08/61] =?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 09/61] =?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 10/61] =?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 11/61] =?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 12/61] =?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 bb4c91110ba8b08064ad3a6280c2feb89aa291e7 Mon Sep 17 00:00:00 2001 From: ippnsj <49394114+ippnsj@users.noreply.github.com> Date: Fri, 13 Oct 2023 14:44:48 +0900 Subject: [PATCH 13/61] =?UTF-8?q?feat:=20#629=20=EC=9D=B4=EC=A0=84?= =?UTF-8?q?=EC=97=90=20=EC=84=A0=ED=83=9D=ED=95=9C=20=EC=A7=80=EC=97=AD=20?= =?UTF-8?q?=EC=9C=A0=EC=A7=80=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?(#631)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/register/RegisterAuctionActivity.kt | 8 ++++---- .../feature/register/RegisterAuctionViewModel.kt | 4 ++-- .../register/region/SelectRegionsActivity.kt | 16 +++++++++++++++- .../register/region/SelectRegionsViewModel.kt | 4 ++++ 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/android/app/src/main/java/com/ddangddangddang/android/feature/register/RegisterAuctionActivity.kt b/android/app/src/main/java/com/ddangddangddang/android/feature/register/RegisterAuctionActivity.kt index 96c6528bd..550b02449 100644 --- a/android/app/src/main/java/com/ddangddangddang/android/feature/register/RegisterAuctionActivity.kt +++ b/android/app/src/main/java/com/ddangddangddang/android/feature/register/RegisterAuctionActivity.kt @@ -150,8 +150,8 @@ class RegisterAuctionActivity : navigationToCategorySelection() } - RegisterAuctionViewModel.RegisterAuctionEvent.PickRegion -> { - navigationToRegionSelection() + is RegisterAuctionViewModel.RegisterAuctionEvent.PickRegion -> { + navigationToRegionSelection(event.regionSelected) } } } @@ -222,8 +222,8 @@ class RegisterAuctionActivity : categoryActivityLauncher.launch(SelectCategoryActivity.getIntent(this)) } - private fun navigationToRegionSelection() { - regionActivityLauncher.launch(SelectRegionsActivity.getIntent(this)) + private fun navigationToRegionSelection(directRegion: List) { + regionActivityLauncher.launch(SelectRegionsActivity.getIntent(this, directRegion)) } private fun setPrice(editText: EditText, watcher: DefaultTextWatcher, price: Int) { diff --git a/android/app/src/main/java/com/ddangddangddang/android/feature/register/RegisterAuctionViewModel.kt b/android/app/src/main/java/com/ddangddangddang/android/feature/register/RegisterAuctionViewModel.kt index d984a513c..8f5c34064 100644 --- a/android/app/src/main/java/com/ddangddangddang/android/feature/register/RegisterAuctionViewModel.kt +++ b/android/app/src/main/java/com/ddangddangddang/android/feature/register/RegisterAuctionViewModel.kt @@ -204,7 +204,7 @@ class RegisterAuctionViewModel @Inject constructor(private val repository: Aucti } fun setPickRegionEvent() { - _event.value = RegisterAuctionEvent.PickRegion + _event.value = RegisterAuctionEvent.PickRegion(_directRegion.value ?: emptyList()) } private fun setBlankExistEvent() { @@ -237,7 +237,7 @@ class RegisterAuctionViewModel @Inject constructor(private val repository: Aucti object MultipleMediaPicker : RegisterAuctionEvent() object PickCategory : RegisterAuctionEvent() - object PickRegion : RegisterAuctionEvent() + class PickRegion(val regionSelected: List) : RegisterAuctionEvent() } companion object { diff --git a/android/app/src/main/java/com/ddangddangddang/android/feature/register/region/SelectRegionsActivity.kt b/android/app/src/main/java/com/ddangddangddang/android/feature/register/region/SelectRegionsActivity.kt index a35ae75fb..bab0145af 100644 --- a/android/app/src/main/java/com/ddangddangddang/android/feature/register/region/SelectRegionsActivity.kt +++ b/android/app/src/main/java/com/ddangddangddang/android/feature/register/region/SelectRegionsActivity.kt @@ -10,6 +10,7 @@ import com.ddangddangddang.android.feature.common.notifyFailureMessage import com.ddangddangddang.android.feature.register.RegisterAuctionActivity import com.ddangddangddang.android.model.RegionSelectionModel import com.ddangddangddang.android.util.binding.BindingActivity +import com.ddangddangddang.android.util.compat.getSerializableExtraCompat import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -43,6 +44,7 @@ class SelectRegionsActivity : setupAdapter() setupObserve() viewModel.loadFirstRegions() + setupRegionSelected() } private fun setupAdapter() { @@ -98,7 +100,19 @@ class SelectRegionsActivity : finish() } + private fun setupRegionSelected() { + val regionSelected = + intent.getSerializableExtraCompat>(KEY_REGION_SELECTED) + regionSelected?.let { viewModel.setupRegionSelected(it.toList()) } + } + companion object { - fun getIntent(context: Context): Intent = Intent(context, SelectRegionsActivity::class.java) + private const val KEY_REGION_SELECTED = "region_selected" + + fun getIntent(context: Context, regionSelected: List): Intent { + val intent = Intent(context, SelectRegionsActivity::class.java) + intent.putExtra(KEY_REGION_SELECTED, regionSelected.toTypedArray()) + return intent + } } } diff --git a/android/app/src/main/java/com/ddangddangddang/android/feature/register/region/SelectRegionsViewModel.kt b/android/app/src/main/java/com/ddangddangddang/android/feature/register/region/SelectRegionsViewModel.kt index f60805b13..c89da5fd8 100644 --- a/android/app/src/main/java/com/ddangddangddang/android/feature/register/region/SelectRegionsViewModel.kt +++ b/android/app/src/main/java/com/ddangddangddang/android/feature/register/region/SelectRegionsViewModel.kt @@ -70,6 +70,10 @@ class SelectRegionsViewModel @Inject constructor(private val regionRepository: R } } + fun setupRegionSelected(regionSelected: List) { + _regionSelections.value = regionSelected + } + fun setExitEvent() { _event.value = SelectRegionsEvent.Exit } From 5a2ab97b46896b722bd6672e04d6764efed93f4a Mon Sep 17 00:00:00 2001 From: ippnsj <49394114+ippnsj@users.noreply.github.com> Date: Fri, 13 Oct 2023 14:46:11 +0900 Subject: [PATCH 14/61] =?UTF-8?q?feat:=20#632=20=EC=B1=84=ED=8C=85=20?= =?UTF-8?q?=EB=B0=8F=20=EC=9E=85=EC=B0=B0=20Submit=20=ED=82=A4=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=B1=84=ED=8C=85?= =?UTF-8?q?=20=EB=AA=A9=EB=A1=9D=EC=97=90=EC=84=9C=20=EB=A7=90=EC=A4=84?= =?UTF-8?q?=EC=9E=84=ED=91=9C=20=EC=82=AC=EC=9A=A9=20(#633)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 입찰 금액 입력 텍스트 색상 변경 * feat: 입찰 완료 버튼 클릭 시 키보드 내리는 기능 추가 * feat: 채팅 엔터 가능하도록 변경 * fix: 메시지 목록에서 닉네임과 메시지 내용 말줄임표 사용 --- .../feature/detail/bid/AuctionBidDialog.kt | 19 +++++++++++++++++++ .../main/res/layout/activity_message_room.xml | 3 ++- .../layout/fragment_auction_bid_dialog.xml | 2 +- .../src/main/res/layout/item_message_room.xml | 4 +++- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/android/app/src/main/java/com/ddangddangddang/android/feature/detail/bid/AuctionBidDialog.kt b/android/app/src/main/java/com/ddangddangddang/android/feature/detail/bid/AuctionBidDialog.kt index 2a40744e1..b4370fc2f 100644 --- a/android/app/src/main/java/com/ddangddangddang/android/feature/detail/bid/AuctionBidDialog.kt +++ b/android/app/src/main/java/com/ddangddangddang/android/feature/detail/bid/AuctionBidDialog.kt @@ -1,5 +1,6 @@ package com.ddangddangddang.android.feature.detail.bid +import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Bundle @@ -8,6 +9,8 @@ import android.text.TextWatcher import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.view.inputmethod.EditorInfo +import android.view.inputmethod.InputMethodManager import androidx.fragment.app.DialogFragment import androidx.fragment.app.FragmentManager import androidx.fragment.app.activityViewModels @@ -62,6 +65,7 @@ class AuctionBidDialog : DialogFragment() { super.onViewCreated(view, savedInstanceState) dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + setupKeyboard() setupListener() setupObserver() } @@ -71,6 +75,21 @@ class AuctionBidDialog : DialogFragment() { binding.etBidPrice.requestFocus() } + private fun setupKeyboard() { + binding.etBidPrice.setOnEditorActionListener { _, actionId, _ -> + if (actionId == EditorInfo.IME_ACTION_DONE) { + hideKeyboard() + return@setOnEditorActionListener true + } + return@setOnEditorActionListener false + } + } + + private fun hideKeyboard() { + val imm = activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(binding.etBidPrice.windowToken, 0) + } + private fun setupListener() { binding.etBidPrice.addTextChangedListener(watcher) binding.etBidPrice.setOnClickListener { diff --git a/android/app/src/main/res/layout/activity_message_room.xml b/android/app/src/main/res/layout/activity_message_room.xml index f4e9eca4d..67f328e81 100644 --- a/android/app/src/main/res/layout/activity_message_room.xml +++ b/android/app/src/main/res/layout/activity_message_room.xml @@ -220,11 +220,12 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" + android:maxLines="4" android:background="@drawable/bg_stroke_gray_radius_1dp" android:backgroundTint="@color/grey_100" android:hint="@string/message_room_message_input_hint" android:padding="16dp" - android:singleLine="true" + android:inputType="textMultiLine" android:text="@={viewModel.inputMessage}" />