From 4fda77d4f7673dd354f35f5d79cae08412514024 Mon Sep 17 00:00:00 2001 From: tkdgur0906 <39580658+tkdgur0906@users.noreply.github.com> Date: Mon, 2 Dec 2024 12:52:15 +0900 Subject: [PATCH 1/4] =?UTF-8?q?[BE]=20=EC=95=84=ED=8B=B0=ED=81=B4=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1,=20=EC=82=AD=EC=A0=9C=EB=A5=BC=20=EC=96=B4?= =?UTF-8?q?=EB=93=9C=EB=AF=BC=EB=A7=8C=20=EC=A0=91=EA=B7=BC=ED=95=98?= =?UTF-8?q?=EA=B2=8C=20=ED=95=9C=EB=8B=A4.=20(#1011)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../article/controller/ArticleController.java | 5 +- .../auth/config/AdminPrincipal.java | 11 +++++ .../AdminPrincipalArgumentResolver.java | 49 +++++++++++++++++++ .../global/config/WebMvcConfig.java | 2 + .../global/exception/ExceptionCode.java | 3 +- .../java/com/bang_ggood/user/domain/User.java | 16 ++++++ .../java/com/bang_ggood/AcceptanceTest.java | 14 ++++-- .../article/controller/ArticleE2ETest.java | 6 +-- .../auth/config/ArgumentResolverTest.java | 38 ++++++++++++-- .../auth/config/TestController.java | 6 +++ .../java/com/bang_ggood/user/UserFixture.java | 4 ++ 11 files changed, 142 insertions(+), 12 deletions(-) create mode 100644 backend/bang-ggood/src/main/java/com/bang_ggood/auth/config/AdminPrincipal.java create mode 100644 backend/bang-ggood/src/main/java/com/bang_ggood/auth/config/AdminPrincipalArgumentResolver.java diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/article/controller/ArticleController.java b/backend/bang-ggood/src/main/java/com/bang_ggood/article/controller/ArticleController.java index ba05787a9..171a5e4f7 100644 --- a/backend/bang-ggood/src/main/java/com/bang_ggood/article/controller/ArticleController.java +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/article/controller/ArticleController.java @@ -4,6 +4,7 @@ import com.bang_ggood.article.dto.response.ArticleResponse; import com.bang_ggood.article.dto.response.ArticlesResponses; import com.bang_ggood.article.service.ArticleService; +import com.bang_ggood.auth.config.AdminPrincipal; import com.bang_ggood.auth.config.AuthRequiredPrincipal; import com.bang_ggood.user.domain.User; import jakarta.validation.Valid; @@ -26,7 +27,7 @@ public ArticleController(ArticleService articleService) { } @PostMapping("/articles") - public ResponseEntity createArticle(@AuthRequiredPrincipal User user, + public ResponseEntity createArticle(@AdminPrincipal User user, @Valid @RequestBody ArticleCreateRequest request) { Long id = articleService.createArticle(request); return ResponseEntity.created(URI.create("/article/" + id)).build(); @@ -43,7 +44,7 @@ public ResponseEntity readArticles() { } @DeleteMapping("/articles/{id}") - public ResponseEntity deleteArticle(@AuthRequiredPrincipal User user, + public ResponseEntity deleteArticle(@AdminPrincipal User user, @PathVariable("id") Long id) { articleService.deleteArticle(id); return ResponseEntity.noContent().build(); diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/auth/config/AdminPrincipal.java b/backend/bang-ggood/src/main/java/com/bang_ggood/auth/config/AdminPrincipal.java new file mode 100644 index 000000000..ab31f2ae5 --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/auth/config/AdminPrincipal.java @@ -0,0 +1,11 @@ +package com.bang_ggood.auth.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface AdminPrincipal { +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/auth/config/AdminPrincipalArgumentResolver.java b/backend/bang-ggood/src/main/java/com/bang_ggood/auth/config/AdminPrincipalArgumentResolver.java new file mode 100644 index 000000000..7542d9805 --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/auth/config/AdminPrincipalArgumentResolver.java @@ -0,0 +1,49 @@ +package com.bang_ggood.auth.config; + +import com.bang_ggood.auth.controller.cookie.CookieResolver; +import com.bang_ggood.auth.service.AuthService; +import com.bang_ggood.global.exception.BangggoodException; +import com.bang_ggood.global.exception.ExceptionCode; +import com.bang_ggood.user.domain.User; +import com.bang_ggood.user.domain.UserType; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.core.MethodParameter; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +@Component +public class AdminPrincipalArgumentResolver implements HandlerMethodArgumentResolver { + + private final CookieResolver cookieResolver; + private final AuthService authService; + + public AdminPrincipalArgumentResolver(CookieResolver cookieResolver, AuthService authService) { + this.cookieResolver = cookieResolver; + this.authService = authService; + } + + @Override + public boolean supportsParameter(MethodParameter parameter) { + return User.class.isAssignableFrom(parameter.getParameterType()) + && parameter.hasParameterAnnotation(AdminPrincipal.class); + } + + @Override + public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, + NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { + HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest(); + + cookieResolver.checkLoginRequired(request); + + String token = cookieResolver.extractAccessToken(request); + + User user = authService.getAuthUser(token); + if (!user.matchesUserType(UserType.ADMIN)) { + throw new BangggoodException(ExceptionCode.UNAUTHORIZED_ACCESS); + } + return user; + } +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/global/config/WebMvcConfig.java b/backend/bang-ggood/src/main/java/com/bang_ggood/global/config/WebMvcConfig.java index 2caa09c3e..ea9f95b92 100644 --- a/backend/bang-ggood/src/main/java/com/bang_ggood/global/config/WebMvcConfig.java +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/global/config/WebMvcConfig.java @@ -1,5 +1,6 @@ package com.bang_ggood.global.config; +import com.bang_ggood.auth.config.AdminPrincipalArgumentResolver; import com.bang_ggood.auth.config.AuthRequiredPrincipalArgumentResolver; import com.bang_ggood.auth.config.UserPrincipalArgumentResolver; import com.bang_ggood.auth.controller.cookie.CookieResolver; @@ -24,5 +25,6 @@ public WebMvcConfig(CookieResolver cookieResolver, AuthService authService) { public void addArgumentResolvers(List resolvers) { resolvers.add(new AuthRequiredPrincipalArgumentResolver(cookieResolver, authService)); resolvers.add(new UserPrincipalArgumentResolver(cookieResolver, authService)); + resolvers.add(new AdminPrincipalArgumentResolver(cookieResolver, authService)); } } diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/global/exception/ExceptionCode.java b/backend/bang-ggood/src/main/java/com/bang_ggood/global/exception/ExceptionCode.java index 620d7011e..3fd94e48e 100644 --- a/backend/bang-ggood/src/main/java/com/bang_ggood/global/exception/ExceptionCode.java +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/global/exception/ExceptionCode.java @@ -96,7 +96,8 @@ public enum ExceptionCode { "카카오 서버와 통신하는 과정 중 예상치 못한 예외가 발생했습니다."), OAUTH_REDIRECT_URI_MISMATCH(HttpStatus.BAD_REQUEST, ClientExceptionCode.OAUTH_SERVER_ERROR, "일치하는 Redirect URI가 존재하지 않습니다."), - + UNAUTHORIZED_ACCESS(HttpStatus.UNAUTHORIZED, ClientExceptionCode.UNAUTH_ERROR, + "권한이 없는 사용자입니다. 접근이 제한되었습니다."), // Article ARTICLE_NOT_FOUND(HttpStatus.BAD_REQUEST, ClientExceptionCode.ARTICLE_NOT_FOUND, "해당 아티클이 존재하지 않습니다."), diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/user/domain/User.java b/backend/bang-ggood/src/main/java/com/bang_ggood/user/domain/User.java index 164733012..fc8f47965 100644 --- a/backend/bang-ggood/src/main/java/com/bang_ggood/user/domain/User.java +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/user/domain/User.java @@ -68,6 +68,10 @@ public boolean isDifferent(String targetPassword) { return password.isDifferent(targetPassword); } + public boolean matchesUserType(UserType userType) { + return this.userType == userType; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -84,4 +88,16 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(id); } + + @Override + public String toString() { + return "User{" + + "id=" + id + + ", name='" + name + '\'' + + ", email=" + email + + ", password=" + password + + ", userType=" + userType + + ", loginType=" + loginType + + '}'; + } } diff --git a/backend/bang-ggood/src/test/java/com/bang_ggood/AcceptanceTest.java b/backend/bang-ggood/src/test/java/com/bang_ggood/AcceptanceTest.java index 1059973e7..47acdbcb9 100644 --- a/backend/bang-ggood/src/test/java/com/bang_ggood/AcceptanceTest.java +++ b/backend/bang-ggood/src/test/java/com/bang_ggood/AcceptanceTest.java @@ -24,6 +24,7 @@ public abstract class AcceptanceTest extends IntegrationTestSupport { protected Headers headers; + protected Headers adminHeaders; @Autowired private JwtTokenProvider jwtTokenProvider; @Autowired @@ -46,12 +47,19 @@ private void setPort() { private void setResponseCookie() { authenticatedUser = userRepository.save(UserFixture.USER1); - String accessToken = jwtTokenProvider.createAccessToken(authenticatedUser); - String refreshToken = jwtTokenProvider.createRefreshToken(authenticatedUser); + headers = createHeaders(authenticatedUser); + adminHeaders = createHeaders(UserFixture.ADMIN_USER1()); + } + + private Headers createHeaders(User user) { + User createdUser = userRepository.save(user); + String accessToken = jwtTokenProvider.createAccessToken(createdUser); + String refreshToken = jwtTokenProvider.createRefreshToken(createdUser); + ResponseCookie accessTokenResponseCookie = cookieProvider.createAccessTokenCookie(accessToken); ResponseCookie refreshTokenCookie = cookieProvider.createRefreshTokenCookie(refreshToken); - headers = new Headers(new Header(HttpHeaders.COOKIE, accessTokenResponseCookie.toString()), + return new Headers(new Header(HttpHeaders.COOKIE, accessTokenResponseCookie.toString()), new Header(HttpHeaders.COOKIE, refreshTokenCookie.toString())); } diff --git a/backend/bang-ggood/src/test/java/com/bang_ggood/article/controller/ArticleE2ETest.java b/backend/bang-ggood/src/test/java/com/bang_ggood/article/controller/ArticleE2ETest.java index 28c9b92dc..be3db4228 100644 --- a/backend/bang-ggood/src/test/java/com/bang_ggood/article/controller/ArticleE2ETest.java +++ b/backend/bang-ggood/src/test/java/com/bang_ggood/article/controller/ArticleE2ETest.java @@ -25,7 +25,7 @@ public class ArticleE2ETest extends AcceptanceTest { void createArticle() { RestAssured.given().log().all() .contentType(ContentType.JSON) - .headers(this.headers) + .headers(this.adminHeaders) .body(ArticleFixture.ARTICLE_CREATE_REQUEST()) .when().post("/articles") .then().log().all() @@ -54,7 +54,7 @@ void createArticle_titleBlank_exception() { RestAssured.given().log().all() .contentType(ContentType.JSON) - .headers(this.headers) + .headers(this.adminHeaders) .body(request) .when().post("/articles") .then().log().all() @@ -104,7 +104,7 @@ void deleteArticle() { Article article = articleRepository.save(ArticleFixture.ARTICLE()); RestAssured.given().log().all() .contentType(ContentType.JSON) - .headers(this.headers) + .headers(this.adminHeaders) .when().delete("/articles/" + article.getId()) .then().log().all() .statusCode(204); diff --git a/backend/bang-ggood/src/test/java/com/bang_ggood/auth/config/ArgumentResolverTest.java b/backend/bang-ggood/src/test/java/com/bang_ggood/auth/config/ArgumentResolverTest.java index 7448f42ab..ae5f5ff96 100644 --- a/backend/bang-ggood/src/test/java/com/bang_ggood/auth/config/ArgumentResolverTest.java +++ b/backend/bang-ggood/src/test/java/com/bang_ggood/auth/config/ArgumentResolverTest.java @@ -2,6 +2,7 @@ import com.bang_ggood.AcceptanceTest; import com.bang_ggood.auth.controller.cookie.CookieProvider; +import com.bang_ggood.auth.service.jwt.JwtTokenProvider; import com.bang_ggood.global.exception.ExceptionCode; import com.bang_ggood.user.UserFixture; import com.bang_ggood.user.domain.User; @@ -10,13 +11,13 @@ import io.restassured.RestAssured; import io.restassured.http.ContentType; import io.restassured.http.Header; -import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseCookie; +import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.containsString; class ArgumentResolverTest extends AcceptanceTest { @@ -25,6 +26,8 @@ class ArgumentResolverTest extends AcceptanceTest { private CookieProvider cookieProvider; @Autowired private UserRepository userRepository; + @Autowired + private JwtTokenProvider jwtTokenProvider; @DisplayName("@UserPrincipal 어노테이션 동작 성공 : 토큰값이 없으면 게스트 유저가 할당된다.") @Test @@ -40,7 +43,7 @@ void resolveUserPrincipalArgument_returnGuestUser() { .extract().as(User.class); // then - Assertions.assertThat(user.getUserType()).isEqualTo(UserType.GUEST); + assertThat(user.getUserType()).isEqualTo(UserType.GUEST); } @DisplayName("@UserPrincipal 어노테이션 동작 성공 : 토큰값이 있으면 인증된 유저를 할당한다.") @@ -56,7 +59,7 @@ void resolveUserPrincipalArgument_returnUser() { .extract().as(User.class); // then - Assertions.assertThat(user.getUserType()).isEqualTo(UserType.USER); + assertThat(user.getUserType()).isEqualTo(UserType.USER); } @DisplayName("@AuthPrincipal 어노테이션 동작 성공 : 쿠키값이 없으면 예외를 발생시킨다.") @@ -115,4 +118,33 @@ void resolveAuthPrincipalArgument_throwException_whenRefreshTokenEmpty() { .statusCode(401) .body("message", containsString(ExceptionCode.AUTHENTICATION_REFRESH_TOKEN_EMPTY.getMessage())); } + + @DisplayName("@AdminPrincipal 어노테이션 동작 성공 : Admin 유저인 경우") + @Test + void resolveAdminPrincipalArgument_returnUser() { + // given & when + User user = RestAssured.given().log().all() + .contentType(ContentType.JSON) + .headers(this.adminHeaders) + .when().get(TestController.ADMIN_PRINCIPAL_URL) + .then().log().all() + .statusCode(200) + .extract().as(User.class); + + // then + assertThat(user.getUserType()).isEqualTo(UserType.ADMIN); + } + + @DisplayName("@AdminPrincipal 어노테이션 동작 성공 : Admin 유저가 아닌 경우") + @Test + void resolveAdminPrincipalArgument_notAdmin_exception() { + // given & when & then + RestAssured.given().log().all() + .contentType(ContentType.JSON) + .headers(this.headers) + .when().get(TestController.ADMIN_PRINCIPAL_URL) + .then().log().all() + .statusCode(401) + .body("message", containsString(ExceptionCode.UNAUTHORIZED_ACCESS.getMessage())); + } } diff --git a/backend/bang-ggood/src/test/java/com/bang_ggood/auth/config/TestController.java b/backend/bang-ggood/src/test/java/com/bang_ggood/auth/config/TestController.java index 81bf4bf8b..f7a6e1f6a 100644 --- a/backend/bang-ggood/src/test/java/com/bang_ggood/auth/config/TestController.java +++ b/backend/bang-ggood/src/test/java/com/bang_ggood/auth/config/TestController.java @@ -9,6 +9,7 @@ public class TestController { public static final String USER_PRINCIPAL_URL = "/test/user-principal"; public static final String AUTH_PRINCIPAL_URL = "/test/auth-principal"; + public static final String ADMIN_PRINCIPAL_URL = "/test/admin-principal"; @GetMapping(USER_PRINCIPAL_URL) public User testUserPrincipal(@UserPrincipal User user) { @@ -19,4 +20,9 @@ public User testUserPrincipal(@UserPrincipal User user) { public User testAuthPrincipal(@AuthRequiredPrincipal User user) { return user; } + + @GetMapping(ADMIN_PRINCIPAL_URL) + public User testAdminPrincipal(@AdminPrincipal User user) { + return user; + } } diff --git a/backend/bang-ggood/src/test/java/com/bang_ggood/user/UserFixture.java b/backend/bang-ggood/src/test/java/com/bang_ggood/user/UserFixture.java index 2e84fd375..07d02824b 100644 --- a/backend/bang-ggood/src/test/java/com/bang_ggood/user/UserFixture.java +++ b/backend/bang-ggood/src/test/java/com/bang_ggood/user/UserFixture.java @@ -28,6 +28,10 @@ public static User GUEST_USER2() { return new User("빵빵이", "bbang-bbang2@gmail.com", UserType.GUEST, LoginType.LOCAL); } + public static User ADMIN_USER1() { + return new User("어드민방방이", "admin-bang-bang1@gmail.com", UserType.ADMIN, LoginType.LOCAL); + } + public static User USER1_WITH_ID() { return new User(1L, "방방이", "bang-bang@gmail.com"); } From d41eadc1d38db9e8eabda378163c1377b5a2f0ee Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Thu, 5 Dec 2024 15:45:39 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=B4=88=EA=B8=B0=ED=99=94=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=EB=A9=94=EC=84=9C=EB=93=9C=20=ED=8A=B8?= =?UTF-8?q?=EB=9E=9C=EC=9E=AD=EC=85=98=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/repository/PasswordResetCodeRepository.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/auth/repository/PasswordResetCodeRepository.java b/backend/bang-ggood/src/main/java/com/bang_ggood/auth/repository/PasswordResetCodeRepository.java index b22fa67f0..6e3469495 100644 --- a/backend/bang-ggood/src/main/java/com/bang_ggood/auth/repository/PasswordResetCodeRepository.java +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/auth/repository/PasswordResetCodeRepository.java @@ -5,8 +5,10 @@ import com.bang_ggood.global.exception.ExceptionCode; import com.bang_ggood.user.domain.Email; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; import java.util.Optional; @@ -31,7 +33,11 @@ default PasswordResetCode getByEmailAndCodeAndCreatedAtAfter(@Param("email") Ema long countByEmail(Email email); + @Transactional + @Modifying(flushAutomatically = true, clearAutomatically = true) void deleteByEmailAndCode(Email email, String code); + @Transactional + @Modifying(flushAutomatically = true, clearAutomatically = true) void deleteByEmail(Email email); } From d2cf519a82a7c76f060beaf51236c3639fc4f276 Mon Sep 17 00:00:00 2001 From: jinwoo22 <98975580+JINU-CHANG@users.noreply.github.com> Date: Fri, 6 Dec 2024 12:45:41 +0900 Subject: [PATCH 3/4] =?UTF-8?q?[BE]=20=EC=B2=B4=ED=81=AC=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=9E=91=EC=84=B1,=20=EC=88=98=EC=A0=95=20API=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=EC=8B=9C=20=EC=A4=91=EB=B3=B5=EB=90=9C=20?= =?UTF-8?q?=EC=9C=84=EB=8F=84,=20=EA=B2=BD=EB=8F=84=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=EB=A5=BC=20=EC=82=AD=EC=A0=9C=ED=95=9C=EB=8B=A4.=20(#1022)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/request/ChecklistRequestV1.java | 4 +--- .../service/ChecklistManageService.java | 17 ++++++++--------- .../dto/request/ChecklistStationRequest.java | 8 -------- .../bang_ggood/checklist/ChecklistFixture.java | 7 ++----- 4 files changed, 11 insertions(+), 25 deletions(-) delete mode 100644 backend/bang-ggood/src/main/java/com/bang_ggood/station/dto/request/ChecklistStationRequest.java diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/request/ChecklistRequestV1.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/request/ChecklistRequestV1.java index 03edc011b..9f243fdbc 100644 --- a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/request/ChecklistRequestV1.java +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/request/ChecklistRequestV1.java @@ -2,13 +2,11 @@ import com.bang_ggood.question.dto.request.QuestionRequest; import com.bang_ggood.room.dto.request.RoomRequest; -import com.bang_ggood.station.dto.request.ChecklistStationRequest; import jakarta.validation.Valid; import java.util.List; public record ChecklistRequestV1(@Valid RoomRequest room, List options, - @Valid List questions, - ChecklistStationRequest geolocation) { + @Valid List questions) { public ChecklistRequest toChecklistRequest() { return new ChecklistRequest(room, options, questions); diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/service/ChecklistManageService.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/service/ChecklistManageService.java index dc073d457..736b5535a 100644 --- a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/service/ChecklistManageService.java +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/service/ChecklistManageService.java @@ -30,10 +30,10 @@ import com.bang_ggood.question.service.ChecklistQuestionService; import com.bang_ggood.question.service.QuestionService; import com.bang_ggood.room.domain.Room; +import com.bang_ggood.room.dto.request.RoomRequest; import com.bang_ggood.room.dto.response.SelectedRoomResponse; import com.bang_ggood.room.service.RoomService; import com.bang_ggood.station.domain.ChecklistStation; -import com.bang_ggood.station.dto.request.ChecklistStationRequest; import com.bang_ggood.station.dto.response.SubwayStationResponse; import com.bang_ggood.station.dto.response.SubwayStationResponses; import com.bang_ggood.station.service.ChecklistStationService; @@ -78,7 +78,7 @@ public Long createChecklistV1(User user, ChecklistRequestV1 checklistRequestV1) createChecklistOptions(checklistRequest, checklist); createChecklistQuestions(checklistRequest, checklist); createChecklistMaintenances(checklistRequest, checklist); - createChecklistStation(checklistRequestV1, checklist); + createChecklistStation(checklistRequestV1.room(), checklist); return checklist.getId(); } @@ -108,9 +108,8 @@ private void createChecklistMaintenances(ChecklistRequest checklistRequest, Chec checklistMaintenanceService.createMaintenances(checklistMaintenances); } - private void createChecklistStation(ChecklistRequestV1 checklistRequestV1, Checklist checklist) { - ChecklistStationRequest geolocation = checklistRequestV1.geolocation(); - checklistStationService.createChecklistStations(checklist, geolocation.latitude(), geolocation.longitude()); + private void createChecklistStation(RoomRequest roomRequest, Checklist checklist) { + checklistStationService.createChecklistStations(checklist, roomRequest.latitude(), roomRequest.longitude()); } @Transactional(readOnly = true) @@ -318,7 +317,7 @@ public void updateChecklistByIdV1(User user, Long checklistId, ChecklistRequestV updateChecklistOptions(checklistRequest, checklist); updateChecklistQuestions(checklistRequest, checklist); updateChecklistMaintenances(checklistRequest, checklist); - updateChecklistStations(checklistRequestV1, checklist); + updateChecklistStations(checklistRequestV1.room(), checklist); } private void updateChecklistOptions(ChecklistRequest checklistRequest, Checklist checklist) { @@ -349,9 +348,9 @@ private void updateChecklistMaintenances(ChecklistRequest checklistRequest, Chec checklistMaintenanceService.updateMaintenances(checklist.getId(), checklistMaintenances); } - private void updateChecklistStations(ChecklistRequestV1 checklistRequestV1, Checklist checklist) { - double latitude = checklistRequestV1.geolocation().latitude(); - double longitude = checklistRequestV1.geolocation().longitude(); + private void updateChecklistStations(RoomRequest roomRequest, Checklist checklist) { + double latitude = roomRequest.latitude(); + double longitude = roomRequest.longitude(); checklistStationService.updateChecklistStation(checklist, latitude, longitude); } } diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/station/dto/request/ChecklistStationRequest.java b/backend/bang-ggood/src/main/java/com/bang_ggood/station/dto/request/ChecklistStationRequest.java deleted file mode 100644 index 4b4db9c47..000000000 --- a/backend/bang-ggood/src/main/java/com/bang_ggood/station/dto/request/ChecklistStationRequest.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.bang_ggood.station.dto.request; - -public record ChecklistStationRequest(double latitude, double longitude) { - - public static ChecklistStationRequest of(double latitude, double longitude) { - return new ChecklistStationRequest(latitude, longitude); - } -} diff --git a/backend/bang-ggood/src/test/java/com/bang_ggood/checklist/ChecklistFixture.java b/backend/bang-ggood/src/test/java/com/bang_ggood/checklist/ChecklistFixture.java index 1d8c9a6f3..6fce11f6d 100644 --- a/backend/bang-ggood/src/test/java/com/bang_ggood/checklist/ChecklistFixture.java +++ b/backend/bang-ggood/src/test/java/com/bang_ggood/checklist/ChecklistFixture.java @@ -13,7 +13,6 @@ import com.bang_ggood.question.dto.request.QuestionRequest; import com.bang_ggood.room.RoomFixture; import com.bang_ggood.room.domain.Room; -import com.bang_ggood.station.dto.request.ChecklistStationRequest; import com.bang_ggood.user.UserFixture; import com.bang_ggood.user.domain.User; import java.util.List; @@ -124,8 +123,7 @@ public static ChecklistRequestV1 CHECKLIST_CREATE_REQUEST_V1() { List.of(Option.REFRIGERATOR.getId(), Option.SINK.getId(), Option.INDUCTION.getId(), Option.SHOE_RACK.getId()), List.of(QUESTION_1_CREATE_REQUEST(), QUESTION_2_CREATE_REQUEST(), - QUESTION_3_CREATE_REQUEST(), QUESTION_5_CREATE_REQUEST()), - ChecklistStationRequest.of(38, 127) + QUESTION_3_CREATE_REQUEST(), QUESTION_5_CREATE_REQUEST()) ); } @@ -162,8 +160,7 @@ public static ChecklistRequestV1 CHECKLIST_UPDATE_REQUEST_V1() { RoomFixture.ROOM_UPDATE_REQUEST(), List.of(Option.REFRIGERATOR.getId(), Option.INDUCTION.getId(), Option.BED.getId(), Option.WASHING_MACHINE.getId()), List.of(QUESTION_1_CREATE_REQUEST(), QUESTION_2_CREATE_REQUEST(), - QUESTION_3_CREATE_REQUEST(), QUESTION_5_UPDATE_REQUEST()), - ChecklistStationRequest.of(37.5, 127.1) + QUESTION_3_CREATE_REQUEST(), QUESTION_5_UPDATE_REQUEST()) ); } From 5ec0b4931da125b409d9b64442ca98701499c54d Mon Sep 17 00:00:00 2001 From: jinwoo22 <98975580+JINU-CHANG@users.noreply.github.com> Date: Fri, 6 Dec 2024 15:19:10 +0900 Subject: [PATCH 4/4] =?UTF-8?q?[BE]=20=EC=95=84=ED=8B=B0=ED=81=B4=20?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=EA=B0=80=20=EC=BA=90=EC=8B=9C?= =?UTF-8?q?=EB=90=98=EC=A7=80=20=EC=95=8A=EB=8F=84=EB=A1=9D=20=ED=95=9C?= =?UTF-8?q?=EB=8B=A4.=20(#1029)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: shin-jisong --- .../article/service/ArticleService.java | 6 +++--- .../bang_ggood/global/cache/CacheTest.java | 20 ++++++++++--------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/article/service/ArticleService.java b/backend/bang-ggood/src/main/java/com/bang_ggood/article/service/ArticleService.java index f9c8b82c2..b9761998a 100644 --- a/backend/bang-ggood/src/main/java/com/bang_ggood/article/service/ArticleService.java +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/article/service/ArticleService.java @@ -6,14 +6,14 @@ import com.bang_ggood.article.dto.response.ArticlesResponse; import com.bang_ggood.article.dto.response.ArticlesResponses; import com.bang_ggood.article.repository.ArticleRepository; -import com.bang_ggood.global.config.cache.CacheName; import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; -import static com.bang_ggood.global.config.cache.CacheName.*; +import static com.bang_ggood.global.config.cache.CacheName.ARTICLE; @RequiredArgsConstructor @Service @@ -35,7 +35,6 @@ public ArticleResponse readArticle(Long id) { return ArticleResponse.from(article); } - @Cacheable(cacheNames = ARTICLE, key = "'articles'") @Transactional(readOnly = true) public ArticlesResponses readArticles() { List articles = articleRepository.findLatestArticles().stream() @@ -44,6 +43,7 @@ public ArticlesResponses readArticles() { return new ArticlesResponses(articles); } + @CacheEvict(cacheNames = ARTICLE, key = "#id") @Transactional public void deleteArticle(Long id) { articleRepository.deleteById(id); diff --git a/backend/bang-ggood/src/test/java/com/bang_ggood/global/cache/CacheTest.java b/backend/bang-ggood/src/test/java/com/bang_ggood/global/cache/CacheTest.java index 2fbc26f34..96999054a 100644 --- a/backend/bang-ggood/src/test/java/com/bang_ggood/global/cache/CacheTest.java +++ b/backend/bang-ggood/src/test/java/com/bang_ggood/global/cache/CacheTest.java @@ -1,7 +1,7 @@ package com.bang_ggood.global.cache; import com.bang_ggood.article.domain.Article; -import com.bang_ggood.article.dto.response.ArticlesResponses; +import com.bang_ggood.article.dto.response.ArticleResponse; import com.bang_ggood.article.repository.ArticleRepository; import com.bang_ggood.article.service.ArticleService; import org.junit.jupiter.api.BeforeEach; @@ -12,7 +12,6 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.ActiveProfiles; -import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -26,22 +25,25 @@ class CacheTest { @Autowired private ArticleService articleService; + private final Long cacheableArticleId = 1L; + private Article article; + @BeforeEach void setUp() { - Article article = new Article("이름", "내용", "키워드", "요약", "썸네일"); - Mockito.when(articleRepository.findLatestArticles()) - .thenReturn(List.of(article)); + article = new Article("이름", "내용", "키워드", "요약", "썸네일"); + Mockito.when(articleRepository.getById(cacheableArticleId)) + .thenReturn(article); } @DisplayName("캐시가 정상적으로 작동한다.") @Test void cacheTest() { - ArticlesResponses firstCallArticles = articleService.readArticles(); - ArticlesResponses secondCallArticles = articleService.readArticles(); + ArticleResponse firstCallArticle = articleService.readArticle(cacheableArticleId); + ArticleResponse secondCallArticle = articleService.readArticle(cacheableArticleId); - Mockito.verify(articleRepository, Mockito.times(1)).findLatestArticles(); + Mockito.verify(articleRepository, Mockito.times(1)).getById(cacheableArticleId); - assertThat(firstCallArticles).isEqualTo(secondCallArticles); + assertThat(firstCallArticle).isEqualTo(secondCallArticle); } }