From 6b14711b86d8648860adad82d041bf178be2ae5f Mon Sep 17 00:00:00 2001 From: woojin Date: Sun, 1 Dec 2024 23:52:38 +0900 Subject: [PATCH 01/21] =?UTF-8?q?fix:=203:3=20=EC=A1=B0=EC=9D=B8=20?= =?UTF-8?q?=EC=8B=9C=20=EC=84=B1=EB=B3=84=20=EC=B2=B4=ED=81=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../meetingteam/service/impl/TripleMeetingService.kt | 1 + .../uoslife/servermeeting/meetingteam/util/Validator.kt | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/main/kotlin/uoslife/servermeeting/meetingteam/service/impl/TripleMeetingService.kt b/src/main/kotlin/uoslife/servermeeting/meetingteam/service/impl/TripleMeetingService.kt index d0f968f1..aa1bd686 100644 --- a/src/main/kotlin/uoslife/servermeeting/meetingteam/service/impl/TripleMeetingService.kt +++ b/src/main/kotlin/uoslife/servermeeting/meetingteam/service/impl/TripleMeetingService.kt @@ -76,6 +76,7 @@ class TripleMeetingService( meetingTeamRepository.findByCode(code) ?: throw MeetingTeamNotFoundException() validator.isTeamFull(meetingTeam) + validator.isGenderSame(meetingTeam, user) val newUserTeam = UserTeam.createUserTeam(meetingTeam, user, false) userTeamRepository.save(newUserTeam) diff --git a/src/main/kotlin/uoslife/servermeeting/meetingteam/util/Validator.kt b/src/main/kotlin/uoslife/servermeeting/meetingteam/util/Validator.kt index f02e76a9..01e68702 100644 --- a/src/main/kotlin/uoslife/servermeeting/meetingteam/util/Validator.kt +++ b/src/main/kotlin/uoslife/servermeeting/meetingteam/util/Validator.kt @@ -61,4 +61,10 @@ class Validator { } return validMBTI } + + fun isGenderSame(meetingTeam: MeetingTeam, user: User) { + if(meetingTeam.gender != user.gender){ + throw TeamConsistOfSameGenderException() + } + } } From 8e81c4410248d519163628a29a38b61d12e492bd Mon Sep 17 00:00:00 2001 From: woojin Date: Sun, 1 Dec 2024 23:53:02 +0900 Subject: [PATCH 02/21] style: apply convention --- .../kotlin/uoslife/servermeeting/meetingteam/util/Validator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/uoslife/servermeeting/meetingteam/util/Validator.kt b/src/main/kotlin/uoslife/servermeeting/meetingteam/util/Validator.kt index 01e68702..765f056d 100644 --- a/src/main/kotlin/uoslife/servermeeting/meetingteam/util/Validator.kt +++ b/src/main/kotlin/uoslife/servermeeting/meetingteam/util/Validator.kt @@ -63,7 +63,7 @@ class Validator { } fun isGenderSame(meetingTeam: MeetingTeam, user: User) { - if(meetingTeam.gender != user.gender){ + if (meetingTeam.gender != user.gender) { throw TeamConsistOfSameGenderException() } } From 1b1253d2c82fb879a3adc09f96ba190dd414fb60 Mon Sep 17 00:00:00 2001 From: woojin Date: Mon, 2 Dec 2024 00:22:17 +0900 Subject: [PATCH 03/21] =?UTF-8?q?fix:=20=EB=AF=B8=ED=8C=85=ED=8C=80=20?= =?UTF-8?q?=EB=82=98=EC=9D=B4=20=EC=A0=9C=ED=95=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/MeetingTeamInfoUpdateRequest.kt | 42 +++++++------------ 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/src/main/kotlin/uoslife/servermeeting/meetingteam/dto/request/MeetingTeamInfoUpdateRequest.kt b/src/main/kotlin/uoslife/servermeeting/meetingteam/dto/request/MeetingTeamInfoUpdateRequest.kt index 110798fa..58b07fc8 100644 --- a/src/main/kotlin/uoslife/servermeeting/meetingteam/dto/request/MeetingTeamInfoUpdateRequest.kt +++ b/src/main/kotlin/uoslife/servermeeting/meetingteam/dto/request/MeetingTeamInfoUpdateRequest.kt @@ -42,8 +42,18 @@ class MeetingTeamInfoUpdateRequest( } fun toSinglePreference(validMBTI: String?, meetingTeam: MeetingTeam): Preference { return Preference( - ageMin = if (ageMin < MINIMUM_AGE) MINIMUM_AGE else ageMin, - ageMax = if (ageMax > MAXIMAL_AGE) MAXIMAL_AGE else ageMax, + ageMin = + if (ageMin < MINIMUM_AGE) { //20살 미만 + MINIMUM_AGE + } else if (ageMin > MAXIMAL_AGE) { //30살 초과 + MAXIMAL_AGE + } else ageMin, + ageMax = + if (ageMax > MAXIMAL_AGE) { + MAXIMAL_AGE + } else if (ageMax < MINIMUM_AGE) { + MINIMUM_AGE + } else ageMax, heightMin = heightMin, heightMax = heightMax, appearanceType = appearanceType, @@ -59,34 +69,10 @@ class MeetingTeamInfoUpdateRequest( fun toTriplePreference(meetingTeam: MeetingTeam): Preference { return Preference( - ageMin = if (ageMin < MINIMUM_AGE) MINIMUM_AGE else ageMin, - ageMax = if (ageMax > MAXIMAL_AGE) MAXIMAL_AGE else ageMax, + ageMin = ageMin, + ageMax = ageMax, mood = mood, meetingTeam = meetingTeam ) } - - fun updatePreference(preference: Preference, validMBTI: String?, teamType: TeamType) { - when (teamType) { - TeamType.SINGLE -> { - preference.ageMin = ageMin ?: preference.ageMin - preference.ageMax = ageMax ?: preference.ageMax - preference.heightMin = heightMin ?: preference.heightMin - preference.heightMax = heightMax ?: preference.heightMax - preference.appearanceType = appearanceType ?: preference.appearanceType - preference.eyelidType = eyelidType ?: preference.eyelidType - preference.smoking = smoking ?: preference.smoking - preference.mbti = validMBTI ?: preference.mbti - preference.weight = weight ?: preference.weight - preference.avoidanceDepartment = - avoidanceDepartment ?: preference.avoidanceDepartment - preference.avoidanceNumber = avoidanceNumber ?: preference.avoidanceNumber - } - TeamType.TRIPLE -> { - preference.ageMin = ageMin ?: preference.ageMin - preference.ageMax = ageMax ?: preference.ageMax - preference.mood = mood ?: preference.mood - } - } - } } From d06482fc0eb98a127ed3362ea9dc7edbfa22361e Mon Sep 17 00:00:00 2001 From: woojin Date: Mon, 2 Dec 2024 01:05:16 +0900 Subject: [PATCH 04/21] style: apply convention --- .../dto/request/MeetingTeamInfoUpdateRequest.kt | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/uoslife/servermeeting/meetingteam/dto/request/MeetingTeamInfoUpdateRequest.kt b/src/main/kotlin/uoslife/servermeeting/meetingteam/dto/request/MeetingTeamInfoUpdateRequest.kt index 58b07fc8..b03e45f6 100644 --- a/src/main/kotlin/uoslife/servermeeting/meetingteam/dto/request/MeetingTeamInfoUpdateRequest.kt +++ b/src/main/kotlin/uoslife/servermeeting/meetingteam/dto/request/MeetingTeamInfoUpdateRequest.kt @@ -6,7 +6,6 @@ import jakarta.validation.constraints.Size import uoslife.servermeeting.meetingteam.entity.MeetingTeam import uoslife.servermeeting.meetingteam.entity.Preference import uoslife.servermeeting.meetingteam.entity.enums.TeamMood -import uoslife.servermeeting.meetingteam.entity.enums.TeamType import uoslife.servermeeting.meetingteam.entity.enums.Weight import uoslife.servermeeting.user.entity.enums.* @@ -43,9 +42,9 @@ class MeetingTeamInfoUpdateRequest( fun toSinglePreference(validMBTI: String?, meetingTeam: MeetingTeam): Preference { return Preference( ageMin = - if (ageMin < MINIMUM_AGE) { //20살 미만 + if (ageMin < MINIMUM_AGE) { // 20살 미만 MINIMUM_AGE - } else if (ageMin > MAXIMAL_AGE) { //30살 초과 + } else if (ageMin > MAXIMAL_AGE) { // 30살 초과 MAXIMAL_AGE } else ageMin, ageMax = @@ -68,11 +67,6 @@ class MeetingTeamInfoUpdateRequest( } fun toTriplePreference(meetingTeam: MeetingTeam): Preference { - return Preference( - ageMin = ageMin, - ageMax = ageMax, - mood = mood, - meetingTeam = meetingTeam - ) + return Preference(ageMin = ageMin, ageMax = ageMax, mood = mood, meetingTeam = meetingTeam) } } From a661e2d2c0a57b2a344b3d8a10ab8de18d7836f8 Mon Sep 17 00:00:00 2001 From: woojin Date: Mon, 2 Dec 2024 02:34:11 +0900 Subject: [PATCH 05/21] =?UTF-8?q?feat:=20=EC=B9=B4=EC=B9=B4=EC=98=A4?= =?UTF-8?q?=ED=86=A1=20ID=20=EC=A4=91=EB=B3=B5=20=EC=8B=9C,=20=EC=9C=A0?= =?UTF-8?q?=EC=A0=80=20ID=20=EC=B2=B4=ED=81=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../servermeeting/global/config/SecurityConfig.kt | 1 - .../uoslife/servermeeting/user/api/UserApi.kt | 4 ++-- .../servermeeting/user/service/UserService.kt | 14 +++++++++----- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/uoslife/servermeeting/global/config/SecurityConfig.kt b/src/main/kotlin/uoslife/servermeeting/global/config/SecurityConfig.kt index 529c887e..6bd249d4 100644 --- a/src/main/kotlin/uoslife/servermeeting/global/config/SecurityConfig.kt +++ b/src/main/kotlin/uoslife/servermeeting/global/config/SecurityConfig.kt @@ -47,7 +47,6 @@ class SecurityConfig( .requestMatchers( "/swagger-ui/**", "/meeting/actuator/health/**", - "/api/user/isDuplicatedKakaoTalkId", "/api/payment/refund/match", "/api/payment/webhook", "/api/auth/reissue", diff --git a/src/main/kotlin/uoslife/servermeeting/user/api/UserApi.kt b/src/main/kotlin/uoslife/servermeeting/user/api/UserApi.kt index 79e35149..8f0d92c0 100644 --- a/src/main/kotlin/uoslife/servermeeting/user/api/UserApi.kt +++ b/src/main/kotlin/uoslife/servermeeting/user/api/UserApi.kt @@ -237,8 +237,8 @@ class UserApi( )] ) @GetMapping("/check/kakao-talk-id") - fun isDuplicatedKakaoTalkId(@RequestParam kakaoTalkId: String): ResponseEntity { - return ResponseEntity.ok(userService.isDuplicatedKakaoTalkId(kakaoTalkId)) + fun isDuplicatedKakaoTalkId(@RequestParam kakaoTalkId: String,@AuthenticationPrincipal userDetails: UserDetails,): ResponseEntity { + return ResponseEntity.ok(userService.isDuplicatedKakaoTalkId(userDetails.username.toLong(), kakaoTalkId)) } @Operation(summary = "유저 미팅팀 별 기본 정보", description = "유저의 1:1, 3:3팀의 현재 상태를 요약합니다") diff --git a/src/main/kotlin/uoslife/servermeeting/user/service/UserService.kt b/src/main/kotlin/uoslife/servermeeting/user/service/UserService.kt index 7d72689d..77db2a1d 100644 --- a/src/main/kotlin/uoslife/servermeeting/user/service/UserService.kt +++ b/src/main/kotlin/uoslife/servermeeting/user/service/UserService.kt @@ -81,10 +81,11 @@ class UserService( @Transactional fun updateUserPersonalInformation(command: UserCommand.UpdateUserPersonalInformation): User { - val user = getUser(command.userId) - if (command.kakaoTalkId != null && command.kakaoTalkId != user.kakaoTalkId) { - isDuplicatedKakaoTalkId(command.kakaoTalkId) + if(command.kakaoTalkId != null){ + isDuplicatedKakaoTalkId(command.userId, command.kakaoTalkId) } + + val user = getUser(command.userId) return updateUserProfile(user, command) } @@ -124,8 +125,11 @@ class UserService( } } - fun isDuplicatedKakaoTalkId(kakaoTalkId: String): Boolean { - if (userRepository.existsByKakaoTalkId(kakaoTalkId)) throw KakaoTalkIdDuplicationException() + fun isDuplicatedKakaoTalkId(userId: Long, kakaoTalkId: String): Boolean { + val user = getUser(userId) + if (kakaoTalkId != user.kakaoTalkId) { + if (userRepository.existsByKakaoTalkId(kakaoTalkId)) throw KakaoTalkIdDuplicationException() + } return true } From 6156e5589d9b3a8c209c788e58f78c939a67c592 Mon Sep 17 00:00:00 2001 From: woojin Date: Mon, 2 Dec 2024 02:34:57 +0900 Subject: [PATCH 06/21] style: apply convention --- .../kotlin/uoslife/servermeeting/user/api/UserApi.kt | 9 +++++++-- .../uoslife/servermeeting/user/service/UserService.kt | 5 +++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/uoslife/servermeeting/user/api/UserApi.kt b/src/main/kotlin/uoslife/servermeeting/user/api/UserApi.kt index 8f0d92c0..49b7cf7b 100644 --- a/src/main/kotlin/uoslife/servermeeting/user/api/UserApi.kt +++ b/src/main/kotlin/uoslife/servermeeting/user/api/UserApi.kt @@ -237,8 +237,13 @@ class UserApi( )] ) @GetMapping("/check/kakao-talk-id") - fun isDuplicatedKakaoTalkId(@RequestParam kakaoTalkId: String,@AuthenticationPrincipal userDetails: UserDetails,): ResponseEntity { - return ResponseEntity.ok(userService.isDuplicatedKakaoTalkId(userDetails.username.toLong(), kakaoTalkId)) + fun isDuplicatedKakaoTalkId( + @RequestParam kakaoTalkId: String, + @AuthenticationPrincipal userDetails: UserDetails, + ): ResponseEntity { + return ResponseEntity.ok( + userService.isDuplicatedKakaoTalkId(userDetails.username.toLong(), kakaoTalkId) + ) } @Operation(summary = "유저 미팅팀 별 기본 정보", description = "유저의 1:1, 3:3팀의 현재 상태를 요약합니다") diff --git a/src/main/kotlin/uoslife/servermeeting/user/service/UserService.kt b/src/main/kotlin/uoslife/servermeeting/user/service/UserService.kt index 77db2a1d..7592b667 100644 --- a/src/main/kotlin/uoslife/servermeeting/user/service/UserService.kt +++ b/src/main/kotlin/uoslife/servermeeting/user/service/UserService.kt @@ -81,7 +81,7 @@ class UserService( @Transactional fun updateUserPersonalInformation(command: UserCommand.UpdateUserPersonalInformation): User { - if(command.kakaoTalkId != null){ + if (command.kakaoTalkId != null) { isDuplicatedKakaoTalkId(command.userId, command.kakaoTalkId) } @@ -128,7 +128,8 @@ class UserService( fun isDuplicatedKakaoTalkId(userId: Long, kakaoTalkId: String): Boolean { val user = getUser(userId) if (kakaoTalkId != user.kakaoTalkId) { - if (userRepository.existsByKakaoTalkId(kakaoTalkId)) throw KakaoTalkIdDuplicationException() + if (userRepository.existsByKakaoTalkId(kakaoTalkId)) + throw KakaoTalkIdDuplicationException() } return true } From a44d70daa1b7e63f8b8d6dbf2c3abe8bb3ade895 Mon Sep 17 00:00:00 2001 From: woojin Date: Mon, 2 Dec 2024 03:09:46 +0900 Subject: [PATCH 07/21] =?UTF-8?q?fix:=20=ED=8F=AC=ED=8A=B8=EC=9B=90=20Acce?= =?UTF-8?q?ss=20Token=20=EC=83=9D=EC=A1=B4=20=EA=B8=B0=EA=B0=84=2060?= =?UTF-8?q?=EC=B4=88=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - try - catch 시 refreshToken 추가 --- .../global/error/exception/ErrorCode.kt | 1 + .../payment/exception/RefundFailedException.kt | 6 ++++++ .../payment/service/impl/PortOneAPIService.kt | 11 ++++++++++- .../payment/service/impl/PortOneService.kt | 16 +++++++++------- 4 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 src/main/kotlin/uoslife/servermeeting/payment/exception/RefundFailedException.kt diff --git a/src/main/kotlin/uoslife/servermeeting/global/error/exception/ErrorCode.kt b/src/main/kotlin/uoslife/servermeeting/global/error/exception/ErrorCode.kt index 428e335c..47bf0ac5 100644 --- a/src/main/kotlin/uoslife/servermeeting/global/error/exception/ErrorCode.kt +++ b/src/main/kotlin/uoslife/servermeeting/global/error/exception/ErrorCode.kt @@ -119,6 +119,7 @@ enum class ErrorCode(val code: String, val message: String, var status: Int) { "User Payment refund is not completed.", HttpStatus.PRECONDITION_FAILED.value() ), + PAYMENT_REFUND_FAILED("P06", "User Refund Failed", HttpStatus.INTERNAL_SERVER_ERROR.value()), // Email Verification EMAIL_INVALID_FORMAT("E01", "Invalid email format.", HttpStatus.BAD_REQUEST.value()), diff --git a/src/main/kotlin/uoslife/servermeeting/payment/exception/RefundFailedException.kt b/src/main/kotlin/uoslife/servermeeting/payment/exception/RefundFailedException.kt new file mode 100644 index 00000000..b3e59dba --- /dev/null +++ b/src/main/kotlin/uoslife/servermeeting/payment/exception/RefundFailedException.kt @@ -0,0 +1,6 @@ +package uoslife.servermeeting.payment.exception + +import uoslife.servermeeting.global.error.exception.BusinessException +import uoslife.servermeeting.global.error.exception.ErrorCode + +class RefundFailedException : BusinessException(ErrorCode.PAYMENT_REFUND_FAILED) diff --git a/src/main/kotlin/uoslife/servermeeting/payment/service/impl/PortOneAPIService.kt b/src/main/kotlin/uoslife/servermeeting/payment/service/impl/PortOneAPIService.kt index 7b046f29..182ac04b 100644 --- a/src/main/kotlin/uoslife/servermeeting/payment/service/impl/PortOneAPIService.kt +++ b/src/main/kotlin/uoslife/servermeeting/payment/service/impl/PortOneAPIService.kt @@ -19,7 +19,7 @@ class PortOneAPIService( companion object { const val ACCESS_TOKEN_KEY = "PORTONE_ACCESS_KEY" const val SUCCESS_CODE = 0 - const val TOKEN_VALID_TIME = 1700L // 포트원 1800초 보다 축소 + const val TOKEN_VALID_TIME = 60L // 포트원 1800초 보다 축소 } private fun getAccessToken(): String { val accessKey = redisTemplate.opsForValue().get(ACCESS_TOKEN_KEY) @@ -36,6 +36,15 @@ class PortOneAPIService( return newAccessToken } + fun refreshAccessToken() { + val accessTokenResponse = requestAccessToken() + checkResponseCode(accessTokenResponse) + val newAccessToken = accessTokenResponse.response!!.access_token + redisTemplate + .opsForValue() + .set(ACCESS_TOKEN_KEY, newAccessToken, Duration.ofSeconds(TOKEN_VALID_TIME)) + } + private fun requestAccessToken(): PortOneResponseDto.AccessTokenResponse { return paymentClient.getAccessToken( PortOneRequestDto.AccessTokenRequest(imp_key = impKey, imp_secret = impSecret) diff --git a/src/main/kotlin/uoslife/servermeeting/payment/service/impl/PortOneService.kt b/src/main/kotlin/uoslife/servermeeting/payment/service/impl/PortOneService.kt index 17a2fc81..84f2d141 100644 --- a/src/main/kotlin/uoslife/servermeeting/payment/service/impl/PortOneService.kt +++ b/src/main/kotlin/uoslife/servermeeting/payment/service/impl/PortOneService.kt @@ -21,10 +21,7 @@ import uoslife.servermeeting.payment.dto.request.PaymentRequestDto import uoslife.servermeeting.payment.dto.response.PaymentResponseDto import uoslife.servermeeting.payment.entity.Payment import uoslife.servermeeting.payment.entity.enums.PaymentStatus -import uoslife.servermeeting.payment.exception.PaymentInValidException -import uoslife.servermeeting.payment.exception.PaymentNotFoundException -import uoslife.servermeeting.payment.exception.RefundPrecedeException -import uoslife.servermeeting.payment.exception.UserAlreadyHavePaymentException +import uoslife.servermeeting.payment.exception.* import uoslife.servermeeting.payment.repository.PaymentRepository import uoslife.servermeeting.payment.service.PaymentService import uoslife.servermeeting.user.dao.UserDao @@ -141,7 +138,9 @@ class PortOneService( updatePaymentStatus(payment, PaymentStatus.SUCCESS, paymentCheckRequest.impUid) return PaymentResponseDto.PaymentCheckResponse(true, "") } - } catch (_: ExternalApiFailedException) {} + } catch (_: ExternalApiFailedException) { + portOneAPIService.refreshAccessToken() + } updatePaymentStatus(payment, PaymentStatus.FAILED, paymentCheckRequest.impUid) return PaymentResponseDto.PaymentCheckResponse(false, "") @@ -165,7 +164,8 @@ class PortOneService( updatePaymentStatus(payment, PaymentStatus.REFUND, payment.impUid!!) } catch (e: ExternalApiFailedException) { - return PaymentResponseDto.PaymentRefundResponse(false, "") + portOneAPIService.refreshAccessToken() + throw RefundFailedException() } when (teamType) { @@ -234,7 +234,9 @@ class PortOneService( pendingPayment!!.status ) } - } catch (_: ExternalApiFailedException) {} + } catch (_: ExternalApiFailedException) { + portOneAPIService.refreshAccessToken() + } logger.info("[결제 검증 실패] merchantUid : ${pendingPayment!!.merchantUid}") pendingPayment!!.status = PaymentStatus.FAILED throw PaymentNotFoundException() From 26a47e8918e7a31ab28a417e87d84df721508a24 Mon Sep 17 00:00:00 2001 From: woojin Date: Mon, 2 Dec 2024 14:16:17 +0900 Subject: [PATCH 08/21] =?UTF-8?q?fix:=20=EC=9C=A0=EC=A0=80=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 학적 상태 졸업생, 대학원생으로 변경 시 학부 학번 삭제 - 전화번호 중복 예외 출력 --- .../global/error/exception/ErrorCode.kt | 1 + .../PhoneNumberDuplicationException.kt | 6 ++++ .../user/repository/UserRepository.kt | 3 +- .../servermeeting/user/service/UserService.kt | 30 +++++++++++++++---- 4 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 src/main/kotlin/uoslife/servermeeting/user/exception/PhoneNumberDuplicationException.kt diff --git a/src/main/kotlin/uoslife/servermeeting/global/error/exception/ErrorCode.kt b/src/main/kotlin/uoslife/servermeeting/global/error/exception/ErrorCode.kt index 47bf0ac5..23ef3ebe 100644 --- a/src/main/kotlin/uoslife/servermeeting/global/error/exception/ErrorCode.kt +++ b/src/main/kotlin/uoslife/servermeeting/global/error/exception/ErrorCode.kt @@ -27,6 +27,7 @@ enum class ErrorCode(val code: String, val message: String, var status: Int) { ), KAKAO_TALK_ID_DUPLICATED("U11", "Kakao Talk ID is Duplicated.", HttpStatus.BAD_REQUEST.value()), USER_TEAM_NOT_FOUND("U12", "UserTeam is not Found.", HttpStatus.BAD_REQUEST.value()), + PHONE_NUMBER_DUPLICATED("U13", "PhoneNumber is Duplicated.", HttpStatus.BAD_REQUEST.value()), // User - Token INVALID_TOKEN("T01", "Token is not valid.", HttpStatus.UNAUTHORIZED.value()), diff --git a/src/main/kotlin/uoslife/servermeeting/user/exception/PhoneNumberDuplicationException.kt b/src/main/kotlin/uoslife/servermeeting/user/exception/PhoneNumberDuplicationException.kt new file mode 100644 index 00000000..6ff6ae52 --- /dev/null +++ b/src/main/kotlin/uoslife/servermeeting/user/exception/PhoneNumberDuplicationException.kt @@ -0,0 +1,6 @@ +package uoslife.servermeeting.user.exception + +import uoslife.servermeeting.global.error.exception.BusinessException +import uoslife.servermeeting.global.error.exception.ErrorCode + +class PhoneNumberDuplicationException : BusinessException(ErrorCode.PHONE_NUMBER_DUPLICATED) diff --git a/src/main/kotlin/uoslife/servermeeting/user/repository/UserRepository.kt b/src/main/kotlin/uoslife/servermeeting/user/repository/UserRepository.kt index 19913b08..aaf96cfc 100644 --- a/src/main/kotlin/uoslife/servermeeting/user/repository/UserRepository.kt +++ b/src/main/kotlin/uoslife/servermeeting/user/repository/UserRepository.kt @@ -4,9 +4,8 @@ import org.springframework.data.jpa.repository.JpaRepository import uoslife.servermeeting.user.entity.User interface UserRepository : JpaRepository { - fun findByPhoneNumber(phoneNumber: String): User? - fun existsByKakaoTalkId(kakaoTalkId: String): Boolean + fun existsByPhoneNumber(phoneNumber: String): Boolean fun findByEmail(email: String): User? } diff --git a/src/main/kotlin/uoslife/servermeeting/user/service/UserService.kt b/src/main/kotlin/uoslife/servermeeting/user/service/UserService.kt index 7592b667..53e79b8d 100644 --- a/src/main/kotlin/uoslife/servermeeting/user/service/UserService.kt +++ b/src/main/kotlin/uoslife/servermeeting/user/service/UserService.kt @@ -22,10 +22,8 @@ import uoslife.servermeeting.user.dao.UserDao import uoslife.servermeeting.user.dto.response.UserBranchResponse import uoslife.servermeeting.user.entity.User import uoslife.servermeeting.user.entity.UserInformation -import uoslife.servermeeting.user.exception.GenderNotUpdatableException -import uoslife.servermeeting.user.exception.KakaoTalkIdDuplicationException -import uoslife.servermeeting.user.exception.UserInformationNotFoundException -import uoslife.servermeeting.user.exception.UserNotFoundException +import uoslife.servermeeting.user.entity.enums.StudentType +import uoslife.servermeeting.user.exception.* import uoslife.servermeeting.user.repository.UserInformationRepository import uoslife.servermeeting.user.repository.UserRepository @@ -84,11 +82,23 @@ class UserService( if (command.kakaoTalkId != null) { isDuplicatedKakaoTalkId(command.userId, command.kakaoTalkId) } + if (command.phoneNumber != null) { + isDuplicatedPhoneNumber(command.userId, command.phoneNumber) + } val user = getUser(command.userId) return updateUserProfile(user, command) } + private fun isDuplicatedPhoneNumber(userId: Long, phoneNumber: String): Boolean { + val user = getUser(userId) + if (phoneNumber != user.phoneNumber) { + if (userRepository.existsByPhoneNumber(phoneNumber)) + throw PhoneNumberDuplicationException() + } + return true + } + /** * id로 유저를 삭제합니다. 유저를 삭제하기 전 진행사항 유저의 1:1 미팅팀 삭제, 유저 3:3 미팅팀 삭제 (팅장일 경우), 유저 3:3 미팅팀 탈퇴 (팅원일 경우) * 외부키로 연결되어 있는 Payment를 삭제합니다. 결제가 이뤄진 경우 진행합니다. @@ -104,10 +114,10 @@ class UserService( // 결제 소프트 삭제 우선 진행 paymentService.deleteUserPayment(user) // 유저 삭제 진행 - val deletedId = user.id + val deletedEmail = user.email userRepository.delete(user) cookieUtils.deleteRefreshTokenCookie(response) - logger.info("[유저 삭제 완료] UserId : $deletedId") + logger.info("[유저 삭제 완료] User Email : $deletedEmail") } private fun deleteUserMeetingTeam(userId: Long, userTeam: UserTeam) { @@ -151,6 +161,14 @@ class UserService( information.eyelidType = command.eyelidType ?: information.eyelidType information.appearanceType = command.appearanceType ?: information.appearanceType information.studentType = command.studentType ?: information.studentType + + if ( + information.studentType == StudentType.GRADUATE || + information.studentType == StudentType.POSTGRADUATE + ) { + information.department = null + information.studentNumber = null + } return user } From 0a504f78e6e9f5c26a52246a8669da4279df45a4 Mon Sep 17 00:00:00 2001 From: woojin Date: Mon, 2 Dec 2024 17:58:15 +0900 Subject: [PATCH 09/21] =?UTF-8?q?fix:=20=EA=B0=9C=EB=B0=9C=EC=9E=90=20API?= =?UTF-8?q?=20=EC=9C=A0=EC=A0=80=20=EC=82=AD=EC=A0=9C=20=EC=8B=9C,=20?= =?UTF-8?q?=EB=A6=AC=ED=94=84=EB=A0=88=EC=8B=9C=20=ED=86=A0=ED=81=B0=20?= =?UTF-8?q?=EC=B4=88=EA=B8=B0=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../uoslife/servermeeting/user/service/UserService.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/uoslife/servermeeting/user/service/UserService.kt b/src/main/kotlin/uoslife/servermeeting/user/service/UserService.kt index 53e79b8d..f470c7af 100644 --- a/src/main/kotlin/uoslife/servermeeting/user/service/UserService.kt +++ b/src/main/kotlin/uoslife/servermeeting/user/service/UserService.kt @@ -7,6 +7,7 @@ import org.springframework.context.annotation.Lazy import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional +import uoslife.servermeeting.global.auth.security.JwtTokenProvider import uoslife.servermeeting.global.auth.util.CookieUtils import uoslife.servermeeting.meetingteam.dao.UserTeamDao import uoslife.servermeeting.meetingteam.entity.MeetingTeam @@ -37,6 +38,7 @@ class UserService( private val userTeamDao: UserTeamDao, private val validator: Validator, private val cookieUtils: CookieUtils, + private val jwtTokenProvider: JwtTokenProvider, @Qualifier("portOneService") private val paymentService: PaymentService, @Lazy @Qualifier("singleMeetingService") private val singleMeetingService: BaseMeetingService, @Lazy @Qualifier("tripleMeetingService") private val tripleMeetingService: BaseMeetingService @@ -115,11 +117,17 @@ class UserService( paymentService.deleteUserPayment(user) // 유저 삭제 진행 val deletedEmail = user.email + + deleteRefreshInfo(user, response) userRepository.delete(user) - cookieUtils.deleteRefreshTokenCookie(response) logger.info("[유저 삭제 완료] User Email : $deletedEmail") } + private fun deleteRefreshInfo(user: User, response: HttpServletResponse) { + cookieUtils.deleteRefreshTokenCookie(response) + jwtTokenProvider.deleteRefreshToken(user.id!!) + } + private fun deleteUserMeetingTeam(userId: Long, userTeam: UserTeam) { when (userTeam.team.type) { TeamType.SINGLE -> { From 9ed60c2853a6ce5328dd36e5aa2ffd83fc7c6d65 Mon Sep 17 00:00:00 2001 From: woojin Date: Tue, 3 Dec 2024 00:50:33 +0900 Subject: [PATCH 10/21] =?UTF-8?q?fix:=20MinAge=20MaxAge=20Null=20=EA=B0=92?= =?UTF-8?q?=20=EA=B1=B0=EC=A0=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../meetingteam/dto/request/MeetingTeamInfoUpdateRequest.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/uoslife/servermeeting/meetingteam/dto/request/MeetingTeamInfoUpdateRequest.kt b/src/main/kotlin/uoslife/servermeeting/meetingteam/dto/request/MeetingTeamInfoUpdateRequest.kt index b03e45f6..26206228 100644 --- a/src/main/kotlin/uoslife/servermeeting/meetingteam/dto/request/MeetingTeamInfoUpdateRequest.kt +++ b/src/main/kotlin/uoslife/servermeeting/meetingteam/dto/request/MeetingTeamInfoUpdateRequest.kt @@ -1,7 +1,7 @@ package uoslife.servermeeting.meetingteam.dto.request import io.swagger.v3.oas.annotations.media.Schema -import jakarta.validation.constraints.NotNull +import jakarta.validation.constraints.Min import jakarta.validation.constraints.Size import uoslife.servermeeting.meetingteam.entity.MeetingTeam import uoslife.servermeeting.meetingteam.entity.Preference @@ -16,8 +16,8 @@ class MeetingTeamInfoUpdateRequest( @Schema(description = "3:3 팀 이름 (2~8자)", example = "우당탕탕 시립대") @field:Size(min = 2, max = 8) val name: String?, - @Schema(description = "최소 나이", example = "20", nullable = false) @field:NotNull val ageMin: Int, - @Schema(description = "최대 나이", example = "30", nullable = false) @field:NotNull val ageMax: Int, + @Schema(description = "최소 나이", example = "20", nullable = false) @field:Min(1) val ageMin: Int, + @Schema(description = "최대 나이", example = "30", nullable = false) @field:Min(1) val ageMax: Int, @Schema(description = "최소 키", example = "150") val heightMin: Int?, @Schema(description = "최대 키", example = "190") val heightMax: Int?, @Schema(description = "외모1 (상관없음 시, 모두)", example = "[\"ARAB\",\"NORMAL\",\"TOFU\"]") From eb69489e9beca0df8fba5aafff7f046d5617a6e7 Mon Sep 17 00:00:00 2001 From: 23tae Date: Wed, 4 Dec 2024 01:02:29 +0900 Subject: [PATCH 11/21] =?UTF-8?q?feat:=20Match=20API=20=EC=97=94=EB=93=9C?= =?UTF-8?q?=ED=8F=AC=EC=9D=B8=ED=8A=B8=20=EA=B2=BD=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - /matches/{matchId}/result -> /matches/result로 변경 - 요청 파라미터를 teamId에서 teamType으로 변경 --- .../uoslife/servermeeting/match/api/MatchApi.kt | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/uoslife/servermeeting/match/api/MatchApi.kt b/src/main/kotlin/uoslife/servermeeting/match/api/MatchApi.kt index 23eb4beb..3943c5fd 100644 --- a/src/main/kotlin/uoslife/servermeeting/match/api/MatchApi.kt +++ b/src/main/kotlin/uoslife/servermeeting/match/api/MatchApi.kt @@ -20,6 +20,7 @@ import uoslife.servermeeting.match.dto.response.MatchResultResponse import uoslife.servermeeting.match.dto.response.MeetingParticipationResponse import uoslife.servermeeting.match.service.MatchingService import uoslife.servermeeting.meetingteam.dto.response.MeetingTeamInformationGetResponse +import uoslife.servermeeting.meetingteam.entity.enums.TeamType @RestController @RequestMapping("/api/match") @@ -78,13 +79,13 @@ class MatchApi( )] )] ) - @GetMapping("/teams/{teamId}/result") + @GetMapping("/{teamType}/result") fun getMatchResult( - @PathVariable teamId: Long, + @PathVariable teamType: TeamType, @AuthenticationPrincipal userDetails: UserDetails ): ResponseEntity { return ResponseEntity.ok( - matchingService.getMatchResult(userDetails.username.toLong(), teamId) + matchingService.getMatchResult(userDetails.username.toLong(), teamType) ) } @@ -138,14 +139,17 @@ class MatchApi( ), ] ) - @GetMapping("/{matchId}/partner") + @GetMapping("/{teamType}/partner") fun getMatchedPartnerInformation( - @PathVariable matchId: Long, + @PathVariable teamType: TeamType, @AuthenticationPrincipal userDetails: UserDetails, ): ResponseEntity { return ResponseEntity.status(HttpStatus.OK) .body( - matchingService.getMatchedPartnerInformation(userDetails.username.toLong(), matchId) + matchingService.getMatchedPartnerInformation( + userDetails.username.toLong(), + teamType + ) ) } } From 87d0c5a2c28029197e978628f2aeb93c7cecd211 Mon Sep 17 00:00:00 2001 From: 23tae Date: Wed, 4 Dec 2024 01:04:47 +0900 Subject: [PATCH 12/21] =?UTF-8?q?refactor:=20MatchService=20=ED=8C=8C?= =?UTF-8?q?=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 파라미터 teamType으로 변경 - 캐시 키 형식 변경 --- .../match/service/MatchingService.kt | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/uoslife/servermeeting/match/service/MatchingService.kt b/src/main/kotlin/uoslife/servermeeting/match/service/MatchingService.kt index 066db20d..ae56e3e0 100644 --- a/src/main/kotlin/uoslife/servermeeting/match/service/MatchingService.kt +++ b/src/main/kotlin/uoslife/servermeeting/match/service/MatchingService.kt @@ -8,7 +8,6 @@ import uoslife.servermeeting.match.dto.response.* import uoslife.servermeeting.match.entity.Match import uoslife.servermeeting.match.exception.MatchNotFoundException import uoslife.servermeeting.match.exception.UnauthorizedMatchAccessException -import uoslife.servermeeting.match.exception.UnauthorizedTeamAccessException import uoslife.servermeeting.meetingteam.dao.UserTeamDao import uoslife.servermeeting.meetingteam.dto.request.CompletionStatus import uoslife.servermeeting.meetingteam.dto.response.MeetingTeamInformationGetResponse @@ -44,11 +43,26 @@ class MatchingService( ) } - @Cacheable(value = ["match-result"], key = "#meetingTeamId", unless = "#result == null") - fun getMatchResult(userId: Long, meetingTeamId: Long): MatchResultResponse { + @Cacheable( + value = ["match-result"], + key = "#userId + ':' + #teamType", + unless = "#result == null" + ) + fun getMatchResult(userId: Long, teamType: TeamType): MatchResultResponse { + // 미팅 참여 여부 확인 + val participation = getUserMeetingParticipation(userId) + val participationStatus = + when (teamType) { + SINGLE -> participation.single + TRIPLE -> participation.triple + } + if (!participationStatus.isParticipated) { + throw MeetingTeamNotFoundException() + } + // 매칭 결과 조회 val result = - matchedDao.findMatchResultByUserIdAndTeamId(userId, meetingTeamId) - ?: throw UnauthorizedTeamAccessException() + matchedDao.findMatchResultByUserIdAndTeamType(userId, teamType) + ?: throw MeetingTeamNotFoundException() return MatchResultResponse( matchType = result.teamType, @@ -59,14 +73,18 @@ class MatchingService( @Cacheable( value = ["partner-info"], - key = "#matchId + ':' + #userId", + key = "#userId + ':' + #teamType", unless = "#result == null" ) fun getMatchedPartnerInformation( userId: Long, - matchId: Long + teamType: TeamType ): MeetingTeamInformationGetResponse { - val response = getPartnerInformation(userId, matchId) + val matchResult = getMatchResult(userId, teamType) + if (!matchResult.isMatched || matchResult.matchId == null) { + throw MatchNotFoundException() + } + val response = getPartnerInformation(userId, matchResult.matchId) return convertPersistentBagToArrayList(response) } From 9fbc9373e7ba4d5eb25ba3349c0a089396d62598 Mon Sep 17 00:00:00 2001 From: 23tae Date: Wed, 4 Dec 2024 01:05:33 +0900 Subject: [PATCH 13/21] =?UTF-8?q?feat:=20teamType=20=EC=82=AC=EC=9A=A9=20?= =?UTF-8?q?=EC=BF=BC=EB=A6=AC=20=EB=A9=94=EC=86=8C=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../uoslife/servermeeting/match/dao/MatchedDao.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/kotlin/uoslife/servermeeting/match/dao/MatchedDao.kt b/src/main/kotlin/uoslife/servermeeting/match/dao/MatchedDao.kt index 1a6eb084..03cceaa5 100644 --- a/src/main/kotlin/uoslife/servermeeting/match/dao/MatchedDao.kt +++ b/src/main/kotlin/uoslife/servermeeting/match/dao/MatchedDao.kt @@ -10,6 +10,7 @@ import uoslife.servermeeting.match.entity.QMatch.match import uoslife.servermeeting.meetingteam.entity.MeetingTeam import uoslife.servermeeting.meetingteam.entity.QMeetingTeam.meetingTeam import uoslife.servermeeting.meetingteam.entity.QUserTeam.userTeam +import uoslife.servermeeting.meetingteam.entity.enums.TeamType @Repository @Transactional @@ -62,4 +63,15 @@ class MatchedDao(private val queryFactory: JPAQueryFactory) { .where(match.id.eq(matchId)) .fetchOne() } + + fun findMatchResultByUserIdAndTeamType(userId: Long, teamType: TeamType): MatchResultDto? { + return queryFactory + .select(Projections.constructor(MatchResultDto::class.java, meetingTeam.type, match.id)) + .from(userTeam) + .join(userTeam.team, meetingTeam) + .leftJoin(match) + .on(meetingTeam.eq(match.maleTeam).or(meetingTeam.eq(match.femaleTeam))) + .where(userTeam.user.id.eq(userId), meetingTeam.type.eq(teamType)) + .fetchOne() + } } From 97c5378fb1506f26f3265d079d94bf199efdfbbc Mon Sep 17 00:00:00 2001 From: 23tae Date: Wed, 4 Dec 2024 01:07:03 +0900 Subject: [PATCH 14/21] =?UTF-8?q?chore:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../servermeeting/match/dao/MatchedDao.kt | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/src/main/kotlin/uoslife/servermeeting/match/dao/MatchedDao.kt b/src/main/kotlin/uoslife/servermeeting/match/dao/MatchedDao.kt index 03cceaa5..88574cc4 100644 --- a/src/main/kotlin/uoslife/servermeeting/match/dao/MatchedDao.kt +++ b/src/main/kotlin/uoslife/servermeeting/match/dao/MatchedDao.kt @@ -33,26 +33,6 @@ class MatchedDao(private val queryFactory: JPAQueryFactory) { .fetchOne() } - fun findByTeam(team: MeetingTeam): Match? { - return queryFactory - .selectFrom(match) - .leftJoin(match.maleTeam, meetingTeam) - .leftJoin(match.femaleTeam, meetingTeam) - .where(match.maleTeam.eq(team).or(match.femaleTeam.eq(team))) - .fetchOne() - } - - fun findMatchResultByUserIdAndTeamId(userId: Long, teamId: Long): MatchResultDto? { - return queryFactory - .select(Projections.constructor(MatchResultDto::class.java, meetingTeam.type, match.id)) - .from(userTeam) - .join(userTeam.team, meetingTeam) - .leftJoin(match) - .on(meetingTeam.eq(match.maleTeam).or(meetingTeam.eq(match.femaleTeam))) - .where(userTeam.user.id.eq(userId), userTeam.team.id.eq(teamId)) - .fetchOne() - } - fun findById(matchId: Long): Match? { return queryFactory .selectFrom(match) From 2bea39ff1f4ca9a44ad144966876525a4c2c4eae Mon Sep 17 00:00:00 2001 From: 23tae Date: Wed, 4 Dec 2024 01:31:24 +0900 Subject: [PATCH 15/21] =?UTF-8?q?chore:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../uoslife/servermeeting/match/service/MatchingService.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/kotlin/uoslife/servermeeting/match/service/MatchingService.kt b/src/main/kotlin/uoslife/servermeeting/match/service/MatchingService.kt index ae56e3e0..036ed792 100644 --- a/src/main/kotlin/uoslife/servermeeting/match/service/MatchingService.kt +++ b/src/main/kotlin/uoslife/servermeeting/match/service/MatchingService.kt @@ -60,9 +60,7 @@ class MatchingService( throw MeetingTeamNotFoundException() } // 매칭 결과 조회 - val result = - matchedDao.findMatchResultByUserIdAndTeamType(userId, teamType) - ?: throw MeetingTeamNotFoundException() + val result = matchedDao.findMatchResultByUserIdAndTeamType(userId, teamType)!! return MatchResultResponse( matchType = result.teamType, From 36dce8fe6356956f5d23895a37a829d2a7e91fd7 Mon Sep 17 00:00:00 2001 From: 23tae Date: Wed, 4 Dec 2024 01:32:21 +0900 Subject: [PATCH 16/21] =?UTF-8?q?docs:=20Swagger=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../servermeeting/global/auth/api/AuthApi.kt | 2 +- .../servermeeting/match/api/MatchApi.kt | 33 +++++++------------ .../verification/api/VerificationApi.kt | 2 +- 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/src/main/kotlin/uoslife/servermeeting/global/auth/api/AuthApi.kt b/src/main/kotlin/uoslife/servermeeting/global/auth/api/AuthApi.kt index 866c7ca0..986f5add 100644 --- a/src/main/kotlin/uoslife/servermeeting/global/auth/api/AuthApi.kt +++ b/src/main/kotlin/uoslife/servermeeting/global/auth/api/AuthApi.kt @@ -20,7 +20,7 @@ import uoslife.servermeeting.global.auth.service.AuthService import uoslife.servermeeting.global.auth.util.CookieUtils import uoslife.servermeeting.global.error.ErrorResponse -@Tag(name = "Auth", description = "Auth API") +@Tag(name = "Auth", description = "인증 API") @RestController @RequestMapping("/api/auth") class AuthApi( diff --git a/src/main/kotlin/uoslife/servermeeting/match/api/MatchApi.kt b/src/main/kotlin/uoslife/servermeeting/match/api/MatchApi.kt index 3943c5fd..432d0b8a 100644 --- a/src/main/kotlin/uoslife/servermeeting/match/api/MatchApi.kt +++ b/src/main/kotlin/uoslife/servermeeting/match/api/MatchApi.kt @@ -24,7 +24,7 @@ import uoslife.servermeeting.meetingteam.entity.enums.TeamType @RestController @RequestMapping("/api/match") -@Tag(name = "Match", description = "매칭 API") +@Tag(name = "Match", description = "매칭 내역 조회 API") class MatchApi( private val matchingService: MatchingService, ) { @@ -63,8 +63,8 @@ class MatchApi( [Content(schema = Schema(implementation = MatchResultResponse::class))] ), ApiResponse( - responseCode = "403", - description = "해당 팀에 대한 접근 권한 없음", + responseCode = "400", + description = "해당 타입의 미팅 신청 내역 없음", content = [ Content( @@ -72,9 +72,9 @@ class MatchApi( examples = [ ExampleObject( - name = "MT03", + name = "Meeting Team Not Found", value = - "{\"message\": \"Unauthorized team access.\", \"status\": 403, \"code\": \"MT03\"}" + "{\"message\": \"Meeting Team is not Found.\", \"status\": 400, \"code\": \"M06\"}" )] )] )] @@ -107,7 +107,7 @@ class MatchApi( ), ApiResponse( responseCode = "400", - description = "매치를 찾을 수 없음", + description = "신청 내역 또는 성공 내역 없음", content = [ Content( @@ -115,25 +115,14 @@ class MatchApi( examples = [ ExampleObject( - name = "MT01", + name = "Meeting Team Not Found", value = - "{\"message\": \"Match is not Found.\", \"status\": 400, \"code\": \"MT01\"}" - )] - )] - ), - ApiResponse( - responseCode = "403", - description = "해당 매치에 대한 접근 권한 없음", - content = - [ - Content( - schema = Schema(implementation = ErrorResponse::class), - examples = - [ + "{\"message\": \"Meeting Team is not Found.\", \"status\": 400, \"code\": \"M06\"}" + ), ExampleObject( - name = "MT04", + name = "Match Not Found", value = - "{\"message\": \"Unauthorized match access.\", \"status\": 403, \"code\": \"MT04\"}" + "{\"message\": \"Match is not Found.\", \"status\": 400, \"code\": \"MT01\"}" )] )] ), diff --git a/src/main/kotlin/uoslife/servermeeting/verification/api/VerificationApi.kt b/src/main/kotlin/uoslife/servermeeting/verification/api/VerificationApi.kt index 0586fe09..156e2c7b 100644 --- a/src/main/kotlin/uoslife/servermeeting/verification/api/VerificationApi.kt +++ b/src/main/kotlin/uoslife/servermeeting/verification/api/VerificationApi.kt @@ -19,7 +19,7 @@ import uoslife.servermeeting.verification.dto.request.VerifyEmailRequest import uoslife.servermeeting.verification.dto.response.SendVerificationEmailResponse import uoslife.servermeeting.verification.service.EmailVerificationService -@Tag(name = "Verification", description = "Verification API") +@Tag(name = "Verification", description = "이메일 인증 API") @RestController @RequestMapping("/api/verification") class VerificationApi( From 67d3d9c7ae53318222de6313b498254a96489fe3 Mon Sep 17 00:00:00 2001 From: 23tae Date: Wed, 4 Dec 2024 02:31:24 +0900 Subject: [PATCH 17/21] =?UTF-8?q?refactor:=20getMatchedPartnerInformation?= =?UTF-8?q?=20API=EC=97=90=EC=84=9C=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C?= =?UTF-8?q?=20preference=20=EC=A0=95=EB=B3=B4=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 책임 분리를 위해 새로운 DTO 생성 - ArrayList 변환 로직에서 preference 변환 제거 --- .../servermeeting/match/api/MatchApi.kt | 3 +- .../MatchedPartnerInformationResponse.kt | 30 +++++++++++++++++++ .../match/service/MatchingService.kt | 13 ++------ 3 files changed, 35 insertions(+), 11 deletions(-) create mode 100644 src/main/kotlin/uoslife/servermeeting/match/dto/response/MatchedPartnerInformationResponse.kt diff --git a/src/main/kotlin/uoslife/servermeeting/match/api/MatchApi.kt b/src/main/kotlin/uoslife/servermeeting/match/api/MatchApi.kt index 432d0b8a..2221a40c 100644 --- a/src/main/kotlin/uoslife/servermeeting/match/api/MatchApi.kt +++ b/src/main/kotlin/uoslife/servermeeting/match/api/MatchApi.kt @@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController import uoslife.servermeeting.global.error.ErrorResponse import uoslife.servermeeting.match.dto.response.MatchResultResponse +import uoslife.servermeeting.match.dto.response.MatchedPartnerInformationResponse import uoslife.servermeeting.match.dto.response.MeetingParticipationResponse import uoslife.servermeeting.match.service.MatchingService import uoslife.servermeeting.meetingteam.dto.response.MeetingTeamInformationGetResponse @@ -132,7 +133,7 @@ class MatchApi( fun getMatchedPartnerInformation( @PathVariable teamType: TeamType, @AuthenticationPrincipal userDetails: UserDetails, - ): ResponseEntity { + ): ResponseEntity { return ResponseEntity.status(HttpStatus.OK) .body( matchingService.getMatchedPartnerInformation( diff --git a/src/main/kotlin/uoslife/servermeeting/match/dto/response/MatchedPartnerInformationResponse.kt b/src/main/kotlin/uoslife/servermeeting/match/dto/response/MatchedPartnerInformationResponse.kt new file mode 100644 index 00000000..09ebb5f0 --- /dev/null +++ b/src/main/kotlin/uoslife/servermeeting/match/dto/response/MatchedPartnerInformationResponse.kt @@ -0,0 +1,30 @@ +package uoslife.servermeeting.match.dto.response + +import uoslife.servermeeting.meetingteam.dto.response.MeetingTeamInformationGetResponse +import uoslife.servermeeting.meetingteam.dto.response.UserCardProfile +import uoslife.servermeeting.meetingteam.entity.enums.TeamType +import uoslife.servermeeting.user.entity.enums.GenderType + +data class MatchedPartnerInformationResponse( + val teamType: TeamType, + val teamName: String?, + val course: String?, + val gender: GenderType, + val code: String?, + val meetingTeamUserProfiles: List? +) + +object MeetingDtoConverter { + fun toMatchedPartnerInformationResponse( + response: MeetingTeamInformationGetResponse + ): MatchedPartnerInformationResponse { + return MatchedPartnerInformationResponse( + teamType = response.teamType, + teamName = response.teamName, + course = response.course, + gender = response.gender, + code = response.code, + meetingTeamUserProfiles = response.meetingTeamUserProfiles + ) + } +} diff --git a/src/main/kotlin/uoslife/servermeeting/match/service/MatchingService.kt b/src/main/kotlin/uoslife/servermeeting/match/service/MatchingService.kt index 036ed792..69327e8e 100644 --- a/src/main/kotlin/uoslife/servermeeting/match/service/MatchingService.kt +++ b/src/main/kotlin/uoslife/servermeeting/match/service/MatchingService.kt @@ -77,13 +77,14 @@ class MatchingService( fun getMatchedPartnerInformation( userId: Long, teamType: TeamType - ): MeetingTeamInformationGetResponse { + ): MatchedPartnerInformationResponse { val matchResult = getMatchResult(userId, teamType) if (!matchResult.isMatched || matchResult.matchId == null) { throw MatchNotFoundException() } val response = getPartnerInformation(userId, matchResult.matchId) - return convertPersistentBagToArrayList(response) + val convertedResponse = convertPersistentBagToArrayList(response) + return MeetingDtoConverter.toMatchedPartnerInformationResponse(convertedResponse) } @Transactional @@ -201,14 +202,6 @@ class MatchingService( meetingTeamUserProfiles = response.meetingTeamUserProfiles?.map { profile -> profile.copy(interest = profile.interest?.let { ArrayList(it) }) - }, - preference = - response.preference?.let { pref -> - pref.copy( - smoking = pref.smoking?.let { ArrayList(it) }, - appearanceType = pref.appearanceType?.let { ArrayList(it) }, - eyelidType = pref.eyelidType?.let { ArrayList(it) } - ) } ) } From 3610b273dba081b41374aeb5bd437ac3d60a357a Mon Sep 17 00:00:00 2001 From: 23tae Date: Wed, 4 Dec 2024 03:15:18 +0900 Subject: [PATCH 18/21] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B9=AD=20API=20?= =?UTF-8?q?=EC=8B=9C=EC=A6=8C=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../servermeeting/match/api/MatchApi.kt | 22 ++++++++++--------- .../match/service/MatchingService.kt | 13 ++++++----- .../meetingteam/dao/UserTeamDao.kt | 8 +++++-- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/main/kotlin/uoslife/servermeeting/match/api/MatchApi.kt b/src/main/kotlin/uoslife/servermeeting/match/api/MatchApi.kt index 2221a40c..03afe7e2 100644 --- a/src/main/kotlin/uoslife/servermeeting/match/api/MatchApi.kt +++ b/src/main/kotlin/uoslife/servermeeting/match/api/MatchApi.kt @@ -11,10 +11,7 @@ import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.security.core.annotation.AuthenticationPrincipal import org.springframework.security.core.userdetails.UserDetails -import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.PathVariable -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RestController +import org.springframework.web.bind.annotation.* import uoslife.servermeeting.global.error.ErrorResponse import uoslife.servermeeting.match.dto.response.MatchResultResponse import uoslife.servermeeting.match.dto.response.MatchedPartnerInformationResponse @@ -47,9 +44,11 @@ class MatchApi( ) @GetMapping("/me/participations") fun getUserMeetingParticipation( - @AuthenticationPrincipal userDetails: UserDetails + @AuthenticationPrincipal userDetails: UserDetails, + @RequestParam season: Int, ): ResponseEntity { - val result = matchingService.getUserMeetingParticipation(userDetails.username.toLong()) + val result = + matchingService.getUserMeetingParticipation(userDetails.username.toLong(), season) return ResponseEntity.ok(result) } @@ -82,11 +81,12 @@ class MatchApi( ) @GetMapping("/{teamType}/result") fun getMatchResult( + @AuthenticationPrincipal userDetails: UserDetails, @PathVariable teamType: TeamType, - @AuthenticationPrincipal userDetails: UserDetails + @RequestParam season: Int, ): ResponseEntity { return ResponseEntity.ok( - matchingService.getMatchResult(userDetails.username.toLong(), teamType) + matchingService.getMatchResult(userDetails.username.toLong(), teamType, season) ) } @@ -131,14 +131,16 @@ class MatchApi( ) @GetMapping("/{teamType}/partner") fun getMatchedPartnerInformation( - @PathVariable teamType: TeamType, @AuthenticationPrincipal userDetails: UserDetails, + @PathVariable teamType: TeamType, + @RequestParam season: Int, ): ResponseEntity { return ResponseEntity.status(HttpStatus.OK) .body( matchingService.getMatchedPartnerInformation( userDetails.username.toLong(), - teamType + teamType, + season ) ) } diff --git a/src/main/kotlin/uoslife/servermeeting/match/service/MatchingService.kt b/src/main/kotlin/uoslife/servermeeting/match/service/MatchingService.kt index 69327e8e..2520e0cc 100644 --- a/src/main/kotlin/uoslife/servermeeting/match/service/MatchingService.kt +++ b/src/main/kotlin/uoslife/servermeeting/match/service/MatchingService.kt @@ -34,8 +34,8 @@ class MatchingService( private val tripleMeetingService: TripleMeetingService, ) { @Cacheable(value = ["meeting-participation"], key = "#userId", unless = "#result == null") - fun getUserMeetingParticipation(userId: Long): MeetingParticipationResponse { - val userTeams = userTeamDao.findAllByUserIdWithPaymentStatus(userId) + fun getUserMeetingParticipation(userId: Long, season: Int): MeetingParticipationResponse { + val userTeams = userTeamDao.findAllByUserIdAndSeasonWithPaymentStatus(userId, season) return MeetingParticipationResponse( single = getParticipationStatus(userTeams.find { it.team.type == SINGLE }), @@ -48,9 +48,9 @@ class MatchingService( key = "#userId + ':' + #teamType", unless = "#result == null" ) - fun getMatchResult(userId: Long, teamType: TeamType): MatchResultResponse { + fun getMatchResult(userId: Long, teamType: TeamType, season: Int): MatchResultResponse { // 미팅 참여 여부 확인 - val participation = getUserMeetingParticipation(userId) + val participation = getUserMeetingParticipation(userId, season) val participationStatus = when (teamType) { SINGLE -> participation.single @@ -76,9 +76,10 @@ class MatchingService( ) fun getMatchedPartnerInformation( userId: Long, - teamType: TeamType + teamType: TeamType, + season: Int ): MatchedPartnerInformationResponse { - val matchResult = getMatchResult(userId, teamType) + val matchResult = getMatchResult(userId, teamType, season) if (!matchResult.isMatched || matchResult.matchId == null) { throw MatchNotFoundException() } diff --git a/src/main/kotlin/uoslife/servermeeting/meetingteam/dao/UserTeamDao.kt b/src/main/kotlin/uoslife/servermeeting/meetingteam/dao/UserTeamDao.kt index a4112982..e95d42e0 100644 --- a/src/main/kotlin/uoslife/servermeeting/meetingteam/dao/UserTeamDao.kt +++ b/src/main/kotlin/uoslife/servermeeting/meetingteam/dao/UserTeamDao.kt @@ -98,7 +98,7 @@ class UserTeamDao( .fetch() } - fun findAllByUserIdWithPaymentStatus(userId: Long): List { + fun findAllByUserIdAndSeasonWithPaymentStatus(userId: Long, season: Int): List { val hasNonSuccessPayment = JPAExpressions.selectOne() .from(payment) @@ -112,7 +112,11 @@ class UserTeamDao( .selectFrom(userTeam) .join(userTeam.team, meetingTeam) .fetchJoin() - .where(userTeam.user.id.eq(userId), hasNonSuccessPayment.not()) + .where( + userTeam.user.id.eq(userId), + meetingTeam.season.eq(season), + hasNonSuccessPayment.not() + ) .fetch() } From 52395bf8ded13c20bfbb6c4238c361e07d60159d Mon Sep 17 00:00:00 2001 From: 23tae Date: Wed, 4 Dec 2024 03:20:13 +0900 Subject: [PATCH 19/21] =?UTF-8?q?feat:=20=ED=95=84=EC=88=98=20=ED=8C=8C?= =?UTF-8?q?=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EB=88=84=EB=9D=BD=EC=8B=9C=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/error/GlobalExceptionHandler.kt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/kotlin/uoslife/servermeeting/global/error/GlobalExceptionHandler.kt b/src/main/kotlin/uoslife/servermeeting/global/error/GlobalExceptionHandler.kt index 3ec283a9..10b85833 100644 --- a/src/main/kotlin/uoslife/servermeeting/global/error/GlobalExceptionHandler.kt +++ b/src/main/kotlin/uoslife/servermeeting/global/error/GlobalExceptionHandler.kt @@ -8,6 +8,7 @@ import org.springframework.http.converter.HttpMessageNotReadableException import org.springframework.security.core.AuthenticationException import org.springframework.web.HttpRequestMethodNotSupportedException import org.springframework.web.bind.MethodArgumentNotValidException +import org.springframework.web.bind.MissingServletRequestParameterException import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.web.bind.annotation.RestControllerAdvice import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException @@ -119,4 +120,14 @@ class GlobalExceptionHandler { val response = ErrorResponse(errorCode) return ResponseEntity(response, HttpStatus.valueOf(errorCode.status)) } + + @ExceptionHandler(MissingServletRequestParameterException::class) + fun handleMissingServletRequestParameterException( + exception: MissingServletRequestParameterException + ): ResponseEntity { + logger.error("MissingServletRequestParameterException", exception) + val errorCode = ErrorCode.INVALID_INPUT_VALUE + val response = ErrorResponse(errorCode) + return ResponseEntity(response, HttpStatus.valueOf(errorCode.status)) + } } From 1831a3617f0fab029f28acf302610872d467aa10 Mon Sep 17 00:00:00 2001 From: woojin Date: Sat, 7 Dec 2024 16:43:04 +0900 Subject: [PATCH 20/21] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EC=9A=A9=20=EC=9E=84=EC=8B=9C=20=EC=9D=B4=EB=A9=94=EC=9D=BC=20?= =?UTF-8?q?=EC=A0=84=EC=86=A1=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../servermeeting/verification/service/AsyncEmailService.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/uoslife/servermeeting/verification/service/AsyncEmailService.kt b/src/main/kotlin/uoslife/servermeeting/verification/service/AsyncEmailService.kt index 8ada7ff1..495caacc 100644 --- a/src/main/kotlin/uoslife/servermeeting/verification/service/AsyncEmailService.kt +++ b/src/main/kotlin/uoslife/servermeeting/verification/service/AsyncEmailService.kt @@ -66,6 +66,6 @@ class AsyncEmailService( .withBody(Body().withHtml(Content(emailBody))) ) .withSource(emailFrom) - sesClient.sendEmail(request) + // sesClient.sendEmail(request) } } From d7ad83aacef88867610b821a2f2e00678f216764 Mon Sep 17 00:00:00 2001 From: woojin Date: Sat, 7 Dec 2024 23:59:52 +0900 Subject: [PATCH 21/21] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B9=AD=20=EC=95=88?= =?UTF-8?q?=EB=90=9C=20=EA=B2=B0=EC=A0=9C=20=EC=A0=95=EB=B3=B4=20=ED=99=98?= =?UTF-8?q?=EB=B6=88=20=EB=A1=9C=EC=A7=81=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/service/AdminService.kt | 2 +- .../global/external/PortOneAPI.kt | 1 - .../payment/service/PaymentService.kt | 2 +- .../payment/service/impl/PortOneService.kt | 56 ++++++++++++------- 4 files changed, 39 insertions(+), 22 deletions(-) diff --git a/src/main/kotlin/uoslife/servermeeting/admin/service/AdminService.kt b/src/main/kotlin/uoslife/servermeeting/admin/service/AdminService.kt index 7712eb51..27056cd3 100644 --- a/src/main/kotlin/uoslife/servermeeting/admin/service/AdminService.kt +++ b/src/main/kotlin/uoslife/servermeeting/admin/service/AdminService.kt @@ -48,7 +48,7 @@ class AdminService( fun refundPayment( requestInfo: RequestInfoDto ): PaymentResponseDto.NotMatchedPaymentRefundResponse { - val result = paymentService.refundPayment() + val result = paymentService.refundUnmatchedPayment() logger.info("[ADMIN-매칭 실패 유저 환불] $requestInfo") return result } diff --git a/src/main/kotlin/uoslife/servermeeting/global/external/PortOneAPI.kt b/src/main/kotlin/uoslife/servermeeting/global/external/PortOneAPI.kt index ba19706d..751831c9 100644 --- a/src/main/kotlin/uoslife/servermeeting/global/external/PortOneAPI.kt +++ b/src/main/kotlin/uoslife/servermeeting/global/external/PortOneAPI.kt @@ -16,7 +16,6 @@ interface PaymentClient { fun getAccessToken( @RequestBody request: PortOneRequestDto.AccessTokenRequest ): PortOneResponseDto.AccessTokenResponse - @GetMapping("/payments/{impUid}", consumes = ["application/json"]) fun checkPayment( @RequestHeader("Authorization") accessToken: String, diff --git a/src/main/kotlin/uoslife/servermeeting/payment/service/PaymentService.kt b/src/main/kotlin/uoslife/servermeeting/payment/service/PaymentService.kt index 606f567c..388d2f9b 100644 --- a/src/main/kotlin/uoslife/servermeeting/payment/service/PaymentService.kt +++ b/src/main/kotlin/uoslife/servermeeting/payment/service/PaymentService.kt @@ -22,7 +22,7 @@ interface PaymentService { userId: Long, teamType: TeamType ): PaymentResponseDto.PaymentRefundResponse - fun refundPayment(): PaymentResponseDto.NotMatchedPaymentRefundResponse + fun refundUnmatchedPayment(): PaymentResponseDto.NotMatchedPaymentRefundResponse fun verifyPayment(userId: Long, teamType: TeamType): PaymentResponseDto.PaymentRequestResponse fun deleteUserPayment(user: User) fun synchronizePayment(paymentWebhookResponse: PaymentResponseDto.PaymentWebhookResponse) diff --git a/src/main/kotlin/uoslife/servermeeting/payment/service/impl/PortOneService.kt b/src/main/kotlin/uoslife/servermeeting/payment/service/impl/PortOneService.kt index 84f2d141..b24f9962 100644 --- a/src/main/kotlin/uoslife/servermeeting/payment/service/impl/PortOneService.kt +++ b/src/main/kotlin/uoslife/servermeeting/payment/service/impl/PortOneService.kt @@ -8,7 +8,7 @@ import org.springframework.beans.factory.annotation.Value import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service import uoslife.servermeeting.global.auth.exception.ExternalApiFailedException -import uoslife.servermeeting.meetingteam.dao.MeetingTeamDao +import uoslife.servermeeting.match.dao.MatchedDao import uoslife.servermeeting.meetingteam.dao.UserTeamDao import uoslife.servermeeting.meetingteam.entity.MeetingTeam import uoslife.servermeeting.meetingteam.entity.UserTeam @@ -24,8 +24,8 @@ import uoslife.servermeeting.payment.entity.enums.PaymentStatus import uoslife.servermeeting.payment.exception.* import uoslife.servermeeting.payment.repository.PaymentRepository import uoslife.servermeeting.payment.service.PaymentService -import uoslife.servermeeting.user.dao.UserDao import uoslife.servermeeting.user.entity.User +import uoslife.servermeeting.user.entity.enums.GenderType import uoslife.servermeeting.user.exception.UserNotFoundException import uoslife.servermeeting.user.repository.UserRepository @@ -33,14 +33,13 @@ import uoslife.servermeeting.user.repository.UserRepository @Qualifier("PortOneService") class PortOneService( private val userRepository: UserRepository, - private val userDao: UserDao, private val userTeamDao: UserTeamDao, private val paymentDao: PaymentDao, - private val meetingTeamDao: MeetingTeamDao, private val paymentRepository: PaymentRepository, private val validator: Validator, private val userTeamRepository: UserTeamRepository, private val portOneAPIService: PortOneAPIService, + private val matchedDao: MatchedDao, @Value("\${portone.api.price.single}") private val singlePrice: Int, @Value("\${portone.api.price.triple}") private val triplePrice: Int, ) : PaymentService { @@ -284,27 +283,46 @@ class PortOneService( } @Transactional - override fun refundPayment(): PaymentResponseDto.NotMatchedPaymentRefundResponse { - val userList = - meetingTeamDao - .findUserIdWithMaleMeetingTeam() - .plus(meetingTeamDao.findUserIdWithFeMaleMeetingTeam()) - val paymentList = userDao.findNotMatchedPayment(userList) - logger.info("Total payment count: " + paymentList.size) + override fun refundUnmatchedPayment(): PaymentResponseDto.NotMatchedPaymentRefundResponse { + val successPayments = paymentRepository.findByStatus(PaymentStatus.SUCCESS) + + val unMatchedPayments = mutableListOf() + successPayments.forEach { payment -> + if (!isMatchedPayment(payment)) { + unMatchedPayments.add(payment) + } + } + logger.info("Total unmatched payment count: " + unMatchedPayments.size) val refundFailedList: MutableList = mutableListOf() - paymentList.forEach { payment -> + unMatchedPayments.forEach { payment -> try { - portOneAPIService.refundPayment(payment.impUid, payment.price) - updatePaymentStatus(payment, PaymentStatus.REFUND, payment.impUid!!) + val refundPayment = portOneAPIService.refundPayment(payment.impUid, payment.price) + if (refundPayment.code == 0) { + updatePaymentStatus(payment, PaymentStatus.REFUND, payment.impUid!!) + } else { + updatePaymentStatus(payment, PaymentStatus.REFUND_FAILED, payment.impUid!!) + refundFailedList.add(payment.impUid.toString()) + } } catch (e: ExternalApiFailedException) { - logger.info( - "[환불 실패] payment_id: ${payment.id}, impUid: ${payment.impUid}, marchantUid: ${payment.merchantUid}" - ) - refundFailedList.add(payment.id.toString()) - payment.status = PaymentStatus.REFUND_FAILED + updatePaymentStatus(payment, PaymentStatus.REFUND_FAILED, payment.impUid!!) + refundFailedList.add(payment.impUid.toString()) } } return PaymentResponseDto.NotMatchedPaymentRefundResponse(refundFailedList) } + + private fun isMatchedPayment(payment: Payment): Boolean { + val meetingTeam = payment.meetingTeam ?: throw MeetingTeamNotFoundException() + val matched = + when (meetingTeam.gender) { + GenderType.MALE -> { + matchedDao.findMatchByMaleTeamWithFemaleTeam(meetingTeam) + } + GenderType.FEMALE -> { + matchedDao.findMatchByFeMaleTeamWithMaleTeam(meetingTeam) + } + } + return matched != null + } }