From f5e884320774e0c89d5dea21c94e82ef45c4024c Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Tue, 19 Sep 2023 20:44:50 +0900 Subject: [PATCH 01/41] =?UTF-8?q?[NAYB-155]=20refactor:=20`OAuthProvider`?= =?UTF-8?q?=20=EC=BD=94=EB=93=9C=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/oauth/handler/OAuthProvider.java | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/prgrms/nabmart/global/auth/oauth/handler/OAuthProvider.java b/src/main/java/com/prgrms/nabmart/global/auth/oauth/handler/OAuthProvider.java index 17d48556e..feea76fa3 100644 --- a/src/main/java/com/prgrms/nabmart/global/auth/oauth/handler/OAuthProvider.java +++ b/src/main/java/com/prgrms/nabmart/global/auth/oauth/handler/OAuthProvider.java @@ -20,21 +20,8 @@ @Getter @RequiredArgsConstructor public enum OAuthProvider { - KAKAO("kakao", attributes -> { - Map properties = (Map) attributes.get("properties"); - String oAuthUserId = String.valueOf(attributes.get("id")); - String nickname = properties.get("nickname"); - Map kakaoAccount = (Map) attributes.get("kakao_account"); - String email = String.valueOf(kakaoAccount.get("email")); - return new OAuthUserInfo(oAuthUserId, nickname, email); - }, new KakaoMessageProvider()), - NAVER("naver", attributes -> { - Map response = (Map) attributes.get("response"); - String oAuthUserId = response.get("id"); - String nickname = response.get("nickname"); - String email = response.get("email"); - return new OAuthUserInfo(oAuthUserId, nickname, email); - }, new NaverMessageProvider()); + KAKAO("kakao", OAuthProvider::extractKakaoUserInfo, new KakaoMessageProvider()), + NAVER("naver", OAuthProvider::extractNaverUserInfo, new NaverMessageProvider()); private static final Map PROVIDERS = Collections.unmodifiableMap(Stream.of(values()) @@ -44,6 +31,23 @@ public enum OAuthProvider { private final Function, OAuthUserInfo> extractUserInfo; private final OAuthHttpMessageProvider oAuthHttpMessageProvider; + private static OAuthUserInfo extractNaverUserInfo(Map attributes) { + Map response = (Map) attributes.get("response"); + String oAuthUserId = response.get("id"); + String nickname = response.get("nickname"); + String email = response.get("email"); + return new OAuthUserInfo(oAuthUserId, nickname, email); + } + + private static OAuthUserInfo extractKakaoUserInfo(Map attributes) { + Map properties = (Map) attributes.get("properties"); + String oAuthUserId = String.valueOf(attributes.get("id")); + String nickname = properties.get("nickname"); + Map kakaoAccount = (Map) attributes.get("kakao_account"); + String email = String.valueOf(kakaoAccount.get("email")); + return new OAuthUserInfo(oAuthUserId, nickname, email); + } + public static OAuthProvider getOAuthProvider(final String provider) { OAuthProvider oAuthProvider = PROVIDERS.get(provider); return Optional.ofNullable(oAuthProvider) From 0834f8cefa3a24af45fdcbf0864f9f391538c203 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Tue, 19 Sep 2023 21:10:35 +0900 Subject: [PATCH 02/41] =?UTF-8?q?[NAYB-155]=20refactor:=20`OAuthHttpMessag?= =?UTF-8?q?eProvider`=20=EA=B5=AC=ED=98=84=EC=B2=B4=EC=9D=98=20=EC=83=81?= =?UTF-8?q?=EC=88=98=EB=93=A4=EC=9D=84=20=EA=B4=80=EB=A6=AC=ED=95=A0=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/client/KakaoMessageProvider.java | 23 +++++----------- .../oauth/client/NaverMessageProvider.java | 17 +++--------- .../auth/oauth/constant/OAuthConstant.java | 26 +++++++++++++++++++ 3 files changed, 35 insertions(+), 31 deletions(-) create mode 100644 src/main/java/com/prgrms/nabmart/global/auth/oauth/constant/OAuthConstant.java diff --git a/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/KakaoMessageProvider.java b/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/KakaoMessageProvider.java index f0ada83f5..971de9a65 100644 --- a/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/KakaoMessageProvider.java +++ b/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/KakaoMessageProvider.java @@ -1,5 +1,9 @@ package com.prgrms.nabmart.global.auth.oauth.client; +import static com.prgrms.nabmart.global.auth.oauth.constant.OAuthConstant.*; +import static org.springframework.http.HttpHeaders.AUTHORIZATION; +import static org.springframework.http.HttpHeaders.CONTENT_TYPE; + import com.prgrms.nabmart.domain.user.service.response.FindUserDetailResponse; import com.prgrms.nabmart.global.auth.exception.OAuthUnlinkFailureException; import com.prgrms.nabmart.global.auth.oauth.dto.OAuthHttpMessage; @@ -8,7 +12,6 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; -import lombok.RequiredArgsConstructor; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; @@ -19,25 +22,10 @@ import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; -@RequiredArgsConstructor public class KakaoMessageProvider implements OAuthHttpMessageProvider { private static final String UNLINK_URI = "https://kapi.kakao.com/v1/user/unlink"; private static final String ACCESS_TOKEN_REFRESH_URI = "https://kauth.kakao.com/oauth/token"; - private static final String CONTENT_TYPE = "Content-Type"; - private static final String AUTHORIZATION = "Authorization"; - private static final String TARGET_ID_TYPE = "target_id_type"; - private static final String USER_ID = "user_id"; - private static final String TARGET_ID = "target_id"; - private static final String ID = "id"; - private static final String APPLICATION_X_WWW_FORM_URLENCODED_CHARSET_UTF_8 - = "application/x-www-form-urlencoded;charset=utf-8"; - private static final String GRANT_TYPE = "grant_type"; - private static final String REFRESH_TOKEN = "refresh_token"; - private static final String CLIENT_ID = "client_id"; - private static final String CLIENT_SECRET = "client_secret"; - private static final String ACCESS_TOKEN = "access_token"; - private static final String EXPIRES_IN = "expires_in"; @Override public OAuthHttpMessage createUserUnlinkRequest( @@ -83,7 +71,8 @@ public void checkSuccessUnlinkRequest(Map unlinkResponse) { } @Override - public OAuthHttpMessage createRefreshAccessTokenRequest(OAuth2AuthorizedClient authorizedClient) { + public OAuthHttpMessage createRefreshAccessTokenRequest( + OAuth2AuthorizedClient authorizedClient) { return new OAuthHttpMessage( ACCESS_TOKEN_REFRESH_URI, createRefreshAccessTokenMessage(authorizedClient), diff --git a/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/NaverMessageProvider.java b/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/NaverMessageProvider.java index 8c6696c4b..6e5cd0f8e 100644 --- a/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/NaverMessageProvider.java +++ b/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/NaverMessageProvider.java @@ -1,5 +1,8 @@ package com.prgrms.nabmart.global.auth.oauth.client; +import static com.prgrms.nabmart.global.auth.oauth.constant.OAuthConstant.*; +import static org.springframework.http.HttpHeaders.CONTENT_TYPE; + import com.prgrms.nabmart.domain.user.service.response.FindUserDetailResponse; import com.prgrms.nabmart.global.auth.exception.OAuthUnlinkFailureException; import com.prgrms.nabmart.global.auth.oauth.dto.OAuthHttpMessage; @@ -7,7 +10,6 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; -import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; @@ -19,7 +21,6 @@ import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; -@Slf4j public class NaverMessageProvider implements OAuthHttpMessageProvider { private static final String UNLINK_URI = "https://nid.naver.com/oauth2.0/token?" @@ -28,18 +29,6 @@ public class NaverMessageProvider implements OAuthHttpMessageProvider { private static final String REFRESH_ACCESS_TOKEN_URI = "https://nid.naver.com/oauth2.0/token?" + "grant_type=refresh_token&client_id={client_id}&" + "client_secret={client_secret}&refresh_token={refresh_token}"; - private static final String CONTENT_TYPE = "Content-Type"; - private static final String CLIENT_ID = "client_id"; - private static final String CLIENT_SECRET = "client_secret"; - private static final String ACCESS_TOKEN = "access_token"; - private static final String GRANT_TYPE = "grant_type"; - private static final String SERVICE_PROVIDER = "service_provider"; - private static final String REFRESH_TOKEN = "refresh_token"; - private static final String EXPIRES_IN = "expires_in"; - private static final String DELETE = "delete"; - private static final String NAVER = "NAVER"; - private static final String RESULT = "result"; - private static final String SUCCESS = "success"; @Override public OAuthHttpMessage createUserUnlinkRequest( diff --git a/src/main/java/com/prgrms/nabmart/global/auth/oauth/constant/OAuthConstant.java b/src/main/java/com/prgrms/nabmart/global/auth/oauth/constant/OAuthConstant.java new file mode 100644 index 000000000..66be3adcd --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/global/auth/oauth/constant/OAuthConstant.java @@ -0,0 +1,26 @@ +package com.prgrms.nabmart.global.auth.oauth.constant; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class OAuthConstant { + + public static final String CLIENT_ID = "client_id"; + public static final String CLIENT_SECRET = "client_secret"; + public static final String ACCESS_TOKEN = "access_token"; + public static final String GRANT_TYPE = "grant_type"; + public static final String SERVICE_PROVIDER = "grant_type"; + public static final String REFRESH_TOKEN = "refresh_token"; + public static final String EXPIRES_IN = "expires_in"; + public static final String DELETE = "delete"; + public static final String NAVER = "NAVER"; + public static final String RESULT = "result"; + public static final String SUCCESS = "success"; + public static final String TARGET_ID_TYPE = "target_id_type"; + public static final String USER_ID = "user_id"; + public static final String TARGET_ID = "target_id"; + public static final String ID = "id"; + public static final String APPLICATION_X_WWW_FORM_URLENCODED_CHARSET_UTF_8 + = "application/x-www-form-urlencoded;charset=utf-8"; +} From 6d5aec120d677d815ac1977ae357ecf428554e90 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Tue, 19 Sep 2023 22:38:59 +0900 Subject: [PATCH 03/41] =?UTF-8?q?[NAYB-155]=20refactor:=20`RestTemplateOAu?= =?UTF-8?q?thClient`=20=EC=BD=94=EB=93=9C=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/oauth/client/RestTemplateOAuthClient.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/RestTemplateOAuthClient.java b/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/RestTemplateOAuthClient.java index f328acc73..fc6eec367 100644 --- a/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/RestTemplateOAuthClient.java +++ b/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/RestTemplateOAuthClient.java @@ -36,10 +36,7 @@ public void callUnlinkOAuthUser(final FindUserDetailResponse userDetailResponse) userDetailResponse.provider(), userDetailResponse.providerId()); - Instant expiresAt = oAuth2AuthorizedClient.getAccessToken().getExpiresAt(); - if(expiresAt.isBefore(Instant.now())) { - refreshAccessToken(userDetailResponse); - } + refreshAccessTokenIfNotValid(userDetailResponse, oAuth2AuthorizedClient); OAuthHttpMessage unlinkHttpMessage = oAuthHttpMessageProvider.createUserUnlinkRequest( userDetailResponse, oAuth2AuthorizedClient); @@ -51,6 +48,14 @@ public void callUnlinkOAuthUser(final FindUserDetailResponse userDetailResponse) userDetailResponse.provider()); } + private void refreshAccessTokenIfNotValid(FindUserDetailResponse userDetailResponse, + OAuth2AuthorizedClient oAuth2AuthorizedClient) { + Instant expiresAt = oAuth2AuthorizedClient.getAccessToken().getExpiresAt(); + if(expiresAt.isBefore(Instant.now())) { + callRefreshAccessToken(userDetailResponse); + } + } + @Override public void refreshAccessToken(final FindUserDetailResponse userDetailResponse) { OAuthProvider oAuthProvider = OAuthProvider.getOAuthProvider(userDetailResponse.provider()); From 55b7dc8a8a956d39ca56774316a7179c9534c1d8 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Tue, 19 Sep 2023 23:06:06 +0900 Subject: [PATCH 04/41] =?UTF-8?q?[NAYB-155]=20refactor:=20`OAuthProvider`?= =?UTF-8?q?=20`oauth`=ED=8C=A8=ED=82=A4=EC=A7=80=20=ED=95=98=EC=9C=84?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nabmart/global/auth/oauth/{handler => }/OAuthProvider.java | 2 +- .../global/auth/oauth/client/RestTemplateOAuthClient.java | 2 +- .../global/auth/oauth/service/CustomOAuth2UserService.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename src/main/java/com/prgrms/nabmart/global/auth/oauth/{handler => }/OAuthProvider.java (98%) diff --git a/src/main/java/com/prgrms/nabmart/global/auth/oauth/handler/OAuthProvider.java b/src/main/java/com/prgrms/nabmart/global/auth/oauth/OAuthProvider.java similarity index 98% rename from src/main/java/com/prgrms/nabmart/global/auth/oauth/handler/OAuthProvider.java rename to src/main/java/com/prgrms/nabmart/global/auth/oauth/OAuthProvider.java index feea76fa3..61f16e8c7 100644 --- a/src/main/java/com/prgrms/nabmart/global/auth/oauth/handler/OAuthProvider.java +++ b/src/main/java/com/prgrms/nabmart/global/auth/oauth/OAuthProvider.java @@ -1,4 +1,4 @@ -package com.prgrms.nabmart.global.auth.oauth.handler; +package com.prgrms.nabmart.global.auth.oauth; import com.prgrms.nabmart.global.auth.exception.InvalidProviderException; import com.prgrms.nabmart.global.auth.oauth.client.KakaoMessageProvider; diff --git a/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/RestTemplateOAuthClient.java b/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/RestTemplateOAuthClient.java index fc6eec367..a1de7b391 100644 --- a/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/RestTemplateOAuthClient.java +++ b/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/RestTemplateOAuthClient.java @@ -2,7 +2,7 @@ import com.prgrms.nabmart.domain.user.service.response.FindUserDetailResponse; import com.prgrms.nabmart.global.auth.oauth.dto.OAuthHttpMessage; -import com.prgrms.nabmart.global.auth.oauth.handler.OAuthProvider; +import com.prgrms.nabmart.global.auth.oauth.OAuthProvider; import java.time.Instant; import java.util.List; import java.util.Map; diff --git a/src/main/java/com/prgrms/nabmart/global/auth/oauth/service/CustomOAuth2UserService.java b/src/main/java/com/prgrms/nabmart/global/auth/oauth/service/CustomOAuth2UserService.java index b7c621a15..151ada593 100644 --- a/src/main/java/com/prgrms/nabmart/global/auth/oauth/service/CustomOAuth2UserService.java +++ b/src/main/java/com/prgrms/nabmart/global/auth/oauth/service/CustomOAuth2UserService.java @@ -7,7 +7,7 @@ import com.prgrms.nabmart.domain.user.service.response.RegisterUserResponse; import com.prgrms.nabmart.global.auth.oauth.dto.CustomOAuth2User; import com.prgrms.nabmart.global.auth.oauth.dto.OAuthUserInfo; -import com.prgrms.nabmart.global.auth.oauth.handler.OAuthProvider; +import com.prgrms.nabmart.global.auth.oauth.OAuthProvider; import java.util.Map; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; From 6ebbbde477b37c18fcb67cefd9e51fc2aa73d8bf Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Tue, 19 Sep 2023 23:14:54 +0900 Subject: [PATCH 05/41] =?UTF-8?q?[NAYB-155]=20refactor:=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4,=20=EB=A9=94=EC=84=9C=EB=93=9C,=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=EB=AA=85=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RiderAuthenticationController.java | 12 +++--- ...ginRequest.java => LoginRiderRequest.java} | 2 +- ...Handler.java => AuthControllerAdvice.java} | 2 +- .../oauth/client/KakaoMessageProvider.java | 13 ++++--- .../oauth/client/NaverMessageProvider.java | 12 +++--- .../client/OAuthHttpMessageProvider.java | 4 +- .../auth/oauth/client/OAuthRestClient.java | 2 +- .../oauth/client/RestTemplateOAuthClient.java | 23 ++++++----- .../service/RiderAuthenticationService.java | 16 ++++---- .../service/request/LoginRiderCommand.java | 8 ++++ .../service/request/RiderLoginCommand.java | 8 ---- .../RiderAuthenticationControllerTest.java | 8 ++-- ...stTest.java => LoginRiderRequestTest.java} | 38 +++++++++---------- ...est.java => AuthControllerAdviceTest.java} | 4 +- .../RiderAuthenticationServiceTest.java | 14 +++---- .../global/auth/support/AuthFixture.java | 12 +++--- 16 files changed, 91 insertions(+), 87 deletions(-) rename src/main/java/com/prgrms/nabmart/global/auth/controller/request/{RiderLoginRequest.java => LoginRiderRequest.java} (95%) rename src/main/java/com/prgrms/nabmart/global/auth/exception/{AuthExceptionHandler.java => AuthControllerAdvice.java} (96%) create mode 100644 src/main/java/com/prgrms/nabmart/global/auth/service/request/LoginRiderCommand.java delete mode 100644 src/main/java/com/prgrms/nabmart/global/auth/service/request/RiderLoginCommand.java rename src/test/java/com/prgrms/nabmart/global/auth/controller/request/{RiderLoginRequestTest.java => LoginRiderRequestTest.java} (75%) rename src/test/java/com/prgrms/nabmart/global/auth/exception/{AuthExceptionHandlerTest.java => AuthControllerAdviceTest.java} (96%) diff --git a/src/main/java/com/prgrms/nabmart/global/auth/controller/RiderAuthenticationController.java b/src/main/java/com/prgrms/nabmart/global/auth/controller/RiderAuthenticationController.java index 264b9ef49..7f93857e3 100644 --- a/src/main/java/com/prgrms/nabmart/global/auth/controller/RiderAuthenticationController.java +++ b/src/main/java/com/prgrms/nabmart/global/auth/controller/RiderAuthenticationController.java @@ -2,9 +2,9 @@ import com.prgrms.nabmart.global.auth.controller.request.SignupRiderRequest; import com.prgrms.nabmart.global.auth.service.request.SignupRiderCommand; -import com.prgrms.nabmart.global.auth.controller.request.RiderLoginRequest; +import com.prgrms.nabmart.global.auth.controller.request.LoginRiderRequest; import com.prgrms.nabmart.global.auth.service.RiderAuthenticationService; -import com.prgrms.nabmart.global.auth.service.request.RiderLoginCommand; +import com.prgrms.nabmart.global.auth.service.request.LoginRiderCommand; import com.prgrms.nabmart.global.auth.service.response.RiderLoginResponse; import jakarta.validation.Valid; import java.net.URI; @@ -37,11 +37,11 @@ public ResponseEntity signupRider(@RequestBody @Valid SignupRiderRequest s @PostMapping("/riders/login") public ResponseEntity riderLogin( - @RequestBody @Valid RiderLoginRequest riderLoginRequest) { - RiderLoginCommand riderLoginCommand - = RiderLoginCommand.of(riderLoginRequest.username(), riderLoginRequest.password()); + @RequestBody @Valid LoginRiderRequest loginRiderRequest) { + LoginRiderCommand loginRiderCommand + = LoginRiderCommand.of(loginRiderRequest.username(), loginRiderRequest.password()); RiderLoginResponse riderLoginResponse - = riderAuthenticationService.riderLogin(riderLoginCommand); + = riderAuthenticationService.loginRider(loginRiderCommand); return ResponseEntity.ok(riderLoginResponse); } } diff --git a/src/main/java/com/prgrms/nabmart/global/auth/controller/request/RiderLoginRequest.java b/src/main/java/com/prgrms/nabmart/global/auth/controller/request/LoginRiderRequest.java similarity index 95% rename from src/main/java/com/prgrms/nabmart/global/auth/controller/request/RiderLoginRequest.java rename to src/main/java/com/prgrms/nabmart/global/auth/controller/request/LoginRiderRequest.java index cd8bfda14..607138eee 100644 --- a/src/main/java/com/prgrms/nabmart/global/auth/controller/request/RiderLoginRequest.java +++ b/src/main/java/com/prgrms/nabmart/global/auth/controller/request/LoginRiderRequest.java @@ -3,7 +3,7 @@ import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Pattern; -public record RiderLoginRequest( +public record LoginRiderRequest( @NotNull(message = "사용자 이름은 필수 입니다.") @Pattern(regexp = "^(?=.*[a-z])[a-z0-9]{6,20}$", message = "사용자 이름은 영어 소문자 또는 영어 소문자와 숫자 6자 이상, 20자 이하로 구성 되어야 합니다.") diff --git a/src/main/java/com/prgrms/nabmart/global/auth/exception/AuthExceptionHandler.java b/src/main/java/com/prgrms/nabmart/global/auth/exception/AuthControllerAdvice.java similarity index 96% rename from src/main/java/com/prgrms/nabmart/global/auth/exception/AuthExceptionHandler.java rename to src/main/java/com/prgrms/nabmart/global/auth/exception/AuthControllerAdvice.java index 5c2b84efe..bbaca4726 100644 --- a/src/main/java/com/prgrms/nabmart/global/auth/exception/AuthExceptionHandler.java +++ b/src/main/java/com/prgrms/nabmart/global/auth/exception/AuthControllerAdvice.java @@ -7,7 +7,7 @@ import org.springframework.web.bind.annotation.RestControllerAdvice; @RestControllerAdvice -public class AuthExceptionHandler { +public class AuthControllerAdvice { @ExceptionHandler(AuthException.class) public ResponseEntity authExHandle(AuthException ex) { diff --git a/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/KakaoMessageProvider.java b/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/KakaoMessageProvider.java index 971de9a65..baf137912 100644 --- a/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/KakaoMessageProvider.java +++ b/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/KakaoMessageProvider.java @@ -28,11 +28,11 @@ public class KakaoMessageProvider implements OAuthHttpMessageProvider { private static final String ACCESS_TOKEN_REFRESH_URI = "https://kauth.kakao.com/oauth/token"; @Override - public OAuthHttpMessage createUserUnlinkRequest( + public OAuthHttpMessage createUnlinkUserRequest( final FindUserDetailResponse userDetailResponse, final OAuth2AuthorizedClient authorizedClient) { String accessToken = getAccessToken(authorizedClient); - HttpEntity> unlinkHttpMeesage = createUnlinkOAuthUserMessage( + HttpEntity> unlinkHttpMeesage = createUnlinkUserMessage( userDetailResponse, accessToken); return new OAuthHttpMessage(UNLINK_URI, unlinkHttpMeesage, new HashMap<>()); } @@ -41,11 +41,12 @@ private String getAccessToken(final OAuth2AuthorizedClient authorizedClient) { return authorizedClient.getAccessToken().getTokenValue(); } - private HttpEntity> createUnlinkOAuthUserMessage( + private HttpEntity> createUnlinkUserMessage( final FindUserDetailResponse userDetailResponse, final String accessToken) { HttpHeaders headers = createHeader(accessToken); - MultiValueMap multiValueMap = createUnlinkMessageBody(userDetailResponse); + MultiValueMap multiValueMap + = createUnlinkUserMessageBody(userDetailResponse); return new HttpEntity<>(multiValueMap, headers); } @@ -56,7 +57,7 @@ private HttpHeaders createHeader(final String accessToken) { return headers; } - private MultiValueMap createUnlinkMessageBody( + private MultiValueMap createUnlinkUserMessageBody( final FindUserDetailResponse userDetailResponse) { MultiValueMap multiValueMap = new LinkedMultiValueMap<>(); multiValueMap.add(TARGET_ID_TYPE, USER_ID); @@ -65,7 +66,7 @@ private MultiValueMap createUnlinkMessageBody( } @Override - public void checkSuccessUnlinkRequest(Map unlinkResponse) { + public void verifySuccessUnlinkUserRequest(Map unlinkResponse) { Optional.ofNullable(unlinkResponse.get(ID)) .orElseThrow(() -> new OAuthUnlinkFailureException("소셜 로그인 연동 해제가 실패하였습니다.")); } diff --git a/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/NaverMessageProvider.java b/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/NaverMessageProvider.java index 6e5cd0f8e..ca024a8eb 100644 --- a/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/NaverMessageProvider.java +++ b/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/NaverMessageProvider.java @@ -31,12 +31,12 @@ public class NaverMessageProvider implements OAuthHttpMessageProvider { + "client_secret={client_secret}&refresh_token={refresh_token}"; @Override - public OAuthHttpMessage createUserUnlinkRequest( + public OAuthHttpMessage createUnlinkUserRequest( final FindUserDetailResponse userDetailResponse, final OAuth2AuthorizedClient authorizedClient) { String accessToken = getAccessToken(authorizedClient); - HttpEntity> unlinkHttpMessage = createUnlinkOAuthUserMessage(); - Map unlinkUriVariables = createUnlinkUriVariables( + HttpEntity> unlinkHttpMessage = createUnlinkUserMessage(); + Map unlinkUriVariables = createUnlinkUserUriVariables( authorizedClient.getClientRegistration(), accessToken); return new OAuthHttpMessage(UNLINK_URI, unlinkHttpMessage, unlinkUriVariables); } @@ -45,7 +45,7 @@ private String getAccessToken(final OAuth2AuthorizedClient authorizedClient) { return authorizedClient.getAccessToken().getTokenValue(); } - private HttpEntity> createUnlinkOAuthUserMessage() { + private HttpEntity> createUnlinkUserMessage() { HttpHeaders header = createHeader(); return new HttpEntity<>(header); } @@ -56,7 +56,7 @@ private HttpHeaders createHeader() { return headers; } - private Map createUnlinkUriVariables( + private Map createUnlinkUserUriVariables( final ClientRegistration clientRegistration, final String accessToken) { Map urlVariables = new HashMap<>(); @@ -69,7 +69,7 @@ private Map createUnlinkUriVariables( } @Override - public void checkSuccessUnlinkRequest(Map unlinkResponse) { + public void verifySuccessUnlinkUserRequest(Map unlinkResponse) { Optional.ofNullable(unlinkResponse.get(RESULT)) .filter(result -> result.equals(SUCCESS)) .orElseThrow(() -> new OAuthUnlinkFailureException("소셜 로그인 연동 해제가 실패하였습니다.")); diff --git a/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/OAuthHttpMessageProvider.java b/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/OAuthHttpMessageProvider.java index c6eb99649..2e0ced006 100644 --- a/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/OAuthHttpMessageProvider.java +++ b/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/OAuthHttpMessageProvider.java @@ -10,11 +10,11 @@ public interface OAuthHttpMessageProvider { - OAuthHttpMessage createUserUnlinkRequest( + OAuthHttpMessage createUnlinkUserRequest( final FindUserDetailResponse userDetailResponse, final OAuth2AuthorizedClient authorizedClient); - void checkSuccessUnlinkRequest(Map unlinkResponse); + void verifySuccessUnlinkUserRequest(Map unlinkResponse); OAuthHttpMessage createRefreshAccessTokenRequest(OAuth2AuthorizedClient authorizedClient); diff --git a/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/OAuthRestClient.java b/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/OAuthRestClient.java index b223fbd00..7a159b965 100644 --- a/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/OAuthRestClient.java +++ b/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/OAuthRestClient.java @@ -6,5 +6,5 @@ public interface OAuthRestClient { void callUnlinkOAuthUser(FindUserDetailResponse userDetailResponse); - void refreshAccessToken(FindUserDetailResponse userDetailResponse); + void callRefreshAccessToken(FindUserDetailResponse userDetailResponse); } diff --git a/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/RestTemplateOAuthClient.java b/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/RestTemplateOAuthClient.java index a1de7b391..52c7e9ef3 100644 --- a/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/RestTemplateOAuthClient.java +++ b/src/main/java/com/prgrms/nabmart/global/auth/oauth/client/RestTemplateOAuthClient.java @@ -38,11 +38,13 @@ public void callUnlinkOAuthUser(final FindUserDetailResponse userDetailResponse) refreshAccessTokenIfNotValid(userDetailResponse, oAuth2AuthorizedClient); - OAuthHttpMessage unlinkHttpMessage = oAuthHttpMessageProvider.createUserUnlinkRequest( + OAuthHttpMessage unlinkHttpMessage = oAuthHttpMessageProvider.createUnlinkUserRequest( userDetailResponse, oAuth2AuthorizedClient); + Map response = sendPostApiRequest(unlinkHttpMessage); log.info("회원의 연결이 종료되었습니다. 회원 ID={}", response); - oAuthHttpMessageProvider.checkSuccessUnlinkRequest(response); + + oAuthHttpMessageProvider.verifySuccessUnlinkUserRequest(response); authorizedClientService.removeAuthorizedClient( userDetailResponse.provider(), userDetailResponse.provider()); @@ -57,7 +59,7 @@ private void refreshAccessTokenIfNotValid(FindUserDetailResponse userDetailRespo } @Override - public void refreshAccessToken(final FindUserDetailResponse userDetailResponse) { + public void callRefreshAccessToken(final FindUserDetailResponse userDetailResponse) { OAuthProvider oAuthProvider = OAuthProvider.getOAuthProvider(userDetailResponse.provider()); OAuthHttpMessageProvider oAuthHttpMessageProvider = oAuthProvider.getOAuthHttpMessageProvider(); OAuth2AuthorizedClient oAuth2AuthorizedClient = authorizedClientService.loadAuthorizedClient( @@ -79,24 +81,25 @@ public void refreshAccessToken(final FindUserDetailResponse userDetailResponse) oAuth2AuthorizedClient.getPrincipalName(), refreshedAccessToken, refreshedRefreshToken); - String principalName = updatedAuthorizedClient.getPrincipalName(); Authentication authenticationForTokenRefresh - = getAuthenticationForTokenRefresh(principalName); + = getAuthenticationForTokenRefresh(updatedAuthorizedClient); authorizedClientService.saveAuthorizedClient( updatedAuthorizedClient, authenticationForTokenRefresh); } - private Authentication getAuthenticationForTokenRefresh(String principalName) { + private Authentication getAuthenticationForTokenRefresh( + OAuth2AuthorizedClient updatedAuthorizedClient) { + String principalName = updatedAuthorizedClient.getPrincipalName(); return UsernamePasswordAuthenticationToken.authenticated( principalName, null, List.of()); } - private Map sendPostApiRequest(OAuthHttpMessage refreshAccessTokenRequest) { + private Map sendPostApiRequest(OAuthHttpMessage request) { return restTemplate.postForObject( - refreshAccessTokenRequest.uri(), - refreshAccessTokenRequest.httpMessage(), + request.uri(), + request.httpMessage(), Map.class, - refreshAccessTokenRequest.uriVariables()); + request.uriVariables()); } } diff --git a/src/main/java/com/prgrms/nabmart/global/auth/service/RiderAuthenticationService.java b/src/main/java/com/prgrms/nabmart/global/auth/service/RiderAuthenticationService.java index 68872aadc..2f33fd670 100644 --- a/src/main/java/com/prgrms/nabmart/global/auth/service/RiderAuthenticationService.java +++ b/src/main/java/com/prgrms/nabmart/global/auth/service/RiderAuthenticationService.java @@ -4,7 +4,7 @@ import com.prgrms.nabmart.global.auth.exception.DuplicateUsernameException; import com.prgrms.nabmart.domain.delivery.repository.RiderRepository; import com.prgrms.nabmart.global.auth.service.request.SignupRiderCommand; -import com.prgrms.nabmart.global.auth.service.request.RiderLoginCommand; +import com.prgrms.nabmart.global.auth.service.request.LoginRiderCommand; import com.prgrms.nabmart.domain.user.UserRole; import com.prgrms.nabmart.global.auth.exception.InvalidPasswordException; import com.prgrms.nabmart.global.auth.exception.InvalidUsernameException; @@ -48,22 +48,22 @@ private Rider createRider(SignupRiderCommand signupRiderCommand) { } @Transactional(readOnly = true) - public RiderLoginResponse riderLogin(RiderLoginCommand riderLoginCommand) { - Rider rider = findRiderByUsername(riderLoginCommand); - checkRiderPassword(riderLoginCommand, rider); + public RiderLoginResponse loginRider(LoginRiderCommand loginRiderCommand) { + Rider rider = findRiderByUsername(loginRiderCommand); + verifyRiderPassword(loginRiderCommand, rider); CreateTokenCommand createTokenCommand = CreateTokenCommand.of(rider.getRiderId(), UserRole.ROLE_RIDER); String accessToken = tokenProvider.createToken(createTokenCommand); return RiderLoginResponse.from(accessToken); } - private Rider findRiderByUsername(RiderLoginCommand riderLoginCommand) { - return riderRepository.findByUsername(riderLoginCommand.username()) + private Rider findRiderByUsername(LoginRiderCommand loginRiderCommand) { + return riderRepository.findByUsername(loginRiderCommand.username()) .orElseThrow(() -> new InvalidUsernameException("사용자의 정보와 일치하지 않습니다.")); } - private void checkRiderPassword(RiderLoginCommand riderLoginCommand, final Rider rider) { - if (!passwordEncoder.matches(riderLoginCommand.password(), rider.getPassword())) { + private void verifyRiderPassword(LoginRiderCommand loginRiderCommand, final Rider rider) { + if (!passwordEncoder.matches(loginRiderCommand.password(), rider.getPassword())) { throw new InvalidPasswordException("사용자의 정보와 일치하지 않습니다."); } } diff --git a/src/main/java/com/prgrms/nabmart/global/auth/service/request/LoginRiderCommand.java b/src/main/java/com/prgrms/nabmart/global/auth/service/request/LoginRiderCommand.java new file mode 100644 index 000000000..c67dacebf --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/global/auth/service/request/LoginRiderCommand.java @@ -0,0 +1,8 @@ +package com.prgrms.nabmart.global.auth.service.request; + +public record LoginRiderCommand(String username, String password) { + + public static LoginRiderCommand of(final String username, final String password) { + return new LoginRiderCommand(username, password); + } +} diff --git a/src/main/java/com/prgrms/nabmart/global/auth/service/request/RiderLoginCommand.java b/src/main/java/com/prgrms/nabmart/global/auth/service/request/RiderLoginCommand.java deleted file mode 100644 index eb5ac580a..000000000 --- a/src/main/java/com/prgrms/nabmart/global/auth/service/request/RiderLoginCommand.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.prgrms.nabmart.global.auth.service.request; - -public record RiderLoginCommand(String username, String password) { - - public static RiderLoginCommand of(final String username, final String password) { - return new RiderLoginCommand(username, password); - } -} diff --git a/src/test/java/com/prgrms/nabmart/global/auth/controller/RiderAuthenticationControllerTest.java b/src/test/java/com/prgrms/nabmart/global/auth/controller/RiderAuthenticationControllerTest.java index b1ee9f1f0..d6702a432 100644 --- a/src/test/java/com/prgrms/nabmart/global/auth/controller/RiderAuthenticationControllerTest.java +++ b/src/test/java/com/prgrms/nabmart/global/auth/controller/RiderAuthenticationControllerTest.java @@ -13,7 +13,7 @@ import com.prgrms.nabmart.base.BaseControllerTest; import com.prgrms.nabmart.global.auth.controller.request.SignupRiderRequest; -import com.prgrms.nabmart.global.auth.controller.request.RiderLoginRequest; +import com.prgrms.nabmart.global.auth.controller.request.LoginRiderRequest; import com.prgrms.nabmart.global.auth.service.response.RiderLoginResponse; import com.prgrms.nabmart.global.auth.support.AuthFixture; import org.junit.jupiter.api.DisplayName; @@ -69,15 +69,15 @@ class RiderLoginTest { @DisplayName("성공") void riderLogin() throws Exception { //given - RiderLoginRequest riderLoginRequest = AuthFixture.riderLoginRequest(); + LoginRiderRequest loginRiderRequest = AuthFixture.riderLoginRequest(); RiderLoginResponse riderLoginResponse = new RiderLoginResponse("accessToken"); - given(riderAuthenticationService.riderLogin(any())).willReturn(riderLoginResponse); + given(riderAuthenticationService.loginRider(any())).willReturn(riderLoginResponse); //when ResultActions resultActions = mockMvc.perform(post("/api/v1/riders/login") .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(riderLoginRequest)) + .content(objectMapper.writeValueAsString(loginRiderRequest)) .accept(MediaType.APPLICATION_JSON)); //then diff --git a/src/test/java/com/prgrms/nabmart/global/auth/controller/request/RiderLoginRequestTest.java b/src/test/java/com/prgrms/nabmart/global/auth/controller/request/LoginRiderRequestTest.java similarity index 75% rename from src/test/java/com/prgrms/nabmart/global/auth/controller/request/RiderLoginRequestTest.java rename to src/test/java/com/prgrms/nabmart/global/auth/controller/request/LoginRiderRequestTest.java index 9f153d8f2..385d3cb67 100644 --- a/src/test/java/com/prgrms/nabmart/global/auth/controller/request/RiderLoginRequestTest.java +++ b/src/test/java/com/prgrms/nabmart/global/auth/controller/request/LoginRiderRequestTest.java @@ -13,7 +13,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; -class RiderLoginRequestTest { +class LoginRiderRequestTest { private final ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); private final Validator validator = factory.getValidator(); @@ -33,11 +33,11 @@ class UsernameTes { @DisplayName("성공") void success(String validUsername) { //given - RiderLoginRequest riderLoginRequest = new RiderLoginRequest(validUsername, password); + LoginRiderRequest loginRiderRequest = new LoginRiderRequest(validUsername, password); //when - Set> result - = validator.validate(riderLoginRequest); + Set> result + = validator.validate(loginRiderRequest); //then assertThat(result).hasSize(0); @@ -50,11 +50,11 @@ void success(String validUsername) { @DisplayName("예외: 유효하지 않은 사용자 이름") void throwExceptionWhenInvalidUsername(String invalidUsername) { //given - RiderLoginRequest riderLoginRequest = new RiderLoginRequest(invalidUsername, password); + LoginRiderRequest loginRiderRequest = new LoginRiderRequest(invalidUsername, password); //when - Set> result - = validator.validate(riderLoginRequest); + Set> result + = validator.validate(loginRiderRequest); //then assertThat(result).hasSize(1); @@ -67,11 +67,11 @@ void throwExceptionWhenInvalidUsername(String invalidUsername) { void throwExceptionWhenUsernameIsNull() { //given String nullUsername = null; - RiderLoginRequest riderLoginRequest = new RiderLoginRequest(nullUsername, password); + LoginRiderRequest loginRiderRequest = new LoginRiderRequest(nullUsername, password); //when - Set> result - = validator.validate(riderLoginRequest); + Set> result + = validator.validate(loginRiderRequest); //then assertThat(result).hasSize(1); assertThat(result).map(ConstraintViolation::getInvalidValue) @@ -90,11 +90,11 @@ class PasswordTest { @DisplayName("성공") void success(String validPassword) { //given - RiderLoginRequest riderLoginRequest = new RiderLoginRequest(username, validPassword); + LoginRiderRequest loginRiderRequest = new LoginRiderRequest(username, validPassword); //when - Set> result - = validator.validate(riderLoginRequest); + Set> result + = validator.validate(loginRiderRequest); //then assertThat(result).hasSize(0); @@ -107,11 +107,11 @@ void success(String validPassword) { @DisplayName("예외: 유효하지 않은 패스워드") void throwExceptionWhenInvalidPassword(String invalidPassword) { //given - RiderLoginRequest riderLoginRequest = new RiderLoginRequest(username, invalidPassword); + LoginRiderRequest loginRiderRequest = new LoginRiderRequest(username, invalidPassword); //when - Set> result - = validator.validate(riderLoginRequest); + Set> result + = validator.validate(loginRiderRequest); //then assertThat(result).hasSize(1); @@ -124,11 +124,11 @@ void throwExceptionWhenInvalidPassword(String invalidPassword) { void throwExceptionWhenPasswordIsNull() { //given String nullPassword = null; - RiderLoginRequest riderLoginRequest = new RiderLoginRequest(username, nullPassword); + LoginRiderRequest loginRiderRequest = new LoginRiderRequest(username, nullPassword); //when - Set> result - = validator.validate(riderLoginRequest); + Set> result + = validator.validate(loginRiderRequest); //then assertThat(result).hasSize(1); diff --git a/src/test/java/com/prgrms/nabmart/global/auth/exception/AuthExceptionHandlerTest.java b/src/test/java/com/prgrms/nabmart/global/auth/exception/AuthControllerAdviceTest.java similarity index 96% rename from src/test/java/com/prgrms/nabmart/global/auth/exception/AuthExceptionHandlerTest.java rename to src/test/java/com/prgrms/nabmart/global/auth/exception/AuthControllerAdviceTest.java index 8bd7a7b1b..fedac5e12 100644 --- a/src/test/java/com/prgrms/nabmart/global/auth/exception/AuthExceptionHandlerTest.java +++ b/src/test/java/com/prgrms/nabmart/global/auth/exception/AuthControllerAdviceTest.java @@ -15,7 +15,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -class AuthExceptionHandlerTest { +class AuthControllerAdviceTest { @RestController static class AuthExceptionTestController { @@ -36,7 +36,7 @@ public void oauthUnlinkEx() { @BeforeEach void setUp() { mvc = MockMvcBuilders.standaloneSetup(new AuthExceptionTestController()) - .setControllerAdvice(new AuthExceptionHandler()) + .setControllerAdvice(new AuthControllerAdvice()) .build(); } diff --git a/src/test/java/com/prgrms/nabmart/global/auth/service/RiderAuthenticationServiceTest.java b/src/test/java/com/prgrms/nabmart/global/auth/service/RiderAuthenticationServiceTest.java index d8a5d0f41..23e4e1ff7 100644 --- a/src/test/java/com/prgrms/nabmart/global/auth/service/RiderAuthenticationServiceTest.java +++ b/src/test/java/com/prgrms/nabmart/global/auth/service/RiderAuthenticationServiceTest.java @@ -14,7 +14,7 @@ import com.prgrms.nabmart.global.auth.exception.InvalidUsernameException; import com.prgrms.nabmart.global.auth.jwt.TokenProvider; import com.prgrms.nabmart.global.auth.jwt.dto.Claims; -import com.prgrms.nabmart.global.auth.service.request.RiderLoginCommand; +import com.prgrms.nabmart.global.auth.service.request.LoginRiderCommand; import com.prgrms.nabmart.global.auth.service.request.SignupRiderCommand; import com.prgrms.nabmart.global.auth.service.response.RiderLoginResponse; import com.prgrms.nabmart.global.auth.support.AuthFixture; @@ -86,7 +86,7 @@ void throwExceptionWhenUsernameDuplicate() { @DisplayName("riderLogin 메서드 실행 시") class RiderLoginTest { - RiderLoginCommand riderLoginCommand = AuthFixture.riderLoginCommand(); + LoginRiderCommand loginRiderCommand = AuthFixture.riderLoginCommand(); Rider rider = AuthFixture.rider(); @Test @@ -98,7 +98,7 @@ void success() { //when RiderLoginResponse riderLoginResponse - = riderAuthenticationService.riderLogin(riderLoginCommand); + = riderAuthenticationService.loginRider(loginRiderCommand); //then Claims claims = tokenProvider.validateToken(riderLoginResponse.accessToken()); @@ -115,7 +115,7 @@ void throwExceptionWhenNotFoundUsername() { //when //then - assertThatThrownBy(() -> riderAuthenticationService.riderLogin(riderLoginCommand)) + assertThatThrownBy(() -> riderAuthenticationService.loginRider(loginRiderCommand)) .isInstanceOf(InvalidUsernameException.class); } @@ -124,14 +124,14 @@ void throwExceptionWhenNotFoundUsername() { void throwExceptionWhenInvalidPassword() { //given String invalidPassword = "invalidPassword123"; - RiderLoginCommand riderLoginCommand - = new RiderLoginCommand(rider.getUsername(), invalidPassword); + LoginRiderCommand loginRiderCommand + = new LoginRiderCommand(rider.getUsername(), invalidPassword); given(riderRepository.findByUsername(any())).willReturn(Optional.ofNullable(rider)); //when //then - assertThatThrownBy(() -> riderAuthenticationService.riderLogin(riderLoginCommand)) + assertThatThrownBy(() -> riderAuthenticationService.loginRider(loginRiderCommand)) .isInstanceOf(InvalidPasswordException.class); } } diff --git a/src/test/java/com/prgrms/nabmart/global/auth/support/AuthFixture.java b/src/test/java/com/prgrms/nabmart/global/auth/support/AuthFixture.java index 0024b3a5c..13c3bbb98 100644 --- a/src/test/java/com/prgrms/nabmart/global/auth/support/AuthFixture.java +++ b/src/test/java/com/prgrms/nabmart/global/auth/support/AuthFixture.java @@ -1,8 +1,8 @@ package com.prgrms.nabmart.global.auth.support; import com.prgrms.nabmart.domain.delivery.Rider; -import com.prgrms.nabmart.global.auth.controller.request.RiderLoginRequest; -import com.prgrms.nabmart.global.auth.service.request.RiderLoginCommand; +import com.prgrms.nabmart.global.auth.controller.request.LoginRiderRequest; +import com.prgrms.nabmart.global.auth.service.request.LoginRiderCommand; import com.prgrms.nabmart.domain.user.UserRole; import com.prgrms.nabmart.domain.user.service.response.RegisterUserResponse; import com.prgrms.nabmart.global.auth.jwt.JavaJwtTokenProvider; @@ -53,12 +53,12 @@ public static String accessToken() { return tokenProvider.createToken(createTokenCommand()); } - public static RiderLoginCommand riderLoginCommand() { - return new RiderLoginCommand(RIDER_USERNAME, RIDER_PASSWORD); + public static LoginRiderCommand riderLoginCommand() { + return new LoginRiderCommand(RIDER_USERNAME, RIDER_PASSWORD); } - public static RiderLoginRequest riderLoginRequest() { - return new RiderLoginRequest(RIDER_USERNAME, RIDER_PASSWORD); + public static LoginRiderRequest riderLoginRequest() { + return new LoginRiderRequest(RIDER_USERNAME, RIDER_PASSWORD); } public static Rider rider() { From 1254f70bf359e0f7b29b12296f15e87766a937d3 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Tue, 19 Sep 2023 23:16:50 +0900 Subject: [PATCH 06/41] =?UTF-8?q?[NAYB-155]=20refactor:=20`AuthControllerA?= =?UTF-8?q?dvice`=20`auth/controller`=20=ED=8C=A8=ED=82=A4=EC=A7=80=20?= =?UTF-8?q?=ED=95=98=EC=9C=84=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/{exception => controller}/AuthControllerAdvice.java | 5 ++++- .../global/auth/exception/AuthControllerAdviceTest.java | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) rename src/main/java/com/prgrms/nabmart/global/auth/{exception => controller}/AuthControllerAdvice.java (76%) diff --git a/src/main/java/com/prgrms/nabmart/global/auth/exception/AuthControllerAdvice.java b/src/main/java/com/prgrms/nabmart/global/auth/controller/AuthControllerAdvice.java similarity index 76% rename from src/main/java/com/prgrms/nabmart/global/auth/exception/AuthControllerAdvice.java rename to src/main/java/com/prgrms/nabmart/global/auth/controller/AuthControllerAdvice.java index bbaca4726..4024fade1 100644 --- a/src/main/java/com/prgrms/nabmart/global/auth/exception/AuthControllerAdvice.java +++ b/src/main/java/com/prgrms/nabmart/global/auth/controller/AuthControllerAdvice.java @@ -1,5 +1,8 @@ -package com.prgrms.nabmart.global.auth.exception; +package com.prgrms.nabmart.global.auth.controller; +import com.prgrms.nabmart.global.auth.exception.AuthException; +import com.prgrms.nabmart.global.auth.exception.OAuthUnlinkFailureException; +import com.prgrms.nabmart.global.auth.exception.UnAuthenticationException; import com.prgrms.nabmart.global.util.ErrorTemplate; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; diff --git a/src/test/java/com/prgrms/nabmart/global/auth/exception/AuthControllerAdviceTest.java b/src/test/java/com/prgrms/nabmart/global/auth/exception/AuthControllerAdviceTest.java index fedac5e12..c0f32bbc1 100644 --- a/src/test/java/com/prgrms/nabmart/global/auth/exception/AuthControllerAdviceTest.java +++ b/src/test/java/com/prgrms/nabmart/global/auth/exception/AuthControllerAdviceTest.java @@ -5,6 +5,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import com.prgrms.nabmart.global.auth.controller.AuthControllerAdvice; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; From b630289cfe08e04190b0c56ec2f7fe440a613a44 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Tue, 19 Sep 2023 23:23:06 +0900 Subject: [PATCH 07/41] =?UTF-8?q?[NAYB-155]=20refactor:=20=EA=B6=8C?= =?UTF-8?q?=ED=95=9C=20=EC=98=88=EC=99=B8=20=EA=B0=81=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=EB=B3=84=EB=A1=9C=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nabmart/domain/delivery/service/DeliveryService.java | 4 ++-- .../item/exception/UnauthorizedLikeItemException.java | 8 ++++++++ .../nabmart/domain/item/service/LikeItemService.java | 4 ++-- .../global/auth/exception/AuthorizationException.java | 8 -------- .../domain/delivery/service/DeliveryServiceTest.java | 3 +-- .../nabmart/domain/item/service/LikeItemServiceTest.java | 4 ++-- 6 files changed, 15 insertions(+), 16 deletions(-) create mode 100644 src/main/java/com/prgrms/nabmart/domain/item/exception/UnauthorizedLikeItemException.java delete mode 100644 src/main/java/com/prgrms/nabmart/global/auth/exception/AuthorizationException.java diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java b/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java index 75aa231a8..4c58bb968 100644 --- a/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java @@ -4,6 +4,7 @@ import com.prgrms.nabmart.domain.delivery.Rider; import com.prgrms.nabmart.domain.delivery.exception.NotFoundDeliveryException; import com.prgrms.nabmart.domain.delivery.exception.NotFoundRiderException; +import com.prgrms.nabmart.domain.delivery.exception.UnauthorizedDeliveryException; import com.prgrms.nabmart.domain.delivery.repository.DeliveryRepository; import com.prgrms.nabmart.domain.delivery.repository.RiderRepository; import com.prgrms.nabmart.domain.delivery.service.request.AcceptDeliveryCommand; @@ -18,7 +19,6 @@ import com.prgrms.nabmart.domain.user.User; import com.prgrms.nabmart.domain.user.exception.NotFoundUserException; import com.prgrms.nabmart.domain.user.repository.UserRepository; -import com.prgrms.nabmart.global.auth.exception.AuthorizationException; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; @@ -42,7 +42,7 @@ public FindDeliveryDetailResponse findDelivery(FindDeliveryCommand findDeliveryC private void checkAuthority(final Delivery delivery, final User user) { if (!delivery.isOwnByUser(user)) { - throw new AuthorizationException("권한이 없습니다."); + throw new UnauthorizedDeliveryException("권한이 없습니다."); } } diff --git a/src/main/java/com/prgrms/nabmart/domain/item/exception/UnauthorizedLikeItemException.java b/src/main/java/com/prgrms/nabmart/domain/item/exception/UnauthorizedLikeItemException.java new file mode 100644 index 000000000..7c8416db2 --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/item/exception/UnauthorizedLikeItemException.java @@ -0,0 +1,8 @@ +package com.prgrms.nabmart.domain.item.exception; + +public class UnauthorizedLikeItemException extends ItemException { + + public UnauthorizedLikeItemException(String message) { + super(message); + } +} diff --git a/src/main/java/com/prgrms/nabmart/domain/item/service/LikeItemService.java b/src/main/java/com/prgrms/nabmart/domain/item/service/LikeItemService.java index bde83311c..935d63ae2 100644 --- a/src/main/java/com/prgrms/nabmart/domain/item/service/LikeItemService.java +++ b/src/main/java/com/prgrms/nabmart/domain/item/service/LikeItemService.java @@ -5,6 +5,7 @@ import com.prgrms.nabmart.domain.item.exception.DuplicateLikeItemException; import com.prgrms.nabmart.domain.item.exception.NotFoundItemException; import com.prgrms.nabmart.domain.item.exception.NotFoundLikeItemException; +import com.prgrms.nabmart.domain.item.exception.UnauthorizedLikeItemException; import com.prgrms.nabmart.domain.item.repository.ItemRepository; import com.prgrms.nabmart.domain.item.repository.LikeItemRepository; import com.prgrms.nabmart.domain.item.service.request.DeleteLikeItemCommand; @@ -14,7 +15,6 @@ import com.prgrms.nabmart.domain.user.User; import com.prgrms.nabmart.domain.user.exception.NotFoundUserException; import com.prgrms.nabmart.domain.user.repository.UserRepository; -import com.prgrms.nabmart.global.auth.exception.AuthorizationException; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; @@ -42,7 +42,7 @@ public Long registerLikeItem(RegisterLikeItemCommand registerLikeItemCommand) { public void deleteLikeItem(DeleteLikeItemCommand deleteLikeItemCommand) { LikeItem likeItem = findLikeItemByLikeItemId(deleteLikeItemCommand); if (!likeItem.isSameUser(deleteLikeItemCommand.userId())) { - throw new AuthorizationException("권한이 없습니다."); + throw new UnauthorizedLikeItemException("권한이 없습니다."); } likeItemRepository.delete(likeItem); } diff --git a/src/main/java/com/prgrms/nabmart/global/auth/exception/AuthorizationException.java b/src/main/java/com/prgrms/nabmart/global/auth/exception/AuthorizationException.java deleted file mode 100644 index d59914f6e..000000000 --- a/src/main/java/com/prgrms/nabmart/global/auth/exception/AuthorizationException.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.prgrms.nabmart.global.auth.exception; - -public class AuthorizationException extends AuthException { - - public AuthorizationException(final String message) { - super(message); - } -} diff --git a/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java b/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java index 241c41ff9..feb097ed6 100644 --- a/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java @@ -36,7 +36,6 @@ import com.prgrms.nabmart.domain.user.exception.NotFoundUserException; import com.prgrms.nabmart.domain.user.repository.UserRepository; import com.prgrms.nabmart.domain.user.support.UserFixture; -import com.prgrms.nabmart.global.auth.exception.AuthorizationException; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.List; @@ -156,7 +155,7 @@ void throwExceptionWhenNotEqualsLoginUserAndOrderUser() { //when //then assertThatThrownBy(() -> deliveryService.findDelivery(findDeliveryCommand)) - .isInstanceOf(AuthorizationException.class); + .isInstanceOf(UnauthorizedDeliveryException.class); } } diff --git a/src/test/java/com/prgrms/nabmart/domain/item/service/LikeItemServiceTest.java b/src/test/java/com/prgrms/nabmart/domain/item/service/LikeItemServiceTest.java index ed0af62f5..d50a5c54b 100644 --- a/src/test/java/com/prgrms/nabmart/domain/item/service/LikeItemServiceTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/item/service/LikeItemServiceTest.java @@ -14,6 +14,7 @@ import com.prgrms.nabmart.domain.item.exception.DuplicateLikeItemException; import com.prgrms.nabmart.domain.item.exception.NotFoundItemException; import com.prgrms.nabmart.domain.item.exception.NotFoundLikeItemException; +import com.prgrms.nabmart.domain.item.exception.UnauthorizedLikeItemException; import com.prgrms.nabmart.domain.item.repository.ItemRepository; import com.prgrms.nabmart.domain.item.repository.LikeItemRepository; import com.prgrms.nabmart.domain.item.service.request.DeleteLikeItemCommand; @@ -26,7 +27,6 @@ import com.prgrms.nabmart.domain.user.exception.NotFoundUserException; import com.prgrms.nabmart.domain.user.repository.UserRepository; import com.prgrms.nabmart.domain.user.support.UserFixture; -import com.prgrms.nabmart.global.auth.exception.AuthorizationException; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -173,7 +173,7 @@ void throwExceptionWhenNotEqualsUser() { //when //then assertThatThrownBy(() -> likeItemService.deleteLikeItem(notEqualsUserIdCommand)) - .isInstanceOf(AuthorizationException.class); + .isInstanceOf(UnauthorizedLikeItemException.class); } } From 1b0d891764c64d72626e7cd129000b86648f4c77 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Tue, 19 Sep 2023 23:50:33 +0900 Subject: [PATCH 08/41] =?UTF-8?q?[NAYB-155]=20feat:=20=EC=9D=B8=EC=A6=9D?= =?UTF-8?q?=20=EC=98=88=EC=99=B8=20=ED=95=B8=EB=93=A4=EB=9F=AC=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 --- .../auth/controller/AuthControllerAdvice.java | 13 ++++++-- .../exception/AuthControllerAdviceTest.java | 33 ++++++++++++++++--- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/prgrms/nabmart/global/auth/controller/AuthControllerAdvice.java b/src/main/java/com/prgrms/nabmart/global/auth/controller/AuthControllerAdvice.java index 4024fade1..94c8c8750 100644 --- a/src/main/java/com/prgrms/nabmart/global/auth/controller/AuthControllerAdvice.java +++ b/src/main/java/com/prgrms/nabmart/global/auth/controller/AuthControllerAdvice.java @@ -1,6 +1,8 @@ package com.prgrms.nabmart.global.auth.controller; import com.prgrms.nabmart.global.auth.exception.AuthException; +import com.prgrms.nabmart.global.auth.exception.DuplicateUsernameException; +import com.prgrms.nabmart.global.auth.exception.InvalidJwtException; import com.prgrms.nabmart.global.auth.exception.OAuthUnlinkFailureException; import com.prgrms.nabmart.global.auth.exception.UnAuthenticationException; import com.prgrms.nabmart.global.util.ErrorTemplate; @@ -18,9 +20,16 @@ public ResponseEntity authExHandle(AuthException ex) { .body(ErrorTemplate.of(ex.getMessage())); } - @ExceptionHandler({OAuthUnlinkFailureException.class, UnAuthenticationException.class}) - public ResponseEntity authenticationFailExHand(AuthException ex) { + @ExceptionHandler({OAuthUnlinkFailureException.class, UnAuthenticationException.class, + InvalidJwtException.class}) + public ResponseEntity authenticationFailExHandle(AuthException ex) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED) .body(ErrorTemplate.of(ex.getMessage())); } + + @ExceptionHandler(DuplicateUsernameException.class) + public ResponseEntity duplicateUsernameExHandle(AuthException ex) { + return ResponseEntity.status(HttpStatus.CONFLICT) + .body(ErrorTemplate.of(ex.getMessage())); + } } diff --git a/src/test/java/com/prgrms/nabmart/global/auth/exception/AuthControllerAdviceTest.java b/src/test/java/com/prgrms/nabmart/global/auth/exception/AuthControllerAdviceTest.java index c0f32bbc1..c33acc640 100644 --- a/src/test/java/com/prgrms/nabmart/global/auth/exception/AuthControllerAdviceTest.java +++ b/src/test/java/com/prgrms/nabmart/global/auth/exception/AuthControllerAdviceTest.java @@ -21,7 +21,7 @@ class AuthControllerAdviceTest { @RestController static class AuthExceptionTestController { - @GetMapping("/auth-ex") + @GetMapping("/jwt-ex") public void authEx() { throw new InvalidJwtException("잘못된 토큰"); } @@ -30,6 +30,16 @@ public void authEx() { public void oauthUnlinkEx() { throw new OAuthUnlinkFailureException("소셜 로그인 연동 해제 실패"); } + + @GetMapping("/un-auth-ex") + public void unAuthEx() { + throw new UnAuthenticationException("인증되지 않음"); + } + + @GetMapping("/duplicate-username-ex") + public void usernameDuplicateEx() { + throw new DuplicateUsernameException("사용자명 중복"); + } } MockMvc mvc; @@ -46,15 +56,15 @@ void setUp() { class AuthExceptionTest { @Test - @DisplayName("성공: authException 잡아서 처리") - void throwAuthException() throws Exception { + @DisplayName("성공: invalidJwtException 잡아서 처리") + void throwInvalidJwtException() throws Exception { //given //when - ResultActions resultActions = mvc.perform(get("/auth-ex")); + ResultActions resultActions = mvc.perform(get("/jwt-ex")); //then resultActions.andDo(print()) - .andExpect(status().isBadRequest()) + .andExpect(status().isUnauthorized()) .andExpect(jsonPath("$.message").isString()); } @@ -70,5 +80,18 @@ void throwOAuthUnlinkFailureException() throws Exception { .andExpect(status().isUnauthorized()) .andExpect(jsonPath("$.message").isString()); } + + @Test + @DisplayName("성공: duplicateUsernameException 잡아서 처리") + void throwDuplicateUsernameException() throws Exception { + //given + //when + ResultActions resultActions = mvc.perform(get("/duplicate-username-ex")); + + //then + resultActions.andDo(print()) + .andExpect(status().isConflict()) + .andExpect(jsonPath("$.message").isString()); + } } } \ No newline at end of file From 13a68c056f2ed5fd02f7c98508685ce2ebad937d Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Wed, 20 Sep 2023 12:33:09 +0900 Subject: [PATCH 09/41] =?UTF-8?q?[NAYB-155]=20feat:=20=ED=86=A0=ED=81=B0?= =?UTF-8?q?=20=EA=B2=80=EC=A6=9D=20=EC=98=88=EC=99=B8=20catch=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 --- .../prgrms/nabmart/global/auth/jwt/JavaJwtTokenProvider.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/prgrms/nabmart/global/auth/jwt/JavaJwtTokenProvider.java b/src/main/java/com/prgrms/nabmart/global/auth/jwt/JavaJwtTokenProvider.java index 8550bf4fc..1e7d3ffa3 100644 --- a/src/main/java/com/prgrms/nabmart/global/auth/jwt/JavaJwtTokenProvider.java +++ b/src/main/java/com/prgrms/nabmart/global/auth/jwt/JavaJwtTokenProvider.java @@ -69,6 +69,8 @@ public Claims validateToken(final String accessToken) { log.info("SignatureVerificationException: 토큰의 서명이 유효하지 않습니다."); } catch (TokenExpiredException ex) { log.info("TokenExpiredException: 토큰이 만료되었습니다."); + } catch (MissingClaimException ex) { + log.info("MissingClaimException: 유효값이 클레임이 포함되어 있지 않습니다."); } catch (JWTVerificationException ex) { log.info("JWTVerificationException: 유효하지 않은 토큰입니다."); } From 2698e8b77beda7403eaf99e3f75b64969c4170f4 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Wed, 20 Sep 2023 14:37:31 +0900 Subject: [PATCH 10/41] =?UTF-8?q?[NAYB-156]=20feat:=20=EC=95=8C=EB=A6=BC?= =?UTF-8?q?=20=ED=81=B4=EB=9D=BC=EC=9D=B4=EC=96=B8=ED=8A=B8=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/EmitterMemoryRepository.java | 32 ++++++++++++ .../repository/EmitterRepository.java | 13 +++++ .../service/NotificationService.java | 52 +++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 src/main/java/com/prgrms/nabmart/domain/notification/repository/EmitterMemoryRepository.java create mode 100644 src/main/java/com/prgrms/nabmart/domain/notification/repository/EmitterRepository.java create mode 100644 src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/repository/EmitterMemoryRepository.java b/src/main/java/com/prgrms/nabmart/domain/notification/repository/EmitterMemoryRepository.java new file mode 100644 index 000000000..0c4e6b6c4 --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/notification/repository/EmitterMemoryRepository.java @@ -0,0 +1,32 @@ +package com.prgrms.nabmart.domain.notification.repository; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; +import org.springframework.stereotype.Repository; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; + +@Repository +public class EmitterMemoryRepository implements + EmitterRepository { + + private final Map emitters = new ConcurrentHashMap<>(); + + @Override + public void save(String emitterId, SseEmitter sseEmitter) { + emitters.put(emitterId, sseEmitter); + } + + @Override + public void deleteById(String emitterId) { + emitters.remove(emitterId); + } + + @Override + public Map findAllByIdStartWith(Long userId) { + String emitterIdPrefix = userId + "_"; + return emitters.entrySet().stream() + .filter(entry -> entry.getKey().startsWith(emitterIdPrefix)) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } +} diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/repository/EmitterRepository.java b/src/main/java/com/prgrms/nabmart/domain/notification/repository/EmitterRepository.java new file mode 100644 index 000000000..4fa18ea83 --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/notification/repository/EmitterRepository.java @@ -0,0 +1,13 @@ +package com.prgrms.nabmart.domain.notification.repository; + +import java.util.Map; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; + +public interface EmitterRepository { + + void save(String emitterId, SseEmitter sseEmitter); + + void deleteById(String emitterId); + + Map findAllByIdStartWith(Long userId); +} diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java b/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java new file mode 100644 index 000000000..56a29bb78 --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java @@ -0,0 +1,52 @@ +package com.prgrms.nabmart.domain.notification.service; + +import static java.text.MessageFormat.format; + +import com.prgrms.nabmart.domain.notification.repository.EmitterRepository; +import java.io.IOException; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; + +@Service +@RequiredArgsConstructor +public class NotificationService { + + private static final Long DEFAULT_TIMEOUT = 60L * 1000 * 120; + + private final EmitterRepository emitterRepository; + + public SseEmitter connection(Long userId, String lastEventId) { + String emitterId = userId + "_" + System.currentTimeMillis(); + SseEmitter emitter = new SseEmitter(DEFAULT_TIMEOUT); + emitterRepository.save(emitterId, emitter); + + emitter.onCompletion(() -> emitterRepository.deleteById(emitterId)); + emitter.onTimeout(() -> emitterRepository.deleteById(emitterId)); + emitter.onError(e -> emitterRepository.deleteById(emitterId)); + + // 연결 직후 데이터 전송이 없으면 503 에러 발생. 에러 방지용 더미 데이터 전송 + sendNotification(emitter, emitterId, format("[Connected] UserId={0}", userId)); + + // 클라이언트 미수신한 event를 모두 전송 + if(!lastEventId.isEmpty()) { + Map events = emitterRepository.findAllByIdStartWith(userId); + events.entrySet().stream() + .filter(entry -> lastEventId.compareTo(entry.getKey()) < 0) + .forEach(entry -> sendNotification(emitter, entry.getKey(), entry.getValue())); + } + + return emitter; + } + + private void sendNotification(SseEmitter emitter, String emitterId, Object data) { + try { + emitter.send(emitter.event() + .id(emitterId) + .data(data)); + } catch (IOException ex) { + emitterRepository.deleteById(emitterId); + } + } +} From 5f7b2fdfbe4e46683ece5186ea6edc2f6e039005 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Wed, 20 Sep 2023 15:12:11 +0900 Subject: [PATCH 11/41] =?UTF-8?q?[NAYB-156]=20feat:=20`Notification`=20?= =?UTF-8?q?=EC=97=94=ED=8B=B0=ED=8B=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/notification/Notification.java | 54 +++++++++++++++++++ .../domain/notification/NotificationType.java | 5 ++ .../InvalidNotificationException.java | 10 ++++ .../exception/NotificationException.java | 8 +++ 4 files changed, 77 insertions(+) create mode 100644 src/main/java/com/prgrms/nabmart/domain/notification/Notification.java create mode 100644 src/main/java/com/prgrms/nabmart/domain/notification/NotificationType.java create mode 100644 src/main/java/com/prgrms/nabmart/domain/notification/exception/InvalidNotificationException.java create mode 100644 src/main/java/com/prgrms/nabmart/domain/notification/exception/NotificationException.java diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/Notification.java b/src/main/java/com/prgrms/nabmart/domain/notification/Notification.java new file mode 100644 index 000000000..5f258431f --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/notification/Notification.java @@ -0,0 +1,54 @@ +package com.prgrms.nabmart.domain.notification; + +import com.prgrms.nabmart.domain.notification.exception.InvalidNotificationException; +import com.prgrms.nabmart.global.BaseTimeEntity; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import java.util.Objects; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Notification extends BaseTimeEntity { + + private static final int CONTENT_LENGTH = 50; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long notificationId; + + @Column(nullable = false) + private String content; + + @Enumerated(EnumType.STRING) + private NotificationType notificationType; + + @Column(nullable = false) + private Long userId; + + @Builder + public Notification( + String content, + Long userId, + NotificationType notificationType) { + validateContent(content); + this.content = content; + this.notificationType = notificationType; + this.userId = userId; + } + + private void validateContent(String content) { + if(Objects.nonNull(content) && content.length() > CONTENT_LENGTH) { + throw new InvalidNotificationException("내용의 길이는 50자 이하여야 합니다."); + } + } +} diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/NotificationType.java b/src/main/java/com/prgrms/nabmart/domain/notification/NotificationType.java new file mode 100644 index 000000000..f9d0c0cc5 --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/notification/NotificationType.java @@ -0,0 +1,5 @@ +package com.prgrms.nabmart.domain.notification; + +public enum NotificationType { + DELIVERY +} diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/exception/InvalidNotificationException.java b/src/main/java/com/prgrms/nabmart/domain/notification/exception/InvalidNotificationException.java new file mode 100644 index 000000000..d49c569b1 --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/notification/exception/InvalidNotificationException.java @@ -0,0 +1,10 @@ +package com.prgrms.nabmart.domain.notification.exception; + +import com.prgrms.nabmart.domain.notification.exception.NotificationException; + +public class InvalidNotificationException extends NotificationException { + + public InvalidNotificationException(String message) { + super(message); + } +} diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/exception/NotificationException.java b/src/main/java/com/prgrms/nabmart/domain/notification/exception/NotificationException.java new file mode 100644 index 000000000..d7b9eafac --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/notification/exception/NotificationException.java @@ -0,0 +1,8 @@ +package com.prgrms.nabmart.domain.notification.exception; + +public abstract class NotificationException extends RuntimeException { + + public NotificationException(String message) { + super(message); + } +} From ba6b3a5ee41386c283c223833dcc22627af19f7a Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Wed, 20 Sep 2023 15:13:33 +0900 Subject: [PATCH 12/41] =?UTF-8?q?[NAYB-156]=20feat:=20`NotificationReposit?= =?UTF-8?q?ory`=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notification/repository/NotificationRepository.java | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/main/java/com/prgrms/nabmart/domain/notification/repository/NotificationRepository.java diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/repository/NotificationRepository.java b/src/main/java/com/prgrms/nabmart/domain/notification/repository/NotificationRepository.java new file mode 100644 index 000000000..0c87b21cb --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/notification/repository/NotificationRepository.java @@ -0,0 +1,8 @@ +package com.prgrms.nabmart.domain.notification.repository; + +import com.prgrms.nabmart.domain.notification.Notification; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface NotificationRepository extends JpaRepository { + +} From ddf1685a38717b9c0f90971e924551e3b88af521 Mon Sep 17 00:00:00 2001 From: hseong3243 <48748265+hseong3243@users.noreply.github.com> Date: Wed, 20 Sep 2023 15:22:48 +0900 Subject: [PATCH 13/41] =?UTF-8?q?[NAYB-155]=20refactor:=20=ED=8C=8C?= =?UTF-8?q?=EB=9D=BC=EB=AF=B8=ED=84=B0=20final=20=ED=82=A4=EC=9B=8C?= =?UTF-8?q?=EB=93=9C=20=EB=B9=A0=EC=A7=84=20=EB=B6=80=EB=B6=84=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 Co-authored-by: 배준일(Bae Junil) <70627982+bjo6300@users.noreply.github.com> --- .../domain/item/exception/UnauthorizedLikeItemException.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/prgrms/nabmart/domain/item/exception/UnauthorizedLikeItemException.java b/src/main/java/com/prgrms/nabmart/domain/item/exception/UnauthorizedLikeItemException.java index 7c8416db2..650c7055c 100644 --- a/src/main/java/com/prgrms/nabmart/domain/item/exception/UnauthorizedLikeItemException.java +++ b/src/main/java/com/prgrms/nabmart/domain/item/exception/UnauthorizedLikeItemException.java @@ -2,7 +2,7 @@ public class UnauthorizedLikeItemException extends ItemException { - public UnauthorizedLikeItemException(String message) { + public UnauthorizedLikeItemException(final String message) { super(message); } } From 2add7545e47776f46b4fd48e2ea43070354329cb Mon Sep 17 00:00:00 2001 From: baejunil Date: Wed, 20 Sep 2023 16:45:00 +0900 Subject: [PATCH 14/41] =?UTF-8?q?[NAYB-154]=20feat=20:=20=EB=A7=A4?= =?UTF-8?q?=EC=A3=BC=20=EC=9B=94=EC=9A=94=EC=9D=BC=EC=97=90=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=A0=95=ED=95=A9=EC=84=B1=20=EB=A7=9E?= =?UTF-8?q?=EC=B6=94=EB=8A=94=20=EC=8A=A4=EC=BC=80=EC=A4=84=EB=9F=AC=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../review/service/RedisCacheService.java | 33 +++++++++++++++++ .../service/ReviewSchedulerService.java | 37 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 src/main/java/com/prgrms/nabmart/domain/review/service/ReviewSchedulerService.java diff --git a/src/main/java/com/prgrms/nabmart/domain/review/service/RedisCacheService.java b/src/main/java/com/prgrms/nabmart/domain/review/service/RedisCacheService.java index 94df973eb..8f943acd7 100644 --- a/src/main/java/com/prgrms/nabmart/domain/review/service/RedisCacheService.java +++ b/src/main/java/com/prgrms/nabmart/domain/review/service/RedisCacheService.java @@ -108,4 +108,37 @@ public void updateAverageRatingByItemId( listOperations.rightPushAll(cacheKey, String.valueOf(dbAverageRating), String.valueOf(dbNumberOfReviews)); } + + public void synchronizeNumberOfReview( + final Long itemId, + final String cacheKey + ) { + long dbCount = reviewRepository.countByItem_ItemId(itemId); + + numberOfReviewsRedisTemplate.opsForValue().set(cacheKey, dbCount); + } + + public void synchronizeAverageRating( + final Long itemId, + final String cacheKey + ) { + String averageRating = listOperations.index(cacheKey, 0); + String totalNumberOfReviews = listOperations.index(cacheKey, 1); + + if (averageRating != null && totalNumberOfReviews != null) { + double dbAverageRating = reviewRepository.findAverageRatingByItemId(itemId); + long dbNumberOfReviews = reviewRepository.countByItem_ItemId(itemId); + + listOperations.set(cacheKey, 0, String.valueOf(dbAverageRating)); + listOperations.set(cacheKey, 1, String.valueOf(dbNumberOfReviews)); + + return; + } + + double dbAverageRating = reviewRepository.findAverageRatingByItemId(itemId); + long dbNumberOfReviews = reviewRepository.countByItem_ItemId(itemId); + + listOperations.rightPushAll(cacheKey, String.valueOf(dbAverageRating), + String.valueOf(dbNumberOfReviews)); + } } diff --git a/src/main/java/com/prgrms/nabmart/domain/review/service/ReviewSchedulerService.java b/src/main/java/com/prgrms/nabmart/domain/review/service/ReviewSchedulerService.java new file mode 100644 index 000000000..c8400d632 --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/review/service/ReviewSchedulerService.java @@ -0,0 +1,37 @@ +package com.prgrms.nabmart.domain.review.service; + +import com.prgrms.nabmart.domain.review.repository.ReviewRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class ReviewSchedulerService { + + private final RedisCacheService redisCacheService; + private final ReviewRepository reviewRepository; + + private static final String AVERAGE_RATE_CACHE_KEY = "averageRating:Item:"; + private static final String REVIEW_COUNT_CACHE_KEY = "reviewCount:Item:"; + + @Scheduled(cron = "0 0 * * 1 *") + public void synchronizeAverageRating() { + reviewRepository.findAll() + .forEach(review -> redisCacheService.synchronizeAverageRating( + review.getItem().getItemId(), + AVERAGE_RATE_CACHE_KEY + review.getItem().getItemId() + )); + } + + @Scheduled(cron = "0 0 * * 1 *") + public void synchronizeNumberOfReview() { + reviewRepository.findAll() + .forEach( + review -> redisCacheService.synchronizeNumberOfReview( + review.getItem().getItemId(), + REVIEW_COUNT_CACHE_KEY + review.getItem().getItemId() + ) + ); + } +} From 64e20602ef15c53e555b5e09d8b2bc572b01e2a3 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Wed, 20 Sep 2023 15:21:59 +0900 Subject: [PATCH 15/41] =?UTF-8?q?[NAYB-156]=20feat:=20=EC=95=8C=EB=A6=BC?= =?UTF-8?q?=20=EC=A0=84=EC=86=A1=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/notification/NotificationType.java | 10 +++- .../repository/EmitterMemoryRepository.java | 3 +- .../service/NotificationService.java | 46 ++++++++++++++++++- .../response/NotificationResponse.java | 22 +++++++++ 4 files changed, 76 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/prgrms/nabmart/domain/notification/service/response/NotificationResponse.java diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/NotificationType.java b/src/main/java/com/prgrms/nabmart/domain/notification/NotificationType.java index f9d0c0cc5..746af2939 100644 --- a/src/main/java/com/prgrms/nabmart/domain/notification/NotificationType.java +++ b/src/main/java/com/prgrms/nabmart/domain/notification/NotificationType.java @@ -1,5 +1,13 @@ package com.prgrms.nabmart.domain.notification; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor public enum NotificationType { - DELIVERY + CONNECT("connect"), + DELIVERY("delivery"); + + private final String value; } diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/repository/EmitterMemoryRepository.java b/src/main/java/com/prgrms/nabmart/domain/notification/repository/EmitterMemoryRepository.java index 0c4e6b6c4..6d20179aa 100644 --- a/src/main/java/com/prgrms/nabmart/domain/notification/repository/EmitterMemoryRepository.java +++ b/src/main/java/com/prgrms/nabmart/domain/notification/repository/EmitterMemoryRepository.java @@ -7,8 +7,7 @@ import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; @Repository -public class EmitterMemoryRepository implements - EmitterRepository { +public class EmitterMemoryRepository implements EmitterRepository { private final Map emitters = new ConcurrentHashMap<>(); diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java b/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java index 56a29bb78..151bdb20c 100644 --- a/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java +++ b/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java @@ -2,7 +2,14 @@ import static java.text.MessageFormat.format; +import com.prgrms.nabmart.domain.notification.Notification; +import com.prgrms.nabmart.domain.notification.NotificationType; import com.prgrms.nabmart.domain.notification.repository.EmitterRepository; +import com.prgrms.nabmart.domain.notification.repository.NotificationRepository; +import com.prgrms.nabmart.domain.notification.service.response.NotificationResponse; +import com.prgrms.nabmart.domain.user.exception.NotFoundUserException; +import com.prgrms.nabmart.domain.user.repository.UserRepository; +import jakarta.transaction.Transactional; import java.io.IOException; import java.util.Map; import lombok.RequiredArgsConstructor; @@ -16,6 +23,8 @@ public class NotificationService { private static final Long DEFAULT_TIMEOUT = 60L * 1000 * 120; private final EmitterRepository emitterRepository; + private final NotificationRepository notificationRepository; + private final UserRepository userRepository; public SseEmitter connection(Long userId, String lastEventId) { String emitterId = userId + "_" + System.currentTimeMillis(); @@ -30,7 +39,7 @@ public SseEmitter connection(Long userId, String lastEventId) { sendNotification(emitter, emitterId, format("[Connected] UserId={0}", userId)); // 클라이언트 미수신한 event를 모두 전송 - if(!lastEventId.isEmpty()) { + if (!lastEventId.isEmpty()) { Map events = emitterRepository.findAllByIdStartWith(userId); events.entrySet().stream() .filter(entry -> lastEventId.compareTo(entry.getKey()) < 0) @@ -42,11 +51,44 @@ public SseEmitter connection(Long userId, String lastEventId) { private void sendNotification(SseEmitter emitter, String emitterId, Object data) { try { - emitter.send(emitter.event() + emitter.send(SseEmitter.event() .id(emitterId) .data(data)); } catch (IOException ex) { emitterRepository.deleteById(emitterId); } } + + @Transactional + public void send(Long userId, String content, NotificationType notificationType) { + verifyExistsUser(userId); + + Notification notification = Notification.builder() + .content(content) + .userId(userId) + .notificationType(notificationType) + .build(); + notificationRepository.save(notification); + + Map emitters = emitterRepository.findAllByIdStartWith(userId); + emitters.forEach((key, emitter) -> { + sendNotification(emitter, key, NotificationResponse.from(notification)); + }); + } + + private void verifyExistsUser(Long userId) { + userRepository.findById(userId) + .orElseThrow(() -> new NotFoundUserException("존재하지 않는 유저입니다.")); + } + + private void sendNotification(SseEmitter emitter, String emitterId, NotificationResponse data) { + try { + emitter.send(SseEmitter.event() + .id(emitterId) + .name(data.notificationType().getValue()) + .data(data)); + } catch (IOException ex) { + emitterRepository.deleteById(emitterId); + } + } } diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/service/response/NotificationResponse.java b/src/main/java/com/prgrms/nabmart/domain/notification/service/response/NotificationResponse.java new file mode 100644 index 000000000..43e1753be --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/notification/service/response/NotificationResponse.java @@ -0,0 +1,22 @@ +package com.prgrms.nabmart.domain.notification.service.response; + +import com.prgrms.nabmart.domain.notification.Notification; +import com.prgrms.nabmart.domain.notification.NotificationType; +import java.time.LocalDateTime; + +public record NotificationResponse( + Long notificationId, + String content, + NotificationType notificationType, + Long userId, + LocalDateTime createdAt) { + + public static NotificationResponse from(Notification notification) { + return new NotificationResponse( + notification.getNotificationId(), + notification.getContent(), + notification.getNotificationType(), + notification.getUserId(), + notification.getCreatedAt()); + } +} From c0640fe9982eeb57838409d177feb43fb1c09f3f Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Wed, 20 Sep 2023 21:53:58 +0900 Subject: [PATCH 16/41] =?UTF-8?q?[NAYB-156]=20chore:=20cors=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/prgrms/nabmart/global/config/WebMvcConfig.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/com/prgrms/nabmart/global/config/WebMvcConfig.java b/src/main/java/com/prgrms/nabmart/global/config/WebMvcConfig.java index f687f217d..dd937fa18 100644 --- a/src/main/java/com/prgrms/nabmart/global/config/WebMvcConfig.java +++ b/src/main/java/com/prgrms/nabmart/global/config/WebMvcConfig.java @@ -4,6 +4,7 @@ import java.util.List; import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration @@ -13,4 +14,13 @@ public class WebMvcConfig implements WebMvcConfigurer { public void addArgumentResolvers(List resolvers) { resolvers.add(new LoginUserArgumentResolver()); } + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins("http://localhost:3000") + .allowedHeaders("*") + .allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS") + .allowCredentials(true); + } } From bac9588fbd83164851ccb9505c5a0c37f9d87b24 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Wed, 20 Sep 2023 21:55:36 +0900 Subject: [PATCH 17/41] =?UTF-8?q?[NAYB-156]=20feat:=20=EC=95=8C=EB=A6=BC?= =?UTF-8?q?=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=EC=97=B0=EA=B2=B0=20api=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 --- .../notification/NotificationController.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/main/java/com/prgrms/nabmart/domain/notification/NotificationController.java diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/NotificationController.java b/src/main/java/com/prgrms/nabmart/domain/notification/NotificationController.java new file mode 100644 index 000000000..e7affc89f --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/notification/NotificationController.java @@ -0,0 +1,28 @@ +package com.prgrms.nabmart.domain.notification; + +import com.prgrms.nabmart.domain.notification.service.NotificationService; +import com.prgrms.nabmart.global.auth.LoginUser; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1/notifications") +public class NotificationController { + + private final NotificationService notificationService; + + @GetMapping(value = "/connect", produces = "text/event-stream") + public ResponseEntity sseConnection( + @RequestHeader(value = "Last-Event-ID", required = false, defaultValue = "") String lastEventId, + @LoginUser Long userId) { + + SseEmitter sseEmitter = notificationService.connection(userId, lastEventId); + return ResponseEntity.ok(sseEmitter); + } +} From 0aac34705b10b86e09c13fc35d72e1ebc599fe01 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Wed, 20 Sep 2023 21:56:40 +0900 Subject: [PATCH 18/41] =?UTF-8?q?[NAYB-156]=20chore:=20=EC=95=8C=EB=A6=BC?= =?UTF-8?q?=20api=20=EC=A0=91=EA=B7=BC=20=EA=B6=8C=ED=95=9C=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/prgrms/nabmart/global/config/WebSecurityConfig.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/prgrms/nabmart/global/config/WebSecurityConfig.java b/src/main/java/com/prgrms/nabmart/global/config/WebSecurityConfig.java index 60d3cc4b6..eb8183068 100644 --- a/src/main/java/com/prgrms/nabmart/global/config/WebSecurityConfig.java +++ b/src/main/java/com/prgrms/nabmart/global/config/WebSecurityConfig.java @@ -65,6 +65,7 @@ public SecurityFilterChain filterChain( private RequestMatcher[] requestPermitAll() { List requestMatchers = List.of( + antMatcher(GET, "/api/v1/notifications/**"), antMatcher(POST, "/oauth2/authorization/**"), antMatcher(POST, "/api/v1/riders/**"), antMatcher(GET, "/api/v1/categories/**"), From f209e662636703db3359a3873a1743c83f3f48a1 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Wed, 20 Sep 2023 22:29:55 +0900 Subject: [PATCH 19/41] =?UTF-8?q?[NAYB-156]=20refactor:=20=EC=BB=A8?= =?UTF-8?q?=EB=B2=A4=EC=85=98=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EC=95=8C?= =?UTF-8?q?=EB=A6=BC=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=EC=9A=94=EC=B2=AD=20?= =?UTF-8?q?dto=EB=A1=9C=20=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NotificationController.java | 7 ++-- .../request/ConnectNotificationCommand.java | 8 +++++ .../service/NotificationService.java | 34 ++++++++++++------- .../request/SendNotificationCommand.java | 16 +++++++++ 4 files changed, 51 insertions(+), 14 deletions(-) rename src/main/java/com/prgrms/nabmart/domain/notification/{ => controller}/NotificationController.java (72%) create mode 100644 src/main/java/com/prgrms/nabmart/domain/notification/controller/request/ConnectNotificationCommand.java create mode 100644 src/main/java/com/prgrms/nabmart/domain/notification/service/request/SendNotificationCommand.java diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/NotificationController.java b/src/main/java/com/prgrms/nabmart/domain/notification/controller/NotificationController.java similarity index 72% rename from src/main/java/com/prgrms/nabmart/domain/notification/NotificationController.java rename to src/main/java/com/prgrms/nabmart/domain/notification/controller/NotificationController.java index e7affc89f..befac13ad 100644 --- a/src/main/java/com/prgrms/nabmart/domain/notification/NotificationController.java +++ b/src/main/java/com/prgrms/nabmart/domain/notification/controller/NotificationController.java @@ -1,5 +1,6 @@ -package com.prgrms.nabmart.domain.notification; +package com.prgrms.nabmart.domain.notification.controller; +import com.prgrms.nabmart.domain.notification.controller.request.ConnectNotificationCommand; import com.prgrms.nabmart.domain.notification.service.NotificationService; import com.prgrms.nabmart.global.auth.LoginUser; import lombok.RequiredArgsConstructor; @@ -22,7 +23,9 @@ public ResponseEntity sseConnection( @RequestHeader(value = "Last-Event-ID", required = false, defaultValue = "") String lastEventId, @LoginUser Long userId) { - SseEmitter sseEmitter = notificationService.connection(userId, lastEventId); + ConnectNotificationCommand connectNotificationCommand + = ConnectNotificationCommand.of(userId, lastEventId); + SseEmitter sseEmitter = notificationService.connectNotification(connectNotificationCommand); return ResponseEntity.ok(sseEmitter); } } diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/controller/request/ConnectNotificationCommand.java b/src/main/java/com/prgrms/nabmart/domain/notification/controller/request/ConnectNotificationCommand.java new file mode 100644 index 000000000..785e4286d --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/notification/controller/request/ConnectNotificationCommand.java @@ -0,0 +1,8 @@ +package com.prgrms.nabmart.domain.notification.controller.request; + +public record ConnectNotificationCommand(Long userId, String lastEventId) { + + public static ConnectNotificationCommand of(final Long userId, final String lastEventId) { + return new ConnectNotificationCommand(userId, lastEventId); + } +} diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java b/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java index 151bdb20c..f28b5dd1f 100644 --- a/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java +++ b/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java @@ -4,8 +4,10 @@ import com.prgrms.nabmart.domain.notification.Notification; import com.prgrms.nabmart.domain.notification.NotificationType; +import com.prgrms.nabmart.domain.notification.controller.request.ConnectNotificationCommand; import com.prgrms.nabmart.domain.notification.repository.EmitterRepository; import com.prgrms.nabmart.domain.notification.repository.NotificationRepository; +import com.prgrms.nabmart.domain.notification.service.request.SendNotificationCommand; import com.prgrms.nabmart.domain.notification.service.response.NotificationResponse; import com.prgrms.nabmart.domain.user.exception.NotFoundUserException; import com.prgrms.nabmart.domain.user.repository.UserRepository; @@ -13,9 +15,11 @@ import java.io.IOException; import java.util.Map; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; +@Slf4j @Service @RequiredArgsConstructor public class NotificationService { @@ -26,8 +30,11 @@ public class NotificationService { private final NotificationRepository notificationRepository; private final UserRepository userRepository; - public SseEmitter connection(Long userId, String lastEventId) { - String emitterId = userId + "_" + System.currentTimeMillis(); + public SseEmitter connectNotification(ConnectNotificationCommand connectNotificationCommand) { + Long userId = connectNotificationCommand.userId(); + String lastEventId = connectNotificationCommand.lastEventId(); + + String emitterId = format("{0}_{1}",userId, System.currentTimeMillis()); SseEmitter emitter = new SseEmitter(DEFAULT_TIMEOUT); emitterRepository.save(emitterId, emitter); @@ -36,33 +43,36 @@ public SseEmitter connection(Long userId, String lastEventId) { emitter.onError(e -> emitterRepository.deleteById(emitterId)); // 연결 직후 데이터 전송이 없으면 503 에러 발생. 에러 방지용 더미 데이터 전송 - sendNotification(emitter, emitterId, format("[Connected] UserId={0}", userId)); + send(emitter, emitterId, format("[Connected] UserId={0}", userId)); // 클라이언트 미수신한 event를 모두 전송 - if (!lastEventId.isEmpty()) { + if (!connectNotificationCommand.lastEventId().isEmpty()) { Map events = emitterRepository.findAllByIdStartWith(userId); - events.entrySet().stream() - .filter(entry -> lastEventId.compareTo(entry.getKey()) < 0) - .forEach(entry -> sendNotification(emitter, entry.getKey(), entry.getValue())); + events.entrySet().stream().filter(entry -> lastEventId.compareTo(entry.getKey()) < 0) + .forEach(entry -> send(emitter, entry.getKey(), entry.getValue())); } return emitter; } - private void sendNotification(SseEmitter emitter, String emitterId, Object data) { + private void send(SseEmitter emitter, String emitterId, Object data) { try { emitter.send(SseEmitter.event() .id(emitterId) .data(data)); } catch (IOException ex) { emitterRepository.deleteById(emitterId); + log.error("알림 전송에 실패했습니다.", ex); } } @Transactional - public void send(Long userId, String content, NotificationType notificationType) { - verifyExistsUser(userId); + public void sendNotification(SendNotificationCommand sendNotificationCommand) { + Long userId = sendNotificationCommand.userId(); + String content = sendNotificationCommand.content(); + NotificationType notificationType = sendNotificationCommand.notificationType(); + verifyExistsUser(userId); Notification notification = Notification.builder() .content(content) .userId(userId) @@ -72,7 +82,7 @@ public void send(Long userId, String content, NotificationType notificationType) Map emitters = emitterRepository.findAllByIdStartWith(userId); emitters.forEach((key, emitter) -> { - sendNotification(emitter, key, NotificationResponse.from(notification)); + send(emitter, key, NotificationResponse.from(notification)); }); } @@ -81,7 +91,7 @@ private void verifyExistsUser(Long userId) { .orElseThrow(() -> new NotFoundUserException("존재하지 않는 유저입니다.")); } - private void sendNotification(SseEmitter emitter, String emitterId, NotificationResponse data) { + private void send(SseEmitter emitter, String emitterId, NotificationResponse data) { try { emitter.send(SseEmitter.event() .id(emitterId) diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/service/request/SendNotificationCommand.java b/src/main/java/com/prgrms/nabmart/domain/notification/service/request/SendNotificationCommand.java new file mode 100644 index 000000000..3a02512dc --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/notification/service/request/SendNotificationCommand.java @@ -0,0 +1,16 @@ +package com.prgrms.nabmart.domain.notification.service.request; + +import com.prgrms.nabmart.domain.notification.NotificationType; + +public record SendNotificationCommand( + Long userId, + String content, + NotificationType notificationType) { + + public static SendNotificationCommand of( + final Long userId, + final String content, + final NotificationType notificationType) { + return new SendNotificationCommand(userId, content, notificationType); + } +} From 627091e092ebc9f63f9d8687f773b7863b3b9077 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Wed, 20 Sep 2023 23:13:04 +0900 Subject: [PATCH 20/41] =?UTF-8?q?[NAYB-156]=20test:=20`BaseControllerTest`?= =?UTF-8?q?=EC=97=90=20`NotificationService`=20=EB=AA=A9=20=EB=B9=88=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 --- src/test/java/com/prgrms/nabmart/base/BaseControllerTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/java/com/prgrms/nabmart/base/BaseControllerTest.java b/src/test/java/com/prgrms/nabmart/base/BaseControllerTest.java index 28c3cf31c..74f6b23da 100644 --- a/src/test/java/com/prgrms/nabmart/base/BaseControllerTest.java +++ b/src/test/java/com/prgrms/nabmart/base/BaseControllerTest.java @@ -11,6 +11,7 @@ import com.prgrms.nabmart.domain.event.service.EventService; import com.prgrms.nabmart.domain.item.service.ItemService; import com.prgrms.nabmart.domain.item.service.LikeItemService; +import com.prgrms.nabmart.domain.notification.service.NotificationService; import com.prgrms.nabmart.domain.order.service.OrderService; import com.prgrms.nabmart.domain.payment.service.PaymentClient; import com.prgrms.nabmart.domain.payment.service.PaymentService; @@ -100,6 +101,9 @@ public abstract class BaseControllerTest { @MockBean protected RiderAuthenticationService riderAuthenticationService; + @MockBean + protected NotificationService notificationService; + protected static final String AUTHORIZATION = "Authorization"; From 0f17c6e940f8bc03d7bc66dcce5fca20f93c3fd5 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Wed, 20 Sep 2023 23:58:23 +0900 Subject: [PATCH 21/41] =?UTF-8?q?[NAYB-157]=20feat:=20=EB=B0=B0=EB=8B=AC?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nabmart/domain/delivery/Delivery.java | 5 +- .../delivery/service/DeliveryService.java | 15 ++++++ .../request/RegisterDeliveryCommand.java | 11 +++++ .../delivery/DeliveryIntegrationTest.java | 2 +- .../delivery/service/DeliveryServiceTest.java | 47 ++++++++++++++++++- 5 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/prgrms/nabmart/domain/delivery/service/request/RegisterDeliveryCommand.java diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/Delivery.java b/src/main/java/com/prgrms/nabmart/domain/delivery/Delivery.java index 5e86c14e5..c9a8ca449 100644 --- a/src/main/java/com/prgrms/nabmart/domain/delivery/Delivery.java +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/Delivery.java @@ -4,6 +4,7 @@ import com.prgrms.nabmart.domain.delivery.exception.InvalidDeliveryException; import com.prgrms.nabmart.domain.delivery.exception.UnauthorizedDeliveryException; import com.prgrms.nabmart.domain.order.Order; +import com.prgrms.nabmart.domain.order.OrderStatus; import com.prgrms.nabmart.domain.user.User; import com.prgrms.nabmart.global.BaseTimeEntity; import jakarta.persistence.Column; @@ -69,13 +70,15 @@ public class Delivery extends BaseTimeEntity { private Integer deliveryFee; @Builder - public Delivery(final Order order) { + public Delivery(final Order order, int estimateMinutes) { this.order = order; this.deliveryStatus = DeliveryStatus.ACCEPTING_ORDER; this.address = order.getAddress(); this.orderPrice = order.getPrice(); this.riderRequest = order.getRiderRequest(); this.deliveryFee = order.getDeliveryFee(); + this.arrivedAt = LocalDateTime.now().plusMinutes(estimateMinutes); + order.updateOrderStatus(OrderStatus.DELIVERING); } public boolean isOwnByUser(final User user) { diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java b/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java index 4c58bb968..ee928ba49 100644 --- a/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java @@ -12,10 +12,14 @@ import com.prgrms.nabmart.domain.delivery.service.request.FindDeliveryCommand; import com.prgrms.nabmart.domain.delivery.service.request.FindRiderDeliveriesCommand; import com.prgrms.nabmart.domain.delivery.service.request.FindWaitingDeliveriesCommand; +import com.prgrms.nabmart.domain.delivery.service.request.RegisterDeliveryCommand; import com.prgrms.nabmart.domain.delivery.service.request.StartDeliveryCommand; import com.prgrms.nabmart.domain.delivery.service.response.FindDeliveryDetailResponse; import com.prgrms.nabmart.domain.delivery.service.response.FindRiderDeliveriesResponse; import com.prgrms.nabmart.domain.delivery.service.response.FindWaitingDeliveriesResponse; +import com.prgrms.nabmart.domain.order.Order; +import com.prgrms.nabmart.domain.order.exception.NotFoundOrderException; +import com.prgrms.nabmart.domain.order.repository.OrderRepository; import com.prgrms.nabmart.domain.user.User; import com.prgrms.nabmart.domain.user.exception.NotFoundUserException; import com.prgrms.nabmart.domain.user.repository.UserRepository; @@ -31,6 +35,17 @@ public class DeliveryService { private final DeliveryRepository deliveryRepository; private final UserRepository userRepository; private final RiderRepository riderRepository; + private final OrderRepository orderRepository; + + public Long registerDelivery(RegisterDeliveryCommand registerDeliveryCommand) { + Order order = orderRepository.findByOrderIdAndUser_UserId( + registerDeliveryCommand.orderId(), + registerDeliveryCommand.userId()) + .orElseThrow(() -> new NotFoundOrderException("존재하지 않는 주문입니다.")); + Delivery delivery = new Delivery(order, registerDeliveryCommand.estimateMinutes()); + deliveryRepository.save(delivery); + return delivery.getDeliveryId(); + } @Transactional(readOnly = true) public FindDeliveryDetailResponse findDelivery(FindDeliveryCommand findDeliveryCommand) { diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/service/request/RegisterDeliveryCommand.java b/src/main/java/com/prgrms/nabmart/domain/delivery/service/request/RegisterDeliveryCommand.java new file mode 100644 index 000000000..5693bf18b --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/service/request/RegisterDeliveryCommand.java @@ -0,0 +1,11 @@ +package com.prgrms.nabmart.domain.delivery.service.request; + +public record RegisterDeliveryCommand(Long orderId, Long userId, int estimateMinutes) { + + public static RegisterDeliveryCommand of( + final Long orderId, + final Long userId, + final int estimateMinutes) { + return new RegisterDeliveryCommand(orderId, userId, estimateMinutes); + } +} diff --git a/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryIntegrationTest.java b/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryIntegrationTest.java index 3b20ad7d7..5be12d820 100644 --- a/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryIntegrationTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryIntegrationTest.java @@ -136,7 +136,7 @@ List createAndSaveRiders(int end) { } private Delivery createAndSaveDelivery() { - Delivery delivery = new Delivery(order); + Delivery delivery = new Delivery(order, 60); deliveryRepository.save(delivery); return delivery; } diff --git a/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java b/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java index feb097ed6..e745b6d31 100644 --- a/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java @@ -6,6 +6,7 @@ import static org.assertj.core.api.Assertions.within; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; import com.prgrms.nabmart.domain.delivery.Delivery; import com.prgrms.nabmart.domain.delivery.DeliveryStatus; @@ -22,6 +23,7 @@ import com.prgrms.nabmart.domain.delivery.service.request.FindDeliveryCommand; import com.prgrms.nabmart.domain.delivery.service.request.FindRiderDeliveriesCommand; import com.prgrms.nabmart.domain.delivery.service.request.FindWaitingDeliveriesCommand; +import com.prgrms.nabmart.domain.delivery.service.request.RegisterDeliveryCommand; import com.prgrms.nabmart.domain.delivery.service.request.StartDeliveryCommand; import com.prgrms.nabmart.domain.delivery.service.response.FindDeliveryDetailResponse; import com.prgrms.nabmart.domain.delivery.service.response.FindRiderDeliveriesResponse; @@ -29,6 +31,8 @@ import com.prgrms.nabmart.domain.delivery.service.response.FindWaitingDeliveriesResponse; import com.prgrms.nabmart.domain.delivery.support.DeliveryFixture; import com.prgrms.nabmart.domain.order.Order; +import com.prgrms.nabmart.domain.order.exception.NotFoundOrderException; +import com.prgrms.nabmart.domain.order.repository.OrderRepository; import com.prgrms.nabmart.domain.order.support.OrderFixture; import com.prgrms.nabmart.domain.user.User; import com.prgrms.nabmart.domain.user.UserGrade; @@ -67,12 +71,53 @@ class DeliveryServiceTest { @Mock RiderRepository riderRepository; + @Mock + OrderRepository orderRepository; + User user = UserFixture.user(); Order order = deliveringOrder(1L, user); Rider rider = DeliveryFixture.rider(); Delivery delivery = DeliveryFixture.acceptedDelivery(order, rider); TemporalUnitOffset withInOneSeconds = within(1, ChronoUnit.SECONDS); + @Nested + @DisplayName("registerDelivery 메서드 실행 시") + class RegisterDeliveryTest { + + Order order = OrderFixture.payingOrder(1L, user); + RegisterDeliveryCommand registerDeliveryCommand = RegisterDeliveryCommand.of( + 1L, + 1L, + 60); + + @Test + @DisplayName("성공") + void success() { + //given + given(orderRepository.findByOrderIdAndUser_UserId(any(), any())) + .willReturn(Optional.ofNullable(order)); + + //when + deliveryService.registerDelivery(registerDeliveryCommand); + + //then + then(deliveryRepository).should().save(any()); + } + + @Test + @DisplayName("예외: orderId, userId와 일치하는 order가 없음") + void throwExceptionWhenNotFoundOrder() { + //given + given(orderRepository.findByOrderIdAndUser_UserId(any(), any())) + .willReturn(Optional.empty()); + + //when + //then + assertThatThrownBy(() -> deliveryService.registerDelivery(registerDeliveryCommand)) + .isInstanceOf(NotFoundOrderException.class); + } + } + @Nested @DisplayName("findDelivery 메서드 실행 시") class FindDeliveryTest { @@ -94,7 +139,7 @@ void success() { //then assertThat(findDeliveryDetailResponse.deliveryStatus()) .isEqualTo(delivery.getDeliveryStatus()); - assertThat(findDeliveryDetailResponse.arrivedAt()) + assertThat(findDeliveryDetailResponse.createdAt()) .isEqualTo(delivery.getCreatedAt()); assertThat(findDeliveryDetailResponse.arrivedAt()) .isEqualTo(delivery.getArrivedAt()); From 28aeeaef6051b4aacc20caafee6320468834e8d1 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Thu, 21 Sep 2023 00:14:37 +0900 Subject: [PATCH 22/41] =?UTF-8?q?[NAYB-157]=20feat:=20=EC=A3=BC=EB=AC=B8?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1=20api=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DeliveryController.java | 20 +++++++++ .../request/RegisterDeliveryRequest.java | 11 +++++ .../controller/DeliveryControllerTest.java | 42 +++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 src/main/java/com/prgrms/nabmart/domain/delivery/controller/request/RegisterDeliveryRequest.java diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryController.java b/src/main/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryController.java index 5e6162f7e..2591fdcad 100644 --- a/src/main/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryController.java +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryController.java @@ -1,6 +1,7 @@ package com.prgrms.nabmart.domain.delivery.controller; import com.prgrms.nabmart.domain.delivery.controller.request.FindRiderDeliveriesRequest; +import com.prgrms.nabmart.domain.delivery.controller.request.RegisterDeliveryRequest; import com.prgrms.nabmart.domain.delivery.controller.request.StartDeliveryRequest; import com.prgrms.nabmart.domain.delivery.exception.AlreadyAssignedDeliveryException; import com.prgrms.nabmart.domain.delivery.exception.DeliveryException; @@ -10,6 +11,7 @@ import com.prgrms.nabmart.domain.delivery.service.request.FindDeliveryCommand; import com.prgrms.nabmart.domain.delivery.service.request.FindRiderDeliveriesCommand; import com.prgrms.nabmart.domain.delivery.service.request.FindWaitingDeliveriesCommand; +import com.prgrms.nabmart.domain.delivery.service.request.RegisterDeliveryCommand; import com.prgrms.nabmart.domain.delivery.service.request.StartDeliveryCommand; import com.prgrms.nabmart.domain.delivery.service.response.FindDeliveryDetailResponse; import com.prgrms.nabmart.domain.delivery.service.response.FindRiderDeliveriesResponse; @@ -17,6 +19,7 @@ import com.prgrms.nabmart.global.auth.LoginUser; import com.prgrms.nabmart.global.util.ErrorTemplate; import jakarta.validation.Valid; +import java.net.URI; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; @@ -26,6 +29,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -35,8 +39,24 @@ @RequestMapping("/api/v1") public class DeliveryController { + private static final String BASE_URI = "/api/v1/deliveries/"; + private final DeliveryService deliveryService; + @PostMapping("/orders/{orderId}/deliveries") + public ResponseEntity registerDelivery( + @PathVariable Long orderId, + @RequestBody RegisterDeliveryRequest registerDeliveryRequest, + @LoginUser Long userId) { + RegisterDeliveryCommand registerDeliveryCommand = RegisterDeliveryCommand.of( + orderId, + userId, + registerDeliveryRequest.estimateMinutes()); + Long deliveryId = deliveryService.registerDelivery(registerDeliveryCommand); + URI location = URI.create(BASE_URI + deliveryId); + return ResponseEntity.created(location).build(); + } + @GetMapping("/orders/{orderId}/deliveries") public ResponseEntity findDelivery( @PathVariable final Long orderId, diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/controller/request/RegisterDeliveryRequest.java b/src/main/java/com/prgrms/nabmart/domain/delivery/controller/request/RegisterDeliveryRequest.java new file mode 100644 index 000000000..7130d7e12 --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/controller/request/RegisterDeliveryRequest.java @@ -0,0 +1,11 @@ +package com.prgrms.nabmart.domain.delivery.controller.request; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; + +public record RegisterDeliveryRequest( + @Positive(message = "배달 예상 소요 시간은 양수여야 합니다.") + @NotNull(message = "배달 예상 소요 시간은 필수입니다.") + Integer estimateMinutes) { + +} diff --git a/src/test/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryControllerTest.java b/src/test/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryControllerTest.java index 516fe7157..93cab122d 100644 --- a/src/test/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryControllerTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryControllerTest.java @@ -5,8 +5,10 @@ import static org.mockito.Mockito.doThrow; import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders; +import static org.springframework.restdocs.headers.HeaderDocumentation.responseHeaders; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.patch; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; import static org.springframework.restdocs.payload.JsonFieldType.ARRAY; import static org.springframework.restdocs.payload.JsonFieldType.NUMBER; import static org.springframework.restdocs.payload.JsonFieldType.STRING; @@ -20,6 +22,7 @@ import com.prgrms.nabmart.base.BaseControllerTest; import com.prgrms.nabmart.domain.delivery.DeliveryStatus; +import com.prgrms.nabmart.domain.delivery.controller.request.RegisterDeliveryRequest; import com.prgrms.nabmart.domain.delivery.controller.request.StartDeliveryRequest; import com.prgrms.nabmart.domain.delivery.exception.AlreadyAssignedDeliveryException; import com.prgrms.nabmart.domain.delivery.service.response.FindDeliveryDetailResponse; @@ -37,6 +40,45 @@ class DeliveryControllerTest extends BaseControllerTest { + @Nested + @DisplayName("배달 생성 API 호출 시") + class RegisterDeliveryTest { + + @Test + @DisplayName("성공") + void registerDelivery() throws Exception { + //given + RegisterDeliveryRequest registerDeliveryRequest + = new RegisterDeliveryRequest(60); + + given(deliveryService.registerDelivery(any())).willReturn(1L); + + //when + ResultActions resultActions = mockMvc.perform( + post("/api/v1/orders/{orderId}/deliveries", 1L) + .header(AUTHORIZATION, accessToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(registerDeliveryRequest))); + + //then + resultActions.andExpect(status().isCreated()) + .andDo(restDocs.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("액세스 토큰") + ), + pathParameters( + parameterWithName("orderId").description("주문 ID") + ), + requestFields( + fieldWithPath("estimateMinutes").type(NUMBER).description("배달 예상 시간(분)") + ), + responseHeaders( + headerWithName("Location").description("생성된 리소스 위치") + ) + )); + } + } + @Nested @DisplayName("배달 현황 조회 API 호출 시") class FindDeliveryTest { From 76616d2a916fee83ef4221c6d19f8f273d1fe959 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Thu, 21 Sep 2023 00:23:01 +0900 Subject: [PATCH 23/41] =?UTF-8?q?[NAYB-157]=20feat:=20=EC=A3=BC=EB=AC=B8?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1=20api=20=EC=A0=91=EA=B7=BC=20=EA=B6=8C?= =?UTF-8?q?=ED=95=9C=20=EC=A7=80=EC=A0=95=20=EB=B0=8F=20employee=20?= =?UTF-8?q?=EA=B6=8C=ED=95=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/prgrms/nabmart/domain/user/UserRole.java | 5 ++++- .../prgrms/nabmart/global/config/WebSecurityConfig.java | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/prgrms/nabmart/domain/user/UserRole.java b/src/main/java/com/prgrms/nabmart/domain/user/UserRole.java index 9dee17862..bf2d904c9 100644 --- a/src/main/java/com/prgrms/nabmart/domain/user/UserRole.java +++ b/src/main/java/com/prgrms/nabmart/domain/user/UserRole.java @@ -8,7 +8,9 @@ public enum UserRole { ROLE_USER(Constants.ROLE_USER, List.of(Constants.ROLE_USER)), ROLE_RIDER(Constants.ROLE_RIDER, List.of(Constants.ROLE_RIDER)), - ROLE_ADMIN(Constants.ROLE_ADMIN, List.of(Constants.ROLE_ADMIN, Constants.ROLE_USER)); + ROLE_EMPLOYEE(Constants.ROLE_EMPLOYEE, List.of(Constants.ROLE_EMPLOYEE)), + ROLE_ADMIN(Constants.ROLE_ADMIN, + List.of(Constants.ROLE_ADMIN, Constants.ROLE_EMPLOYEE, Constants.ROLE_USER)); private final String value; private final List authorities; @@ -21,6 +23,7 @@ public enum UserRole { private static class Constants { private static final String ROLE_USER = "ROLE_USER"; private static final String ROLE_RIDER = "ROLE_RIDER"; + private static final String ROLE_EMPLOYEE = "ROLE_EMPLOYEE"; private static final String ROLE_ADMIN = "ROLE_ADMIN"; } } diff --git a/src/main/java/com/prgrms/nabmart/global/config/WebSecurityConfig.java b/src/main/java/com/prgrms/nabmart/global/config/WebSecurityConfig.java index 60d3cc4b6..9faf60d47 100644 --- a/src/main/java/com/prgrms/nabmart/global/config/WebSecurityConfig.java +++ b/src/main/java/com/prgrms/nabmart/global/config/WebSecurityConfig.java @@ -46,6 +46,7 @@ public SecurityFilterChain filterChain( .requestMatchers(requestPermitAll()).permitAll() .requestMatchers(requestHasRoleUser()).hasRole("USER") .requestMatchers(requestHasRoleRider()).hasRole("RIDER") + .requestMatchers(requestHasRoleEmployee()).hasRole("EMPLOYEE") .requestMatchers(requestHasRoleAdmin()).hasRole("ADMIN") .anyRequest().denyAll()) .csrf(AbstractHttpConfigurer::disable) @@ -95,6 +96,13 @@ private RequestMatcher[] requestHasRoleRider() { return requestMatchers.toArray(RequestMatcher[]::new); } + private RequestMatcher[] requestHasRoleEmployee() { + List requestMatchers = List.of( + antMatcher(POST, "/api/v1/orders/*/deliveries") + ); + return requestMatchers.toArray(RequestMatcher[]::new); + } + private RequestMatcher[] requestHasRoleAdmin() { List requestMatchers = List.of( antMatcher("/api/v1/main-categories/**"), From 3b9e5041e149e1708f60b37528d8f0fc70c4d749 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Thu, 21 Sep 2023 09:01:21 +0900 Subject: [PATCH 24/41] =?UTF-8?q?[NAYB-157]=20feat:=20=EB=B0=B0=EB=8B=AC?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1=20=EC=8B=9C=20order=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=EC=97=90=20=EB=B9=84=EA=B4=80=EC=A0=81=20=EB=9D=BD=EC=9D=84=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nabmart/domain/delivery/Delivery.java | 2 +- .../controller/DeliveryController.java | 6 +- .../AlreadyRegisteredDeliveryException.java | 8 ++ .../repository/DeliveryRepository.java | 3 + .../delivery/service/DeliveryService.java | 20 +++- .../order/repository/OrderRepository.java | 6 + .../delivery/DeliveryIntegrationTest.java | 106 +++++++++++++----- .../delivery/service/DeliveryServiceTest.java | 5 +- 8 files changed, 115 insertions(+), 41 deletions(-) create mode 100644 src/main/java/com/prgrms/nabmart/domain/delivery/exception/AlreadyRegisteredDeliveryException.java diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/Delivery.java b/src/main/java/com/prgrms/nabmart/domain/delivery/Delivery.java index c9a8ca449..4e698eca1 100644 --- a/src/main/java/com/prgrms/nabmart/domain/delivery/Delivery.java +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/Delivery.java @@ -70,7 +70,7 @@ public class Delivery extends BaseTimeEntity { private Integer deliveryFee; @Builder - public Delivery(final Order order, int estimateMinutes) { + public Delivery(final Order order, final int estimateMinutes) { this.order = order; this.deliveryStatus = DeliveryStatus.ACCEPTING_ORDER; this.address = order.getAddress(); diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryController.java b/src/main/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryController.java index 2591fdcad..fcc2ea2a4 100644 --- a/src/main/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryController.java +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryController.java @@ -45,9 +45,9 @@ public class DeliveryController { @PostMapping("/orders/{orderId}/deliveries") public ResponseEntity registerDelivery( - @PathVariable Long orderId, - @RequestBody RegisterDeliveryRequest registerDeliveryRequest, - @LoginUser Long userId) { + @PathVariable final Long orderId, + @RequestBody final RegisterDeliveryRequest registerDeliveryRequest, + @LoginUser final Long userId) { RegisterDeliveryCommand registerDeliveryCommand = RegisterDeliveryCommand.of( orderId, userId, diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/exception/AlreadyRegisteredDeliveryException.java b/src/main/java/com/prgrms/nabmart/domain/delivery/exception/AlreadyRegisteredDeliveryException.java new file mode 100644 index 000000000..13c3318f3 --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/exception/AlreadyRegisteredDeliveryException.java @@ -0,0 +1,8 @@ +package com.prgrms.nabmart.domain.delivery.exception; + +public class AlreadyRegisteredDeliveryException extends DeliveryException { + + public AlreadyRegisteredDeliveryException(String message) { + super(message); + } +} diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/repository/DeliveryRepository.java b/src/main/java/com/prgrms/nabmart/domain/delivery/repository/DeliveryRepository.java index 3b4cc19a3..e16bb28fe 100644 --- a/src/main/java/com/prgrms/nabmart/domain/delivery/repository/DeliveryRepository.java +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/repository/DeliveryRepository.java @@ -3,6 +3,7 @@ import com.prgrms.nabmart.domain.delivery.Delivery; import com.prgrms.nabmart.domain.delivery.DeliveryStatus; import com.prgrms.nabmart.domain.delivery.Rider; +import com.prgrms.nabmart.domain.order.Order; import com.prgrms.nabmart.domain.user.User; import jakarta.persistence.LockModeType; import java.util.List; @@ -38,4 +39,6 @@ Page findRiderDeliveries( @Query("select d from Delivery d join d.order o where o.user = :user") List findAllByUser(@Param("user") User user); + + boolean existsByOrder(Order order); } diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java b/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java index ee928ba49..1995ed455 100644 --- a/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java @@ -2,6 +2,7 @@ import com.prgrms.nabmart.domain.delivery.Delivery; import com.prgrms.nabmart.domain.delivery.Rider; +import com.prgrms.nabmart.domain.delivery.exception.AlreadyRegisteredDeliveryException; import com.prgrms.nabmart.domain.delivery.exception.NotFoundDeliveryException; import com.prgrms.nabmart.domain.delivery.exception.NotFoundRiderException; import com.prgrms.nabmart.domain.delivery.exception.UnauthorizedDeliveryException; @@ -37,16 +38,27 @@ public class DeliveryService { private final RiderRepository riderRepository; private final OrderRepository orderRepository; + @Transactional public Long registerDelivery(RegisterDeliveryCommand registerDeliveryCommand) { - Order order = orderRepository.findByOrderIdAndUser_UserId( - registerDeliveryCommand.orderId(), - registerDeliveryCommand.userId()) - .orElseThrow(() -> new NotFoundOrderException("존재하지 않는 주문입니다.")); + Order order = findOrderByOrderIdPessimistic(registerDeliveryCommand); + checkAlreadyRegisteredDelivery(order); Delivery delivery = new Delivery(order, registerDeliveryCommand.estimateMinutes()); deliveryRepository.save(delivery); return delivery.getDeliveryId(); } + private Order findOrderByOrderIdPessimistic(RegisterDeliveryCommand registerDeliveryCommand) { + Order order = orderRepository.findByIdPessimistic(registerDeliveryCommand.orderId()) + .orElseThrow(() -> new NotFoundOrderException("존재하지 않는 주문입니다.")); + return order; + } + + private void checkAlreadyRegisteredDelivery(final Order order) { + if(deliveryRepository.existsByOrder(order)) { + throw new AlreadyRegisteredDeliveryException("이미 배달이 생성된 주문입니다."); + } + } + @Transactional(readOnly = true) public FindDeliveryDetailResponse findDelivery(FindDeliveryCommand findDeliveryCommand) { User user = findUserByUserId(findDeliveryCommand.userId()); diff --git a/src/main/java/com/prgrms/nabmart/domain/order/repository/OrderRepository.java b/src/main/java/com/prgrms/nabmart/domain/order/repository/OrderRepository.java index 32596aa08..4bde90fd4 100644 --- a/src/main/java/com/prgrms/nabmart/domain/order/repository/OrderRepository.java +++ b/src/main/java/com/prgrms/nabmart/domain/order/repository/OrderRepository.java @@ -3,12 +3,14 @@ import com.prgrms.nabmart.domain.order.Order; import com.prgrms.nabmart.domain.order.OrderStatus; import com.prgrms.nabmart.domain.user.User; +import jakarta.persistence.LockModeType; import java.time.LocalDateTime; import java.util.List; import java.util.Optional; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Lock; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -25,4 +27,8 @@ List findByStatusInBeforeExpiredTime(@Param("expiredTime") LocalDateTime @Param("statusList") List statusList); void deleteByUser(User findUser); + + @Lock(LockModeType.PESSIMISTIC_WRITE) + @Query("select o from Order o where o.orderId = :orderId") + Optional findByIdPessimistic(@Param("orderId") Long orderId); } diff --git a/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryIntegrationTest.java b/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryIntegrationTest.java index 5be12d820..751aa7d04 100644 --- a/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryIntegrationTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryIntegrationTest.java @@ -11,6 +11,7 @@ import com.prgrms.nabmart.domain.delivery.repository.RiderRepository; import com.prgrms.nabmart.domain.delivery.service.DeliveryService; import com.prgrms.nabmart.domain.delivery.service.request.AcceptDeliveryCommand; +import com.prgrms.nabmart.domain.delivery.service.request.RegisterDeliveryCommand; import com.prgrms.nabmart.domain.item.Item; import com.prgrms.nabmart.domain.item.repository.ItemRepository; import com.prgrms.nabmart.domain.item.support.ItemFixture; @@ -24,6 +25,7 @@ import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManagerFactory; import jakarta.persistence.EntityTransaction; +import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.concurrent.CountDownLatch; @@ -93,6 +95,80 @@ static void beforeAll() { properties.setProperty("spring.data.redis.port", "6379"); } + User user = UserFixture.user(); + MainCategory mainCategory = CategoryFixture.mainCategory(); + SubCategory subCategory = CategoryFixture.subCategory(mainCategory); + Item item = ItemFixture.item(mainCategory, subCategory); + OrderItem orderItem = new OrderItem(item, 5); + Order order = new Order(user, List.of(orderItem)); + + @BeforeEach + void setUpData() { + userRepository.save(user); + mainCategoryRepository.save(mainCategory); + subCategoryRepository.save(subCategory); + itemRepository.save(item); + orderRepository.save(order); + } + + @AfterEach + void tearDown() { + deliveryRepository.deleteAll(); + riderRepository.deleteAll(); + orderRepository.deleteAll(); + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + tx.begin(); + em.createQuery("delete from Item").executeUpdate(); // 소프트 딜리트 아이템 강제 삭제 + tx.commit(); + subCategoryRepository.deleteAll(); + mainCategoryRepository.deleteAll(); + } + + @Nested + @DisplayName("registerDelivery 메서드 실행 시") + class RegisterDeliveryTest { + + ExecutorService service; + CountDownLatch latch; + int treadPoolSize = 100; + User employee; + + @BeforeEach + void setUpConcurrent() { + service = Executors.newFixedThreadPool(treadPoolSize); + latch = new CountDownLatch(treadPoolSize); + } + + @Test + @DisplayName("성공: 여러명의 점원 중 한 명만 성공") + void success() throws InterruptedException { + //given + Long noUseUserId = 1L; + List exList = new ArrayList<>(); + int estimateMinutes = 30; + RegisterDeliveryCommand registerDeliveryCommand + = RegisterDeliveryCommand.of(order.getOrderId(), noUseUserId, estimateMinutes); + + //when + for(int i=0; i { + try { + deliveryService.registerDelivery(registerDeliveryCommand); + } catch (Exception ex) { + exList.add(ex); + } finally { + latch.countDown(); + } + }); + } + latch.await(); + + //then + assertThat(exList).hasSize(treadPoolSize-1); + } + } + @Nested @DisplayName("acceptDelivery 메서드 실행 시") @@ -101,28 +177,12 @@ class AcceptDeliveryTest { ExecutorService service; CountDownLatch latch; - User user = UserFixture.user(); - MainCategory mainCategory = CategoryFixture.mainCategory(); - SubCategory subCategory = CategoryFixture.subCategory(mainCategory); - Item item = ItemFixture.item(mainCategory, subCategory); - OrderItem orderItem = new OrderItem(item, 5); - Order order = new Order(user, List.of(orderItem)); - @BeforeEach void setUpConcurrent() { service = Executors.newFixedThreadPool(4); latch = new CountDownLatch(4); } - @BeforeEach - void setUpData() { - userRepository.save(user); - mainCategoryRepository.save(mainCategory); - subCategoryRepository.save(subCategory); - itemRepository.save(item); - orderRepository.save(order); - } - List createAndSaveRiders(int end) { List riders = IntStream.range(0, end) .mapToObj(i -> Rider.builder() @@ -141,20 +201,6 @@ private Delivery createAndSaveDelivery() { return delivery; } - @AfterEach - void tearDown() { - deliveryRepository.deleteAll(); - riderRepository.deleteAll(); - orderRepository.deleteAll(); - EntityManager em = emf.createEntityManager(); - EntityTransaction tx = em.getTransaction(); - tx.begin(); - em.createQuery("delete from Item").executeUpdate(); // 소프트 딜리트 아이템 강제 삭제 - tx.commit(); - subCategoryRepository.deleteAll(); - mainCategoryRepository.deleteAll(); - } - @Test @DisplayName("성공: 여러 명의 라이더 중 한 명만 성공") void success() throws InterruptedException { diff --git a/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java b/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java index e745b6d31..f661718f6 100644 --- a/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java @@ -94,7 +94,7 @@ class RegisterDeliveryTest { @DisplayName("성공") void success() { //given - given(orderRepository.findByOrderIdAndUser_UserId(any(), any())) + given(orderRepository.findByIdPessimistic(any())) .willReturn(Optional.ofNullable(order)); //when @@ -108,8 +108,7 @@ void success() { @DisplayName("예외: orderId, userId와 일치하는 order가 없음") void throwExceptionWhenNotFoundOrder() { //given - given(orderRepository.findByOrderIdAndUser_UserId(any(), any())) - .willReturn(Optional.empty()); + given(orderRepository.findByIdPessimistic(any())).willReturn(Optional.empty()); //when //then From 696e57d93c58d52f8b1e3e915a6c8099c74ffcf2 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Thu, 21 Sep 2023 09:33:07 +0900 Subject: [PATCH 25/41] =?UTF-8?q?[NAYB-157]=20feat:=20=EC=A3=BC=EB=AC=B8?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1=20=EC=8B=9C=20=EB=A1=9C=EA=B7=B8=EC=9D=B8?= =?UTF-8?q?=20=EC=82=AC=EC=9A=A9=EC=9E=90=20employee=20=EA=B6=8C=ED=95=9C?= =?UTF-8?q?=20=EA=B2=80=EC=A6=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../delivery/service/DeliveryService.java | 11 ++++-- .../com/prgrms/nabmart/domain/user/User.java | 4 +++ .../delivery/DeliveryIntegrationTest.java | 10 +++--- .../delivery/service/DeliveryServiceTest.java | 34 ++++++++++++++++++- .../domain/user/support/UserFixture.java | 13 +++++++ 5 files changed, 65 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java b/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java index 1995ed455..93d5c3319 100644 --- a/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java @@ -40,6 +40,7 @@ public class DeliveryService { @Transactional public Long registerDelivery(RegisterDeliveryCommand registerDeliveryCommand) { + checkUserHasRegisterDeliveryAuthority(registerDeliveryCommand.userId()); Order order = findOrderByOrderIdPessimistic(registerDeliveryCommand); checkAlreadyRegisteredDelivery(order); Delivery delivery = new Delivery(order, registerDeliveryCommand.estimateMinutes()); @@ -47,10 +48,16 @@ public Long registerDelivery(RegisterDeliveryCommand registerDeliveryCommand) { return delivery.getDeliveryId(); } + private void checkUserHasRegisterDeliveryAuthority(final Long userId) { + User user = findUserByUserId(userId); + if(!user.isEmployee()) { + throw new UnauthorizedDeliveryException("권한이 없습니다."); + } + } + private Order findOrderByOrderIdPessimistic(RegisterDeliveryCommand registerDeliveryCommand) { - Order order = orderRepository.findByIdPessimistic(registerDeliveryCommand.orderId()) + return orderRepository.findByIdPessimistic(registerDeliveryCommand.orderId()) .orElseThrow(() -> new NotFoundOrderException("존재하지 않는 주문입니다.")); - return order; } private void checkAlreadyRegisteredDelivery(final Order order) { diff --git a/src/main/java/com/prgrms/nabmart/domain/user/User.java b/src/main/java/com/prgrms/nabmart/domain/user/User.java index e8351caff..21f3f5cef 100644 --- a/src/main/java/com/prgrms/nabmart/domain/user/User.java +++ b/src/main/java/com/prgrms/nabmart/domain/user/User.java @@ -107,4 +107,8 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(getProvider(), getProviderId()); } + + public boolean isEmployee() { + return userRole == UserRole.ROLE_EMPLOYEE; + } } diff --git a/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryIntegrationTest.java b/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryIntegrationTest.java index 751aa7d04..e17c9c7d7 100644 --- a/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryIntegrationTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryIntegrationTest.java @@ -132,23 +132,25 @@ class RegisterDeliveryTest { ExecutorService service; CountDownLatch latch; int treadPoolSize = 100; - User employee; + User employee = UserFixture.employee(); @BeforeEach void setUpConcurrent() { service = Executors.newFixedThreadPool(treadPoolSize); latch = new CountDownLatch(treadPoolSize); + userRepository.save(employee); } @Test @DisplayName("성공: 여러명의 점원 중 한 명만 성공") void success() throws InterruptedException { //given - Long noUseUserId = 1L; List exList = new ArrayList<>(); int estimateMinutes = 30; - RegisterDeliveryCommand registerDeliveryCommand - = RegisterDeliveryCommand.of(order.getOrderId(), noUseUserId, estimateMinutes); + RegisterDeliveryCommand registerDeliveryCommand = RegisterDeliveryCommand.of( + order.getOrderId(), + employee.getUserId(), + estimateMinutes); //when for(int i=0; i deliveryService.registerDelivery(registerDeliveryCommand)) + .isInstanceOf(UnauthorizedDeliveryException.class); + } + + @Test + @DisplayName("예외: 이미 배달이 만들어진 주문") + void throwExceptionWhenAlreadyRegisteredDelivery() { + //given + given(userRepository.findById(any())).willReturn(Optional.ofNullable(employee)); + given(orderRepository.findByIdPessimistic(any())) + .willReturn(Optional.ofNullable(order)); + given(deliveryRepository.existsByOrder(any())).willReturn(true); + + //when + //then + assertThatThrownBy(() -> deliveryService.registerDelivery(registerDeliveryCommand)) + .isInstanceOf(AlreadyRegisteredDeliveryException.class); + } + + @Test + @DisplayName("예외: 존재하지 않는 order") void throwExceptionWhenNotFoundOrder() { //given + given(userRepository.findById(any())).willReturn(Optional.ofNullable(employee)); given(orderRepository.findByIdPessimistic(any())).willReturn(Optional.empty()); //when diff --git a/src/test/java/com/prgrms/nabmart/domain/user/support/UserFixture.java b/src/test/java/com/prgrms/nabmart/domain/user/support/UserFixture.java index e9eb0f7f9..49eee6457 100644 --- a/src/test/java/com/prgrms/nabmart/domain/user/support/UserFixture.java +++ b/src/test/java/com/prgrms/nabmart/domain/user/support/UserFixture.java @@ -19,6 +19,7 @@ public class UserFixture { private static final String ADDRESS = "기본 배송지"; private static final UserRole USER_ROLE = UserRole.ROLE_USER; private static final UserGrade USER_GRADE = UserGrade.NORMAL; + private static final UserRole EMPLOYEE = UserRole.ROLE_EMPLOYEE; public static User user() { return User.builder() @@ -47,6 +48,18 @@ public static User userWithUserId() { return user; } + public static User employee() { + return User.builder() + .nickname(NICKNAME) + .email(EMAIL) + .provider(PROVIDER) + .providerId(PROVIDER_ID) + .userRole(EMPLOYEE) + .userGrade(USER_GRADE) + .address(ADDRESS) + .build(); + } + public static RegisterUserCommand registerUserCommand() { return RegisterUserCommand.builder() .nickname(NICKNAME) From b1bca5c186a345702bb5b663404f58fba30e65d1 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Thu, 21 Sep 2023 12:05:31 +0900 Subject: [PATCH 26/41] =?UTF-8?q?[NAYB-157]=20feat:=20=EA=B2=B0=EC=A0=9C?= =?UTF-8?q?=20=EC=99=84=EB=A3=8C=EB=90=9C=20=EC=A3=BC=EB=AC=B8=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=EC=84=9C=EB=B9=84=EC=8A=A4=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/UnauthorizedOrderException.java | 8 +++ .../order/repository/OrderRepository.java | 3 + .../domain/order/service/OrderService.java | 21 +++++++ .../response/FindPayedOrdersResponse.java | 33 ++++++++++ .../request/FindPayedOrdersCommand.java | 8 +++ .../order/service/OrderServiceTest.java | 62 +++++++++++++++++++ 6 files changed, 135 insertions(+) create mode 100644 src/main/java/com/prgrms/nabmart/domain/order/exception/UnauthorizedOrderException.java create mode 100644 src/main/java/com/prgrms/nabmart/domain/order/service/response/FindPayedOrdersResponse.java create mode 100644 src/main/java/com/prgrms/nabmart/domain/payment/service/request/FindPayedOrdersCommand.java diff --git a/src/main/java/com/prgrms/nabmart/domain/order/exception/UnauthorizedOrderException.java b/src/main/java/com/prgrms/nabmart/domain/order/exception/UnauthorizedOrderException.java new file mode 100644 index 000000000..9d75b07fb --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/order/exception/UnauthorizedOrderException.java @@ -0,0 +1,8 @@ +package com.prgrms.nabmart.domain.order.exception; + +public class UnauthorizedOrderException extends OrderException { + + public UnauthorizedOrderException(String message) { + super(message); + } +} diff --git a/src/main/java/com/prgrms/nabmart/domain/order/repository/OrderRepository.java b/src/main/java/com/prgrms/nabmart/domain/order/repository/OrderRepository.java index 4bde90fd4..cb93bb2b4 100644 --- a/src/main/java/com/prgrms/nabmart/domain/order/repository/OrderRepository.java +++ b/src/main/java/com/prgrms/nabmart/domain/order/repository/OrderRepository.java @@ -31,4 +31,7 @@ List findByStatusInBeforeExpiredTime(@Param("expiredTime") LocalDateTime @Lock(LockModeType.PESSIMISTIC_WRITE) @Query("select o from Order o where o.orderId = :orderId") Optional findByIdPessimistic(@Param("orderId") Long orderId); + + @Query("select o from Order o where o.status = com.prgrms.nabmart.domain.order.OrderStatus.PAYED") + Page findAllStatusIsPayed(Pageable pageable); } diff --git a/src/main/java/com/prgrms/nabmart/domain/order/service/OrderService.java b/src/main/java/com/prgrms/nabmart/domain/order/service/OrderService.java index 84eace35f..3847f4eac 100644 --- a/src/main/java/com/prgrms/nabmart/domain/order/service/OrderService.java +++ b/src/main/java/com/prgrms/nabmart/domain/order/service/OrderService.java @@ -14,13 +14,16 @@ import com.prgrms.nabmart.domain.order.OrderStatus; import com.prgrms.nabmart.domain.order.controller.request.CreateOrderRequest.CreateOrderItemRequest; import com.prgrms.nabmart.domain.order.exception.NotFoundOrderException; +import com.prgrms.nabmart.domain.order.exception.UnauthorizedOrderException; import com.prgrms.nabmart.domain.order.repository.OrderRepository; import com.prgrms.nabmart.domain.order.service.request.CreateOrdersCommand; import com.prgrms.nabmart.domain.order.service.request.UpdateOrderByCouponCommand; import com.prgrms.nabmart.domain.order.service.response.CreateOrderResponse; import com.prgrms.nabmart.domain.order.service.response.FindOrderDetailResponse; import com.prgrms.nabmart.domain.order.service.response.FindOrdersResponse; +import com.prgrms.nabmart.domain.order.service.response.FindPayedOrdersResponse; import com.prgrms.nabmart.domain.order.service.response.UpdateOrderByCouponResponse; +import com.prgrms.nabmart.domain.payment.service.request.FindPayedOrdersCommand; import com.prgrms.nabmart.domain.user.User; import com.prgrms.nabmart.domain.user.exception.NotFoundUserException; import com.prgrms.nabmart.domain.user.repository.UserRepository; @@ -156,6 +159,24 @@ private void validationCoupon(Order order, Coupon coupon) { } } + @Transactional(readOnly = true) + public FindPayedOrdersResponse findPayedOrders(FindPayedOrdersCommand findPayedOrdersCommand) { + checkUserHasEmployeeAuthority(findPayedOrdersCommand.userId()); + PageRequest pageRequest = PageRequest.of(findPayedOrdersCommand.page(), PAGE_SIZE); + Page findOrders = orderRepository.findAllStatusIsPayed(pageRequest); + return FindPayedOrdersResponse.of( + findOrders.getContent(), + findOrders.getNumber(), + findOrders.getTotalElements()); + } + + private void checkUserHasEmployeeAuthority(Long userId) { + User user = findUserByUserId(userId); + if(!user.isEmployee()) { + throw new UnauthorizedOrderException("권한이 없습니다."); + } + } + public Order getOrderByOrderIdAndUserId(final Long orderId, final Long userId) { return orderRepository.findByOrderIdAndUser_UserId(orderId, userId) .orElseThrow(() -> new NotFoundOrderException("order 가 존재하지 않습니다")); diff --git a/src/main/java/com/prgrms/nabmart/domain/order/service/response/FindPayedOrdersResponse.java b/src/main/java/com/prgrms/nabmart/domain/order/service/response/FindPayedOrdersResponse.java new file mode 100644 index 000000000..58accdd2d --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/order/service/response/FindPayedOrdersResponse.java @@ -0,0 +1,33 @@ +package com.prgrms.nabmart.domain.order.service.response; + +import com.prgrms.nabmart.domain.order.Order; +import java.util.List; + +public record FindPayedOrdersResponse( + List orders, + int page, + long totalElements) { + + public static FindPayedOrdersResponse of( + List orders, + int page, + long totalElements) { + List content = orders.stream() + .map(FindPayedOrderResponse::from) + .toList(); + return new FindPayedOrdersResponse(content, page, totalElements); + } + + public record FindPayedOrderResponse( + Long orderId, + String name, + int price) { + + public static FindPayedOrderResponse from(Order order) { + return new FindPayedOrderResponse( + order.getOrderId(), + order.getName(), + order.getPrice()); + } + } +} diff --git a/src/main/java/com/prgrms/nabmart/domain/payment/service/request/FindPayedOrdersCommand.java b/src/main/java/com/prgrms/nabmart/domain/payment/service/request/FindPayedOrdersCommand.java new file mode 100644 index 000000000..e8b1c4608 --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/payment/service/request/FindPayedOrdersCommand.java @@ -0,0 +1,8 @@ +package com.prgrms.nabmart.domain.payment.service.request; + +public record FindPayedOrdersCommand(Long userId, int page) { + + public static FindPayedOrdersCommand of(Long userId, int page) { + return new FindPayedOrdersCommand(userId, page); + } +} diff --git a/src/test/java/com/prgrms/nabmart/domain/order/service/OrderServiceTest.java b/src/test/java/com/prgrms/nabmart/domain/order/service/OrderServiceTest.java index 5433805ab..ca5c915cc 100644 --- a/src/test/java/com/prgrms/nabmart/domain/order/service/OrderServiceTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/order/service/OrderServiceTest.java @@ -11,9 +11,11 @@ import static com.prgrms.nabmart.domain.order.support.OrderFixture.updateOrderByCouponCommand; import static com.prgrms.nabmart.domain.user.support.UserFixture.user; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.catchException; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -32,17 +34,23 @@ import com.prgrms.nabmart.domain.order.controller.request.CreateOrderRequest; import com.prgrms.nabmart.domain.order.controller.request.CreateOrderRequest.CreateOrderItemRequest; import com.prgrms.nabmart.domain.order.exception.NotFoundOrderException; +import com.prgrms.nabmart.domain.order.exception.UnauthorizedOrderException; import com.prgrms.nabmart.domain.order.repository.OrderRepository; +import com.prgrms.nabmart.domain.order.service.response.FindPayedOrdersResponse; +import com.prgrms.nabmart.domain.order.service.response.FindPayedOrdersResponse.FindPayedOrderResponse; import com.prgrms.nabmart.domain.order.service.request.CreateOrdersCommand; import com.prgrms.nabmart.domain.order.service.request.UpdateOrderByCouponCommand; import com.prgrms.nabmart.domain.order.service.response.CreateOrderResponse; import com.prgrms.nabmart.domain.order.service.response.FindOrderDetailResponse; import com.prgrms.nabmart.domain.order.service.response.FindOrdersResponse; import com.prgrms.nabmart.domain.order.service.response.UpdateOrderByCouponResponse; +import com.prgrms.nabmart.domain.payment.service.request.FindPayedOrdersCommand; import com.prgrms.nabmart.domain.user.User; import com.prgrms.nabmart.domain.user.repository.UserRepository; +import com.prgrms.nabmart.domain.user.support.UserFixture; import java.util.List; import java.util.Optional; +import java.util.stream.IntStream; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -341,4 +349,58 @@ void success() { verify(orderRepository, times(1)).delete(order); } } + + @Nested + @DisplayName("findPayedOrders 메서드 실행 시") + class FindOrdersWaitingDeliveryTest { + + User user = UserFixture.user(); + User employee = UserFixture.employee(); + FindPayedOrdersCommand findPayedOrdersCommand + = FindPayedOrdersCommand.of(1L, 0); + Item item = item(); + int orderItemQuantity = 5; + + private List createOrders(int end) { + return IntStream.range(0, end) + .mapToObj(i -> { + OrderItem orderItem = new OrderItem(item, orderItemQuantity); + return new Order(user, List.of(orderItem)); + }).toList(); + } + + @Test + @DisplayName("성공") + void success() { + //given + List orders = createOrders(5); + PageImpl ordersPage = new PageImpl<>(orders); + + given(userRepository.findById(any())).willReturn(Optional.ofNullable(employee)); + given(orderRepository.findAllStatusIsPayed(any())).willReturn(ordersPage); + + //when + FindPayedOrdersResponse result = orderService.findPayedOrders( + findPayedOrdersCommand); + + //then + int expectedPrice = item.getPrice() * orderItemQuantity; + assertThat(result.orders()).hasSize(5); + assertThat(result.orders()).map(FindPayedOrderResponse::price) + .containsOnly(expectedPrice); + } + + @Test + @DisplayName("예외: 로그인 유저가 employee가 아님") + void throwExceptionWhenLoginUserIsNotEmployee() { + //given + given(userRepository.findById(any())).willReturn(Optional.ofNullable(user)); + + //when + //then + assertThatThrownBy( + () -> orderService.findPayedOrders(findPayedOrdersCommand)) + .isInstanceOf(UnauthorizedOrderException.class); + } + } } From 542ffb6d8e13d0961d948358a767e5341a1b10d1 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Thu, 21 Sep 2023 12:32:59 +0900 Subject: [PATCH 27/41] =?UTF-8?q?[NAYB-157]=20feat:=20=EA=B2=B0=EC=A0=9C?= =?UTF-8?q?=20=EC=99=84=EB=A3=8C=EB=90=9C=20=EC=A3=BC=EB=AC=B8=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20api=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../order/controller/OrderController.java | 14 +++++ .../request/FindPayedOrdersRequest.java | 12 +++++ .../order/controller/OrderControllerTest.java | 52 +++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 src/main/java/com/prgrms/nabmart/domain/order/controller/request/FindPayedOrdersRequest.java diff --git a/src/main/java/com/prgrms/nabmart/domain/order/controller/OrderController.java b/src/main/java/com/prgrms/nabmart/domain/order/controller/OrderController.java index 3f39ece8f..6759bafb2 100644 --- a/src/main/java/com/prgrms/nabmart/domain/order/controller/OrderController.java +++ b/src/main/java/com/prgrms/nabmart/domain/order/controller/OrderController.java @@ -1,7 +1,9 @@ package com.prgrms.nabmart.domain.order.controller; import com.prgrms.nabmart.domain.order.controller.request.CreateOrderRequest; +import com.prgrms.nabmart.domain.order.controller.request.FindPayedOrdersRequest; import com.prgrms.nabmart.domain.order.exception.OrderException; +import com.prgrms.nabmart.domain.order.service.response.FindPayedOrdersResponse; import com.prgrms.nabmart.domain.order.service.OrderService; import com.prgrms.nabmart.domain.order.service.request.CreateOrdersCommand; import com.prgrms.nabmart.domain.order.service.request.UpdateOrderByCouponCommand; @@ -9,6 +11,7 @@ import com.prgrms.nabmart.domain.order.service.response.FindOrderDetailResponse; import com.prgrms.nabmart.domain.order.service.response.FindOrdersResponse; import com.prgrms.nabmart.domain.order.service.response.UpdateOrderByCouponResponse; +import com.prgrms.nabmart.domain.payment.service.request.FindPayedOrdersCommand; import com.prgrms.nabmart.global.auth.LoginUser; import com.prgrms.nabmart.global.util.ErrorTemplate; import jakarta.validation.Valid; @@ -83,6 +86,17 @@ public ResponseEntity deleteOrder( return ResponseEntity.noContent().build(); } + @GetMapping("/payed") + public ResponseEntity findPayedOrders( + @RequestBody @Valid FindPayedOrdersRequest findPayedOrdersRequest, + @LoginUser Long userId) { + FindPayedOrdersCommand command = FindPayedOrdersCommand.of( + userId, + findPayedOrdersRequest.page()); + FindPayedOrdersResponse orders = orderService.findPayedOrders(command); + return ResponseEntity.ok(orders); + } + @ExceptionHandler(OrderException.class) public ResponseEntity handleException( final OrderException orderException) { diff --git a/src/main/java/com/prgrms/nabmart/domain/order/controller/request/FindPayedOrdersRequest.java b/src/main/java/com/prgrms/nabmart/domain/order/controller/request/FindPayedOrdersRequest.java new file mode 100644 index 000000000..e9caff59b --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/order/controller/request/FindPayedOrdersRequest.java @@ -0,0 +1,12 @@ +package com.prgrms.nabmart.domain.order.controller.request; + +import jakarta.validation.constraints.PositiveOrZero; + +public record FindPayedOrdersRequest( + @PositiveOrZero(message = "페이지 번호는 음수일 수 없습니다.") + Integer page) { + + public FindPayedOrdersRequest { + page = 0; + } +} diff --git a/src/test/java/com/prgrms/nabmart/domain/order/controller/OrderControllerTest.java b/src/test/java/com/prgrms/nabmart/domain/order/controller/OrderControllerTest.java index 6f77c5413..34c954bb5 100644 --- a/src/test/java/com/prgrms/nabmart/domain/order/controller/OrderControllerTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/order/controller/OrderControllerTest.java @@ -10,14 +10,19 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.when; +import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; +import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.payload.JsonFieldType.ARRAY; import static org.springframework.restdocs.payload.JsonFieldType.NUMBER; import static org.springframework.restdocs.payload.JsonFieldType.STRING; import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; @@ -28,6 +33,9 @@ import com.prgrms.nabmart.domain.coupon.UserCoupon; import com.prgrms.nabmart.domain.order.Order; import com.prgrms.nabmart.domain.order.controller.request.CreateOrderRequest; +import com.prgrms.nabmart.domain.order.controller.request.FindPayedOrdersRequest; +import com.prgrms.nabmart.domain.order.service.response.FindPayedOrdersResponse; +import com.prgrms.nabmart.domain.order.service.response.FindPayedOrdersResponse.FindPayedOrderResponse; import com.prgrms.nabmart.domain.order.service.response.CreateOrderResponse; import com.prgrms.nabmart.domain.order.service.response.FindOrderDetailResponse; import com.prgrms.nabmart.domain.order.service.response.FindOrdersResponse; @@ -224,4 +232,48 @@ void deleteOrder() throws Exception { )); } } + + @Nested + @DisplayName("결제 완료된 주문 목록 조회 api 호출 시") + class FindPayedOrdersTest { + + @Test + @DisplayName("성공") + void findPayedOrders() throws Exception { + //given + int page = 0; + FindPayedOrdersRequest findPayedOrdersRequest = new FindPayedOrdersRequest(page); + FindPayedOrderResponse findPayedOrderResponse + = new FindPayedOrderResponse(1L, "비비고 왕교자 외 2개", 20000); + FindPayedOrdersResponse findPayedOrdersResponse = new FindPayedOrdersResponse( + List.of(findPayedOrderResponse), 0, 1); + + given(orderService.findPayedOrders(any())).willReturn(findPayedOrdersResponse); + + //when + ResultActions resultActions = mockMvc.perform(get("/api/v1/orders/payed") + .header(AUTHORIZATION, accessToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(findPayedOrdersRequest))); + + //then + resultActions.andExpect(status().isOk()) + .andDo(restDocs.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("액세스 토큰") + ), + requestFields( + fieldWithPath("page").type(NUMBER).description("페이지 번호") + ), + responseFields( + fieldWithPath("orders").type(ARRAY).description("주문 목록"), + fieldWithPath("orders[].orderId").type(NUMBER).description("주문 ID"), + fieldWithPath("orders[].name").type(STRING).description("주문 이름"), + fieldWithPath("orders[].price").type(NUMBER).description("주문 가격"), + fieldWithPath("page").type(NUMBER).description("페이지 번호"), + fieldWithPath("totalElements").type(NUMBER).description("총 요소 개수") + ) + )); + } + } } From ca65651a24647469399b102a1e37580de22b985c Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Thu, 21 Sep 2023 12:55:21 +0900 Subject: [PATCH 28/41] =?UTF-8?q?[NAYB-157]=20feat:=20`Delivery`=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EC=8B=9C=20=EA=B2=80=EC=A6=9D=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 --- .../nabmart/domain/delivery/Delivery.java | 8 ++++ .../prgrms/nabmart/domain/order/Order.java | 4 ++ .../delivery/DeliveryIntegrationTest.java | 3 ++ .../nabmart/domain/delivery/DeliveryTest.java | 45 ++++++++++++++++++- .../delivery/service/DeliveryServiceTest.java | 2 +- .../delivery/support/DeliveryFixture.java | 2 + .../domain/order/support/OrderFixture.java | 8 ++++ 7 files changed, 69 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/Delivery.java b/src/main/java/com/prgrms/nabmart/domain/delivery/Delivery.java index 4e698eca1..f3cbe23e6 100644 --- a/src/main/java/com/prgrms/nabmart/domain/delivery/Delivery.java +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/Delivery.java @@ -71,6 +71,8 @@ public class Delivery extends BaseTimeEntity { @Builder public Delivery(final Order order, final int estimateMinutes) { + validateOrderStatus(order); + validateEstimateMinutes(estimateMinutes); this.order = order; this.deliveryStatus = DeliveryStatus.ACCEPTING_ORDER; this.address = order.getAddress(); @@ -81,6 +83,12 @@ public Delivery(final Order order, final int estimateMinutes) { order.updateOrderStatus(OrderStatus.DELIVERING); } + private void validateOrderStatus(Order order) { + if(!order.isPayed()) { + throw new InvalidDeliveryException("결제 완료된 주문이 아닙니다."); + } + } + public boolean isOwnByUser(final User user) { return this.order.isOwnByUser(user); } diff --git a/src/main/java/com/prgrms/nabmart/domain/order/Order.java b/src/main/java/com/prgrms/nabmart/domain/order/Order.java index 230e4814c..0a46b8e18 100644 --- a/src/main/java/com/prgrms/nabmart/domain/order/Order.java +++ b/src/main/java/com/prgrms/nabmart/domain/order/Order.java @@ -161,4 +161,8 @@ public void unUseCoupon() { userCoupon.unUse(); } } + + public boolean isPayed() { + return this.status == OrderStatus.PAYED; + } } diff --git a/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryIntegrationTest.java b/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryIntegrationTest.java index e17c9c7d7..e1ea9ec01 100644 --- a/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryIntegrationTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryIntegrationTest.java @@ -17,6 +17,7 @@ import com.prgrms.nabmart.domain.item.support.ItemFixture; import com.prgrms.nabmart.domain.order.Order; import com.prgrms.nabmart.domain.order.OrderItem; +import com.prgrms.nabmart.domain.order.OrderStatus; import com.prgrms.nabmart.domain.order.repository.OrderItemRepository; import com.prgrms.nabmart.domain.order.repository.OrderRepository; import com.prgrms.nabmart.domain.user.User; @@ -40,6 +41,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.util.ReflectionTestUtils; @SpringBootTest public class DeliveryIntegrationTest { @@ -108,6 +110,7 @@ void setUpData() { mainCategoryRepository.save(mainCategory); subCategoryRepository.save(subCategory); itemRepository.save(item); + ReflectionTestUtils.setField(order, "status", OrderStatus.PAYED); orderRepository.save(order); } diff --git a/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryTest.java b/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryTest.java index 3d7019d7d..49124302a 100644 --- a/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryTest.java @@ -1,11 +1,15 @@ package com.prgrms.nabmart.domain.delivery; -import static com.prgrms.nabmart.domain.order.support.OrderFixture.deliveringOrder; +import static com.prgrms.nabmart.domain.order.support.OrderFixture.payingOrder; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import com.prgrms.nabmart.domain.delivery.exception.InvalidDeliveryException; import com.prgrms.nabmart.domain.order.Order; +import com.prgrms.nabmart.domain.order.OrderStatus; import com.prgrms.nabmart.domain.user.User; import com.prgrms.nabmart.domain.user.support.UserFixture; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -17,21 +21,58 @@ class DeliveryTest { class NewDeliveryTest { User user = UserFixture.user(); - Order order = deliveringOrder(1L, user); + Order order = payingOrder(1L, user); + + @BeforeEach + void setUp() { + order.updateOrderStatus(OrderStatus.PAYED); + } @Test @DisplayName("성공") void success() { //given String address = "주소지"; + int estimateMinutes = 30; //when Delivery delivery = Delivery.builder() .order(order) + .estimateMinutes(estimateMinutes) .build(); //then assertThat(delivery.getOrder()).isEqualTo(order); } + + @Test + @DisplayName("예외: 배송 예상 완료 시간이 음수") + void throwExceptionWhenEstimateMinutesIsMinus() { + //given + int estimateMinutes = -1; + + //when + //then + assertThatThrownBy(() -> Delivery.builder() + .order(order) + .estimateMinutes(estimateMinutes) + .build()) + .isInstanceOf(InvalidDeliveryException.class); + } + + @Test + @DisplayName("예외: 결제 완료된 주문이 아님") + void throwExceptionWhenOrderIsNotPayed() { + //given + Order noPayedOrder = payingOrder(1L, user); + + //when + //then + assertThatThrownBy(() -> Delivery.builder() + .order(noPayedOrder) + .estimateMinutes(30) + .build()) + .isInstanceOf(InvalidDeliveryException.class); + } } } diff --git a/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java b/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java index 807d7b5c3..8950ffa2f 100644 --- a/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java @@ -86,7 +86,7 @@ class DeliveryServiceTest { class RegisterDeliveryTest { User employee = UserFixture.employee(); - Order order = OrderFixture.payingOrder(1L, user); + Order order = OrderFixture.payedOrder(1L, user); RegisterDeliveryCommand registerDeliveryCommand = RegisterDeliveryCommand.of( 1L, 1L, diff --git a/src/test/java/com/prgrms/nabmart/domain/delivery/support/DeliveryFixture.java b/src/test/java/com/prgrms/nabmart/domain/delivery/support/DeliveryFixture.java index 1d072a0b7..7e4c03411 100644 --- a/src/test/java/com/prgrms/nabmart/domain/delivery/support/DeliveryFixture.java +++ b/src/test/java/com/prgrms/nabmart/domain/delivery/support/DeliveryFixture.java @@ -8,6 +8,7 @@ import com.prgrms.nabmart.domain.delivery.service.response.FindWaitingDeliveriesResponse.FindWaitingDeliveryResponse; import com.prgrms.nabmart.domain.delivery.service.response.FindDeliveryDetailResponse; import com.prgrms.nabmart.domain.order.Order; +import com.prgrms.nabmart.domain.order.OrderStatus; import java.time.LocalDateTime; import java.util.List; import lombok.AccessLevel; @@ -33,6 +34,7 @@ public final class DeliveryFixture { private static final String RIDER_ADDRESS = "address"; public static Delivery waitingDelivery(Order order) { + order.updateOrderStatus(OrderStatus.PAYED); return Delivery.builder() .order(order) .build(); diff --git a/src/test/java/com/prgrms/nabmart/domain/order/support/OrderFixture.java b/src/test/java/com/prgrms/nabmart/domain/order/support/OrderFixture.java index a069b142e..3ce4043f3 100644 --- a/src/test/java/com/prgrms/nabmart/domain/order/support/OrderFixture.java +++ b/src/test/java/com/prgrms/nabmart/domain/order/support/OrderFixture.java @@ -43,6 +43,14 @@ public static Order payingOrder(long orderId, User user) { return order; } + + public static Order payedOrder(long orderId, User user) { + Order order = payingOrder(orderId, user); + ReflectionTestUtils.setField(order, "orderId", orderId); + ReflectionTestUtils.setField(order, "status", OrderStatus.PAYED); + + return order; + } public static Order deliveringOrder(long orderId, User user) { Order order = new Order(user, List.of(orderItem())); From 7313071413ad3ff2e84a58c912291a920403377d Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Thu, 21 Sep 2023 12:59:30 +0900 Subject: [PATCH 29/41] =?UTF-8?q?[NAYB-157]=20chore:=20=EA=B2=B0=EC=A0=9C?= =?UTF-8?q?=20=EC=99=84=EB=A3=8C=EB=90=9C=20=EC=A3=BC=EB=AC=B8=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20api=20=EC=A0=91=EA=B7=BC=20?= =?UTF-8?q?=EA=B6=8C=ED=95=9C=20=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/prgrms/nabmart/global/config/WebSecurityConfig.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/prgrms/nabmart/global/config/WebSecurityConfig.java b/src/main/java/com/prgrms/nabmart/global/config/WebSecurityConfig.java index 9d3c2b643..78d4f1ae9 100644 --- a/src/main/java/com/prgrms/nabmart/global/config/WebSecurityConfig.java +++ b/src/main/java/com/prgrms/nabmart/global/config/WebSecurityConfig.java @@ -99,7 +99,8 @@ private RequestMatcher[] requestHasRoleRider() { private RequestMatcher[] requestHasRoleEmployee() { List requestMatchers = List.of( - antMatcher(POST, "/api/v1/orders/*/deliveries") + antMatcher(POST, "/api/v1/orders/*/deliveries"), + antMatcher(GET, "/api/v1/orders/payed") ); return requestMatchers.toArray(RequestMatcher[]::new); } From e7ecebd6f67e44c7deb57b8dbd6733c7b33c2cc6 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Thu, 21 Sep 2023 12:05:31 +0900 Subject: [PATCH 30/41] =?UTF-8?q?[NAYB-158]=20chore:=20NAYB-157=20?= =?UTF-8?q?=EB=B8=8C=EB=9E=9C=EC=B9=98=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nabmart/domain/delivery/Delivery.java | 8 +++ .../prgrms/nabmart/domain/order/Order.java | 4 ++ .../order/controller/OrderController.java | 14 +++++ .../request/FindPayedOrdersRequest.java | 12 ++++ .../exception/UnauthorizedOrderException.java | 8 +++ .../order/repository/OrderRepository.java | 3 + .../domain/order/service/OrderService.java | 21 +++++++ .../response/FindPayedOrdersResponse.java | 33 ++++++++++ .../request/FindPayedOrdersCommand.java | 8 +++ .../global/config/WebSecurityConfig.java | 3 +- .../delivery/DeliveryIntegrationTest.java | 3 + .../nabmart/domain/delivery/DeliveryTest.java | 45 +++++++++++++- .../delivery/service/DeliveryServiceTest.java | 2 +- .../delivery/support/DeliveryFixture.java | 2 + .../order/controller/OrderControllerTest.java | 52 ++++++++++++++++ .../order/service/OrderServiceTest.java | 62 +++++++++++++++++++ .../domain/order/support/OrderFixture.java | 8 +++ 17 files changed, 284 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/prgrms/nabmart/domain/order/controller/request/FindPayedOrdersRequest.java create mode 100644 src/main/java/com/prgrms/nabmart/domain/order/exception/UnauthorizedOrderException.java create mode 100644 src/main/java/com/prgrms/nabmart/domain/order/service/response/FindPayedOrdersResponse.java create mode 100644 src/main/java/com/prgrms/nabmart/domain/payment/service/request/FindPayedOrdersCommand.java diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/Delivery.java b/src/main/java/com/prgrms/nabmart/domain/delivery/Delivery.java index 4e698eca1..f3cbe23e6 100644 --- a/src/main/java/com/prgrms/nabmart/domain/delivery/Delivery.java +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/Delivery.java @@ -71,6 +71,8 @@ public class Delivery extends BaseTimeEntity { @Builder public Delivery(final Order order, final int estimateMinutes) { + validateOrderStatus(order); + validateEstimateMinutes(estimateMinutes); this.order = order; this.deliveryStatus = DeliveryStatus.ACCEPTING_ORDER; this.address = order.getAddress(); @@ -81,6 +83,12 @@ public Delivery(final Order order, final int estimateMinutes) { order.updateOrderStatus(OrderStatus.DELIVERING); } + private void validateOrderStatus(Order order) { + if(!order.isPayed()) { + throw new InvalidDeliveryException("결제 완료된 주문이 아닙니다."); + } + } + public boolean isOwnByUser(final User user) { return this.order.isOwnByUser(user); } diff --git a/src/main/java/com/prgrms/nabmart/domain/order/Order.java b/src/main/java/com/prgrms/nabmart/domain/order/Order.java index 230e4814c..0a46b8e18 100644 --- a/src/main/java/com/prgrms/nabmart/domain/order/Order.java +++ b/src/main/java/com/prgrms/nabmart/domain/order/Order.java @@ -161,4 +161,8 @@ public void unUseCoupon() { userCoupon.unUse(); } } + + public boolean isPayed() { + return this.status == OrderStatus.PAYED; + } } diff --git a/src/main/java/com/prgrms/nabmart/domain/order/controller/OrderController.java b/src/main/java/com/prgrms/nabmart/domain/order/controller/OrderController.java index 3f39ece8f..6759bafb2 100644 --- a/src/main/java/com/prgrms/nabmart/domain/order/controller/OrderController.java +++ b/src/main/java/com/prgrms/nabmart/domain/order/controller/OrderController.java @@ -1,7 +1,9 @@ package com.prgrms.nabmart.domain.order.controller; import com.prgrms.nabmart.domain.order.controller.request.CreateOrderRequest; +import com.prgrms.nabmart.domain.order.controller.request.FindPayedOrdersRequest; import com.prgrms.nabmart.domain.order.exception.OrderException; +import com.prgrms.nabmart.domain.order.service.response.FindPayedOrdersResponse; import com.prgrms.nabmart.domain.order.service.OrderService; import com.prgrms.nabmart.domain.order.service.request.CreateOrdersCommand; import com.prgrms.nabmart.domain.order.service.request.UpdateOrderByCouponCommand; @@ -9,6 +11,7 @@ import com.prgrms.nabmart.domain.order.service.response.FindOrderDetailResponse; import com.prgrms.nabmart.domain.order.service.response.FindOrdersResponse; import com.prgrms.nabmart.domain.order.service.response.UpdateOrderByCouponResponse; +import com.prgrms.nabmart.domain.payment.service.request.FindPayedOrdersCommand; import com.prgrms.nabmart.global.auth.LoginUser; import com.prgrms.nabmart.global.util.ErrorTemplate; import jakarta.validation.Valid; @@ -83,6 +86,17 @@ public ResponseEntity deleteOrder( return ResponseEntity.noContent().build(); } + @GetMapping("/payed") + public ResponseEntity findPayedOrders( + @RequestBody @Valid FindPayedOrdersRequest findPayedOrdersRequest, + @LoginUser Long userId) { + FindPayedOrdersCommand command = FindPayedOrdersCommand.of( + userId, + findPayedOrdersRequest.page()); + FindPayedOrdersResponse orders = orderService.findPayedOrders(command); + return ResponseEntity.ok(orders); + } + @ExceptionHandler(OrderException.class) public ResponseEntity handleException( final OrderException orderException) { diff --git a/src/main/java/com/prgrms/nabmart/domain/order/controller/request/FindPayedOrdersRequest.java b/src/main/java/com/prgrms/nabmart/domain/order/controller/request/FindPayedOrdersRequest.java new file mode 100644 index 000000000..e9caff59b --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/order/controller/request/FindPayedOrdersRequest.java @@ -0,0 +1,12 @@ +package com.prgrms.nabmart.domain.order.controller.request; + +import jakarta.validation.constraints.PositiveOrZero; + +public record FindPayedOrdersRequest( + @PositiveOrZero(message = "페이지 번호는 음수일 수 없습니다.") + Integer page) { + + public FindPayedOrdersRequest { + page = 0; + } +} diff --git a/src/main/java/com/prgrms/nabmart/domain/order/exception/UnauthorizedOrderException.java b/src/main/java/com/prgrms/nabmart/domain/order/exception/UnauthorizedOrderException.java new file mode 100644 index 000000000..9d75b07fb --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/order/exception/UnauthorizedOrderException.java @@ -0,0 +1,8 @@ +package com.prgrms.nabmart.domain.order.exception; + +public class UnauthorizedOrderException extends OrderException { + + public UnauthorizedOrderException(String message) { + super(message); + } +} diff --git a/src/main/java/com/prgrms/nabmart/domain/order/repository/OrderRepository.java b/src/main/java/com/prgrms/nabmart/domain/order/repository/OrderRepository.java index 4bde90fd4..cb93bb2b4 100644 --- a/src/main/java/com/prgrms/nabmart/domain/order/repository/OrderRepository.java +++ b/src/main/java/com/prgrms/nabmart/domain/order/repository/OrderRepository.java @@ -31,4 +31,7 @@ List findByStatusInBeforeExpiredTime(@Param("expiredTime") LocalDateTime @Lock(LockModeType.PESSIMISTIC_WRITE) @Query("select o from Order o where o.orderId = :orderId") Optional findByIdPessimistic(@Param("orderId") Long orderId); + + @Query("select o from Order o where o.status = com.prgrms.nabmart.domain.order.OrderStatus.PAYED") + Page findAllStatusIsPayed(Pageable pageable); } diff --git a/src/main/java/com/prgrms/nabmart/domain/order/service/OrderService.java b/src/main/java/com/prgrms/nabmart/domain/order/service/OrderService.java index 84eace35f..3847f4eac 100644 --- a/src/main/java/com/prgrms/nabmart/domain/order/service/OrderService.java +++ b/src/main/java/com/prgrms/nabmart/domain/order/service/OrderService.java @@ -14,13 +14,16 @@ import com.prgrms.nabmart.domain.order.OrderStatus; import com.prgrms.nabmart.domain.order.controller.request.CreateOrderRequest.CreateOrderItemRequest; import com.prgrms.nabmart.domain.order.exception.NotFoundOrderException; +import com.prgrms.nabmart.domain.order.exception.UnauthorizedOrderException; import com.prgrms.nabmart.domain.order.repository.OrderRepository; import com.prgrms.nabmart.domain.order.service.request.CreateOrdersCommand; import com.prgrms.nabmart.domain.order.service.request.UpdateOrderByCouponCommand; import com.prgrms.nabmart.domain.order.service.response.CreateOrderResponse; import com.prgrms.nabmart.domain.order.service.response.FindOrderDetailResponse; import com.prgrms.nabmart.domain.order.service.response.FindOrdersResponse; +import com.prgrms.nabmart.domain.order.service.response.FindPayedOrdersResponse; import com.prgrms.nabmart.domain.order.service.response.UpdateOrderByCouponResponse; +import com.prgrms.nabmart.domain.payment.service.request.FindPayedOrdersCommand; import com.prgrms.nabmart.domain.user.User; import com.prgrms.nabmart.domain.user.exception.NotFoundUserException; import com.prgrms.nabmart.domain.user.repository.UserRepository; @@ -156,6 +159,24 @@ private void validationCoupon(Order order, Coupon coupon) { } } + @Transactional(readOnly = true) + public FindPayedOrdersResponse findPayedOrders(FindPayedOrdersCommand findPayedOrdersCommand) { + checkUserHasEmployeeAuthority(findPayedOrdersCommand.userId()); + PageRequest pageRequest = PageRequest.of(findPayedOrdersCommand.page(), PAGE_SIZE); + Page findOrders = orderRepository.findAllStatusIsPayed(pageRequest); + return FindPayedOrdersResponse.of( + findOrders.getContent(), + findOrders.getNumber(), + findOrders.getTotalElements()); + } + + private void checkUserHasEmployeeAuthority(Long userId) { + User user = findUserByUserId(userId); + if(!user.isEmployee()) { + throw new UnauthorizedOrderException("권한이 없습니다."); + } + } + public Order getOrderByOrderIdAndUserId(final Long orderId, final Long userId) { return orderRepository.findByOrderIdAndUser_UserId(orderId, userId) .orElseThrow(() -> new NotFoundOrderException("order 가 존재하지 않습니다")); diff --git a/src/main/java/com/prgrms/nabmart/domain/order/service/response/FindPayedOrdersResponse.java b/src/main/java/com/prgrms/nabmart/domain/order/service/response/FindPayedOrdersResponse.java new file mode 100644 index 000000000..58accdd2d --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/order/service/response/FindPayedOrdersResponse.java @@ -0,0 +1,33 @@ +package com.prgrms.nabmart.domain.order.service.response; + +import com.prgrms.nabmart.domain.order.Order; +import java.util.List; + +public record FindPayedOrdersResponse( + List orders, + int page, + long totalElements) { + + public static FindPayedOrdersResponse of( + List orders, + int page, + long totalElements) { + List content = orders.stream() + .map(FindPayedOrderResponse::from) + .toList(); + return new FindPayedOrdersResponse(content, page, totalElements); + } + + public record FindPayedOrderResponse( + Long orderId, + String name, + int price) { + + public static FindPayedOrderResponse from(Order order) { + return new FindPayedOrderResponse( + order.getOrderId(), + order.getName(), + order.getPrice()); + } + } +} diff --git a/src/main/java/com/prgrms/nabmart/domain/payment/service/request/FindPayedOrdersCommand.java b/src/main/java/com/prgrms/nabmart/domain/payment/service/request/FindPayedOrdersCommand.java new file mode 100644 index 000000000..e8b1c4608 --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/payment/service/request/FindPayedOrdersCommand.java @@ -0,0 +1,8 @@ +package com.prgrms.nabmart.domain.payment.service.request; + +public record FindPayedOrdersCommand(Long userId, int page) { + + public static FindPayedOrdersCommand of(Long userId, int page) { + return new FindPayedOrdersCommand(userId, page); + } +} diff --git a/src/main/java/com/prgrms/nabmart/global/config/WebSecurityConfig.java b/src/main/java/com/prgrms/nabmart/global/config/WebSecurityConfig.java index 9d3c2b643..78d4f1ae9 100644 --- a/src/main/java/com/prgrms/nabmart/global/config/WebSecurityConfig.java +++ b/src/main/java/com/prgrms/nabmart/global/config/WebSecurityConfig.java @@ -99,7 +99,8 @@ private RequestMatcher[] requestHasRoleRider() { private RequestMatcher[] requestHasRoleEmployee() { List requestMatchers = List.of( - antMatcher(POST, "/api/v1/orders/*/deliveries") + antMatcher(POST, "/api/v1/orders/*/deliveries"), + antMatcher(GET, "/api/v1/orders/payed") ); return requestMatchers.toArray(RequestMatcher[]::new); } diff --git a/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryIntegrationTest.java b/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryIntegrationTest.java index e17c9c7d7..e1ea9ec01 100644 --- a/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryIntegrationTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryIntegrationTest.java @@ -17,6 +17,7 @@ import com.prgrms.nabmart.domain.item.support.ItemFixture; import com.prgrms.nabmart.domain.order.Order; import com.prgrms.nabmart.domain.order.OrderItem; +import com.prgrms.nabmart.domain.order.OrderStatus; import com.prgrms.nabmart.domain.order.repository.OrderItemRepository; import com.prgrms.nabmart.domain.order.repository.OrderRepository; import com.prgrms.nabmart.domain.user.User; @@ -40,6 +41,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.util.ReflectionTestUtils; @SpringBootTest public class DeliveryIntegrationTest { @@ -108,6 +110,7 @@ void setUpData() { mainCategoryRepository.save(mainCategory); subCategoryRepository.save(subCategory); itemRepository.save(item); + ReflectionTestUtils.setField(order, "status", OrderStatus.PAYED); orderRepository.save(order); } diff --git a/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryTest.java b/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryTest.java index 3d7019d7d..49124302a 100644 --- a/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/delivery/DeliveryTest.java @@ -1,11 +1,15 @@ package com.prgrms.nabmart.domain.delivery; -import static com.prgrms.nabmart.domain.order.support.OrderFixture.deliveringOrder; +import static com.prgrms.nabmart.domain.order.support.OrderFixture.payingOrder; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import com.prgrms.nabmart.domain.delivery.exception.InvalidDeliveryException; import com.prgrms.nabmart.domain.order.Order; +import com.prgrms.nabmart.domain.order.OrderStatus; import com.prgrms.nabmart.domain.user.User; import com.prgrms.nabmart.domain.user.support.UserFixture; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -17,21 +21,58 @@ class DeliveryTest { class NewDeliveryTest { User user = UserFixture.user(); - Order order = deliveringOrder(1L, user); + Order order = payingOrder(1L, user); + + @BeforeEach + void setUp() { + order.updateOrderStatus(OrderStatus.PAYED); + } @Test @DisplayName("성공") void success() { //given String address = "주소지"; + int estimateMinutes = 30; //when Delivery delivery = Delivery.builder() .order(order) + .estimateMinutes(estimateMinutes) .build(); //then assertThat(delivery.getOrder()).isEqualTo(order); } + + @Test + @DisplayName("예외: 배송 예상 완료 시간이 음수") + void throwExceptionWhenEstimateMinutesIsMinus() { + //given + int estimateMinutes = -1; + + //when + //then + assertThatThrownBy(() -> Delivery.builder() + .order(order) + .estimateMinutes(estimateMinutes) + .build()) + .isInstanceOf(InvalidDeliveryException.class); + } + + @Test + @DisplayName("예외: 결제 완료된 주문이 아님") + void throwExceptionWhenOrderIsNotPayed() { + //given + Order noPayedOrder = payingOrder(1L, user); + + //when + //then + assertThatThrownBy(() -> Delivery.builder() + .order(noPayedOrder) + .estimateMinutes(30) + .build()) + .isInstanceOf(InvalidDeliveryException.class); + } } } diff --git a/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java b/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java index 807d7b5c3..8950ffa2f 100644 --- a/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java @@ -86,7 +86,7 @@ class DeliveryServiceTest { class RegisterDeliveryTest { User employee = UserFixture.employee(); - Order order = OrderFixture.payingOrder(1L, user); + Order order = OrderFixture.payedOrder(1L, user); RegisterDeliveryCommand registerDeliveryCommand = RegisterDeliveryCommand.of( 1L, 1L, diff --git a/src/test/java/com/prgrms/nabmart/domain/delivery/support/DeliveryFixture.java b/src/test/java/com/prgrms/nabmart/domain/delivery/support/DeliveryFixture.java index 1d072a0b7..7e4c03411 100644 --- a/src/test/java/com/prgrms/nabmart/domain/delivery/support/DeliveryFixture.java +++ b/src/test/java/com/prgrms/nabmart/domain/delivery/support/DeliveryFixture.java @@ -8,6 +8,7 @@ import com.prgrms.nabmart.domain.delivery.service.response.FindWaitingDeliveriesResponse.FindWaitingDeliveryResponse; import com.prgrms.nabmart.domain.delivery.service.response.FindDeliveryDetailResponse; import com.prgrms.nabmart.domain.order.Order; +import com.prgrms.nabmart.domain.order.OrderStatus; import java.time.LocalDateTime; import java.util.List; import lombok.AccessLevel; @@ -33,6 +34,7 @@ public final class DeliveryFixture { private static final String RIDER_ADDRESS = "address"; public static Delivery waitingDelivery(Order order) { + order.updateOrderStatus(OrderStatus.PAYED); return Delivery.builder() .order(order) .build(); diff --git a/src/test/java/com/prgrms/nabmart/domain/order/controller/OrderControllerTest.java b/src/test/java/com/prgrms/nabmart/domain/order/controller/OrderControllerTest.java index 6f77c5413..34c954bb5 100644 --- a/src/test/java/com/prgrms/nabmart/domain/order/controller/OrderControllerTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/order/controller/OrderControllerTest.java @@ -10,14 +10,19 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.when; +import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; +import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.payload.JsonFieldType.ARRAY; import static org.springframework.restdocs.payload.JsonFieldType.NUMBER; import static org.springframework.restdocs.payload.JsonFieldType.STRING; import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; @@ -28,6 +33,9 @@ import com.prgrms.nabmart.domain.coupon.UserCoupon; import com.prgrms.nabmart.domain.order.Order; import com.prgrms.nabmart.domain.order.controller.request.CreateOrderRequest; +import com.prgrms.nabmart.domain.order.controller.request.FindPayedOrdersRequest; +import com.prgrms.nabmart.domain.order.service.response.FindPayedOrdersResponse; +import com.prgrms.nabmart.domain.order.service.response.FindPayedOrdersResponse.FindPayedOrderResponse; import com.prgrms.nabmart.domain.order.service.response.CreateOrderResponse; import com.prgrms.nabmart.domain.order.service.response.FindOrderDetailResponse; import com.prgrms.nabmart.domain.order.service.response.FindOrdersResponse; @@ -224,4 +232,48 @@ void deleteOrder() throws Exception { )); } } + + @Nested + @DisplayName("결제 완료된 주문 목록 조회 api 호출 시") + class FindPayedOrdersTest { + + @Test + @DisplayName("성공") + void findPayedOrders() throws Exception { + //given + int page = 0; + FindPayedOrdersRequest findPayedOrdersRequest = new FindPayedOrdersRequest(page); + FindPayedOrderResponse findPayedOrderResponse + = new FindPayedOrderResponse(1L, "비비고 왕교자 외 2개", 20000); + FindPayedOrdersResponse findPayedOrdersResponse = new FindPayedOrdersResponse( + List.of(findPayedOrderResponse), 0, 1); + + given(orderService.findPayedOrders(any())).willReturn(findPayedOrdersResponse); + + //when + ResultActions resultActions = mockMvc.perform(get("/api/v1/orders/payed") + .header(AUTHORIZATION, accessToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(findPayedOrdersRequest))); + + //then + resultActions.andExpect(status().isOk()) + .andDo(restDocs.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("액세스 토큰") + ), + requestFields( + fieldWithPath("page").type(NUMBER).description("페이지 번호") + ), + responseFields( + fieldWithPath("orders").type(ARRAY).description("주문 목록"), + fieldWithPath("orders[].orderId").type(NUMBER).description("주문 ID"), + fieldWithPath("orders[].name").type(STRING).description("주문 이름"), + fieldWithPath("orders[].price").type(NUMBER).description("주문 가격"), + fieldWithPath("page").type(NUMBER).description("페이지 번호"), + fieldWithPath("totalElements").type(NUMBER).description("총 요소 개수") + ) + )); + } + } } diff --git a/src/test/java/com/prgrms/nabmart/domain/order/service/OrderServiceTest.java b/src/test/java/com/prgrms/nabmart/domain/order/service/OrderServiceTest.java index 5433805ab..ca5c915cc 100644 --- a/src/test/java/com/prgrms/nabmart/domain/order/service/OrderServiceTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/order/service/OrderServiceTest.java @@ -11,9 +11,11 @@ import static com.prgrms.nabmart.domain.order.support.OrderFixture.updateOrderByCouponCommand; import static com.prgrms.nabmart.domain.user.support.UserFixture.user; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.catchException; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -32,17 +34,23 @@ import com.prgrms.nabmart.domain.order.controller.request.CreateOrderRequest; import com.prgrms.nabmart.domain.order.controller.request.CreateOrderRequest.CreateOrderItemRequest; import com.prgrms.nabmart.domain.order.exception.NotFoundOrderException; +import com.prgrms.nabmart.domain.order.exception.UnauthorizedOrderException; import com.prgrms.nabmart.domain.order.repository.OrderRepository; +import com.prgrms.nabmart.domain.order.service.response.FindPayedOrdersResponse; +import com.prgrms.nabmart.domain.order.service.response.FindPayedOrdersResponse.FindPayedOrderResponse; import com.prgrms.nabmart.domain.order.service.request.CreateOrdersCommand; import com.prgrms.nabmart.domain.order.service.request.UpdateOrderByCouponCommand; import com.prgrms.nabmart.domain.order.service.response.CreateOrderResponse; import com.prgrms.nabmart.domain.order.service.response.FindOrderDetailResponse; import com.prgrms.nabmart.domain.order.service.response.FindOrdersResponse; import com.prgrms.nabmart.domain.order.service.response.UpdateOrderByCouponResponse; +import com.prgrms.nabmart.domain.payment.service.request.FindPayedOrdersCommand; import com.prgrms.nabmart.domain.user.User; import com.prgrms.nabmart.domain.user.repository.UserRepository; +import com.prgrms.nabmart.domain.user.support.UserFixture; import java.util.List; import java.util.Optional; +import java.util.stream.IntStream; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -341,4 +349,58 @@ void success() { verify(orderRepository, times(1)).delete(order); } } + + @Nested + @DisplayName("findPayedOrders 메서드 실행 시") + class FindOrdersWaitingDeliveryTest { + + User user = UserFixture.user(); + User employee = UserFixture.employee(); + FindPayedOrdersCommand findPayedOrdersCommand + = FindPayedOrdersCommand.of(1L, 0); + Item item = item(); + int orderItemQuantity = 5; + + private List createOrders(int end) { + return IntStream.range(0, end) + .mapToObj(i -> { + OrderItem orderItem = new OrderItem(item, orderItemQuantity); + return new Order(user, List.of(orderItem)); + }).toList(); + } + + @Test + @DisplayName("성공") + void success() { + //given + List orders = createOrders(5); + PageImpl ordersPage = new PageImpl<>(orders); + + given(userRepository.findById(any())).willReturn(Optional.ofNullable(employee)); + given(orderRepository.findAllStatusIsPayed(any())).willReturn(ordersPage); + + //when + FindPayedOrdersResponse result = orderService.findPayedOrders( + findPayedOrdersCommand); + + //then + int expectedPrice = item.getPrice() * orderItemQuantity; + assertThat(result.orders()).hasSize(5); + assertThat(result.orders()).map(FindPayedOrderResponse::price) + .containsOnly(expectedPrice); + } + + @Test + @DisplayName("예외: 로그인 유저가 employee가 아님") + void throwExceptionWhenLoginUserIsNotEmployee() { + //given + given(userRepository.findById(any())).willReturn(Optional.ofNullable(user)); + + //when + //then + assertThatThrownBy( + () -> orderService.findPayedOrders(findPayedOrdersCommand)) + .isInstanceOf(UnauthorizedOrderException.class); + } + } } diff --git a/src/test/java/com/prgrms/nabmart/domain/order/support/OrderFixture.java b/src/test/java/com/prgrms/nabmart/domain/order/support/OrderFixture.java index a069b142e..3ce4043f3 100644 --- a/src/test/java/com/prgrms/nabmart/domain/order/support/OrderFixture.java +++ b/src/test/java/com/prgrms/nabmart/domain/order/support/OrderFixture.java @@ -43,6 +43,14 @@ public static Order payingOrder(long orderId, User user) { return order; } + + public static Order payedOrder(long orderId, User user) { + Order order = payingOrder(orderId, user); + ReflectionTestUtils.setField(order, "orderId", orderId); + ReflectionTestUtils.setField(order, "status", OrderStatus.PAYED); + + return order; + } public static Order deliveringOrder(long orderId, User user) { Order order = new Order(user, List.of(orderItem())); From 51226158f0c007b0bf0289775024102d193fcfab Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Thu, 21 Sep 2023 13:47:13 +0900 Subject: [PATCH 31/41] =?UTF-8?q?[NAYB-158]=20feat:=20=EC=95=8C=EB=A6=BC?= =?UTF-8?q?=20=EC=A0=84=EC=86=A1=EC=9D=84=20=EC=9C=84=ED=95=B4=20`Delivery?= =?UTF-8?q?`=EC=97=90=20`userId`=EB=A5=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/prgrms/nabmart/domain/delivery/Delivery.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/Delivery.java b/src/main/java/com/prgrms/nabmart/domain/delivery/Delivery.java index f3cbe23e6..29f10fff7 100644 --- a/src/main/java/com/prgrms/nabmart/domain/delivery/Delivery.java +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/Delivery.java @@ -69,6 +69,9 @@ public class Delivery extends BaseTimeEntity { @Column private Integer deliveryFee; + @Column + private Long userId; + @Builder public Delivery(final Order order, final int estimateMinutes) { validateOrderStatus(order); @@ -80,6 +83,7 @@ public Delivery(final Order order, final int estimateMinutes) { this.riderRequest = order.getRiderRequest(); this.deliveryFee = order.getDeliveryFee(); this.arrivedAt = LocalDateTime.now().plusMinutes(estimateMinutes); + this.userId = order.getUser().getUserId(); order.updateOrderStatus(OrderStatus.DELIVERING); } From fdb68c8346b96bb3f214c82ea28f9d3227991eea Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Thu, 21 Sep 2023 14:18:55 +0900 Subject: [PATCH 32/41] =?UTF-8?q?[NAYB-158]=20feat:=20`Notification`=20?= =?UTF-8?q?=EC=95=8C=EB=A6=BC=20=EC=A0=9C=EB=AA=A9=20=ED=95=84=EB=93=9C=20?= =?UTF-8?q?`title`=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/notification/Notification.java | 15 +++- .../service/NotificationService.java | 2 + .../request/SendNotificationCommand.java | 4 +- .../response/NotificationResponse.java | 2 + .../domain/notification/NotificationTest.java | 71 +++++++++++++++++++ 5 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 src/test/java/com/prgrms/nabmart/domain/notification/NotificationTest.java diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/Notification.java b/src/main/java/com/prgrms/nabmart/domain/notification/Notification.java index 5f258431f..7c7ec8921 100644 --- a/src/main/java/com/prgrms/nabmart/domain/notification/Notification.java +++ b/src/main/java/com/prgrms/nabmart/domain/notification/Notification.java @@ -20,12 +20,16 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Notification extends BaseTimeEntity { + private static final int TITLE_LENGTH = 20; private static final int CONTENT_LENGTH = 50; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long notificationId; + @Column(nullable = false) + private String title; + @Column(nullable = false) private String content; @@ -37,17 +41,26 @@ public class Notification extends BaseTimeEntity { @Builder public Notification( + String title, String content, Long userId, NotificationType notificationType) { + validateTitle(title); validateContent(content); + this.title = title; this.content = content; this.notificationType = notificationType; this.userId = userId; } + private void validateTitle(String title) { + if (Objects.nonNull(title) && title.length() > TITLE_LENGTH) { + throw new InvalidNotificationException("제목의 길이는 20자 이하여야 합니다."); + } + } + private void validateContent(String content) { - if(Objects.nonNull(content) && content.length() > CONTENT_LENGTH) { + if (Objects.nonNull(content) && content.length() > CONTENT_LENGTH) { throw new InvalidNotificationException("내용의 길이는 50자 이하여야 합니다."); } } diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java b/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java index f28b5dd1f..3d6ccd719 100644 --- a/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java +++ b/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java @@ -69,11 +69,13 @@ private void send(SseEmitter emitter, String emitterId, Object data) { @Transactional public void sendNotification(SendNotificationCommand sendNotificationCommand) { Long userId = sendNotificationCommand.userId(); + String title = sendNotificationCommand.title(); String content = sendNotificationCommand.content(); NotificationType notificationType = sendNotificationCommand.notificationType(); verifyExistsUser(userId); Notification notification = Notification.builder() + .title(title) .content(content) .userId(userId) .notificationType(notificationType) diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/service/request/SendNotificationCommand.java b/src/main/java/com/prgrms/nabmart/domain/notification/service/request/SendNotificationCommand.java index 3a02512dc..f460e50d7 100644 --- a/src/main/java/com/prgrms/nabmart/domain/notification/service/request/SendNotificationCommand.java +++ b/src/main/java/com/prgrms/nabmart/domain/notification/service/request/SendNotificationCommand.java @@ -4,13 +4,15 @@ public record SendNotificationCommand( Long userId, + String title, String content, NotificationType notificationType) { public static SendNotificationCommand of( final Long userId, + final String title, final String content, final NotificationType notificationType) { - return new SendNotificationCommand(userId, content, notificationType); + return new SendNotificationCommand(userId, title, content, notificationType); } } diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/service/response/NotificationResponse.java b/src/main/java/com/prgrms/nabmart/domain/notification/service/response/NotificationResponse.java index 43e1753be..f7b02a48e 100644 --- a/src/main/java/com/prgrms/nabmart/domain/notification/service/response/NotificationResponse.java +++ b/src/main/java/com/prgrms/nabmart/domain/notification/service/response/NotificationResponse.java @@ -6,6 +6,7 @@ public record NotificationResponse( Long notificationId, + String title, String content, NotificationType notificationType, Long userId, @@ -14,6 +15,7 @@ public record NotificationResponse( public static NotificationResponse from(Notification notification) { return new NotificationResponse( notification.getNotificationId(), + notification.getTitle(), notification.getContent(), notification.getNotificationType(), notification.getUserId(), diff --git a/src/test/java/com/prgrms/nabmart/domain/notification/NotificationTest.java b/src/test/java/com/prgrms/nabmart/domain/notification/NotificationTest.java new file mode 100644 index 000000000..2662fd068 --- /dev/null +++ b/src/test/java/com/prgrms/nabmart/domain/notification/NotificationTest.java @@ -0,0 +1,71 @@ +package com.prgrms.nabmart.domain.notification; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.prgrms.nabmart.domain.notification.exception.InvalidNotificationException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class NotificationTest { + + @Nested + @DisplayName("notification 생성 시") + class NewNotificationTest { + + @Test + @DisplayName("성공") + void success() { + //given + String title = "제목"; + String content = "내용"; + + //when + Notification notification = Notification.builder() + .title(title) + .content(content) + .userId(1L) + .notificationType(NotificationType.DELIVERY) + .build(); + + //then + assertThat(notification.getTitle()).isEqualTo(title); + assertThat(notification.getContent()).isEqualTo(content); + } + + @Test + @DisplayName("예외: 제목 길이가 20자를 초과") + void throwExceptionWhenTitleLengthGGraterThan20() { + //given + String titleGT20 = "a".repeat(21); + + //when + //then + assertThatThrownBy(() -> Notification.builder() + .title(titleGT20) + .content("내용") + .userId(1L) + .notificationType(NotificationType.DELIVERY) + .build()) + .isInstanceOf(InvalidNotificationException.class); + } + + @Test + @DisplayName("예외: 내용 길이가 50자를 초과") + void throwExceptionWhenContentLengthGraterThan50() { + //given + String contentGT50 = "a".repeat(51); + + //when + //then + assertThatThrownBy(() -> Notification.builder() + .title("title") + .content(contentGT50) + .userId(1L) + .notificationType(NotificationType.DELIVERY) + .build()) + .isInstanceOf(InvalidNotificationException.class); + } + } +} From 2f50a654ff8e47d5c45b4243133d29641b2568cd Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Thu, 21 Sep 2023 15:35:05 +0900 Subject: [PATCH 33/41] =?UTF-8?q?[NAYB-158]=20feat:=20`Notification`=20=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EC=A1=B0=EA=B1=B4=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/notification/Notification.java | 4 ++-- .../domain/notification/NotificationTest.java | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/Notification.java b/src/main/java/com/prgrms/nabmart/domain/notification/Notification.java index 7c7ec8921..f527b0c16 100644 --- a/src/main/java/com/prgrms/nabmart/domain/notification/Notification.java +++ b/src/main/java/com/prgrms/nabmart/domain/notification/Notification.java @@ -20,8 +20,8 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Notification extends BaseTimeEntity { - private static final int TITLE_LENGTH = 20; - private static final int CONTENT_LENGTH = 50; + private static final int TITLE_LENGTH = 30; + private static final int CONTENT_LENGTH = 100; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/src/test/java/com/prgrms/nabmart/domain/notification/NotificationTest.java b/src/test/java/com/prgrms/nabmart/domain/notification/NotificationTest.java index 2662fd068..d592311f3 100644 --- a/src/test/java/com/prgrms/nabmart/domain/notification/NotificationTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/notification/NotificationTest.java @@ -35,15 +35,15 @@ void success() { } @Test - @DisplayName("예외: 제목 길이가 20자를 초과") - void throwExceptionWhenTitleLengthGGraterThan20() { + @DisplayName("예외: 제목 길이가 30자를 초과") + void throwExceptionWhenTitleLengthGGraterThan31() { //given - String titleGT20 = "a".repeat(21); + String titleGT30 = "a".repeat(31); //when //then assertThatThrownBy(() -> Notification.builder() - .title(titleGT20) + .title(titleGT30) .content("내용") .userId(1L) .notificationType(NotificationType.DELIVERY) @@ -52,16 +52,16 @@ void throwExceptionWhenTitleLengthGGraterThan20() { } @Test - @DisplayName("예외: 내용 길이가 50자를 초과") - void throwExceptionWhenContentLengthGraterThan50() { + @DisplayName("예외: 내용 길이가 100자를 초과") + void throwExceptionWhenContentLengthGraterThan100() { //given - String contentGT50 = "a".repeat(51); + String contentGT100 = "a".repeat(101); //when //then assertThatThrownBy(() -> Notification.builder() .title("title") - .content(contentGT50) + .content(contentGT100) .userId(1L) .notificationType(NotificationType.DELIVERY) .build()) From 00ae9a9a4c320f1b46f095b6917714914c41e352 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Thu, 21 Sep 2023 15:35:33 +0900 Subject: [PATCH 34/41] =?UTF-8?q?[NAYB-158]=20feat:=20=EB=B0=B0=EB=8B=AC?= =?UTF-8?q?=20=EC=83=81=ED=83=9C=20=EB=B3=80=EA=B2=BD=20=EC=8B=9C=20?= =?UTF-8?q?=EC=95=8C=EB=A6=BC=20=EC=A0=84=EC=86=A1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../delivery/service/DeliveryService.java | 53 ++++++++++++++++++- .../notification/NotificationMessage.java | 21 ++++++++ .../delivery/service/DeliveryServiceTest.java | 37 +++++++++++++ 3 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/prgrms/nabmart/domain/notification/NotificationMessage.java diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java b/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java index 93d5c3319..4e4d7e3f9 100644 --- a/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java @@ -1,5 +1,9 @@ package com.prgrms.nabmart.domain.delivery.service; +import static com.prgrms.nabmart.domain.notification.NotificationMessage.COMPLETE_DELIVERY; +import static com.prgrms.nabmart.domain.notification.NotificationMessage.REGISTER_DELIVERY; +import static com.prgrms.nabmart.domain.notification.NotificationMessage.START_DELIVERY; + import com.prgrms.nabmart.domain.delivery.Delivery; import com.prgrms.nabmart.domain.delivery.Rider; import com.prgrms.nabmart.domain.delivery.exception.AlreadyRegisteredDeliveryException; @@ -18,6 +22,9 @@ import com.prgrms.nabmart.domain.delivery.service.response.FindDeliveryDetailResponse; import com.prgrms.nabmart.domain.delivery.service.response.FindRiderDeliveriesResponse; import com.prgrms.nabmart.domain.delivery.service.response.FindWaitingDeliveriesResponse; +import com.prgrms.nabmart.domain.notification.NotificationType; +import com.prgrms.nabmart.domain.notification.service.NotificationService; +import com.prgrms.nabmart.domain.notification.service.request.SendNotificationCommand; import com.prgrms.nabmart.domain.order.Order; import com.prgrms.nabmart.domain.order.exception.NotFoundOrderException; import com.prgrms.nabmart.domain.order.repository.OrderRepository; @@ -37,6 +44,7 @@ public class DeliveryService { private final UserRepository userRepository; private final RiderRepository riderRepository; private final OrderRepository orderRepository; + private final NotificationService notificationService; @Transactional public Long registerDelivery(RegisterDeliveryCommand registerDeliveryCommand) { @@ -45,12 +53,29 @@ public Long registerDelivery(RegisterDeliveryCommand registerDeliveryCommand) { checkAlreadyRegisteredDelivery(order); Delivery delivery = new Delivery(order, registerDeliveryCommand.estimateMinutes()); deliveryRepository.save(delivery); + + sendRegisterDeliveryNotification(registerDeliveryCommand, delivery, order); + return delivery.getDeliveryId(); } + private void sendRegisterDeliveryNotification( + RegisterDeliveryCommand registerDeliveryCommand, + Delivery delivery, + Order order) { + SendNotificationCommand notificationCommand = SendNotificationCommand.of( + delivery.getUserId(), + REGISTER_DELIVERY.getTitle(), + REGISTER_DELIVERY.getContentFromFormat( + order.getName(), + registerDeliveryCommand.estimateMinutes()), + NotificationType.DELIVERY); + notificationService.sendNotification(notificationCommand); + } + private void checkUserHasRegisterDeliveryAuthority(final Long userId) { User user = findUserByUserId(userId); - if(!user.isEmployee()) { + if (!user.isEmployee()) { throw new UnauthorizedDeliveryException("권한이 없습니다."); } } @@ -61,7 +86,7 @@ private Order findOrderByOrderIdPessimistic(RegisterDeliveryCommand registerDeli } private void checkAlreadyRegisteredDelivery(final Order order) { - if(deliveryRepository.existsByOrder(order)) { + if (deliveryRepository.existsByOrder(order)) { throw new AlreadyRegisteredDeliveryException("이미 배달이 생성된 주문입니다."); } } @@ -99,6 +124,19 @@ public void startDelivery(StartDeliveryCommand startDeliveryCommand) { Delivery delivery = findDeliveryByDeliveryId(startDeliveryCommand.deliveryId()); delivery.checkAuthority(rider); delivery.startDelivery(startDeliveryCommand.deliveryEstimateMinutes()); + + sendStartDeliveryNotification(startDeliveryCommand, delivery); + } + + private void sendStartDeliveryNotification( + StartDeliveryCommand startDeliveryCommand, + Delivery delivery) { + SendNotificationCommand notificationCommand = SendNotificationCommand.of( + delivery.getUserId(), + START_DELIVERY.getTitle(), + START_DELIVERY.getContentFromFormat(startDeliveryCommand.deliveryEstimateMinutes()), + NotificationType.DELIVERY); + notificationService.sendNotification(notificationCommand); } @Transactional @@ -107,6 +145,17 @@ public void completeDelivery(CompleteDeliveryCommand completeDeliveryCommand) { Delivery delivery = findDeliveryByDeliveryId(completeDeliveryCommand.deliveryId()); delivery.checkAuthority(rider); delivery.completeDelivery(); + + sendCompleteDeliveryNotification(delivery); + } + + private void sendCompleteDeliveryNotification(Delivery delivery) { + SendNotificationCommand notificationCommand = SendNotificationCommand.of( + delivery.getUserId(), + COMPLETE_DELIVERY.getTitle(), + COMPLETE_DELIVERY.getContentFromFormat(), + NotificationType.DELIVERY); + notificationService.sendNotification(notificationCommand); } private Rider findRiderByRiderId(final Long riderId) { diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/NotificationMessage.java b/src/main/java/com/prgrms/nabmart/domain/notification/NotificationMessage.java new file mode 100644 index 000000000..441a540d7 --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/notification/NotificationMessage.java @@ -0,0 +1,21 @@ +package com.prgrms.nabmart.domain.notification; + +import java.text.MessageFormat; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum NotificationMessage { + REGISTER_DELIVERY("주문이 접수되었습니다.", + "주문하신 {0} 이(가) {1}분 내에 도착할 예정입니다."), + START_DELIVERY("라이더가 주문을 픽업하였습니다.", "약 {0}분 후에 도착할 예정입니다."), + COMPLETE_DELIVERY("배달이 완료되었습니다.", "네이B마트를 이용해주셔서 감사합니다."); + + private final String title; + private final String contentFormat; + + public String getContentFromFormat(Object... arguments) { + return MessageFormat.format(contentFormat, arguments); + } +} diff --git a/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java b/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java index 8950ffa2f..7fdc7c25b 100644 --- a/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java @@ -31,6 +31,7 @@ import com.prgrms.nabmart.domain.delivery.service.response.FindRiderDeliveriesResponse.FindRiderDeliveryResponse; import com.prgrms.nabmart.domain.delivery.service.response.FindWaitingDeliveriesResponse; import com.prgrms.nabmart.domain.delivery.support.DeliveryFixture; +import com.prgrms.nabmart.domain.notification.service.NotificationService; import com.prgrms.nabmart.domain.order.Order; import com.prgrms.nabmart.domain.order.exception.NotFoundOrderException; import com.prgrms.nabmart.domain.order.repository.OrderRepository; @@ -75,6 +76,9 @@ class DeliveryServiceTest { @Mock OrderRepository orderRepository; + @Mock + NotificationService notificationService; + User user = UserFixture.user(); Order order = deliveringOrder(1L, user); Rider rider = DeliveryFixture.rider(); @@ -106,6 +110,7 @@ void success() { //then then(deliveryRepository).should().save(any()); + then(notificationService).should().sendNotification(any()); } @Test @@ -262,6 +267,24 @@ void success() { assertThat(delivery.getDeliveryStatus()).isEqualTo(DeliveryStatus.START_DELIVERY); } + @Test + @DisplayName("성공: 배달 시작 알림 전송") + void successThenNotify() { + //given + int deliveryEstimateMinutes = 20; + StartDeliveryCommand startDeliveryCommand + = StartDeliveryCommand.of(1L, deliveryEstimateMinutes, 1L); + + given(riderRepository.findById(any())).willReturn(Optional.ofNullable(rider)); + given(deliveryRepository.findById(any())).willReturn(Optional.ofNullable(delivery)); + + //when + deliveryService.startDelivery(startDeliveryCommand); + + //then + then(notificationService).should().sendNotification(any()); + } + @Test @DisplayName("예외: 존재하지 않는 라이더") void throwExceptionWhenNotFoundRider() { @@ -349,6 +372,20 @@ void success() { assertThat(delivery.getDeliveryStatus()).isEqualTo(DeliveryStatus.DELIVERED); } + @Test + @DisplayName("성공: 배달 완료 알림 전송") + void successThenNotify() { + //given + given(riderRepository.findById(any())).willReturn(Optional.ofNullable(rider)); + given(deliveryRepository.findById(any())).willReturn(Optional.ofNullable(delivery)); + + //when + deliveryService.completeDelivery(completeDeliveryCommand); + + //then + then(notificationService).should().sendNotification(any()); + } + @Test @DisplayName("예외: 존재하지 않는 라이더") void throwExceptionWhenNotFoundRider() { From 7c83980316ad0417e317130ecf8c898ec9ee8676 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Thu, 21 Sep 2023 15:52:13 +0900 Subject: [PATCH 35/41] =?UTF-8?q?[NAYB-158]=20feat:=20`Notification`=20?= =?UTF-8?q?=EC=97=94=ED=8B=B0=ED=8B=B0=EC=97=90=EC=84=9C=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EB=AA=A8=EB=8D=B8=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 --- .../domain/notification/Notification.java | 19 ------------------- .../repository/NotificationRepository.java | 8 -------- .../service/NotificationService.java | 3 --- .../response/NotificationResponse.java | 2 -- 4 files changed, 32 deletions(-) delete mode 100644 src/main/java/com/prgrms/nabmart/domain/notification/repository/NotificationRepository.java diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/Notification.java b/src/main/java/com/prgrms/nabmart/domain/notification/Notification.java index f527b0c16..59b21fc5d 100644 --- a/src/main/java/com/prgrms/nabmart/domain/notification/Notification.java +++ b/src/main/java/com/prgrms/nabmart/domain/notification/Notification.java @@ -2,20 +2,12 @@ import com.prgrms.nabmart.domain.notification.exception.InvalidNotificationException; import com.prgrms.nabmart.global.BaseTimeEntity; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; import java.util.Objects; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -@Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Notification extends BaseTimeEntity { @@ -23,20 +15,9 @@ public class Notification extends BaseTimeEntity { private static final int TITLE_LENGTH = 30; private static final int CONTENT_LENGTH = 100; - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long notificationId; - - @Column(nullable = false) private String title; - - @Column(nullable = false) private String content; - - @Enumerated(EnumType.STRING) private NotificationType notificationType; - - @Column(nullable = false) private Long userId; @Builder diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/repository/NotificationRepository.java b/src/main/java/com/prgrms/nabmart/domain/notification/repository/NotificationRepository.java deleted file mode 100644 index 0c87b21cb..000000000 --- a/src/main/java/com/prgrms/nabmart/domain/notification/repository/NotificationRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.prgrms.nabmart.domain.notification.repository; - -import com.prgrms.nabmart.domain.notification.Notification; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface NotificationRepository extends JpaRepository { - -} diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java b/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java index 3d6ccd719..a3152bc0d 100644 --- a/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java +++ b/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java @@ -6,7 +6,6 @@ import com.prgrms.nabmart.domain.notification.NotificationType; import com.prgrms.nabmart.domain.notification.controller.request.ConnectNotificationCommand; import com.prgrms.nabmart.domain.notification.repository.EmitterRepository; -import com.prgrms.nabmart.domain.notification.repository.NotificationRepository; import com.prgrms.nabmart.domain.notification.service.request.SendNotificationCommand; import com.prgrms.nabmart.domain.notification.service.response.NotificationResponse; import com.prgrms.nabmart.domain.user.exception.NotFoundUserException; @@ -27,7 +26,6 @@ public class NotificationService { private static final Long DEFAULT_TIMEOUT = 60L * 1000 * 120; private final EmitterRepository emitterRepository; - private final NotificationRepository notificationRepository; private final UserRepository userRepository; public SseEmitter connectNotification(ConnectNotificationCommand connectNotificationCommand) { @@ -80,7 +78,6 @@ public void sendNotification(SendNotificationCommand sendNotificationCommand) { .userId(userId) .notificationType(notificationType) .build(); - notificationRepository.save(notification); Map emitters = emitterRepository.findAllByIdStartWith(userId); emitters.forEach((key, emitter) -> { diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/service/response/NotificationResponse.java b/src/main/java/com/prgrms/nabmart/domain/notification/service/response/NotificationResponse.java index f7b02a48e..6c04b5c27 100644 --- a/src/main/java/com/prgrms/nabmart/domain/notification/service/response/NotificationResponse.java +++ b/src/main/java/com/prgrms/nabmart/domain/notification/service/response/NotificationResponse.java @@ -5,7 +5,6 @@ import java.time.LocalDateTime; public record NotificationResponse( - Long notificationId, String title, String content, NotificationType notificationType, @@ -14,7 +13,6 @@ public record NotificationResponse( public static NotificationResponse from(Notification notification) { return new NotificationResponse( - notification.getNotificationId(), notification.getTitle(), notification.getContent(), notification.getNotificationType(), From e584653c36505d5b218b1148d1865b302dab480c Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Thu, 21 Sep 2023 16:38:46 +0900 Subject: [PATCH 36/41] =?UTF-8?q?[NAYB-158]=20fix:=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=ED=8A=B8=EB=9E=9C=EC=9E=AD=EC=85=98=20?= =?UTF-8?q?=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/notification/service/NotificationService.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java b/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java index a3152bc0d..f4b792da1 100644 --- a/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java +++ b/src/main/java/com/prgrms/nabmart/domain/notification/service/NotificationService.java @@ -10,7 +10,6 @@ import com.prgrms.nabmart.domain.notification.service.response.NotificationResponse; import com.prgrms.nabmart.domain.user.exception.NotFoundUserException; import com.prgrms.nabmart.domain.user.repository.UserRepository; -import jakarta.transaction.Transactional; import java.io.IOException; import java.util.Map; import lombok.RequiredArgsConstructor; @@ -63,8 +62,7 @@ private void send(SseEmitter emitter, String emitterId, Object data) { log.error("알림 전송에 실패했습니다.", ex); } } - - @Transactional + public void sendNotification(SendNotificationCommand sendNotificationCommand) { Long userId = sendNotificationCommand.userId(); String title = sendNotificationCommand.title(); From a2bcb360f528202aa125c2ef9dd9201a8ca64d75 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Thu, 21 Sep 2023 22:01:24 +0900 Subject: [PATCH 37/41] =?UTF-8?q?[NAYB-157]=20refactor:=20=EC=BB=A8?= =?UTF-8?q?=EB=B2=A4=EC=85=98=EC=97=90=20=EB=94=B0=EB=A5=B8=20=ED=8C=8C?= =?UTF-8?q?=EB=9D=BC=EB=AF=B8=ED=84=B0=20`final`=20=ED=82=A4=EC=9B=8C?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/AlreadyRegisteredDeliveryException.java | 2 +- .../order/exception/UnauthorizedOrderException.java | 2 +- .../order/service/response/FindPayedOrdersResponse.java | 8 ++++---- .../payment/service/request/FindPayedOrdersCommand.java | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/exception/AlreadyRegisteredDeliveryException.java b/src/main/java/com/prgrms/nabmart/domain/delivery/exception/AlreadyRegisteredDeliveryException.java index 13c3318f3..f67ffe5aa 100644 --- a/src/main/java/com/prgrms/nabmart/domain/delivery/exception/AlreadyRegisteredDeliveryException.java +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/exception/AlreadyRegisteredDeliveryException.java @@ -2,7 +2,7 @@ public class AlreadyRegisteredDeliveryException extends DeliveryException { - public AlreadyRegisteredDeliveryException(String message) { + public AlreadyRegisteredDeliveryException(final String message) { super(message); } } diff --git a/src/main/java/com/prgrms/nabmart/domain/order/exception/UnauthorizedOrderException.java b/src/main/java/com/prgrms/nabmart/domain/order/exception/UnauthorizedOrderException.java index 9d75b07fb..783b291b8 100644 --- a/src/main/java/com/prgrms/nabmart/domain/order/exception/UnauthorizedOrderException.java +++ b/src/main/java/com/prgrms/nabmart/domain/order/exception/UnauthorizedOrderException.java @@ -2,7 +2,7 @@ public class UnauthorizedOrderException extends OrderException { - public UnauthorizedOrderException(String message) { + public UnauthorizedOrderException(final String message) { super(message); } } diff --git a/src/main/java/com/prgrms/nabmart/domain/order/service/response/FindPayedOrdersResponse.java b/src/main/java/com/prgrms/nabmart/domain/order/service/response/FindPayedOrdersResponse.java index 58accdd2d..dc30e7be1 100644 --- a/src/main/java/com/prgrms/nabmart/domain/order/service/response/FindPayedOrdersResponse.java +++ b/src/main/java/com/prgrms/nabmart/domain/order/service/response/FindPayedOrdersResponse.java @@ -9,9 +9,9 @@ public record FindPayedOrdersResponse( long totalElements) { public static FindPayedOrdersResponse of( - List orders, - int page, - long totalElements) { + final List orders, + final int page, + final long totalElements) { List content = orders.stream() .map(FindPayedOrderResponse::from) .toList(); @@ -23,7 +23,7 @@ public record FindPayedOrderResponse( String name, int price) { - public static FindPayedOrderResponse from(Order order) { + public static FindPayedOrderResponse from(final Order order) { return new FindPayedOrderResponse( order.getOrderId(), order.getName(), diff --git a/src/main/java/com/prgrms/nabmart/domain/payment/service/request/FindPayedOrdersCommand.java b/src/main/java/com/prgrms/nabmart/domain/payment/service/request/FindPayedOrdersCommand.java index e8b1c4608..794bcd0ae 100644 --- a/src/main/java/com/prgrms/nabmart/domain/payment/service/request/FindPayedOrdersCommand.java +++ b/src/main/java/com/prgrms/nabmart/domain/payment/service/request/FindPayedOrdersCommand.java @@ -2,7 +2,7 @@ public record FindPayedOrdersCommand(Long userId, int page) { - public static FindPayedOrdersCommand of(Long userId, int page) { + public static FindPayedOrdersCommand of(final Long userId, final int page) { return new FindPayedOrdersCommand(userId, page); } } From 69fea0e8d7f2505dd0074a2bc3f225e68e1f036a Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Thu, 21 Sep 2023 22:24:48 +0900 Subject: [PATCH 38/41] =?UTF-8?q?[NAYB-159]=20feat:=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=EB=B0=B0=EB=8B=AC=20=EC=83=81=EC=84=B8=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=9D=B4=EB=A6=84=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DeliveryController.java | 15 +++++---- .../delivery/service/DeliveryService.java | 13 ++++---- .../request/FindDeliveryByOrderCommand.java | 8 +++++ .../service/request/FindDeliveryCommand.java | 8 ----- ....java => FindDeliveryByOrderResponse.java} | 6 ++-- .../controller/DeliveryControllerTest.java | 6 ++-- .../delivery/service/DeliveryServiceTest.java | 32 +++++++++---------- .../delivery/support/DeliveryFixture.java | 12 +++---- 8 files changed, 51 insertions(+), 49 deletions(-) create mode 100644 src/main/java/com/prgrms/nabmart/domain/delivery/service/request/FindDeliveryByOrderCommand.java delete mode 100644 src/main/java/com/prgrms/nabmart/domain/delivery/service/request/FindDeliveryCommand.java rename src/main/java/com/prgrms/nabmart/domain/delivery/service/response/{FindDeliveryDetailResponse.java => FindDeliveryByOrderResponse.java} (81%) diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryController.java b/src/main/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryController.java index fcc2ea2a4..b563712a4 100644 --- a/src/main/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryController.java +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryController.java @@ -8,12 +8,12 @@ import com.prgrms.nabmart.domain.delivery.service.DeliveryService; import com.prgrms.nabmart.domain.delivery.service.request.AcceptDeliveryCommand; import com.prgrms.nabmart.domain.delivery.service.request.CompleteDeliveryCommand; -import com.prgrms.nabmart.domain.delivery.service.request.FindDeliveryCommand; +import com.prgrms.nabmart.domain.delivery.service.request.FindDeliveryByOrderCommand; import com.prgrms.nabmart.domain.delivery.service.request.FindRiderDeliveriesCommand; import com.prgrms.nabmart.domain.delivery.service.request.FindWaitingDeliveriesCommand; import com.prgrms.nabmart.domain.delivery.service.request.RegisterDeliveryCommand; import com.prgrms.nabmart.domain.delivery.service.request.StartDeliveryCommand; -import com.prgrms.nabmart.domain.delivery.service.response.FindDeliveryDetailResponse; +import com.prgrms.nabmart.domain.delivery.service.response.FindDeliveryByOrderResponse; import com.prgrms.nabmart.domain.delivery.service.response.FindRiderDeliveriesResponse; import com.prgrms.nabmart.domain.delivery.service.response.FindWaitingDeliveriesResponse; import com.prgrms.nabmart.global.auth.LoginUser; @@ -58,13 +58,14 @@ public ResponseEntity registerDelivery( } @GetMapping("/orders/{orderId}/deliveries") - public ResponseEntity findDelivery( + public ResponseEntity findDeliveryByOrder( @PathVariable final Long orderId, @LoginUser final Long userId) { - FindDeliveryCommand findDeliveryCommand = FindDeliveryCommand.of(userId, orderId); - FindDeliveryDetailResponse findDeliveryDetailResponse - = deliveryService.findDelivery(findDeliveryCommand); - return ResponseEntity.ok(findDeliveryDetailResponse); + FindDeliveryByOrderCommand findDeliveryByOrderCommand + = FindDeliveryByOrderCommand.of(userId, orderId); + FindDeliveryByOrderResponse findDeliveryByOrderResponse + = deliveryService.findDeliveryByOrder(findDeliveryByOrderCommand); + return ResponseEntity.ok(findDeliveryByOrderResponse); } @PatchMapping("/deliveries/{deliveryId}/accept") diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java b/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java index 4e4d7e3f9..c1433e025 100644 --- a/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java @@ -14,12 +14,12 @@ import com.prgrms.nabmart.domain.delivery.repository.RiderRepository; import com.prgrms.nabmart.domain.delivery.service.request.AcceptDeliveryCommand; import com.prgrms.nabmart.domain.delivery.service.request.CompleteDeliveryCommand; -import com.prgrms.nabmart.domain.delivery.service.request.FindDeliveryCommand; +import com.prgrms.nabmart.domain.delivery.service.request.FindDeliveryByOrderCommand; import com.prgrms.nabmart.domain.delivery.service.request.FindRiderDeliveriesCommand; import com.prgrms.nabmart.domain.delivery.service.request.FindWaitingDeliveriesCommand; import com.prgrms.nabmart.domain.delivery.service.request.RegisterDeliveryCommand; import com.prgrms.nabmart.domain.delivery.service.request.StartDeliveryCommand; -import com.prgrms.nabmart.domain.delivery.service.response.FindDeliveryDetailResponse; +import com.prgrms.nabmart.domain.delivery.service.response.FindDeliveryByOrderResponse; import com.prgrms.nabmart.domain.delivery.service.response.FindRiderDeliveriesResponse; import com.prgrms.nabmart.domain.delivery.service.response.FindWaitingDeliveriesResponse; import com.prgrms.nabmart.domain.notification.NotificationType; @@ -92,11 +92,12 @@ private void checkAlreadyRegisteredDelivery(final Order order) { } @Transactional(readOnly = true) - public FindDeliveryDetailResponse findDelivery(FindDeliveryCommand findDeliveryCommand) { - User user = findUserByUserId(findDeliveryCommand.userId()); - Delivery delivery = findDeliveryByOrderWithOrder(findDeliveryCommand.orderId()); + public FindDeliveryByOrderResponse findDeliveryByOrder( + FindDeliveryByOrderCommand findDeliveryByOrderCommand) { + User user = findUserByUserId(findDeliveryByOrderCommand.userId()); + Delivery delivery = findDeliveryByOrderWithOrder(findDeliveryByOrderCommand.orderId()); checkAuthority(delivery, user); - return FindDeliveryDetailResponse.from(delivery); + return FindDeliveryByOrderResponse.from(delivery); } private void checkAuthority(final Delivery delivery, final User user) { diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/service/request/FindDeliveryByOrderCommand.java b/src/main/java/com/prgrms/nabmart/domain/delivery/service/request/FindDeliveryByOrderCommand.java new file mode 100644 index 000000000..956610ad7 --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/service/request/FindDeliveryByOrderCommand.java @@ -0,0 +1,8 @@ +package com.prgrms.nabmart.domain.delivery.service.request; + +public record FindDeliveryByOrderCommand(Long userId, Long orderId) { + + public static FindDeliveryByOrderCommand of(final Long userId,final Long orderId) { + return new FindDeliveryByOrderCommand(userId, orderId); + } +} diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/service/request/FindDeliveryCommand.java b/src/main/java/com/prgrms/nabmart/domain/delivery/service/request/FindDeliveryCommand.java deleted file mode 100644 index 0fea5ffef..000000000 --- a/src/main/java/com/prgrms/nabmart/domain/delivery/service/request/FindDeliveryCommand.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.prgrms.nabmart.domain.delivery.service.request; - -public record FindDeliveryCommand(Long userId, Long orderId) { - - public static FindDeliveryCommand of(final Long userId,final Long orderId) { - return new FindDeliveryCommand(userId, orderId); - } -} diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/service/response/FindDeliveryDetailResponse.java b/src/main/java/com/prgrms/nabmart/domain/delivery/service/response/FindDeliveryByOrderResponse.java similarity index 81% rename from src/main/java/com/prgrms/nabmart/domain/delivery/service/response/FindDeliveryDetailResponse.java rename to src/main/java/com/prgrms/nabmart/domain/delivery/service/response/FindDeliveryByOrderResponse.java index cd678602d..1e4b50516 100644 --- a/src/main/java/com/prgrms/nabmart/domain/delivery/service/response/FindDeliveryDetailResponse.java +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/service/response/FindDeliveryByOrderResponse.java @@ -4,7 +4,7 @@ import com.prgrms.nabmart.domain.delivery.DeliveryStatus; import java.time.LocalDateTime; -public record FindDeliveryDetailResponse( +public record FindDeliveryByOrderResponse( Long deliveryId, DeliveryStatus deliveryStatus, LocalDateTime createdAt, @@ -14,8 +14,8 @@ public record FindDeliveryDetailResponse( int orderPrice, String riderRequest) { - public static FindDeliveryDetailResponse from(final Delivery delivery) { - return new FindDeliveryDetailResponse( + public static FindDeliveryByOrderResponse from(final Delivery delivery) { + return new FindDeliveryByOrderResponse( delivery.getDeliveryId(), delivery.getDeliveryStatus(), delivery.getCreatedAt(), diff --git a/src/test/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryControllerTest.java b/src/test/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryControllerTest.java index 93cab122d..fe9096fd0 100644 --- a/src/test/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryControllerTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryControllerTest.java @@ -25,7 +25,7 @@ import com.prgrms.nabmart.domain.delivery.controller.request.RegisterDeliveryRequest; import com.prgrms.nabmart.domain.delivery.controller.request.StartDeliveryRequest; import com.prgrms.nabmart.domain.delivery.exception.AlreadyAssignedDeliveryException; -import com.prgrms.nabmart.domain.delivery.service.response.FindDeliveryDetailResponse; +import com.prgrms.nabmart.domain.delivery.service.response.FindDeliveryByOrderResponse; import com.prgrms.nabmart.domain.delivery.service.response.FindRiderDeliveriesResponse; import com.prgrms.nabmart.domain.delivery.service.response.FindRiderDeliveriesResponse.FindRiderDeliveryResponse; import com.prgrms.nabmart.domain.delivery.service.response.FindWaitingDeliveriesResponse; @@ -88,10 +88,10 @@ class FindDeliveryTest { void findDelivery() throws Exception { //given Long orderId = 1L; - FindDeliveryDetailResponse findDeliveryDetailResponse + FindDeliveryByOrderResponse findDeliveryByOrderResponse = DeliveryFixture.findDeliveryDetailResponse(); - given(deliveryService.findDelivery(any())).willReturn(findDeliveryDetailResponse); + given(deliveryService.findDeliveryByOrder(any())).willReturn(findDeliveryByOrderResponse); //when ResultActions resultActions = mockMvc diff --git a/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java b/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java index 7fdc7c25b..5567aecac 100644 --- a/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java @@ -21,12 +21,12 @@ import com.prgrms.nabmart.domain.delivery.repository.RiderRepository; import com.prgrms.nabmart.domain.delivery.service.request.AcceptDeliveryCommand; import com.prgrms.nabmart.domain.delivery.service.request.CompleteDeliveryCommand; -import com.prgrms.nabmart.domain.delivery.service.request.FindDeliveryCommand; +import com.prgrms.nabmart.domain.delivery.service.request.FindDeliveryByOrderCommand; import com.prgrms.nabmart.domain.delivery.service.request.FindRiderDeliveriesCommand; import com.prgrms.nabmart.domain.delivery.service.request.FindWaitingDeliveriesCommand; import com.prgrms.nabmart.domain.delivery.service.request.RegisterDeliveryCommand; import com.prgrms.nabmart.domain.delivery.service.request.StartDeliveryCommand; -import com.prgrms.nabmart.domain.delivery.service.response.FindDeliveryDetailResponse; +import com.prgrms.nabmart.domain.delivery.service.response.FindDeliveryByOrderResponse; import com.prgrms.nabmart.domain.delivery.service.response.FindRiderDeliveriesResponse; import com.prgrms.nabmart.domain.delivery.service.response.FindRiderDeliveriesResponse.FindRiderDeliveryResponse; import com.prgrms.nabmart.domain.delivery.service.response.FindWaitingDeliveriesResponse; @@ -155,10 +155,10 @@ void throwExceptionWhenNotFoundOrder() { } @Nested - @DisplayName("findDelivery 메서드 실행 시") - class FindDeliveryTest { + @DisplayName("findDeliveryByOrder 메서드 실행 시") + class FindDeliveryByOrderTest { - FindDeliveryCommand findDeliveryCommand = DeliveryFixture.findDeliveryCommand(); + FindDeliveryByOrderCommand findDeliveryByOrderCommand = DeliveryFixture.findDeliveryCommand(); @Test @DisplayName("성공") @@ -169,21 +169,21 @@ void success() { .willReturn(Optional.ofNullable(delivery)); //when - FindDeliveryDetailResponse findDeliveryDetailResponse - = deliveryService.findDelivery(findDeliveryCommand); + FindDeliveryByOrderResponse findDeliveryByOrderResponse + = deliveryService.findDeliveryByOrder(findDeliveryByOrderCommand); //then - assertThat(findDeliveryDetailResponse.deliveryStatus()) + assertThat(findDeliveryByOrderResponse.deliveryStatus()) .isEqualTo(delivery.getDeliveryStatus()); - assertThat(findDeliveryDetailResponse.createdAt()) + assertThat(findDeliveryByOrderResponse.createdAt()) .isEqualTo(delivery.getCreatedAt()); - assertThat(findDeliveryDetailResponse.arrivedAt()) + assertThat(findDeliveryByOrderResponse.arrivedAt()) .isEqualTo(delivery.getArrivedAt()); - assertThat(findDeliveryDetailResponse.orderName()) + assertThat(findDeliveryByOrderResponse.orderName()) .isEqualTo(delivery.getOrder().getName()); - assertThat(findDeliveryDetailResponse.orderPrice()) + assertThat(findDeliveryByOrderResponse.orderPrice()) .isEqualTo(delivery.getOrder().getPrice()); - assertThat(findDeliveryDetailResponse.riderRequest()) + assertThat(findDeliveryByOrderResponse.riderRequest()) .isEqualTo(delivery.getOrder().getRiderRequest()); } @@ -195,7 +195,7 @@ void throwExceptionWhenNotFoundUser() { //when //then - assertThatThrownBy(() -> deliveryService.findDelivery(findDeliveryCommand)) + assertThatThrownBy(() -> deliveryService.findDeliveryByOrder(findDeliveryByOrderCommand)) .isInstanceOf(NotFoundUserException.class); } @@ -209,7 +209,7 @@ void throwExceptionWhenNotFoundDelivery() { //when //then - assertThatThrownBy(() -> deliveryService.findDelivery(findDeliveryCommand)) + assertThatThrownBy(() -> deliveryService.findDeliveryByOrder(findDeliveryByOrderCommand)) .isInstanceOf(NotFoundDeliveryException.class); } @@ -235,7 +235,7 @@ void throwExceptionWhenNotEqualsLoginUserAndOrderUser() { //when //then - assertThatThrownBy(() -> deliveryService.findDelivery(findDeliveryCommand)) + assertThatThrownBy(() -> deliveryService.findDeliveryByOrder(findDeliveryByOrderCommand)) .isInstanceOf(UnauthorizedDeliveryException.class); } } diff --git a/src/test/java/com/prgrms/nabmart/domain/delivery/support/DeliveryFixture.java b/src/test/java/com/prgrms/nabmart/domain/delivery/support/DeliveryFixture.java index 7e4c03411..12320dbe1 100644 --- a/src/test/java/com/prgrms/nabmart/domain/delivery/support/DeliveryFixture.java +++ b/src/test/java/com/prgrms/nabmart/domain/delivery/support/DeliveryFixture.java @@ -3,10 +3,10 @@ import com.prgrms.nabmart.domain.delivery.Delivery; import com.prgrms.nabmart.domain.delivery.DeliveryStatus; import com.prgrms.nabmart.domain.delivery.Rider; -import com.prgrms.nabmart.domain.delivery.service.request.FindDeliveryCommand; +import com.prgrms.nabmart.domain.delivery.service.request.FindDeliveryByOrderCommand; import com.prgrms.nabmart.domain.delivery.service.response.FindWaitingDeliveriesResponse; import com.prgrms.nabmart.domain.delivery.service.response.FindWaitingDeliveriesResponse.FindWaitingDeliveryResponse; -import com.prgrms.nabmart.domain.delivery.service.response.FindDeliveryDetailResponse; +import com.prgrms.nabmart.domain.delivery.service.response.FindDeliveryByOrderResponse; import com.prgrms.nabmart.domain.order.Order; import com.prgrms.nabmart.domain.order.OrderStatus; import java.time.LocalDateTime; @@ -52,12 +52,12 @@ public static Delivery completedDelivery(Order order, Rider rider) { return delivery; } - public static FindDeliveryCommand findDeliveryCommand() { - return new FindDeliveryCommand(USER_ID, ORDER_ID); + public static FindDeliveryByOrderCommand findDeliveryCommand() { + return new FindDeliveryByOrderCommand(USER_ID, ORDER_ID); } - public static FindDeliveryDetailResponse findDeliveryDetailResponse() { - return new FindDeliveryDetailResponse( + public static FindDeliveryByOrderResponse findDeliveryDetailResponse() { + return new FindDeliveryByOrderResponse( DELIVERY_ID, DELIVERY_STATUS, NOW, From b630516317a695e518abd475837c77722b0cda77 Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Thu, 21 Sep 2023 22:53:39 +0900 Subject: [PATCH 39/41] =?UTF-8?q?[NAYB-159]=20feat:=20=EB=B0=B0=EB=8B=AC?= =?UTF-8?q?=20=EC=83=81=EC=84=B8=20=EC=A1=B0=ED=9A=8C(=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EB=8D=94,=20=EC=A7=81=EC=9B=90)=20=EC=84=9C=EB=B9=84=EC=8A=A4?= =?UTF-8?q?=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FindDeliveryDetailResponse.java | 46 ++++++++++++++ .../repository/DeliveryRepository.java | 7 +++ .../delivery/service/DeliveryService.java | 17 +++++ .../request/FindDeliveryDetailCommand.java | 8 +++ .../delivery/service/DeliveryServiceTest.java | 62 +++++++++++++++++++ 5 files changed, 140 insertions(+) create mode 100644 src/main/java/com/prgrms/nabmart/domain/delivery/controller/FindDeliveryDetailResponse.java create mode 100644 src/main/java/com/prgrms/nabmart/domain/delivery/service/request/FindDeliveryDetailCommand.java diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/controller/FindDeliveryDetailResponse.java b/src/main/java/com/prgrms/nabmart/domain/delivery/controller/FindDeliveryDetailResponse.java new file mode 100644 index 000000000..77fcec698 --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/controller/FindDeliveryDetailResponse.java @@ -0,0 +1,46 @@ +package com.prgrms.nabmart.domain.delivery.controller; + +import com.prgrms.nabmart.domain.delivery.Delivery; +import com.prgrms.nabmart.domain.delivery.DeliveryStatus; +import com.prgrms.nabmart.domain.order.OrderItem; +import java.time.LocalDateTime; +import java.util.List; + +public record FindDeliveryDetailResponse( + Long deliveryId, + DeliveryStatus deliveryStatus, + LocalDateTime arrivedAt, + String address, + String orderName, + int orderPrice, + String riderRequest, + int deliveryFee, + List items) { + + + public static FindDeliveryDetailResponse from(final Delivery delivery) { + List items = delivery.getOrder().getOrderItems().stream() + .map(OrderItemResponse::from) + .toList(); + return new FindDeliveryDetailResponse( + delivery.getDeliveryId(), + delivery.getDeliveryStatus(), + delivery.getArrivedAt(), + delivery.getAddress(), + delivery.getOrder().getName(), + delivery.getOrderPrice(), + delivery.getRiderRequest(), + delivery.getDeliveryFee(), + items); + } + + public record OrderItemResponse(String name, int quantity, int price) { + + public static OrderItemResponse from(final OrderItem orderItem) { + return new OrderItemResponse( + orderItem.getItem().getName(), + orderItem.getQuantity(), + orderItem.getItem().getPrice()); + } + } +} diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/repository/DeliveryRepository.java b/src/main/java/com/prgrms/nabmart/domain/delivery/repository/DeliveryRepository.java index e16bb28fe..27112e0f2 100644 --- a/src/main/java/com/prgrms/nabmart/domain/delivery/repository/DeliveryRepository.java +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/repository/DeliveryRepository.java @@ -41,4 +41,11 @@ Page findRiderDeliveries( List findAllByUser(@Param("user") User user); boolean existsByOrder(Order order); + + @Query("select d from Delivery d" + + " join fetch d.order o" + + " join fetch o.orderItems oi" + + " join fetch oi.item i" + + " where d.deliveryId = :deliveryId") + Optional findByIdWithOrderAndItems(@Param("deliveryId") Long deliveryId); } diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java b/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java index c1433e025..7969eae81 100644 --- a/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/service/DeliveryService.java @@ -6,6 +6,7 @@ import com.prgrms.nabmart.domain.delivery.Delivery; import com.prgrms.nabmart.domain.delivery.Rider; +import com.prgrms.nabmart.domain.delivery.controller.FindDeliveryDetailResponse; import com.prgrms.nabmart.domain.delivery.exception.AlreadyRegisteredDeliveryException; import com.prgrms.nabmart.domain.delivery.exception.NotFoundDeliveryException; import com.prgrms.nabmart.domain.delivery.exception.NotFoundRiderException; @@ -15,6 +16,7 @@ import com.prgrms.nabmart.domain.delivery.service.request.AcceptDeliveryCommand; import com.prgrms.nabmart.domain.delivery.service.request.CompleteDeliveryCommand; import com.prgrms.nabmart.domain.delivery.service.request.FindDeliveryByOrderCommand; +import com.prgrms.nabmart.domain.delivery.service.request.FindDeliveryDetailCommand; import com.prgrms.nabmart.domain.delivery.service.request.FindRiderDeliveriesCommand; import com.prgrms.nabmart.domain.delivery.service.request.FindWaitingDeliveriesCommand; import com.prgrms.nabmart.domain.delivery.service.request.RegisterDeliveryCommand; @@ -106,6 +108,21 @@ private void checkAuthority(final Delivery delivery, final User user) { } } + @Transactional(readOnly = true) + public FindDeliveryDetailResponse findDelivery( + FindDeliveryDetailCommand findDeliveryDetailCommand) { + Delivery delivery = findDeliveryByDeliveryIdWithOrderAndOrderItems( + findDeliveryDetailCommand); + return FindDeliveryDetailResponse.from(delivery); + } + + private Delivery findDeliveryByDeliveryIdWithOrderAndOrderItems( + FindDeliveryDetailCommand findDeliveryDetailCommand) { + return deliveryRepository.findByIdWithOrderAndItems( + findDeliveryDetailCommand.deliveryId()) + .orElseThrow(() -> new NotFoundDeliveryException("존재하지 않는 배달입니다.")); + } + @Transactional public void acceptDelivery(AcceptDeliveryCommand acceptDeliveryCommand) { Rider rider = findRiderByRiderId(acceptDeliveryCommand.riderId()); diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/service/request/FindDeliveryDetailCommand.java b/src/main/java/com/prgrms/nabmart/domain/delivery/service/request/FindDeliveryDetailCommand.java new file mode 100644 index 000000000..bdd41cd42 --- /dev/null +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/service/request/FindDeliveryDetailCommand.java @@ -0,0 +1,8 @@ +package com.prgrms.nabmart.domain.delivery.service.request; + +public record FindDeliveryDetailCommand(Long deliveryId) { + + public static FindDeliveryDetailCommand from(final Long deliveryId) { + return new FindDeliveryDetailCommand(deliveryId); + } +} diff --git a/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java b/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java index 5567aecac..91042bc79 100644 --- a/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/delivery/service/DeliveryServiceTest.java @@ -11,6 +11,7 @@ import com.prgrms.nabmart.domain.delivery.Delivery; import com.prgrms.nabmart.domain.delivery.DeliveryStatus; import com.prgrms.nabmart.domain.delivery.Rider; +import com.prgrms.nabmart.domain.delivery.controller.FindDeliveryDetailResponse; import com.prgrms.nabmart.domain.delivery.exception.AlreadyAssignedDeliveryException; import com.prgrms.nabmart.domain.delivery.exception.AlreadyRegisteredDeliveryException; import com.prgrms.nabmart.domain.delivery.exception.InvalidDeliveryException; @@ -22,6 +23,7 @@ import com.prgrms.nabmart.domain.delivery.service.request.AcceptDeliveryCommand; import com.prgrms.nabmart.domain.delivery.service.request.CompleteDeliveryCommand; import com.prgrms.nabmart.domain.delivery.service.request.FindDeliveryByOrderCommand; +import com.prgrms.nabmart.domain.delivery.service.request.FindDeliveryDetailCommand; import com.prgrms.nabmart.domain.delivery.service.request.FindRiderDeliveriesCommand; import com.prgrms.nabmart.domain.delivery.service.request.FindWaitingDeliveriesCommand; import com.prgrms.nabmart.domain.delivery.service.request.RegisterDeliveryCommand; @@ -31,8 +33,12 @@ import com.prgrms.nabmart.domain.delivery.service.response.FindRiderDeliveriesResponse.FindRiderDeliveryResponse; import com.prgrms.nabmart.domain.delivery.service.response.FindWaitingDeliveriesResponse; import com.prgrms.nabmart.domain.delivery.support.DeliveryFixture; +import com.prgrms.nabmart.domain.item.Item; +import com.prgrms.nabmart.domain.item.support.ItemFixture; import com.prgrms.nabmart.domain.notification.service.NotificationService; import com.prgrms.nabmart.domain.order.Order; +import com.prgrms.nabmart.domain.order.OrderItem; +import com.prgrms.nabmart.domain.order.OrderStatus; import com.prgrms.nabmart.domain.order.exception.NotFoundOrderException; import com.prgrms.nabmart.domain.order.repository.OrderRepository; import com.prgrms.nabmart.domain.order.support.OrderFixture; @@ -57,6 +63,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; +import org.springframework.test.util.ReflectionTestUtils; @ExtendWith(MockitoExtension.class) class DeliveryServiceTest { @@ -599,4 +606,59 @@ void throwExceptionWhenNotFoundRider() { .isInstanceOf(NotFoundRiderException.class); } } + + @Nested + @DisplayName("findDelivery 메서드 실행 시") + class FindDeliveryTest { + + Item item = ItemFixture.item(); + int orderItemQuantity = 5; + OrderItem orderItem = new OrderItem(item, orderItemQuantity); + Order order = new Order(user, List.of(orderItem)); + FindDeliveryDetailCommand findDeliveryDetailCommand = + new FindDeliveryDetailCommand(1L); + + @Test + @DisplayName("성공") + void success() { + //given + ReflectionTestUtils.setField(order, "status", OrderStatus.PAYED); + Delivery delivery = Delivery.builder() + .order(order) + .estimateMinutes(60) + .build(); + + given(deliveryRepository.findByIdWithOrderAndItems(any())).willReturn( + Optional.ofNullable(delivery)); + + //when + FindDeliveryDetailResponse result = deliveryService.findDelivery( + findDeliveryDetailCommand); + + //then + assertThat(result.deliveryStatus()).isEqualTo(delivery.getDeliveryStatus()); + assertThat(result.address()).isEqualTo(delivery.getAddress()); + assertThat(result.deliveryFee()).isEqualTo(delivery.getDeliveryFee()); + assertThat(result.arrivedAt()).isEqualTo(delivery.getArrivedAt()); + assertThat(result.orderName()).isEqualTo(order.getName()); + assertThat(result.riderRequest()).isEqualTo(delivery.getRiderRequest()); + assertThat(result.items()).hasSize(1); + assertThat(result.items().get(0).name()).isEqualTo(item.getName()); + assertThat(result.items().get(0).quantity()).isEqualTo(orderItemQuantity); + assertThat(result.items().get(0).name()).isEqualTo(item.getName()); + } + + @Test + @DisplayName("예외: 존재하지 않는 배달") + void throwExceptionWhenNotFoundDelivery() { + //given + given(deliveryRepository.findByIdWithOrderAndItems(any())).willReturn( + Optional.empty()); + + //when + //then + assertThatThrownBy(() -> deliveryService.findDelivery(findDeliveryDetailCommand)) + .isInstanceOf(NotFoundDeliveryException.class); + } + } } From 09c3d231b062cdc32a03baa4062d8682b8fa4d2e Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Thu, 21 Sep 2023 23:07:43 +0900 Subject: [PATCH 40/41] =?UTF-8?q?[NAYB-159]=20feat:=20=EB=B0=B0=EB=8B=AC?= =?UTF-8?q?=20=EC=83=81=EC=84=B8=20=EC=A1=B0=ED=9A=8C(=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EB=8D=94,=20=EC=A7=81=EC=9B=90)=20api=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DeliveryController.java | 11 ++++ .../controller/DeliveryControllerTest.java | 60 ++++++++++++++++++- 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryController.java b/src/main/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryController.java index b563712a4..684be67bf 100644 --- a/src/main/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryController.java +++ b/src/main/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryController.java @@ -9,6 +9,7 @@ import com.prgrms.nabmart.domain.delivery.service.request.AcceptDeliveryCommand; import com.prgrms.nabmart.domain.delivery.service.request.CompleteDeliveryCommand; import com.prgrms.nabmart.domain.delivery.service.request.FindDeliveryByOrderCommand; +import com.prgrms.nabmart.domain.delivery.service.request.FindDeliveryDetailCommand; import com.prgrms.nabmart.domain.delivery.service.request.FindRiderDeliveriesCommand; import com.prgrms.nabmart.domain.delivery.service.request.FindWaitingDeliveriesCommand; import com.prgrms.nabmart.domain.delivery.service.request.RegisterDeliveryCommand; @@ -68,6 +69,16 @@ public ResponseEntity findDeliveryByOrder( return ResponseEntity.ok(findDeliveryByOrderResponse); } + @GetMapping("/deliveries/{deliveryId}") + public ResponseEntity findDelivery( + @PathVariable final Long deliveryId) { + FindDeliveryDetailCommand findDeliveryDetailCommand + = FindDeliveryDetailCommand.from(deliveryId); + FindDeliveryDetailResponse findDeliveryDetailResponse = deliveryService.findDelivery( + findDeliveryDetailCommand); + return ResponseEntity.ok(findDeliveryDetailResponse); + } + @PatchMapping("/deliveries/{deliveryId}/accept") public ResponseEntity acceptDelivery( @PathVariable final Long deliveryId, diff --git a/src/test/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryControllerTest.java b/src/test/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryControllerTest.java index fe9096fd0..961174bd6 100644 --- a/src/test/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryControllerTest.java +++ b/src/test/java/com/prgrms/nabmart/domain/delivery/controller/DeliveryControllerTest.java @@ -22,6 +22,7 @@ import com.prgrms.nabmart.base.BaseControllerTest; import com.prgrms.nabmart.domain.delivery.DeliveryStatus; +import com.prgrms.nabmart.domain.delivery.controller.FindDeliveryDetailResponse.OrderItemResponse; import com.prgrms.nabmart.domain.delivery.controller.request.RegisterDeliveryRequest; import com.prgrms.nabmart.domain.delivery.controller.request.StartDeliveryRequest; import com.prgrms.nabmart.domain.delivery.exception.AlreadyAssignedDeliveryException; @@ -81,11 +82,11 @@ void registerDelivery() throws Exception { @Nested @DisplayName("배달 현황 조회 API 호출 시") - class FindDeliveryTest { + class FindDeliveryByOrderTest { @Test @DisplayName("성공") - void findDelivery() throws Exception { + void findDeliveryByOrder() throws Exception { //given Long orderId = 1L; FindDeliveryByOrderResponse findDeliveryByOrderResponse @@ -348,4 +349,59 @@ void findRiderDeliveries() throws Exception { )); } } + + @Nested + @DisplayName("배달 상세 조회(라이더, 직원) API 조회") + class FindDeliveryTest { + + @Test + @DisplayName("성공") + void findDelivery() throws Exception { + //given + Long deliveryId = 1L; + OrderItemResponse orderItemResponse = new OrderItemResponse("비비고 왕교자", 2, 5990); + FindDeliveryDetailResponse findDeliveryDetailResponse = new FindDeliveryDetailResponse( + 1L, + DeliveryStatus.ACCEPTING_ORDER, + LocalDateTime.now().plusMinutes(30), + "address", + "비비고 왕교자 외 2개", + 30000, + "배달 요청 사항", + 3000, + List.of(orderItemResponse)); + + given(deliveryService.findDelivery(any())).willReturn(findDeliveryDetailResponse); + + //when + ResultActions resultActions = mockMvc.perform( + get("/api/v1/deliveries/{deliveryId}", deliveryId) + .header(AUTHORIZATION, accessToken)); + + //then + resultActions.andExpect(status().isOk()) + .andDo(restDocs.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("액세스 토큰") + ), + pathParameters( + parameterWithName("deliveryId").description("배달 ID") + ), + responseFields( + fieldWithPath("deliveryId").type(NUMBER).description("배달 ID"), + fieldWithPath("deliveryStatus").type(STRING).description("배달 상태"), + fieldWithPath("arrivedAt").type(STRING).description("배달 예상 도착 시간"), + fieldWithPath("address").type(STRING).description("배달지 주소"), + fieldWithPath("orderName").type(STRING).description("주문 이름"), + fieldWithPath("orderPrice").type(NUMBER).description("주문 가격"), + fieldWithPath("riderRequest").type(STRING).description("배달 요청 사항"), + fieldWithPath("deliveryFee").type(NUMBER).description("배달비"), + fieldWithPath("items").type(ARRAY).description("상품 목록"), + fieldWithPath("items[].name").type(STRING).description("상품 이름"), + fieldWithPath("items[].quantity").type(NUMBER).description("상품 갯수"), + fieldWithPath("items[].price").type(NUMBER).description("상품 가격") + ) + )); + } + } } From 7dc2ebe09ac0fa7d3bad4c8daf9d3d28978c41ae Mon Sep 17 00:00:00 2001 From: hseong3243 Date: Thu, 21 Sep 2023 23:26:04 +0900 Subject: [PATCH 41/41] =?UTF-8?q?[NAYB-159]=20chore:=20=EB=B0=B0=EB=8B=AC?= =?UTF-8?q?=20=EC=83=81=EC=84=B8=20=EC=A1=B0=ED=9A=8C(=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EB=8D=94,=20=EC=A7=81=EC=9B=90)=20api=20=EC=A0=91=EA=B7=BC=20?= =?UTF-8?q?=EA=B6=8C=ED=95=9C=20=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/prgrms/nabmart/global/config/WebSecurityConfig.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/prgrms/nabmart/global/config/WebSecurityConfig.java b/src/main/java/com/prgrms/nabmart/global/config/WebSecurityConfig.java index 78d4f1ae9..962dc20ae 100644 --- a/src/main/java/com/prgrms/nabmart/global/config/WebSecurityConfig.java +++ b/src/main/java/com/prgrms/nabmart/global/config/WebSecurityConfig.java @@ -100,7 +100,8 @@ private RequestMatcher[] requestHasRoleRider() { private RequestMatcher[] requestHasRoleEmployee() { List requestMatchers = List.of( antMatcher(POST, "/api/v1/orders/*/deliveries"), - antMatcher(GET, "/api/v1/orders/payed") + antMatcher(GET, "/api/v1/orders/payed"), + antMatcher(GET, "/api/v1/deliveries/[0-9]+") ); return requestMatchers.toArray(RequestMatcher[]::new); }