From 8646b1ab6ca01c586fd34f598e593576e72610bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A4=80=ED=8C=8D=28junpak=29?= <112045553+junpakPark@users.noreply.github.com> Date: Tue, 18 Jul 2023 13:49:45 +0900 Subject: [PATCH 01/35] =?UTF-8?q?[Docs]=20GitHub=20Issue=20=EB=B0=8F=20PR?= =?UTF-8?q?=20Template=20=EC=84=A4=EC=A0=95=20(#37)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: .gitignore 추가 * chore: GitHub PR 및 Issue Template * Revert "chore: GitHub PR 및 Issue Template" This reverts commit 65915f72740bbf22899ef7ac52fefa99cde96a8b. * Revert "chore: .gitignore 추가" This reverts commit 1e1865a1cb7f0a279b4e74c12cd0f66631809ff3. * chore: .gitignore 추가 * chore: GitHub Issue 및 PR Template 추가 --- .github/ISSUE_TEMPLATE/bug.yml | 44 ++++++++++++++++++++++++++++ .github/ISSUE_TEMPLATE/deploy.yml | 28 ++++++++++++++++++ .github/ISSUE_TEMPLATE/env.yml | 28 ++++++++++++++++++ .github/ISSUE_TEMPLATE/feat.yml | 28 ++++++++++++++++++ .github/ISSUE_TEMPLATE/meeting.yml | 36 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/refactor.yml | 28 ++++++++++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 21 +++++++++++++ .gitignore | 41 ++++++++++++++++++++++++++ 8 files changed, 254 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug.yml create mode 100644 .github/ISSUE_TEMPLATE/deploy.yml create mode 100644 .github/ISSUE_TEMPLATE/env.yml create mode 100644 .github/ISSUE_TEMPLATE/feat.yml create mode 100644 .github/ISSUE_TEMPLATE/meeting.yml create mode 100644 .github/ISSUE_TEMPLATE/refactor.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .gitignore diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 000000000..ba8e60888 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,44 @@ +name: "bug" +description: "버그 발생 시" +labels: "bug" +body: + - type: textarea + attributes: + label: 🐞버그 설명 + description: 버그에 대한 설명을 작성해 주세요. + placeholder: 자세히 적을수록 좋습니다! + validations: + required: true + - type: textarea + attributes: + label: 📄 버그 로그 + description: 로그가 있으면 입력해 주세요. + render: shell + validations: + required: false + - type: textarea + attributes: + label: 🌏 버그 발생 환경 + description: 버그가 발생한 환경에 대해 작성해 주세요. + placeholder: | + OS: macOS + validations: + required: true + - type: textarea + attributes: + label: ✅ 버그 재현 방법 + description: Given-When-Then 형식으로 버그를 재현할 수 있는 방법에 대해 작성해 주세요. + validations: + required: false + - type: textarea + attributes: + label: 📎 참고 자료 + description: 발생한 버그에 대한 참고 자료가 있다면 작성해 주세요. + validations: + required: false + - type: textarea + attributes: + label: ⏰ 추정 시간 + description: 버그를 해결하기 위한 추정 시간(비관적 추정, 낙관적 추정)에 대해 작성해주세요. + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/deploy.yml b/.github/ISSUE_TEMPLATE/deploy.yml new file mode 100644 index 000000000..778c62372 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/deploy.yml @@ -0,0 +1,28 @@ +name: "deploy" +description: "배포 시" +labels: "deploy" +body: + - type: textarea + attributes: + label: 📄 작업 설명 + description: 배포에 대한 설명을 작성해 주세요. + placeholder: 자세히 적을수록 좋습니다! + validations: + required: true + - type: textarea + attributes: + label: ✅ 작업 내용 + description: 배포에 대한 Tasks를 작성해 주세요. + placeholder: 최대한 세분화 해서 적어주세요! + validations: + required: true + - type: textarea + attributes: + label: 📎 참고 자료 + description: 배포에 대한 참고 자료가 있다면 작성해 주세요. + - type: textarea + attributes: + label: ⏰ 추정 시간 + description: 배포를 위한 추정 시간(비관적 추정, 낙관적 추정)에 대해 작성해주세요. + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/env.yml b/.github/ISSUE_TEMPLATE/env.yml new file mode 100644 index 000000000..af06b0b4e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/env.yml @@ -0,0 +1,28 @@ +name: "env" +description: "환경 설정 시" +labels: "env" +body: + - type: textarea + attributes: + label: 📄 작업 대상 + description: 작업할 환경 설정에 대해 설명해 주세요. + placeholder: 자세히 적을수록 좋습니다! + validations: + required: true + - type: textarea + attributes: + label: ✅ 작업할 내용 + description: 환경 설정에 대한 Tasks를 작성해주세요. + placeholder: 최대한 세분화 해서 적어주세요! + validations: + required: true + - type: textarea + attributes: + label: 📎 참고 자료 + description: 환경 설정에 대한 참고 자료가 있다면 작성해 주세요. + - type: textarea + attributes: + label: ⏰ 추정 시간 + description: 환경설정을 추가하기 위한 추정 시간(비관적 추정, 낙관적 추정)에 대해 작성해주세요. + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/feat.yml b/.github/ISSUE_TEMPLATE/feat.yml new file mode 100644 index 000000000..5abde3749 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feat.yml @@ -0,0 +1,28 @@ +name: "feat" +description: "기능 추가 시" +labels: "feat" +body: + - type: textarea + attributes: + label: 📄 작업 대상 + description: 작업할 기능에 대한 설명을 작성해 주세요. + placeholder: 자세히 적을수록 좋습니다! + validations: + required: true + - type: textarea + attributes: + label: ✅ 작업 내용 + description: 기능 구현에 대한 Tasks를 작성해 주세요. + placeholder: 최대한 세분화 해서 적어주세요! + validations: + required: true + - type: textarea + attributes: + label: 📎 참고 자료 + description: 새로운 기능에 대한 참고 자료가 있다면 URL을 작성해 주세요. + - type: textarea + attributes: + label: ⏰ 추정 시간 + description: 새로운 기능을 추가하기 위한 추정 시간(비관적 추정, 낙관적 추정)에 대해 작성해주세요. + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/meeting.yml b/.github/ISSUE_TEMPLATE/meeting.yml new file mode 100644 index 000000000..d07e0f303 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/meeting.yml @@ -0,0 +1,36 @@ +name: "meeting" +description: "회의 시" +labels: "meeting" +body: + - type: textarea + attributes: + label: 📝 설명 + description: 회의 주제에 대한 설명을 작성해 주세요. + placeholder: 자세히 적을수록 좋습니다! + validations: + required: true + - type: textarea + attributes: + label: 🙋🏻 참가 인원 + validations: + required: true + description: 회의에 참여할 인원 및 역할(진행자, 서기)을 작성해 주세요. + - type: textarea + attributes: + label: ⏰ 회의 시간 + validations: + required: true + description: 회의 날짜와 시간을 입력해 주세요. + - type: textarea + attributes: + label: ✅ 회의 안건 + description: 해야 하는 일에 대한 Tasks를 작성해 주세요. + placeholder: 최대한 세분화 해서 적어 주세요! + validations: + required: true + - type: textarea + attributes: + label: ⏰ 추정 시간 + description: 회의를 진행하는데 필요한 추정 시간(비관적 추정, 낙관적 추정)에 대해 작성해주세요. + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/refactor.yml b/.github/ISSUE_TEMPLATE/refactor.yml new file mode 100644 index 000000000..ae5d0d05a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/refactor.yml @@ -0,0 +1,28 @@ +name: "refactor" +description: "리팩터링 시" +labels: "refactor" +body: + - type: textarea + attributes: + label: 🛠️ 작업 대상 + description: 리팩터링에 해야할 범위를 설명해 주세요. + placeholder: 자세히 적을수록 좋습니다! + validations: + required: true + - type: textarea + attributes: + label: ✅ 작업 내용 + description: 리팩터링을 할 부분에 대한 Tasks를 작성해 주세요. + placeholder: 최대한 세분화 해서 적어주세요! + validations: + required: true + - type: textarea + attributes: + label: 📎 참고 자료 + description: 리팩터링에 대한 참고 자료가 있다면 작성해 주세요. + - type: textarea + attributes: + label: ⏰ 추정 시간 + description: 리펙토링을 위한 추정 시간(비관적 추정, 낙관적 추정)에 대해 작성해주세요. + validations: + required: true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..3f5b9136e --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,21 @@ + + +## 작업 대상 + + +## 📄 작업 내용 + + +## 🙋🏻 주의 사항 + + +## 스크린샷 + + +## 📎 관련 이슈 + + + + +## 레퍼런스 + diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..8ccd3c55b --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +node_modules/ + +dist/ From 5b153cc49d884ad80e672ec9f98b4e03b0c8e9c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A4=80=ED=8C=8D=28junpak=29?= <112045553+junpakPark@users.noreply.github.com> Date: Tue, 18 Jul 2023 13:56:16 +0900 Subject: [PATCH 02/35] =?UTF-8?q?[Docs]=20GitHub=20Issue=20Template=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=EB=AA=85=20=EC=98=A4=EB=A5=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20(#39)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: .gitignore 추가 * chore: GitHub PR 및 Issue Template * Revert "chore: GitHub PR 및 Issue Template" This reverts commit 65915f72740bbf22899ef7ac52fefa99cde96a8b. * Revert "chore: .gitignore 추가" This reverts commit 1e1865a1cb7f0a279b4e74c12cd0f66631809ff3. * chore: .gitignore 추가 * chore: GitHub Issue 및 PR Template 추가 * chore: GitHub Issue 및 PR Template 추가 --- .github/ISSUE_TEMPLATE/bug.yml | 44 +++++++++++++++++++++++++++++ .github/ISSUE_TEMPLATE/deploy.yml | 28 ++++++++++++++++++ .github/ISSUE_TEMPLATE/refactor.yml | 28 ++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug.yml create mode 100644 .github/ISSUE_TEMPLATE/deploy.yml create mode 100644 .github/ISSUE_TEMPLATE/refactor.yml diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 000000000..ba8e60888 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,44 @@ +name: "bug" +description: "버그 발생 시" +labels: "bug" +body: + - type: textarea + attributes: + label: 🐞버그 설명 + description: 버그에 대한 설명을 작성해 주세요. + placeholder: 자세히 적을수록 좋습니다! + validations: + required: true + - type: textarea + attributes: + label: 📄 버그 로그 + description: 로그가 있으면 입력해 주세요. + render: shell + validations: + required: false + - type: textarea + attributes: + label: 🌏 버그 발생 환경 + description: 버그가 발생한 환경에 대해 작성해 주세요. + placeholder: | + OS: macOS + validations: + required: true + - type: textarea + attributes: + label: ✅ 버그 재현 방법 + description: Given-When-Then 형식으로 버그를 재현할 수 있는 방법에 대해 작성해 주세요. + validations: + required: false + - type: textarea + attributes: + label: 📎 참고 자료 + description: 발생한 버그에 대한 참고 자료가 있다면 작성해 주세요. + validations: + required: false + - type: textarea + attributes: + label: ⏰ 추정 시간 + description: 버그를 해결하기 위한 추정 시간(비관적 추정, 낙관적 추정)에 대해 작성해주세요. + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/deploy.yml b/.github/ISSUE_TEMPLATE/deploy.yml new file mode 100644 index 000000000..778c62372 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/deploy.yml @@ -0,0 +1,28 @@ +name: "deploy" +description: "배포 시" +labels: "deploy" +body: + - type: textarea + attributes: + label: 📄 작업 설명 + description: 배포에 대한 설명을 작성해 주세요. + placeholder: 자세히 적을수록 좋습니다! + validations: + required: true + - type: textarea + attributes: + label: ✅ 작업 내용 + description: 배포에 대한 Tasks를 작성해 주세요. + placeholder: 최대한 세분화 해서 적어주세요! + validations: + required: true + - type: textarea + attributes: + label: 📎 참고 자료 + description: 배포에 대한 참고 자료가 있다면 작성해 주세요. + - type: textarea + attributes: + label: ⏰ 추정 시간 + description: 배포를 위한 추정 시간(비관적 추정, 낙관적 추정)에 대해 작성해주세요. + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/refactor.yml b/.github/ISSUE_TEMPLATE/refactor.yml new file mode 100644 index 000000000..ae5d0d05a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/refactor.yml @@ -0,0 +1,28 @@ +name: "refactor" +description: "리팩터링 시" +labels: "refactor" +body: + - type: textarea + attributes: + label: 🛠️ 작업 대상 + description: 리팩터링에 해야할 범위를 설명해 주세요. + placeholder: 자세히 적을수록 좋습니다! + validations: + required: true + - type: textarea + attributes: + label: ✅ 작업 내용 + description: 리팩터링을 할 부분에 대한 Tasks를 작성해 주세요. + placeholder: 최대한 세분화 해서 적어주세요! + validations: + required: true + - type: textarea + attributes: + label: 📎 참고 자료 + description: 리팩터링에 대한 참고 자료가 있다면 작성해 주세요. + - type: textarea + attributes: + label: ⏰ 추정 시간 + description: 리펙토링을 위한 추정 시간(비관적 추정, 낙관적 추정)에 대해 작성해주세요. + validations: + required: true From 46f453bb369142cf56cfc250bf0ecb11d1e07aaa Mon Sep 17 00:00:00 2001 From: jaeyeon kim Date: Thu, 10 Aug 2023 15:07:43 +0900 Subject: [PATCH 03/35] =?UTF-8?q?feat=20:=20Oauth=20=EC=9E=91=EC=97=85?= =?UTF-8?q?=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/build.gradle | 1 + .../mapbefine/member/domain/MemberInfo.java | 2 +- .../mapbefine/oauth/HttpInterfaceConfig.java | 25 +++++++++++ .../mapbefine/oauth/KakaoApiClient.java | 14 ++++++ .../mapbefine/mapbefine/oauth/KakaoToken.java | 16 +++++++ .../oauth/application/OauthService.java | 43 +++++++++++++++++++ .../oauth/presentation/OauthController.java | 38 ++++++++++++++++ backend/src/main/resources/application.yml | 6 +++ 8 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/oauth/HttpInterfaceConfig.java create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoApiClient.java create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoToken.java create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java diff --git a/backend/build.gradle b/backend/build.gradle index ce4240209..2aae35cc0 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -27,6 +27,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.springframework.boot:spring-boot-starter-webflux' implementation 'mysql:mysql-connector-java:8.0.32' diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/MemberInfo.java b/backend/src/main/java/com/mapbefine/mapbefine/member/domain/MemberInfo.java index 7bce3e921..a5af5cffc 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/MemberInfo.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/member/domain/MemberInfo.java @@ -20,7 +20,7 @@ public class MemberInfo { private static final int MAX_NICK_NAME_LENGTH = 20; private static final String VALID_EMAIL_URL_REGEX = "^[a-zA-Z0-9]+@[a-zA-Z]+\\.[a-zA-Z]{2,}$"; - @Column(nullable = false, length = 20, unique = true) + @Column(nullable = false, length = 20, unique = true) // Nick Name private String nickName; @Column(nullable = false, unique = true) diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/HttpInterfaceConfig.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/HttpInterfaceConfig.java new file mode 100644 index 000000000..0bfefd990 --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/HttpInterfaceConfig.java @@ -0,0 +1,25 @@ +package com.mapbefine.mapbefine.oauth; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.support.WebClientAdapter; +import org.springframework.web.service.invoker.HttpServiceProxyFactory; + +@Configuration +public class HttpInterfaceConfig { + + @Bean + public KakaoApiClient kakaoApiClient() { + return createHttpInterface(KakaoApiClient.class); + } + + private T createHttpInterface(Class clazz) { + WebClient webClient = WebClient.create(); + HttpServiceProxyFactory build = HttpServiceProxyFactory + .builder(WebClientAdapter.forClient(webClient)).build(); + return build.createClient(clazz); + } + +} + diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoApiClient.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoApiClient.java new file mode 100644 index 000000000..1d3508c96 --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoApiClient.java @@ -0,0 +1,14 @@ +package com.mapbefine.mapbefine.oauth; + +import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; + +import org.springframework.util.MultiValueMap; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.service.annotation.PostExchange; + +public interface KakaoApiClient { + + @PostExchange(url = "https://kauth.kakao.com/oauth/token", contentType = APPLICATION_FORM_URLENCODED_VALUE) + KakaoToken fetchToken(@RequestBody MultiValueMap params); + +} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoToken.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoToken.java new file mode 100644 index 000000000..4a8ae0d38 --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoToken.java @@ -0,0 +1,16 @@ +package com.mapbefine.mapbefine.oauth; + +import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; +import com.fasterxml.jackson.databind.annotation.JsonNaming; + +@JsonNaming(SnakeCaseStrategy.class) +public record KakaoToken( + String tokenType, + String accessToken, + String idToken, + Integer expiresIn, + String refreshToken, + Integer refreshTokenExpiresIn, + String scope +) { +} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java new file mode 100644 index 000000000..ac04af76e --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java @@ -0,0 +1,43 @@ +package com.mapbefine.mapbefine.oauth.application; + +import com.mapbefine.mapbefine.oauth.KakaoApiClient; +import com.mapbefine.mapbefine.oauth.KakaoToken; +import org.springframework.stereotype.Service; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +@Service +public class OauthService { + + private KakaoApiClient kakaoApiClient; + + public OauthService(final KakaoApiClient kakaoApiClient) { + this.kakaoApiClient = kakaoApiClient; + } + + public String getAuthCodeRequestUrl() { + return "https://kauth.kakao.com/oauth/authorize" + + "?response_type=" + RESPONSE_TYPE + + "&client_id=" + CLIENT_ID + + "&redirect_uri=" + REDIRECT_URI + + "&scope=" + SCOPE; + } + + public KakaoToken fetch(String code) { + KakaoToken kakaoToken = kakaoApiClient.fetchToken(tokenRequestParams(code)); + + return kakaoToken; + } + + private MultiValueMap tokenRequestParams(String code) { + MultiValueMap params = new LinkedMultiValueMap<>(); + params.add("grant_type", GRANT_TYPE); + params.add("client_id", CLIENT_ID); + params.add("redirect_uri", REDIRECT_URI); + params.add("code", code); + params.add("client_secret", CLIENT_SECRET); + + return params; + } + +} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java new file mode 100644 index 000000000..53c8a4bf2 --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java @@ -0,0 +1,38 @@ +package com.mapbefine.mapbefine.oauth.presentation; + +import com.mapbefine.mapbefine.oauth.KakaoToken; +import com.mapbefine.mapbefine.oauth.application.OauthService; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/oauth") +public class OauthController { + + private final OauthService oauthService; + + public OauthController(final OauthService oauthService) { + this.oauthService = oauthService; + } + + @GetMapping("/kakao") + public ResponseEntity redirection(HttpServletResponse response) throws IOException { + String redirectUrl = oauthService.getAuthCodeRequestUrl(); + response.sendRedirect(redirectUrl); + + return ResponseEntity.ok().build(); + } + + @GetMapping("/login/kakao") + public ResponseEntity login(@RequestParam String code) { + KakaoToken token = oauthService.fetch(code); + + return ResponseEntity.ok(token); + } + +} diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 3a8259581..31efbf43c 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -21,3 +21,9 @@ logging: descriptor: sql: BasicBinder: TRACE +oauth: + kakao: + client_id: ${KAKAO_CLIENT_ID} + redirect_uri: ${KAKAO_REDIRECT_URL} + client_secret: ${KAKAO_CLIENT_SECRET} + scope: ${KAKAO_SCOPE} \ No newline at end of file From 819bd4632579f9211a04e0b529446d41f1163ed0 Mon Sep 17 00:00:00 2001 From: yoondgu Date: Thu, 10 Aug 2023 18:16:04 +0900 Subject: [PATCH 04/35] =?UTF-8?q?feat:=20=EC=86=8C=EC=85=9C=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EB=B0=8F=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 민감 정보 환경변수 관리가 아직 진행되지 않아 해당 상수 삭제 후 커밋 Co-authored-by: kpeel5839 --- .../member/domain/MemberRepository.java | 3 +- .../mapbefine/member/domain/OauthId.java | 22 ++++++++ .../mapbefine/oauth/KakaoApiClient.java | 7 +++ .../oauth/application/OauthService.java | 39 ++++++++++++-- .../oauth/dto/KakaoMemberResponse.java | 52 +++++++++++++++++++ .../mapbefine/oauth/{ => dto}/KakaoToken.java | 2 +- .../oauth/presentation/OauthController.java | 8 +-- 7 files changed, 122 insertions(+), 11 deletions(-) create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/member/domain/OauthId.java create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/KakaoMemberResponse.java rename backend/src/main/java/com/mapbefine/mapbefine/oauth/{ => dto}/KakaoToken.java (90%) diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/MemberRepository.java b/backend/src/main/java/com/mapbefine/mapbefine/member/domain/MemberRepository.java index 175c0d1a8..6fd3857cc 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/MemberRepository.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/member/domain/MemberRepository.java @@ -7,8 +7,7 @@ public interface MemberRepository extends JpaRepository { Optional findByMemberInfoEmail(String email); - boolean existsByMemberInfoNickName(String name); - boolean existsByMemberInfoEmail(String email); + Optional findByOauthIdOauthServerId(Long oauthServerId); } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/OauthId.java b/backend/src/main/java/com/mapbefine/mapbefine/member/domain/OauthId.java new file mode 100644 index 000000000..598e49544 --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/member/domain/OauthId.java @@ -0,0 +1,22 @@ +package com.mapbefine.mapbefine.member.domain; + +import static lombok.AccessLevel.PROTECTED; + +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Embeddable +@NoArgsConstructor(access = PROTECTED) +@Getter +public class OauthId { + + @Column(nullable = false) + private Long oauthServerId; + + public OauthId(Long oauthServerId) { + this.oauthServerId = oauthServerId; + } + +} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoApiClient.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoApiClient.java index 1d3508c96..e092edc28 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoApiClient.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoApiClient.java @@ -1,9 +1,14 @@ package com.mapbefine.mapbefine.oauth; +import static org.springframework.http.HttpHeaders.AUTHORIZATION; import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; +import com.mapbefine.mapbefine.oauth.dto.KakaoMemberResponse; +import com.mapbefine.mapbefine.oauth.dto.KakaoToken; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.service.annotation.GetExchange; import org.springframework.web.service.annotation.PostExchange; public interface KakaoApiClient { @@ -11,4 +16,6 @@ public interface KakaoApiClient { @PostExchange(url = "https://kauth.kakao.com/oauth/token", contentType = APPLICATION_FORM_URLENCODED_VALUE) KakaoToken fetchToken(@RequestBody MultiValueMap params); + @GetExchange("https://kapi.kakao.com/v2/user/me") + KakaoMemberResponse fetchMember(@RequestHeader(name = AUTHORIZATION) String bearerToken); } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java index ac04af76e..392c0483c 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java @@ -1,7 +1,13 @@ package com.mapbefine.mapbefine.oauth.application; +import com.mapbefine.mapbefine.member.domain.Member; +import com.mapbefine.mapbefine.member.domain.MemberRepository; +import com.mapbefine.mapbefine.member.domain.OauthId; +import com.mapbefine.mapbefine.member.domain.Role; +import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; import com.mapbefine.mapbefine.oauth.KakaoApiClient; -import com.mapbefine.mapbefine.oauth.KakaoToken; +import com.mapbefine.mapbefine.oauth.dto.KakaoMemberResponse; +import com.mapbefine.mapbefine.oauth.dto.KakaoToken; import org.springframework.stereotype.Service; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; @@ -10,9 +16,11 @@ public class OauthService { private KakaoApiClient kakaoApiClient; + private MemberRepository memberRepository; - public OauthService(final KakaoApiClient kakaoApiClient) { + public OauthService(KakaoApiClient kakaoApiClient, MemberRepository memberRepository) { this.kakaoApiClient = kakaoApiClient; + this.memberRepository = memberRepository; } public String getAuthCodeRequestUrl() { @@ -23,10 +31,21 @@ public String getAuthCodeRequestUrl() { + "&scope=" + SCOPE; } - public KakaoToken fetch(String code) { + public MemberDetailResponse login(String code) { KakaoToken kakaoToken = kakaoApiClient.fetchToken(tokenRequestParams(code)); - return kakaoToken; + KakaoMemberResponse kakaoMemberResponse = kakaoApiClient.fetchMember( + kakaoToken.tokenType() + " " + kakaoToken.accessToken() + ); + + Long oauthId = kakaoMemberResponse.id(); + Member member = memberRepository.findByOauthIdOauthServerId(oauthId) + .orElseGet(() -> register(kakaoMemberResponse, oauthId)); + + // TODO: 2023/08/10 nickname을 소셜 로그인으로 받아온 정보를 저장함으로서, nickname의 unique를 보장할 수 없어짐 + // 일부 사용자가 직접 입력하는 플로우를 추가할 필요가 있음 + + return MemberDetailResponse.from(member); } private MultiValueMap tokenRequestParams(String code) { @@ -40,4 +59,16 @@ private MultiValueMap tokenRequestParams(String code) { return params; } + private Member register(KakaoMemberResponse kakaoMemberResponse, Long oauthId) { + Member member = Member.of( + kakaoMemberResponse.kakaoAccount().profile().nickname(), + kakaoMemberResponse.kakaoAccount().email(), + kakaoMemberResponse.kakaoAccount().profile().profileImageUrl(), + Role.USER, + new OauthId(oauthId) + ); + + return memberRepository.save(member); + } + } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/KakaoMemberResponse.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/KakaoMemberResponse.java new file mode 100644 index 000000000..fdb8ff8e8 --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/KakaoMemberResponse.java @@ -0,0 +1,52 @@ +package com.mapbefine.mapbefine.oauth.dto; + +import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import java.time.LocalDateTime; + +@JsonNaming(SnakeCaseStrategy.class) +public record KakaoMemberResponse( + Long id, + boolean hasSignedUp, + LocalDateTime connectedAt, + KakaoAccount kakaoAccount +) { + + @JsonNaming(SnakeCaseStrategy.class) + public record KakaoAccount( + boolean profileNeedsAgreement, + boolean profileNicknameNeedsAgreement, + boolean profileImageNeedsAgreement, + Profile profile, + boolean nameNeedsAgreement, + String name, + boolean emailNeedsAgreement, + boolean isEmailValid, + boolean isEmailVerified, + String email, + boolean ageRangeNeedsAgreement, + String ageRange, + boolean birthyearNeedsAgreement, + String birthyear, + boolean birthdayNeedsAgreement, + String birthday, + String birthdayType, + boolean genderNeedsAgreement, + String gender, + boolean phoneNumberNeedsAgreement, + String phoneNumber, + boolean ciNeedsAgreement, + String ci, + LocalDateTime ciAuthenticatedAt + ) { + } + + @JsonNaming(SnakeCaseStrategy.class) + public record Profile( + String nickname, + String thumbnailImageUrl, + String profileImageUrl, + boolean isDefaultImage + ) { + } +} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoToken.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/KakaoToken.java similarity index 90% rename from backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoToken.java rename to backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/KakaoToken.java index 4a8ae0d38..1af105ef2 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoToken.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/KakaoToken.java @@ -1,4 +1,4 @@ -package com.mapbefine.mapbefine.oauth; +package com.mapbefine.mapbefine.oauth.dto; import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; import com.fasterxml.jackson.databind.annotation.JsonNaming; diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java index 53c8a4bf2..537cfe488 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java @@ -1,6 +1,6 @@ package com.mapbefine.mapbefine.oauth.presentation; -import com.mapbefine.mapbefine.oauth.KakaoToken; +import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; import com.mapbefine.mapbefine.oauth.application.OauthService; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; @@ -29,10 +29,10 @@ public ResponseEntity redirection(HttpServletResponse response) throws IOE } @GetMapping("/login/kakao") - public ResponseEntity login(@RequestParam String code) { - KakaoToken token = oauthService.fetch(code); + public ResponseEntity login(@RequestParam String code) { + MemberDetailResponse member = oauthService.login(code); - return ResponseEntity.ok(token); + return ResponseEntity.ok(member); } } From 7a1869f8d0246774cc154b40d7c949d0ed86fcb5 Mon Sep 17 00:00:00 2001 From: yoondgu Date: Fri, 11 Aug 2023 17:08:29 +0900 Subject: [PATCH 05/35] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EC=9D=B8=EA=B0=80=EB=A5=BC=20=EC=9C=84=ED=95=9C=20JWT=20?= =?UTF-8?q?=ED=86=A0=ED=81=B0=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: kpeel5839 --- backend/build.gradle | 3 + .../auth/application/AuthService.java | 16 +++--- .../mapbefine/auth/dto/AuthInfo.java | 2 +- .../BasicAuthorizationExtractor.java | 46 ---------------- .../BearerAuthorizationExtractor.java | 31 +++++++++++ .../auth/infrastructure/JwtTokenProvider.java | 42 ++++++++++++++ .../common/interceptor/AuthInterceptor.java | 55 ++++++++++++++++--- .../common/resolver/AuthArgumentResolver.java | 28 +++------- .../oauth/application/OauthService.java | 15 +++-- .../oauth/dto/LoginInfoResponse.java | 15 +++++ .../oauth/presentation/OauthController.java | 8 +-- backend/src/main/resources/application.yml | 2 +- 12 files changed, 171 insertions(+), 92 deletions(-) delete mode 100644 backend/src/main/java/com/mapbefine/mapbefine/auth/infrastructure/BasicAuthorizationExtractor.java create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/auth/infrastructure/BearerAuthorizationExtractor.java create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/auth/infrastructure/JwtTokenProvider.java create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/LoginInfoResponse.java diff --git a/backend/build.gradle b/backend/build.gradle index 2aae35cc0..be07241a0 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -31,6 +31,9 @@ dependencies { implementation 'mysql:mysql-connector-java:8.0.32' + implementation 'io.jsonwebtoken:jjwt:0.9.1' + implementation 'javax.xml.bind:jaxb-api:2.4.0-b180830.0359' + annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' diff --git a/backend/src/main/java/com/mapbefine/mapbefine/auth/application/AuthService.java b/backend/src/main/java/com/mapbefine/mapbefine/auth/application/AuthService.java index 804342ab9..c660b742c 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/auth/application/AuthService.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/auth/application/AuthService.java @@ -2,13 +2,12 @@ import com.mapbefine.mapbefine.auth.domain.AuthMember; import com.mapbefine.mapbefine.auth.domain.member.Admin; -import com.mapbefine.mapbefine.auth.domain.member.Guest; import com.mapbefine.mapbefine.auth.domain.member.User; -import com.mapbefine.mapbefine.auth.dto.AuthInfo; import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.member.domain.MemberRepository; import com.mapbefine.mapbefine.topic.domain.Topic; import java.util.List; +import java.util.Objects; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -22,14 +21,17 @@ public AuthService(MemberRepository memberRepository) { this.memberRepository = memberRepository; } - public boolean isMember(AuthInfo authInfo) { - return memberRepository.existsByMemberInfoEmail(authInfo.email()); + public boolean isMember(Long memberId) { + if (Objects.isNull(memberId)) { + return false; + } + return memberRepository.existsById(memberId); } - public AuthMember findAuthMemberByEmail(AuthInfo authInfo) { - return memberRepository.findByMemberInfoEmail(authInfo.email()) + public AuthMember findAuthMemberByMemberId(Long memberId) { + return memberRepository.findById(memberId) .map(this::convertToAuthMember) - .orElseGet(Guest::new); + .orElseThrow(() -> new IllegalArgumentException("")); } private AuthMember convertToAuthMember(Member member) { diff --git a/backend/src/main/java/com/mapbefine/mapbefine/auth/dto/AuthInfo.java b/backend/src/main/java/com/mapbefine/mapbefine/auth/dto/AuthInfo.java index c6f6ab341..ab570ee32 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/auth/dto/AuthInfo.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/auth/dto/AuthInfo.java @@ -1,6 +1,6 @@ package com.mapbefine.mapbefine.auth.dto; public record AuthInfo( - String email + String accessToken ) { } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/auth/infrastructure/BasicAuthorizationExtractor.java b/backend/src/main/java/com/mapbefine/mapbefine/auth/infrastructure/BasicAuthorizationExtractor.java deleted file mode 100644 index 8502069ff..000000000 --- a/backend/src/main/java/com/mapbefine/mapbefine/auth/infrastructure/BasicAuthorizationExtractor.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.mapbefine.mapbefine.auth.infrastructure; - - -import static org.springframework.http.HttpHeaders.AUTHORIZATION; -import static org.springframework.util.StringUtils.hasText; - -import com.mapbefine.mapbefine.auth.dto.AuthInfo; -import jakarta.servlet.http.HttpServletRequest; -import org.apache.tomcat.util.codec.binary.Base64; -import org.springframework.stereotype.Component; - -@Component -public class BasicAuthorizationExtractor implements AuthorizationExtractor { - - private static final String BASIC_TYPE = "Basic"; - - @Override - public AuthInfo extract(final HttpServletRequest request) { - String requestHeader = request.getHeader(AUTHORIZATION); - - validateRequestHeader(requestHeader); - - String authorization = decode(requestHeader); - validateAuthorization(authorization); - String email = authorization.substring(BASIC_TYPE.length()).trim(); - - return new AuthInfo(email); - } - - private void validateRequestHeader(String requestHeader) { - if (!hasText(requestHeader)) { - throw new IllegalArgumentException("로그인 유저가 아닙니다."); - } - } - - private String decode(String authorization) { - return new String(Base64.decodeBase64(authorization)); - } - - private void validateAuthorization(final String authorization) { - if (!authorization.toLowerCase().startsWith(BASIC_TYPE.toLowerCase())) { - throw new IllegalArgumentException("잘못된 인증방법입니다."); - } - } - -} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/auth/infrastructure/BearerAuthorizationExtractor.java b/backend/src/main/java/com/mapbefine/mapbefine/auth/infrastructure/BearerAuthorizationExtractor.java new file mode 100644 index 000000000..595844700 --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/auth/infrastructure/BearerAuthorizationExtractor.java @@ -0,0 +1,31 @@ +package com.mapbefine.mapbefine.auth.infrastructure; + +import static org.springframework.http.HttpHeaders.AUTHORIZATION; + +import com.mapbefine.mapbefine.auth.dto.AuthInfo; +import jakarta.servlet.http.HttpServletRequest; +import java.util.Enumeration; +import org.springframework.stereotype.Component; + +@Component +public class BearerAuthorizationExtractor implements AuthorizationExtractor { + private static final String BEARER_TYPE = "Bearer"; + + @Override + public AuthInfo extract(HttpServletRequest request) { + Enumeration headers = request.getHeaders(AUTHORIZATION); + while (headers.hasMoreElements()) { + String value = headers.nextElement(); + if ((value.toLowerCase().startsWith(BEARER_TYPE.toLowerCase()))) { + String authHeaderValue = value.substring(BEARER_TYPE.length()).trim(); + int commaIndex = authHeaderValue.indexOf(','); + if (commaIndex > 0) { + authHeaderValue = authHeaderValue.substring(0, commaIndex); + } + return new AuthInfo(authHeaderValue); + } + } + + return null; + } +} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/auth/infrastructure/JwtTokenProvider.java b/backend/src/main/java/com/mapbefine/mapbefine/auth/infrastructure/JwtTokenProvider.java new file mode 100644 index 000000000..0ec5eb0aa --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/auth/infrastructure/JwtTokenProvider.java @@ -0,0 +1,42 @@ +package com.mapbefine.mapbefine.auth.infrastructure; + +import io.jsonwebtoken.*; +import java.util.Date; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class JwtTokenProvider { + @Value("${security.jwt.token.secret-key}") + private String secretKey; + @Value("${security.jwt.token.expire-length}") + private long validityInMilliseconds; + + public String createToken(String payload) { + Claims claims = Jwts.claims().setSubject(payload); + Date now = new Date(); + Date validity = new Date(now.getTime() + validityInMilliseconds); + + return Jwts.builder() + .setClaims(claims) + .setIssuedAt(now) + .setExpiration(validity) + .signWith(SignatureAlgorithm.HS256, secretKey) + .compact(); + } + + public String getPayload(String token) { + return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject(); + } + + public boolean validateToken(String token) { + try { + Jws claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token); + + return !claims.getBody().getExpiration().before(new Date()); + } catch (JwtException | IllegalArgumentException e) { + return false; + } + } +} + diff --git a/backend/src/main/java/com/mapbefine/mapbefine/common/interceptor/AuthInterceptor.java b/backend/src/main/java/com/mapbefine/mapbefine/common/interceptor/AuthInterceptor.java index d6dcbd25e..9ac0e34f0 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/common/interceptor/AuthInterceptor.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/common/interceptor/AuthInterceptor.java @@ -1,11 +1,14 @@ package com.mapbefine.mapbefine.common.interceptor; import com.mapbefine.mapbefine.auth.application.AuthService; +import com.mapbefine.mapbefine.auth.domain.AuthMember; import com.mapbefine.mapbefine.auth.dto.AuthInfo; import com.mapbefine.mapbefine.auth.infrastructure.AuthorizationExtractor; +import com.mapbefine.mapbefine.auth.infrastructure.JwtTokenProvider; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.util.Objects; +import org.springframework.core.MethodParameter; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; @@ -15,10 +18,16 @@ public class AuthInterceptor implements HandlerInterceptor { private final AuthorizationExtractor authorizationExtractor; private final AuthService authService; + private final JwtTokenProvider jwtTokenProvider; - public AuthInterceptor(AuthorizationExtractor authorizationExtractor, AuthService authService) { + public AuthInterceptor( + AuthorizationExtractor authorizationExtractor, + AuthService authService, + JwtTokenProvider jwtTokenProvider + ) { this.authorizationExtractor = authorizationExtractor; this.authService = authService; + this.jwtTokenProvider = jwtTokenProvider; } @Override @@ -27,8 +36,29 @@ public boolean preHandle( HttpServletResponse response, Object handler ) throws Exception { - if ((handler instanceof HandlerMethod) && isLoginRequired((HandlerMethod) handler)) { - return isMember(request); + if (!(handler instanceof HandlerMethod handlerMethod)) { + return true; + } + + if (isAuthMemberNotRequired(handlerMethod)) { + return true; + } + + Long memberId = extractMemberIdFromToken(request); + request.setAttribute("memberId", memberId); + + if (isLoginRequired((HandlerMethod) handler)) { + // TODO: 2023/08/11 403 반환 + return isMember(memberId); + } + return true; + } + + private boolean isAuthMemberNotRequired(HandlerMethod handlerMethod) { + for (MethodParameter parameter : handlerMethod.getMethodParameters()) { + if (parameter.getParameterType().equals(AuthMember.class)) { + return false; + } } return true; } @@ -39,10 +69,21 @@ private boolean isLoginRequired(HandlerMethod handlerMethod) { return !Objects.isNull(loginRequired); } - private boolean isMember(HttpServletRequest request) { - AuthInfo authInfo = authorizationExtractor.extract(request); + private boolean isMember(Long memberId) { + + return authService.isMember(memberId); + } - return authService.isMember(authInfo); + private Long extractMemberIdFromToken(HttpServletRequest request) { + AuthInfo authInfo = authorizationExtractor.extract(request); + if (Objects.isNull(authInfo)) { + return null; + } + String accessToken = authInfo.accessToken(); + if (!jwtTokenProvider.validateToken(accessToken)) { + throw new IllegalArgumentException("유효하지 않은 토큰입니다."); + } + return Long.parseLong(jwtTokenProvider.getPayload(accessToken)); } - + } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/common/resolver/AuthArgumentResolver.java b/backend/src/main/java/com/mapbefine/mapbefine/common/resolver/AuthArgumentResolver.java index 4c406d661..a04a773d7 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/common/resolver/AuthArgumentResolver.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/common/resolver/AuthArgumentResolver.java @@ -2,10 +2,8 @@ import com.mapbefine.mapbefine.auth.application.AuthService; import com.mapbefine.mapbefine.auth.domain.AuthMember; -import com.mapbefine.mapbefine.auth.dto.AuthInfo; -import com.mapbefine.mapbefine.auth.infrastructure.AuthorizationExtractor; +import com.mapbefine.mapbefine.auth.domain.member.Guest; import jakarta.servlet.http.HttpServletRequest; -import java.util.Optional; import org.springframework.core.MethodParameter; import org.springframework.stereotype.Component; import org.springframework.web.bind.support.WebDataBinderFactory; @@ -16,16 +14,9 @@ @Component public class AuthArgumentResolver implements HandlerMethodArgumentResolver { - private static final String EMPTY_EMAIL = ""; - - private final AuthorizationExtractor authorizationExtractor; private final AuthService authService; - public AuthArgumentResolver( - AuthorizationExtractor authorizationExtractor, - AuthService authService - ) { - this.authorizationExtractor = authorizationExtractor; + public AuthArgumentResolver(AuthService authService) { this.authService = authService; } @@ -54,17 +45,12 @@ private void validateRequest(HttpServletRequest request) { } private AuthMember createAuthMember(HttpServletRequest request) { - AuthInfo authInfo = getAuthInfo(request) - .orElseGet(() -> new AuthInfo(EMPTY_EMAIL)); + Long memberId = (Long) request.getAttribute("memberId"); + if (memberId == null) { + return new Guest(); + } - return authService.findAuthMemberByEmail(authInfo); + return authService.findAuthMemberByMemberId(memberId); } - private Optional getAuthInfo(HttpServletRequest request) { - try { - return Optional.of(authorizationExtractor.extract(request)); - } catch (IllegalArgumentException e) { - return Optional.empty(); - } - } } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java index 392c0483c..2358beedf 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java @@ -1,13 +1,14 @@ package com.mapbefine.mapbefine.oauth.application; +import com.mapbefine.mapbefine.auth.infrastructure.JwtTokenProvider; import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.member.domain.MemberRepository; import com.mapbefine.mapbefine.member.domain.OauthId; import com.mapbefine.mapbefine.member.domain.Role; -import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; import com.mapbefine.mapbefine.oauth.KakaoApiClient; import com.mapbefine.mapbefine.oauth.dto.KakaoMemberResponse; import com.mapbefine.mapbefine.oauth.dto.KakaoToken; +import com.mapbefine.mapbefine.oauth.dto.LoginInfoResponse; import org.springframework.stereotype.Service; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; @@ -17,10 +18,14 @@ public class OauthService { private KakaoApiClient kakaoApiClient; private MemberRepository memberRepository; + private JwtTokenProvider jwtTokenProvider; - public OauthService(KakaoApiClient kakaoApiClient, MemberRepository memberRepository) { + public OauthService(KakaoApiClient kakaoApiClient, + MemberRepository memberRepository, + JwtTokenProvider jwtTokenProvider) { this.kakaoApiClient = kakaoApiClient; this.memberRepository = memberRepository; + this.jwtTokenProvider = jwtTokenProvider; } public String getAuthCodeRequestUrl() { @@ -31,7 +36,7 @@ public String getAuthCodeRequestUrl() { + "&scope=" + SCOPE; } - public MemberDetailResponse login(String code) { + public LoginInfoResponse login(String code) { KakaoToken kakaoToken = kakaoApiClient.fetchToken(tokenRequestParams(code)); KakaoMemberResponse kakaoMemberResponse = kakaoApiClient.fetchMember( @@ -41,11 +46,11 @@ public MemberDetailResponse login(String code) { Long oauthId = kakaoMemberResponse.id(); Member member = memberRepository.findByOauthIdOauthServerId(oauthId) .orElseGet(() -> register(kakaoMemberResponse, oauthId)); - // TODO: 2023/08/10 nickname을 소셜 로그인으로 받아온 정보를 저장함으로서, nickname의 unique를 보장할 수 없어짐 // 일부 사용자가 직접 입력하는 플로우를 추가할 필요가 있음 + String accessToken = jwtTokenProvider.createToken(String.valueOf(member.getId())); - return MemberDetailResponse.from(member); + return LoginInfoResponse.of(accessToken, member); } private MultiValueMap tokenRequestParams(String code) { diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/LoginInfoResponse.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/LoginInfoResponse.java new file mode 100644 index 000000000..bdf523944 --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/LoginInfoResponse.java @@ -0,0 +1,15 @@ +package com.mapbefine.mapbefine.oauth.dto; + +import com.mapbefine.mapbefine.member.domain.Member; +import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; + +public record LoginInfoResponse( + String accessToken, + MemberDetailResponse member +) { + + public static LoginInfoResponse of(String accessToken, Member member) { + return new LoginInfoResponse(accessToken, MemberDetailResponse.from(member)); + } + +} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java index 537cfe488..5331ecd15 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java @@ -1,7 +1,7 @@ package com.mapbefine.mapbefine.oauth.presentation; -import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; import com.mapbefine.mapbefine.oauth.application.OauthService; +import com.mapbefine.mapbefine.oauth.dto.LoginInfoResponse; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import org.springframework.http.ResponseEntity; @@ -29,10 +29,10 @@ public ResponseEntity redirection(HttpServletResponse response) throws IOE } @GetMapping("/login/kakao") - public ResponseEntity login(@RequestParam String code) { - MemberDetailResponse member = oauthService.login(code); + public ResponseEntity login(@RequestParam String code) { + LoginInfoResponse loginInfo = oauthService.login(code); - return ResponseEntity.ok(member); + return ResponseEntity.ok(loginInfo); } } diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 31efbf43c..51894ffb2 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -26,4 +26,4 @@ oauth: client_id: ${KAKAO_CLIENT_ID} redirect_uri: ${KAKAO_REDIRECT_URL} client_secret: ${KAKAO_CLIENT_SECRET} - scope: ${KAKAO_SCOPE} \ No newline at end of file + scope: ${KAKAO_SCOPE} From 3ba21e45c1adba753b0453a52f736287d11f5a81 Mon Sep 17 00:00:00 2001 From: jaeyeon kim Date: Fri, 11 Aug 2023 18:12:50 +0900 Subject: [PATCH 06/35] =?UTF-8?q?refactor=20:=20=EC=86=8C=EC=85=9C?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=ED=94=8C=EB=9E=AB=ED=8F=BC=20?= =?UTF-8?q?=ED=99=95=EC=9E=A5=EC=97=90=20=EC=9C=A0=EC=97=B0=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EA=B5=AC=EC=A1=B0=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mapbefine/MapbefineApplication.java | 2 + .../mapbefine/common/config/WebConfig.java | 7 ++ .../member/domain/MemberRepository.java | 3 + .../mapbefine/member/domain/OauthId.java | 12 ++- .../oauth/AuthCodeRequestUrlProvider.java | 9 +++ .../AuthCodeRequestUrlProviderComposite.java | 33 +++++++++ ...kaoAuthCodeRequestUrlProviderProvider.java | 31 ++++++++ .../mapbefine/oauth/KakaoMemberClient.java | 49 +++++++++++++ .../mapbefine/oauth/KakaoOauthConfig.java | 12 +++ .../mapbefine/oauth/OauthMemberClient.java | 11 +++ .../oauth/OauthMemberClientComposite.java | 34 +++++++++ .../mapbefine/oauth/OauthServerType.java | 15 ++++ .../oauth/OauthServerTypeConverter.java | 12 +++ .../oauth/application/OauthService.java | 73 ++++++------------- .../oauth/dto/KakaoMemberResponse.java | 15 ++++ .../oauth/presentation/OauthController.java | 20 +++-- backend/src/main/resources/application.yml | 6 -- 17 files changed, 282 insertions(+), 62 deletions(-) create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/oauth/AuthCodeRequestUrlProvider.java create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/oauth/AuthCodeRequestUrlProviderComposite.java create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoAuthCodeRequestUrlProviderProvider.java create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoMemberClient.java create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoOauthConfig.java create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMemberClient.java create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMemberClientComposite.java create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthServerType.java create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthServerTypeConverter.java diff --git a/backend/src/main/java/com/mapbefine/mapbefine/MapbefineApplication.java b/backend/src/main/java/com/mapbefine/mapbefine/MapbefineApplication.java index 5f934815f..f52ed2d23 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/MapbefineApplication.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/MapbefineApplication.java @@ -2,8 +2,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; @SpringBootApplication +@ConfigurationPropertiesScan public class MapbefineApplication { public static void main(String[] args) { diff --git a/backend/src/main/java/com/mapbefine/mapbefine/common/config/WebConfig.java b/backend/src/main/java/com/mapbefine/mapbefine/common/config/WebConfig.java index 411ee749c..faa1a1bc2 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/common/config/WebConfig.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/common/config/WebConfig.java @@ -1,6 +1,8 @@ package com.mapbefine.mapbefine.common.config; +import com.mapbefine.mapbefine.oauth.OauthServerTypeConverter; import org.springframework.context.annotation.Configuration; +import org.springframework.format.FormatterRegistry; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -15,4 +17,9 @@ public void addCorsMappings(CorsRegistry registry) { .exposedHeaders("Location"); } + @Override + public void addFormatters(FormatterRegistry registry) { + registry.addConverter(new OauthServerTypeConverter()); + } + } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/MemberRepository.java b/backend/src/main/java/com/mapbefine/mapbefine/member/domain/MemberRepository.java index 6fd3857cc..16b57c059 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/MemberRepository.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/member/domain/MemberRepository.java @@ -10,4 +10,7 @@ public interface MemberRepository extends JpaRepository { boolean existsByMemberInfoEmail(String email); Optional findByOauthIdOauthServerId(Long oauthServerId); + + Optional findByOauthId(OauthId oauthId); + } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/OauthId.java b/backend/src/main/java/com/mapbefine/mapbefine/member/domain/OauthId.java index 598e49544..0fcd42686 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/OauthId.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/member/domain/OauthId.java @@ -2,8 +2,11 @@ import static lombok.AccessLevel.PROTECTED; +import com.mapbefine.mapbefine.oauth.OauthServerType; import jakarta.persistence.Column; import jakarta.persistence.Embeddable; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; import lombok.Getter; import lombok.NoArgsConstructor; @@ -15,8 +18,15 @@ public class OauthId { @Column(nullable = false) private Long oauthServerId; - public OauthId(Long oauthServerId) { + @Enumerated(EnumType.STRING) + private OauthServerType oauthServerType; + + public OauthId( + Long oauthServerId, + OauthServerType oauthServerType + ) { this.oauthServerId = oauthServerId; + this.oauthServerType = oauthServerType; } } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/AuthCodeRequestUrlProvider.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/AuthCodeRequestUrlProvider.java new file mode 100644 index 000000000..62fc08ca3 --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/AuthCodeRequestUrlProvider.java @@ -0,0 +1,9 @@ +package com.mapbefine.mapbefine.oauth; + +public interface AuthCodeRequestUrlProvider { + + OauthServerType supportServer(); + + String provide(); + +} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/AuthCodeRequestUrlProviderComposite.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/AuthCodeRequestUrlProviderComposite.java new file mode 100644 index 000000000..c940bdce7 --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/AuthCodeRequestUrlProviderComposite.java @@ -0,0 +1,33 @@ +package com.mapbefine.mapbefine.oauth; + +import static java.util.function.UnaryOperator.identity; +import static java.util.stream.Collectors.toMap; + +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import org.springframework.stereotype.Component; + +@Component +public class AuthCodeRequestUrlProviderComposite { + + private final Map mapping; + + public AuthCodeRequestUrlProviderComposite(Set providers) { + mapping = providers.stream() + .collect(toMap( + AuthCodeRequestUrlProvider::supportServer, + identity() + )); + } + + public String provide(OauthServerType oauthServerType) { + return getProvider(oauthServerType).provide(); + } + + public AuthCodeRequestUrlProvider getProvider(OauthServerType oauthServerType) { + return Optional.ofNullable(mapping.get(oauthServerType)) + .orElseThrow(() -> new RuntimeException("지원하지 않는 소셜 로그인 타입입니다.")); + } + +} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoAuthCodeRequestUrlProviderProvider.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoAuthCodeRequestUrlProviderProvider.java new file mode 100644 index 000000000..45dc696ff --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoAuthCodeRequestUrlProviderProvider.java @@ -0,0 +1,31 @@ +package com.mapbefine.mapbefine.oauth; + +import org.springframework.stereotype.Component; +import org.springframework.web.util.UriComponentsBuilder; + +@Component +public class KakaoAuthCodeRequestUrlProviderProvider implements AuthCodeRequestUrlProvider { + + private final KakaoOauthConfig kakaoOauthConfig; + + public KakaoAuthCodeRequestUrlProviderProvider(KakaoOauthConfig kakaoOauthConfig) { + this.kakaoOauthConfig = kakaoOauthConfig; + } + + @Override + public OauthServerType supportServer() { + return OauthServerType.KAKAO; + } + + @Override + public String provide() { + return UriComponentsBuilder + .fromUriString("https://kauth.kakao.com/oauth/authorize") + .queryParam("response_type", "code") + .queryParam("client_id", kakaoOauthConfig.clientId()) + .queryParam("redirect_uri", kakaoOauthConfig.redirectUri()) + .queryParam("scope", String.join(",", kakaoOauthConfig.scope())) + .toUriString(); + } + +} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoMemberClient.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoMemberClient.java new file mode 100644 index 000000000..d081b9ca0 --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoMemberClient.java @@ -0,0 +1,49 @@ +package com.mapbefine.mapbefine.oauth; + +import com.mapbefine.mapbefine.member.domain.Member; +import com.mapbefine.mapbefine.oauth.dto.KakaoMemberResponse; +import com.mapbefine.mapbefine.oauth.dto.KakaoToken; +import org.springframework.stereotype.Component; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +@Component +public class KakaoMemberClient implements OauthMemberClient { + + private KakaoApiClient kakaoApiClient; + private KakaoOauthConfig kakaoOauthConfig; + + public KakaoMemberClient( + KakaoApiClient kakaoApiClient, + KakaoOauthConfig kakaoOauthConfig + ) { + this.kakaoApiClient = kakaoApiClient; + this.kakaoOauthConfig = kakaoOauthConfig; + } + + @Override + public OauthServerType supportServer() { + return OauthServerType.KAKAO; + } + + @Override + public Member fetch(String authCode) { + KakaoToken kakaoToken = kakaoApiClient.fetchToken(tokenRequestParams(authCode)); + KakaoMemberResponse kakaoMemberResponse = kakaoApiClient.fetchMember( + kakaoToken.tokenType() + " " + kakaoToken.accessToken() + ); + + return kakaoMemberResponse.toDomain(); + } + + private MultiValueMap tokenRequestParams(String authCode) { + MultiValueMap params = new LinkedMultiValueMap<>(); + params.add("grant_type", "authorization_code"); + params.add("client_id", kakaoOauthConfig.clientId()); + params.add("redirect_uri", kakaoOauthConfig.redirectUri()); + params.add("code", authCode); + params.add("client_secret", kakaoOauthConfig.clientSecret()); + return params; + } + +} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoOauthConfig.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoOauthConfig.java new file mode 100644 index 000000000..89d2cddff --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoOauthConfig.java @@ -0,0 +1,12 @@ +package com.mapbefine.mapbefine.oauth; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix = "oauth.kakao") +public record KakaoOauthConfig( + String redirectUri, + String clientId, + String clientSecret, + String[] scope +) { +} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMemberClient.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMemberClient.java new file mode 100644 index 000000000..f76d39914 --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMemberClient.java @@ -0,0 +1,11 @@ +package com.mapbefine.mapbefine.oauth; + +import com.mapbefine.mapbefine.member.domain.Member; + +public interface OauthMemberClient { + + OauthServerType supportServer(); + + Member fetch(String authCode); + +} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMemberClientComposite.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMemberClientComposite.java new file mode 100644 index 000000000..863c95ee4 --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMemberClientComposite.java @@ -0,0 +1,34 @@ +package com.mapbefine.mapbefine.oauth; + +import static java.util.function.UnaryOperator.identity; +import static java.util.stream.Collectors.toMap; + +import com.mapbefine.mapbefine.member.domain.Member; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import org.springframework.stereotype.Component; + +@Component +public class OauthMemberClientComposite { + + private final Map mapping; + + public OauthMemberClientComposite(Set clients) { + mapping = clients.stream() + .collect(toMap( + OauthMemberClient::supportServer, + identity() + )); + } + + public Member fetch(OauthServerType oauthServerType, String authCode) { + return getClient(oauthServerType).fetch(authCode); + } + + private OauthMemberClient getClient(OauthServerType oauthServerType) { + return Optional.ofNullable(mapping.get(oauthServerType)) + .orElseThrow(() -> new RuntimeException("지원하지 않는 소셜 로그인 타입입니다.")); + } + +} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthServerType.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthServerType.java new file mode 100644 index 000000000..66288d58c --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthServerType.java @@ -0,0 +1,15 @@ +package com.mapbefine.mapbefine.oauth; + +import static java.util.Locale.ENGLISH; + +public enum OauthServerType { + + KAKAO, + ; + + public static OauthServerType fromName(String type) { + return OauthServerType.valueOf(type.toUpperCase(ENGLISH)); + } + +} + diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthServerTypeConverter.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthServerTypeConverter.java new file mode 100644 index 000000000..ce39272d0 --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthServerTypeConverter.java @@ -0,0 +1,12 @@ +package com.mapbefine.mapbefine.oauth; + +import org.springframework.core.convert.converter.Converter; + +public class OauthServerTypeConverter implements Converter { + + @Override + public OauthServerType convert(String source) { + return OauthServerType.fromName(source); + } + +} \ No newline at end of file diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java index 2358beedf..db641370b 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java @@ -4,75 +4,50 @@ import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.member.domain.MemberRepository; import com.mapbefine.mapbefine.member.domain.OauthId; -import com.mapbefine.mapbefine.member.domain.Role; -import com.mapbefine.mapbefine.oauth.KakaoApiClient; -import com.mapbefine.mapbefine.oauth.dto.KakaoMemberResponse; -import com.mapbefine.mapbefine.oauth.dto.KakaoToken; +import com.mapbefine.mapbefine.oauth.AuthCodeRequestUrlProviderComposite; +import com.mapbefine.mapbefine.oauth.OauthMemberClientComposite; +import com.mapbefine.mapbefine.oauth.OauthServerType; import com.mapbefine.mapbefine.oauth.dto.LoginInfoResponse; import org.springframework.stereotype.Service; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; @Service public class OauthService { - private KakaoApiClient kakaoApiClient; private MemberRepository memberRepository; private JwtTokenProvider jwtTokenProvider; - - public OauthService(KakaoApiClient kakaoApiClient, - MemberRepository memberRepository, - JwtTokenProvider jwtTokenProvider) { - this.kakaoApiClient = kakaoApiClient; + private AuthCodeRequestUrlProviderComposite authCodeRequestUrlProviderComposite; + private OauthMemberClientComposite oauthMemberClientComposite; + + public OauthService( + MemberRepository memberRepository, + JwtTokenProvider jwtTokenProvider, + AuthCodeRequestUrlProviderComposite authCodeRequestUrlProviderComposite, + OauthMemberClientComposite oauthMemberClientComposite + ) { this.memberRepository = memberRepository; this.jwtTokenProvider = jwtTokenProvider; + this.authCodeRequestUrlProviderComposite = authCodeRequestUrlProviderComposite; + this.oauthMemberClientComposite = oauthMemberClientComposite; } - public String getAuthCodeRequestUrl() { - return "https://kauth.kakao.com/oauth/authorize" - + "?response_type=" + RESPONSE_TYPE - + "&client_id=" + CLIENT_ID - + "&redirect_uri=" + REDIRECT_URI - + "&scope=" + SCOPE; + public String getAuthCodeRequestUrl(OauthServerType oauthServerType) { + return authCodeRequestUrlProviderComposite.provide(oauthServerType); } - public LoginInfoResponse login(String code) { - KakaoToken kakaoToken = kakaoApiClient.fetchToken(tokenRequestParams(code)); - - KakaoMemberResponse kakaoMemberResponse = kakaoApiClient.fetchMember( - kakaoToken.tokenType() + " " + kakaoToken.accessToken() - ); + public LoginInfoResponse login(OauthServerType oauthServerType, String code) { + Member oauthMember = oauthMemberClientComposite.fetch(oauthServerType, code); + OauthId oauthId = oauthMember.getOauthId(); + Member savedMember = memberRepository.findByOauthId(oauthId) + .orElseGet(() -> register(oauthMember)); - Long oauthId = kakaoMemberResponse.id(); - Member member = memberRepository.findByOauthIdOauthServerId(oauthId) - .orElseGet(() -> register(kakaoMemberResponse, oauthId)); // TODO: 2023/08/10 nickname을 소셜 로그인으로 받아온 정보를 저장함으로서, nickname의 unique를 보장할 수 없어짐 // 일부 사용자가 직접 입력하는 플로우를 추가할 필요가 있음 - String accessToken = jwtTokenProvider.createToken(String.valueOf(member.getId())); - - return LoginInfoResponse.of(accessToken, member); - } - - private MultiValueMap tokenRequestParams(String code) { - MultiValueMap params = new LinkedMultiValueMap<>(); - params.add("grant_type", GRANT_TYPE); - params.add("client_id", CLIENT_ID); - params.add("redirect_uri", REDIRECT_URI); - params.add("code", code); - params.add("client_secret", CLIENT_SECRET); + String accessToken = jwtTokenProvider.createToken(String.valueOf(savedMember.getId())); - return params; + return LoginInfoResponse.of(accessToken, savedMember); } - private Member register(KakaoMemberResponse kakaoMemberResponse, Long oauthId) { - Member member = Member.of( - kakaoMemberResponse.kakaoAccount().profile().nickname(), - kakaoMemberResponse.kakaoAccount().email(), - kakaoMemberResponse.kakaoAccount().profile().profileImageUrl(), - Role.USER, - new OauthId(oauthId) - ); - + private Member register(Member member) { return memberRepository.save(member); } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/KakaoMemberResponse.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/KakaoMemberResponse.java index fdb8ff8e8..4d6dc0f70 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/KakaoMemberResponse.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/KakaoMemberResponse.java @@ -1,7 +1,12 @@ package com.mapbefine.mapbefine.oauth.dto; +import static com.mapbefine.mapbefine.oauth.OauthServerType.KAKAO; + import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; import com.fasterxml.jackson.databind.annotation.JsonNaming; +import com.mapbefine.mapbefine.member.domain.Member; +import com.mapbefine.mapbefine.member.domain.OauthId; +import com.mapbefine.mapbefine.member.domain.Role; import java.time.LocalDateTime; @JsonNaming(SnakeCaseStrategy.class) @@ -12,6 +17,16 @@ public record KakaoMemberResponse( KakaoAccount kakaoAccount ) { + public Member toDomain() { + return Member.of( + kakaoAccount().profile().nickname(), + kakaoAccount().email(), + kakaoAccount().profile().profileImageUrl(), + Role.USER, + new OauthId(id, KAKAO) + ); + } + @JsonNaming(SnakeCaseStrategy.class) public record KakaoAccount( boolean profileNeedsAgreement, diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java index 5331ecd15..50644845c 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java @@ -1,11 +1,13 @@ package com.mapbefine.mapbefine.oauth.presentation; +import com.mapbefine.mapbefine.oauth.OauthServerType; import com.mapbefine.mapbefine.oauth.application.OauthService; import com.mapbefine.mapbefine.oauth.dto.LoginInfoResponse; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -20,17 +22,23 @@ public OauthController(final OauthService oauthService) { this.oauthService = oauthService; } - @GetMapping("/kakao") - public ResponseEntity redirection(HttpServletResponse response) throws IOException { - String redirectUrl = oauthService.getAuthCodeRequestUrl(); + @GetMapping("/{oauthServerType}") + public ResponseEntity redirection( + @PathVariable OauthServerType oauthServerType, + HttpServletResponse response + ) throws IOException { + String redirectUrl = oauthService.getAuthCodeRequestUrl(oauthServerType); response.sendRedirect(redirectUrl); return ResponseEntity.ok().build(); } - @GetMapping("/login/kakao") - public ResponseEntity login(@RequestParam String code) { - LoginInfoResponse loginInfo = oauthService.login(code); + @GetMapping("/login/{oauthServerType}") + public ResponseEntity login( + @PathVariable OauthServerType oauthServerType, + @RequestParam String code + ) { + LoginInfoResponse loginInfo = oauthService.login(oauthServerType, code); return ResponseEntity.ok(loginInfo); } diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 51894ffb2..3a8259581 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -21,9 +21,3 @@ logging: descriptor: sql: BasicBinder: TRACE -oauth: - kakao: - client_id: ${KAKAO_CLIENT_ID} - redirect_uri: ${KAKAO_REDIRECT_URL} - client_secret: ${KAKAO_CLIENT_SECRET} - scope: ${KAKAO_SCOPE} From c7a6b03d000ccaca2e9cfdcb6b3c505f9ad438a2 Mon Sep 17 00:00:00 2001 From: yoondgu Date: Sat, 12 Aug 2023 00:28:22 +0900 Subject: [PATCH 07/35] =?UTF-8?q?fix:=20Location=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EA=B0=84=20=EC=83=81=EC=88=98=20=EA=B3=B5=EC=9C=A0?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20=EA=B2=A9=EB=A6=AC=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/mapbefine/mapbefine/location/LocationFixture.java | 8 ++++---- .../location/application/LocationQueryServiceTest.java | 6 ++++-- .../mapbefine/mapbefine/location/domain/LocationTest.java | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/backend/src/test/java/com/mapbefine/mapbefine/location/LocationFixture.java b/backend/src/test/java/com/mapbefine/mapbefine/location/LocationFixture.java index 5eb27624a..9762eaba7 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/location/LocationFixture.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/location/LocationFixture.java @@ -16,7 +16,6 @@ public class LocationFixture { ROAD_ADDRESS, LEGAL_DONG_CODE ); - /** * BASE_COORDINATE 부터의 직선 거리 * UNDER_METER: 직선 거리 약 0.669 미터, @@ -29,7 +28,6 @@ public class LocationFixture { public static final Coordinate SEVEN_METER = Coordinate.of(37.6274194, 127.0447922); public static final Coordinate EIGHTEEN_FORTY_SIX_METER = Coordinate.of(37.6316286, 127.0650012); public static final Coordinate SIXTY_FOUR_THIRTY_METER = Coordinate.of(37.6507643, 127.1115283); - public static final List COORDINATES = List.of( LocationFixture.UNDER_ONE_METER, LocationFixture.SEVEN_METER, @@ -37,12 +35,14 @@ public class LocationFixture { LocationFixture.SIXTY_FOUR_THIRTY_METER ); - public static final Location LOCATION = new Location(ADDRESS, BASE_COORDINATE); - public static Location create() { return new Location(ADDRESS, Coordinate.of(35, 127)); } + public static Location create(Address address, Coordinate coordinate) { + return new Location(address, coordinate); + } + public static Location from(Coordinate coordinate) { return new Location(ADDRESS, coordinate); } diff --git a/backend/src/test/java/com/mapbefine/mapbefine/location/application/LocationQueryServiceTest.java b/backend/src/test/java/com/mapbefine/mapbefine/location/application/LocationQueryServiceTest.java index 14c416076..20e936457 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/location/application/LocationQueryServiceTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/location/application/LocationQueryServiceTest.java @@ -1,5 +1,7 @@ package com.mapbefine.mapbefine.location.application; +import static com.mapbefine.mapbefine.location.LocationFixture.ADDRESS; +import static com.mapbefine.mapbefine.location.LocationFixture.BASE_COORDINATE; import static org.assertj.core.api.Assertions.assertThat; import com.mapbefine.mapbefine.auth.domain.AuthMember; @@ -49,7 +51,7 @@ void setup() { member = memberRepository.save(MemberFixture.create("member", "member@naver.com", Role.ADMIN)); authMember = new Admin(member.getId()); - allPinsLocation = LocationFixture.LOCATION; + allPinsLocation = LocationFixture.create(ADDRESS, BASE_COORDINATE); locationRepository.save(allPinsLocation); topics = List.of( @@ -72,7 +74,7 @@ private Topic createAndSaveTopic(String topicName, int pinCounts) { @DisplayName("주어진 좌표의 3KM 이내 Topic들을 Pin 개수의 내림차순으로 정렬하여 조회한다.") void findNearbyTopicsSortedByPinCount() { // given - Coordinate baseCoordinate = LocationFixture.BASE_COORDINATE; + Coordinate baseCoordinate = BASE_COORDINATE; // when List currentTopics = locationQueryService.findNearbyTopicsSortedByPinCount( diff --git a/backend/src/test/java/com/mapbefine/mapbefine/location/domain/LocationTest.java b/backend/src/test/java/com/mapbefine/mapbefine/location/domain/LocationTest.java index 7a973a8d8..c82ddd951 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/location/domain/LocationTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/location/domain/LocationTest.java @@ -45,7 +45,7 @@ void addPin() { //given Member member = MemberFixture.create("member", "member@naver.com", Role.USER); Topic topic = TopicFixture.createByName("쥬니의 오락실", member); - Location location = LocationFixture.LOCATION; + Location location = LocationFixture.create(); Pin pin = PinFixture.create(location, topic, member); @@ -62,7 +62,7 @@ void addPin() { @DisplayName("같은 주소를 입력하면 참을 반환한다") void isSameAddress() { //given - Location location = LocationFixture.LOCATION; + Location location = LocationFixture.create(); //when boolean sameParcelAddress = location.isSameAddress(LocationFixture.PARCEL_ADDRESS); From 10084aa69242625b5dd163ae3e718ec352e76bc7 Mon Sep 17 00:00:00 2001 From: yoondgu Date: Sat, 12 Aug 2023 00:45:50 +0900 Subject: [PATCH 08/35] =?UTF-8?q?test:=20=EC=86=8C=EC=85=9C=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EC=A0=81=EC=9A=A9,=20=EC=9D=B8=EA=B0=80?= =?UTF-8?q?=20=EB=B0=A9=EC=8B=9D=20=EB=B3=80=EA=B2=BD=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B8=ED=95=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 소셜 로그인 적용으로 인해 생긴 OauthService를 다른 서비스 테스트에서는 Mock으로 주입함 - 인수 테스트에서 사용하는 AuthHeader 를 변경된 JWT 토큰 방식으로 적용함 --- .../oauth/application/OauthService.java | 3 +- .../mapbefine/common/IntegrationTest.java | 3 + .../common/TestAccessTokenProvider.java | 21 ++ .../common/annotation/ServiceTest.java | 3 + .../common/config/MockBeansConfig.java | 12 + .../mapbefine/member/MemberFixture.java | 15 +- .../mapbefine/member/domain/MemberTest.java | 5 +- .../presentation/MemberIntegrationTest.java | 280 ++++++------------ .../mapbefine/pin/PinIntegrationTest.java | 11 +- .../mapbefine/topic/TopicIntegrationTest.java | 93 ++---- 10 files changed, 173 insertions(+), 273 deletions(-) create mode 100644 backend/src/test/java/com/mapbefine/mapbefine/common/TestAccessTokenProvider.java create mode 100644 backend/src/test/java/com/mapbefine/mapbefine/common/config/MockBeansConfig.java diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java index db641370b..4afc2b3cc 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java @@ -35,13 +35,12 @@ public String getAuthCodeRequestUrl(OauthServerType oauthServerType) { } public LoginInfoResponse login(OauthServerType oauthServerType, String code) { + // TODO: 2023/08/11 nickname 카카오에서 받은 값 그대로 쓰지 않고 UUID 사용해 unique 하게 만들기 Member oauthMember = oauthMemberClientComposite.fetch(oauthServerType, code); OauthId oauthId = oauthMember.getOauthId(); Member savedMember = memberRepository.findByOauthId(oauthId) .orElseGet(() -> register(oauthMember)); - // TODO: 2023/08/10 nickname을 소셜 로그인으로 받아온 정보를 저장함으로서, nickname의 unique를 보장할 수 없어짐 - // 일부 사용자가 직접 입력하는 플로우를 추가할 필요가 있음 String accessToken = jwtTokenProvider.createToken(String.valueOf(savedMember.getId())); return LoginInfoResponse.of(accessToken, savedMember); diff --git a/backend/src/test/java/com/mapbefine/mapbefine/common/IntegrationTest.java b/backend/src/test/java/com/mapbefine/mapbefine/common/IntegrationTest.java index 1aa17b132..5844691fc 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/common/IntegrationTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/common/IntegrationTest.java @@ -11,6 +11,9 @@ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class IntegrationTest { + @Autowired + protected TestAccessTokenProvider testAccessTokenProvider; + @LocalServerPort private int port; diff --git a/backend/src/test/java/com/mapbefine/mapbefine/common/TestAccessTokenProvider.java b/backend/src/test/java/com/mapbefine/mapbefine/common/TestAccessTokenProvider.java new file mode 100644 index 000000000..9ef1af6a9 --- /dev/null +++ b/backend/src/test/java/com/mapbefine/mapbefine/common/TestAccessTokenProvider.java @@ -0,0 +1,21 @@ +package com.mapbefine.mapbefine.common; + +import com.mapbefine.mapbefine.auth.infrastructure.JwtTokenProvider; +import com.mapbefine.mapbefine.member.domain.Member; +import org.springframework.stereotype.Component; + +@Component +public class TestAccessTokenProvider { + + private JwtTokenProvider jwtTokenProvider; + + public TestAccessTokenProvider(JwtTokenProvider jwtTokenProvider) { + this.jwtTokenProvider = jwtTokenProvider; + } + + public String createToken(Member member) { + Long memberId = member.getId(); + return "Bearer " + jwtTokenProvider.createToken(String.valueOf(memberId)); + } + +} diff --git a/backend/src/test/java/com/mapbefine/mapbefine/common/annotation/ServiceTest.java b/backend/src/test/java/com/mapbefine/mapbefine/common/annotation/ServiceTest.java index fb28a2f0f..a071eae93 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/common/annotation/ServiceTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/common/annotation/ServiceTest.java @@ -1,5 +1,6 @@ package com.mapbefine.mapbefine.common.annotation; +import com.mapbefine.mapbefine.common.config.MockBeansConfig; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -7,6 +8,7 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.FilterType; +import org.springframework.context.annotation.Import; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -18,5 +20,6 @@ type = FilterType.ANNOTATION, value = Service.class ) ) +@Import(MockBeansConfig.class) public @interface ServiceTest { } diff --git a/backend/src/test/java/com/mapbefine/mapbefine/common/config/MockBeansConfig.java b/backend/src/test/java/com/mapbefine/mapbefine/common/config/MockBeansConfig.java new file mode 100644 index 000000000..dc4ebd1d8 --- /dev/null +++ b/backend/src/test/java/com/mapbefine/mapbefine/common/config/MockBeansConfig.java @@ -0,0 +1,12 @@ +package com.mapbefine.mapbefine.common.config; + +import com.mapbefine.mapbefine.oauth.application.OauthService; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class MockBeansConfig { + + @MockBean + private OauthService oauthService; +} diff --git a/backend/src/test/java/com/mapbefine/mapbefine/member/MemberFixture.java b/backend/src/test/java/com/mapbefine/mapbefine/member/MemberFixture.java index cc531f775..cd163b558 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/member/MemberFixture.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/member/MemberFixture.java @@ -3,7 +3,9 @@ import com.mapbefine.mapbefine.auth.domain.AuthMember; import com.mapbefine.mapbefine.auth.domain.member.User; import com.mapbefine.mapbefine.member.domain.Member; +import com.mapbefine.mapbefine.member.domain.OauthId; import com.mapbefine.mapbefine.member.domain.Role; +import com.mapbefine.mapbefine.oauth.OauthServerType; import com.mapbefine.mapbefine.topic.domain.Topic; public class MemberFixture { @@ -13,10 +15,21 @@ public static Member create(String name, String email, Role role) { name, email, "https://map-befine-official.github.io/favicon.png", - role + role, + new OauthId(1L, OauthServerType.KAKAO) ); } + public static Member createWithOauthId(String name, String email, Role role, OauthId oauthId) { + return Member.of( + name, + email, + "https://map-befine-official.github.io/favicon.png", + role, + oauthId) + ; + } + public static AuthMember createUser(Member member) { return new User( member.getId(), diff --git a/backend/src/test/java/com/mapbefine/mapbefine/member/domain/MemberTest.java b/backend/src/test/java/com/mapbefine/mapbefine/member/domain/MemberTest.java index b23efecf4..80ea71215 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/member/domain/MemberTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/member/domain/MemberTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.mapbefine.mapbefine.oauth.OauthServerType; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -21,8 +22,8 @@ void createMember_success() { nickName, email, imageUrl, - role - ); + role, + new OauthId(1L, OauthServerType.KAKAO)); // then assertThat(member).isNotNull(); diff --git a/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberIntegrationTest.java b/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberIntegrationTest.java index f27eeab63..95fa5ab72 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberIntegrationTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberIntegrationTest.java @@ -1,6 +1,7 @@ package com.mapbefine.mapbefine.member.presentation; -import static io.restassured.RestAssured.given; +import static com.mapbefine.mapbefine.oauth.OauthServerType.KAKAO; +import static io.restassured.RestAssured.*; import static org.apache.http.HttpHeaders.AUTHORIZATION; import static org.assertj.core.api.Assertions.assertThat; @@ -13,8 +14,8 @@ import com.mapbefine.mapbefine.member.domain.MemberRepository; import com.mapbefine.mapbefine.member.domain.MemberTopicPermission; import com.mapbefine.mapbefine.member.domain.MemberTopicPermissionRepository; +import com.mapbefine.mapbefine.member.domain.OauthId; import com.mapbefine.mapbefine.member.domain.Role; -import com.mapbefine.mapbefine.member.dto.request.MemberCreateRequest; import com.mapbefine.mapbefine.member.dto.request.MemberTopicPermissionCreateRequest; import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; import com.mapbefine.mapbefine.member.dto.response.MemberResponse; @@ -28,12 +29,11 @@ import com.mapbefine.mapbefine.topic.domain.Topic; import com.mapbefine.mapbefine.topic.domain.TopicRepository; import com.mapbefine.mapbefine.topic.dto.response.TopicResponse; -import io.restassured.common.mapper.TypeRef; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; +import io.restassured.common.mapper.*; +import io.restassured.response.*; import java.time.LocalDateTime; import java.util.List; -import org.apache.commons.codec.binary.Base64; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -57,31 +57,57 @@ class MemberIntegrationTest extends IntegrationTest { @Autowired private MemberTopicPermissionRepository memberTopicPermissionRepository; + private Member creator; + private Member user1; + private Member user2; + private String creatorAuthHeader; + private String user1AuthHeader; + + @Override + @BeforeEach + public void setUp() { + super.setUp(); + creator = memberRepository.save( + MemberFixture.createWithOauthId( + "creator", + "creator@naver.com", + Role.USER, + new OauthId(1L, KAKAO) + ) + ); + user1 = memberRepository.save( + MemberFixture.createWithOauthId( + "user1", + "user1@naver.com", + Role.USER, + new OauthId(2L, KAKAO) + ) + ); + user2 = memberRepository.save( + MemberFixture.createWithOauthId( + "user2", + "user2@naver.com", + Role.USER, + new OauthId(3L, KAKAO) + ) + ); + creatorAuthHeader = testAccessTokenProvider.createToken(creator); + user1AuthHeader = testAccessTokenProvider.createToken(user1); + } + @Test @DisplayName("Topic 을 만든자가 특정 유저에게 권한을 준다.") void addMemberTopicPermission() { // given - Member creator = memberRepository.save( - Member.of( - "memberr", - "memberr@naver.com", - "https://map-befine-official.github.io/favicon.png", - Role.USER - ) - ); - Member member = memberRepository.save(MemberFixture.create("member", "member@naver.com", Role.USER)); - String authHeader = Base64.encodeBase64String( - ("Basic " + creator.getMemberInfo().getEmail()).getBytes() - ); Topic topic = topicRepository.save(TopicFixture.createByName("topicName", creator)); + + // when MemberTopicPermissionCreateRequest request = new MemberTopicPermissionCreateRequest( topic.getId(), - member.getId() + user1.getId() ); - - // when ExtractableResponse response = given().log().all() - .header(AUTHORIZATION, authHeader) + .header(AUTHORIZATION, creatorAuthHeader) .contentType(MediaType.APPLICATION_JSON_VALUE) .body(request) .when().post("/members/permissions") @@ -97,31 +123,14 @@ void addMemberTopicPermission() { @DisplayName("Topic 을 만든자가 특정 유저에게 권한을 삭제한다.") void deleteMemberTopicPermission() { // given - Member creator = memberRepository.save( - Member.of( - "memberr", - "memberr@naver.com", - "https://map-befine-official.github.io/favicon.png", - Role.USER - ) - ); - Member member = memberRepository.save(MemberFixture.create( - "member", - "member@naver.com", - Role.USER - ) - ); - String authHeader = Base64.encodeBase64String( - ("Basic " + creator.getMemberInfo().getEmail()).getBytes() - ); Topic topic = topicRepository.save(TopicFixture.createByName("topicName", creator)); - - // when MemberTopicPermission memberTopicPermission = - MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic, member); + MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic, user1); Long savedId = memberTopicPermissionRepository.save(memberTopicPermission).getId(); + + // when ExtractableResponse response = given().log().all() - .header(AUTHORIZATION, authHeader) + .header(AUTHORIZATION, creatorAuthHeader) .when().delete("/members/permissions/" + savedId) .then().log().all() .extract(); @@ -135,181 +144,94 @@ void deleteMemberTopicPermission() { @DisplayName("Topic 에 권한을 가진 자들을 모두 조회한다.") void findMemberTopicPermissionAll() { // given - Member creator = memberRepository.save( - Member.of( - "memberr", - "memberr@naver.com", - "https://map-befine-official.github.io/favicon.png", - Role.USER - ) - ); - Member member1 = memberRepository.save( - MemberFixture.create( - "memberrr", - "memberrr@naver.com", - Role.USER - ) - ); - Member member2 = memberRepository.save( - MemberFixture.create( - "member", - "member@naver.com", - Role.USER - ) - ); - String authHeader = Base64.encodeBase64String( - ("Basic " + creator.getMemberInfo().getEmail()).getBytes() - ); Topic topic = topicRepository.save(TopicFixture.createByName("topicName", creator)); MemberTopicPermission memberTopicPermission1 = - MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic, member1); + MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic, user1); MemberTopicPermission memberTopicPermission2 = - MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic, member2); - - // when + MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic, user2); memberTopicPermissionRepository.save(memberTopicPermission1); memberTopicPermissionRepository.save(memberTopicPermission2); + + // when ExtractableResponse response = given().log().all() - .header(AUTHORIZATION, authHeader) + .header(AUTHORIZATION, creatorAuthHeader) .when().get("/members/permissions/topics/" + topic.getId()) .then().log().all() .extract(); // then - List memberTopicPermissionResponses = response.as(new TypeRef<>() {}); + List memberTopicPermissionResponses = response.as(new TypeRef<>() { + }); assertThat(response.statusCode()) .isEqualTo(HttpStatus.OK.value()); assertThat(memberTopicPermissionResponses) .hasSize(2) .extracting(MemberTopicPermissionResponse::memberResponse) .usingRecursiveComparison() - .isEqualTo(List.of(MemberResponse.from(member1), MemberResponse.from(member2))); + .isEqualTo(List.of(MemberResponse.from(user1), MemberResponse.from(user2))); } @Test @DisplayName("Topic 에 권한을 가진 자를 조회한다.") void findMemberTopicPermissionById() { // given - Member creator = memberRepository.save( - Member.of( - "memberr", - "memberr@naver.com", - "https://map-befine-official.github.io/favicon.png", - Role.USER - ) - ); - Member member = memberRepository.save(MemberFixture.create("memberrr", "memberrr@naver.com", Role.USER)); - String authHeader = Base64.encodeBase64String( - ("Basic " + creator.getMemberInfo().getEmail()).getBytes() - ); Topic topic = topicRepository.save(TopicFixture.createByName("topicName", creator)); MemberTopicPermission memberTopicPermission = - MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic, member); + MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic, user1); + memberTopicPermission = memberTopicPermissionRepository.save(memberTopicPermission); // when - memberTopicPermission = memberTopicPermissionRepository.save(memberTopicPermission); ExtractableResponse response = given().log().all() - .header(AUTHORIZATION, authHeader) + .header(AUTHORIZATION, creatorAuthHeader) .when().get("/members/permissions/" + memberTopicPermission.getId()) .then().log().all() .extract(); // then - MemberTopicPermissionDetailResponse memberTopicPermissionDetailResponse = response.as(MemberTopicPermissionDetailResponse.class); + MemberTopicPermissionDetailResponse memberTopicPermissionDetailResponse = response.as( + MemberTopicPermissionDetailResponse.class); assertThat(response.statusCode()) .isEqualTo(HttpStatus.OK.value()); assertThat(memberTopicPermissionDetailResponse) .extracting(MemberTopicPermissionDetailResponse::memberDetailResponse) .usingRecursiveComparison() .ignoringFieldsOfTypes(LocalDateTime.class) - .isEqualTo(MemberDetailResponse.from(member)); - } - - @Test - @DisplayName("유저를 생성한다.") - void add() { - // given - MemberCreateRequest request = new MemberCreateRequest( - "member", - "member@naver.com", - "https://map-befine-official.github.io/favicon.png", - Role.USER - ); - - // when - ExtractableResponse response = given().log().all() - .contentType(MediaType.APPLICATION_JSON_VALUE) - .body(request) - .when().post("/members") - .then().log().all() - .extract(); - - // then - assertThat(response.header("Location")).isNotBlank(); - assertThat(response.statusCode()).isEqualTo(HttpStatus.CREATED.value()); + .isEqualTo(MemberDetailResponse.from(user1)); } @Test @DisplayName("유저 목록을 조회한다.") void findAllMember() { - // given - Member member = Member.of( - "member", - "member@naver.com", - "https://map-befine-official.github.io/favicon.png", - Role.USER - ); - Member memberr = Member.of( - "memberr", - "memberr@naver.com", - "https://map-befine-official.github.io/favicon.png", - Role.USER - ); - String authHeader = Base64.encodeBase64String( - ("Basic " + member.getMemberInfo().getEmail()).getBytes() - ); - - // when - memberRepository.save(member); - memberRepository.save(memberr); - + // given, when ExtractableResponse response = given().log().all() - .header(AUTHORIZATION, authHeader) + .header(AUTHORIZATION, user1AuthHeader) .contentType(MediaType.APPLICATION_JSON_VALUE) .when().get("/members") .then().log().all() .extract(); - List memberResponses = response.as(new TypeRef<>() {}); + List memberResponses = response.as(new TypeRef<>() { + }); // then assertThat(response.statusCode()).isEqualTo(HttpStatus.OK.value()); - assertThat(memberResponses).hasSize(2) + assertThat(memberResponses).hasSize(3) .usingRecursiveComparison() - .isEqualTo(List.of(MemberResponse.from(member), MemberResponse.from(memberr))); + .isEqualTo(List.of( + MemberResponse.from(creator), + MemberResponse.from(user1), + MemberResponse.from(user2)) + ); } @Test @DisplayName("유저를 단일 조회한다.") void findMemberById() { - // given - Member member = Member.of( - "member", - "member@naver.com", - "https://map-befine-official.github.io/favicon.png", - Role.USER - ); - String authHeader = Base64.encodeBase64String( - ("Basic " + member.getMemberInfo().getEmail()).getBytes() - ); - - // when - member = memberRepository.save(member); - + // given, when ExtractableResponse response = given().log().all() - .header(AUTHORIZATION, authHeader) + .header(AUTHORIZATION, user1AuthHeader) .contentType(MediaType.APPLICATION_JSON_VALUE) - .when().get("/members/" + member.getId()) + .when().get("/members/" + user1.getId()) .then().log().all() .extract(); @@ -320,48 +242,27 @@ void findMemberById() { assertThat(memberDetailResponse) .usingRecursiveComparison() .ignoringFields("updatedAt") - .isEqualTo(MemberDetailResponse.from(member)); + .isEqualTo(MemberDetailResponse.from(user1)); } @Test @DisplayName("유저가 생성한 핀을 조회한다.") void findPinsByMember() { // given - Member creator = memberRepository.save( - MemberFixture.create( - "member", - "member@naver.com", - Role.USER - ) - ); Location location = locationRepository.save(LocationFixture.create()); Topic topic = topicRepository.save(TopicFixture.createByName("topic", creator)); - Pin pin1 = pinRepository.save( - PinFixture.create( - location, - topic, - creator - ) - ); - Pin pin2 = pinRepository.save( - PinFixture.create( - location, - topic, - creator - ) - ); - String authHeader = Base64.encodeBase64String( - ("Basic " + creator.getMemberInfo().getEmail()).getBytes() - ); + Pin pin1 = pinRepository.save(PinFixture.create(location, topic, creator)); + Pin pin2 = pinRepository.save(PinFixture.create(location, topic, creator)); // when ExtractableResponse response = given().log().all() - .header(AUTHORIZATION, authHeader) + .header(AUTHORIZATION, creatorAuthHeader) .contentType(MediaType.APPLICATION_JSON_VALUE) .when().get("/members/pins") .then().log().all() .extract(); - List pinResponses = response.as(new TypeRef<>() {}); + List pinResponses = response.as(new TypeRef<>() { + }); // then assertThat(pinResponses).hasSize(2) @@ -373,23 +274,18 @@ void findPinsByMember() { @DisplayName("유저가 생성한 토픽을 조회한다.") void findTopicsByMember() { // given - Member creator = memberRepository.save( - MemberFixture.create("member", "member@naver.com", Role.USER) - ); Topic topic1 = topicRepository.save(TopicFixture.createByName("topic1", creator)); Topic topic2 = topicRepository.save(TopicFixture.createByName("topic2", creator)); - String authHeader = Base64.encodeBase64String( - ("Basic " + creator.getMemberInfo().getEmail()).getBytes() - ); // when ExtractableResponse response = given().log().all() - .header(AUTHORIZATION, authHeader) + .header(AUTHORIZATION, creatorAuthHeader) .contentType(MediaType.APPLICATION_JSON_VALUE) .when().get("/members/topics") .then().log().all() .extract(); - List topicResponses = response.as(new TypeRef<>() {}); + List topicResponses = response.as(new TypeRef<>() { + }); // then assertThat(topicResponses).hasSize(2) diff --git a/backend/src/test/java/com/mapbefine/mapbefine/pin/PinIntegrationTest.java b/backend/src/test/java/com/mapbefine/mapbefine/pin/PinIntegrationTest.java index 8944b9e3a..a8664ddc5 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/pin/PinIntegrationTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/pin/PinIntegrationTest.java @@ -17,11 +17,9 @@ import com.mapbefine.mapbefine.topic.TopicFixture; import com.mapbefine.mapbefine.topic.domain.Topic; import com.mapbefine.mapbefine.topic.domain.TopicRepository; -import io.restassured.RestAssured; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; +import io.restassured.*; +import io.restassured.response.*; import java.util.List; -import org.apache.tomcat.util.codec.binary.Base64; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -31,7 +29,6 @@ class PinIntegrationTest extends IntegrationTest { - private static final String BASIC_FORMAT = "Basic %s"; private static final String BASE_IMAGE = "https://map-befine-official.github.io/favicon.png"; private Topic topic; @@ -55,9 +52,7 @@ class PinIntegrationTest extends IntegrationTest { @BeforeEach void saveTopicAndLocation() { member = memberRepository.save(MemberFixture.create("member", "member@naver.com", Role.ADMIN)); - authHeader = Base64.encodeBase64String( - String.format(BASIC_FORMAT, member.getMemberInfo().getEmail()).getBytes() - ); + authHeader = testAccessTokenProvider.createToken(member); topic = topicRepository.save(TopicFixture.createByName("PinIntegration 토픽", member)); location = locationRepository.save(LocationFixture.createByCoordinate(37.5152933, 127.1029866)); diff --git a/backend/src/test/java/com/mapbefine/mapbefine/topic/TopicIntegrationTest.java b/backend/src/test/java/com/mapbefine/mapbefine/topic/TopicIntegrationTest.java index bb779cdde..e33daca02 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/topic/TopicIntegrationTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/topic/TopicIntegrationTest.java @@ -1,5 +1,6 @@ package com.mapbefine.mapbefine.topic; +import static org.apache.http.HttpHeaders.AUTHORIZATION; import static org.assertj.core.api.Assertions.assertThat; import com.mapbefine.mapbefine.common.IntegrationTest; @@ -20,12 +21,12 @@ import com.mapbefine.mapbefine.topic.dto.request.TopicCreateRequest; import com.mapbefine.mapbefine.topic.dto.request.TopicMergeRequest; import com.mapbefine.mapbefine.topic.dto.request.TopicUpdateRequest; -import io.restassured.RestAssured; -import io.restassured.response.ExtractableResponse; -import io.restassured.response.Response; +import com.mapbefine.mapbefine.topic.dto.response.TopicDetailResponse; +import io.restassured.*; +import io.restassured.response.*; import java.util.Collections; import java.util.List; -import org.apache.tomcat.util.codec.binary.Base64; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -34,9 +35,6 @@ class TopicIntegrationTest extends IntegrationTest { - private static final String BASIC_FORMAT = "Basic %s"; - private static final String AUTHORIZATION = "Authorization"; - @Autowired private PinRepository pinRepository; @@ -49,12 +47,24 @@ class TopicIntegrationTest extends IntegrationTest { @Autowired private MemberRepository memberRepository; + + private Member member; + private Topic topic; + private Location location; + private String authHeader; + + @BeforeEach + void setMember() { + member = memberRepository.save(MemberFixture.create("other", "other@othter.com", Role.ADMIN)); + topic = topicRepository.save(TopicFixture.createPublicAndAllMembersTopic(member)); + location = locationRepository.save(LocationFixture.create()); + authHeader = testAccessTokenProvider.createToken(member); + } + + @Test @DisplayName("Pin 목록 없이 Topic을 생성하면 201을 반환한다") void createNewTopicWithoutPins_Success() { - Member member = MemberFixture.create("member", "member@naver.com", Role.USER); - memberRepository.save(member); - TopicCreateRequest 준팍의_또간집 = new TopicCreateRequest( "준팍의 또간집", "https://map-befine-official.github.io/favicon.png", @@ -64,10 +74,6 @@ void createNewTopicWithoutPins_Success() { Collections.emptyList() ); - String authHeader = Base64.encodeBase64String( - String.format(BASIC_FORMAT, member.getMemberInfo().getEmail()).getBytes() - ); - // when ExtractableResponse response = createNewTopic(준팍의_또간집, authHeader); @@ -76,8 +82,7 @@ void createNewTopicWithoutPins_Success() { assertThat(response.header("Location")).isNotBlank(); } - private ExtractableResponse createNewTopic(TopicCreateRequest request, - String authHeader) { + private ExtractableResponse createNewTopic(TopicCreateRequest request, String authHeader) { return RestAssured.given() .log().all() .header(AUTHORIZATION, authHeader) @@ -91,25 +96,14 @@ private ExtractableResponse createNewTopic(TopicCreateRequest request, @Test @DisplayName("Pin 목록과 함께 Topic을 생성하면 201을 반환한다") void createNewTopicWithPins_Success() { - Member member = MemberFixture.create("member", "member@naver.com", Role.USER); - memberRepository.save(member); - - Location location = LocationFixture.create(); - locationRepository.save(location); - Topic topic = TopicFixture.createPublicAndAllMembersTopic(member); - Pin pin = PinFixture.create(location, topic, member); - topicRepository.save(topic); + PinFixture.create(location, topic, member); List pins = pinRepository.findAll(); List pinIds = pins.stream() .map(Pin::getId) .toList(); - String authHeader = Base64.encodeBase64String( - String.format(BASIC_FORMAT, member.getMemberInfo().getEmail()).getBytes() - ); - TopicCreateRequest 준팍의_또간집 = new TopicCreateRequest( "준팍의 또간집", "https://map-befine-official.github.io/favicon.png", @@ -131,13 +125,6 @@ void createNewTopicWithPins_Success() { @DisplayName("여러개의 토픽을 병합하면 201을 반환한다") void createMergeTopic_Success() { // given - Member member = MemberFixture.create("member", "member@naver.com", Role.USER); - memberRepository.save(member); - - String authHeader = Base64.encodeBase64String( - String.format(BASIC_FORMAT, member.getMemberInfo().getEmail()).getBytes() - ); - TopicCreateRequest 준팍의_또간집 = new TopicCreateRequest( "준팍의 또간집", "https://map-befine-official.github.io/favicon.png", @@ -187,13 +174,6 @@ void createMergeTopic_Success() { @Test @DisplayName("Topic을 수정하면 200을 반환한다") void updateTopic_Success() { - Member member = MemberFixture.create("member", "member@naver.com", Role.USER); - memberRepository.save(member); - - String authHeader = Base64.encodeBase64String( - String.format(BASIC_FORMAT, member.getMemberInfo().getEmail()).getBytes() - ); - ExtractableResponse newTopic = createNewTopic( new TopicCreateRequest( "준팍의 또간집", @@ -231,12 +211,6 @@ void updateTopic_Success() { @Test @DisplayName("Topic을 삭제하면 204를 반환한다") void deleteTopic_Success() { - Member member = MemberFixture.create("member", "member@naver.com", Role.ADMIN); - memberRepository.save(member); - - String authHeader = Base64.encodeBase64String( - String.format(BASIC_FORMAT, member.getMemberInfo().getEmail()).getBytes() - ); ExtractableResponse newTopic = createNewTopic( new TopicCreateRequest( "준팍의 또간집", @@ -266,14 +240,6 @@ void deleteTopic_Success() { @Test @DisplayName("Topic 목록을 조회하면 200을 반환한다") void findTopics_Success() { - //given - Member member = MemberFixture.create("member", "member@naver.com", Role.USER); - memberRepository.save(member); - - String authHeader = Base64.encodeBase64String( - String.format(BASIC_FORMAT, member.getMemberInfo().getEmail()).getBytes() - ); - // when ExtractableResponse response = RestAssured .given().log().all() @@ -291,12 +257,6 @@ void findTopics_Success() { @DisplayName("Topic 상세 정보를 조회하면 200을 반환한다") void findTopicDetail_Success() { //given - Member member = MemberFixture.create("member", "member@naver.com", Role.USER); - memberRepository.save(member); - - String authHeader = Base64.encodeBase64String( - String.format(BASIC_FORMAT, member.getMemberInfo().getEmail()).getBytes() - ); TopicCreateRequest request = new TopicCreateRequest( "topicName", "https://map-befine-official.github.io/favicon.png", @@ -326,12 +286,6 @@ void findTopicDetail_Success() { @DisplayName("Topic 상세 정보 여러개를 조회하면 200을 반환한다") void findTopicDetailsByIds_Success() { //given - Member member = MemberFixture.create("member", "member@naver.com", Role.USER); - memberRepository.save(member); - - String authHeader = Base64.encodeBase64String( - String.format(BASIC_FORMAT, member.getMemberInfo().getEmail()).getBytes() - ); TopicCreateRequest request = new TopicCreateRequest( "topicName", "https://map-befine-official.github.io/favicon.png", @@ -357,7 +311,10 @@ void findTopicDetailsByIds_Success() { .then().log().all() .extract(); + List responses = response.jsonPath().getList(".", TopicDetailResponse.class); + // then assertThat(response.statusCode()).isEqualTo(HttpStatus.OK.value()); + assertThat(responses).hasSize(2); } } From e6f39b014f63a5356522ef3782eb5e7466fb4cb6 Mon Sep 17 00:00:00 2001 From: yoondgu Date: Sat, 12 Aug 2023 11:54:05 +0900 Subject: [PATCH 09/35] =?UTF-8?q?chore:=20=EA=B5=AC=EC=84=B1=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=EC=97=90=20=EC=9D=B8=EC=A6=9D=20=EC=9D=B8=EA=B0=80=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=ED=99=98=EA=B2=BD=EB=B3=80=EC=88=98=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: kpeel5839 --- backend/src/main/resources/application-dev.yml | 13 +++++++++++++ backend/src/main/resources/application-prod.yml | 13 +++++++++++++ backend/src/main/resources/application.yml | 13 +++++++++++++ backend/src/test/resources/application.yml | 13 +++++++++++++ 4 files changed, 52 insertions(+) diff --git a/backend/src/main/resources/application-dev.yml b/backend/src/main/resources/application-dev.yml index ccee44470..8db955b88 100644 --- a/backend/src/main/resources/application-dev.yml +++ b/backend/src/main/resources/application-dev.yml @@ -19,3 +19,16 @@ logging: descriptor: sql: BasicBinder: TRACE + +oauth: + kakao: + client_id: ${OAUTH_KAKAO_CLIENT_ID} + redirect_uri: ${OAUTH_KAKAO_REDIRECT_URI} + client_secret: ${OAUTH_KAKAO_CLIENT_SECRET} + scope: ${OAUTH_KAKAO_SCOPE} + +security: + jwt: + token: + secret-key: ${JWT_TOKEN_SECRET_KEY} + expire-length: ${JWT_TOKEN_EXPIRE_LENGTH} diff --git a/backend/src/main/resources/application-prod.yml b/backend/src/main/resources/application-prod.yml index 0752d2677..55c5b068e 100644 --- a/backend/src/main/resources/application-prod.yml +++ b/backend/src/main/resources/application-prod.yml @@ -7,3 +7,16 @@ spring: jpa: hibernate: ddl-auto: none + +oauth: + kakao: + client_id: ${OAUTH_KAKAO_CLIENT_ID} + redirect_uri: ${OAUTH_KAKAO_REDIRECT_URI} + client_secret: ${OAUTH_KAKAO_CLIENT_SECRET} + scope: ${OAUTH_KAKAO_SCOPE} + +security: + jwt: + token: + secret-key: ${JWT_TOKEN_SECRET_KEY} + expire-length: ${JWT_TOKEN_EXPIRE_LENGTH} diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 3a8259581..3a75b6ddf 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -21,3 +21,16 @@ logging: descriptor: sql: BasicBinder: TRACE + +oauth: + kakao: + client_id: ${OAUTH_KAKAO_CLIENT_ID} + redirect_uri: ${OAUTH_KAKAO_REDIRECT_URI} + client_secret: ${OAUTH_KAKAO_CLIENT_SECRET} + scope: ${OAUTH_KAKAO_SCOPE} + +security: + jwt: + token: + secret-key: ${JWT_TOKEN_SECRET_KEY} + expire-length: ${JWT_TOKEN_EXPIRE_LENGTH} diff --git a/backend/src/test/resources/application.yml b/backend/src/test/resources/application.yml index 3761dba00..3acf2336d 100644 --- a/backend/src/test/resources/application.yml +++ b/backend/src/test/resources/application.yml @@ -23,3 +23,16 @@ logging: org.hibernate.orm.jdbc.bind: trace org.hibernate.type: trace org.hibernate.stat: debug + +oauth: + kakao: + client_id: ${OAUTH_KAKAO_CLIENT_ID} + redirect_uri: ${OAUTH_KAKAO_REDIRECT_URI} + client_secret: ${OAUTH_KAKAO_CLIENT_SECRET} + scope: ${OAUTH_KAKAO_SCOPE} + +security: + jwt: + token: + secret-key: ${JWT_TOKEN_SECRET_KEY} + expire-length: ${JWT_TOKEN_EXPIRE_LENGTH} From 39f38c27edecd95f0fc3a4ff76f33ee09f225d3a Mon Sep 17 00:00:00 2001 From: yoondgu Date: Sat, 12 Aug 2023 12:00:01 +0900 Subject: [PATCH 10/35] =?UTF-8?q?refactor:=20=EC=86=8C=EC=85=9C=20?= =?UTF-8?q?=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85=20=EC=8B=9C=20=EB=8B=89?= =?UTF-8?q?=EB=84=A4=EC=9E=84=20=EB=9E=9C=EB=8D=A4=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD,=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=B6=94=EC=83=81=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - KakaoMemberResponse 이전에 OauthServerType을 추상화한 OauthMember 계층 추가 - OauthMember에 필요한 정보만 받아와서, 새로 가입할 Member 객체 생성 - Member 객체 생성 시 닉네임 랜덤 생성 - 이를 통해 Service의 로직을 줄이면서 다른 소셜 로그인 타입에서도 똑같이 닉네임 랜덤 생성 가능하도록 함 - 이를 통해 member 패키지와의 참조 최소화 Co-authored-by: kpeel5839 --- .../mapbefine/member/domain/Member.java | 22 ++++++++++ .../mapbefine/oauth/KakaoMemberClient.java | 5 +-- .../mapbefine/oauth/OauthMember.java | 43 +++++++++++++++++++ .../mapbefine/oauth/OauthMemberClient.java | 4 +- .../oauth/OauthMemberClientComposite.java | 3 +- .../oauth/application/OauthService.java | 13 +++--- .../oauth/dto/KakaoMemberResponse.java | 17 +++----- 7 files changed, 82 insertions(+), 25 deletions(-) create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMember.java diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/Member.java b/backend/src/main/java/com/mapbefine/mapbefine/member/domain/Member.java index 280e47ea1..8ceea7652 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/Member.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/member/domain/Member.java @@ -1,5 +1,6 @@ package com.mapbefine.mapbefine.member.domain; +import static java.util.UUID.randomUUID; import static lombok.AccessLevel.PROTECTED; import com.mapbefine.mapbefine.common.entity.BaseTimeEntity; @@ -21,6 +22,9 @@ @Getter public class Member extends BaseTimeEntity { + private static final String DEFAULT_NICKNAME_PREFIX = "모험가"; + private static final int DEFAULT_NICKNAME_SUFFIX_LENGTH = 7; + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @@ -57,6 +61,24 @@ public static Member of( return new Member(memberInfo); } + public static Member ofRandomNickname( + String email, + String imageUrl, + Role role, + OauthId oauthId + ) { + String nickName = DEFAULT_NICKNAME_PREFIX + createNicknameSuffix(); + + return Member.of(nickName, email, imageUrl, role, oauthId); + } + + private static String createNicknameSuffix() { + return randomUUID() + .toString() + .replaceAll("-", "") + .substring(0, DEFAULT_NICKNAME_SUFFIX_LENGTH); + } + public void update( String nickName, String email, diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoMemberClient.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoMemberClient.java index d081b9ca0..22813ede6 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoMemberClient.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoMemberClient.java @@ -1,6 +1,5 @@ package com.mapbefine.mapbefine.oauth; -import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.oauth.dto.KakaoMemberResponse; import com.mapbefine.mapbefine.oauth.dto.KakaoToken; import org.springframework.stereotype.Component; @@ -27,13 +26,13 @@ public OauthServerType supportServer() { } @Override - public Member fetch(String authCode) { + public OauthMember fetch(String authCode) { KakaoToken kakaoToken = kakaoApiClient.fetchToken(tokenRequestParams(authCode)); KakaoMemberResponse kakaoMemberResponse = kakaoApiClient.fetchMember( kakaoToken.tokenType() + " " + kakaoToken.accessToken() ); - return kakaoMemberResponse.toDomain(); + return kakaoMemberResponse.extract(); } private MultiValueMap tokenRequestParams(String authCode) { diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMember.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMember.java new file mode 100644 index 000000000..9e6acb85c --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMember.java @@ -0,0 +1,43 @@ +package com.mapbefine.mapbefine.oauth; + +import com.mapbefine.mapbefine.member.domain.Member; +import com.mapbefine.mapbefine.member.domain.OauthId; +import com.mapbefine.mapbefine.member.domain.Role; +import lombok.Getter; + +@Getter +public class OauthMember { + + private String email; + private String profileImageUrl; + private OauthId oauthId; + + private OauthMember( + String email, + String profileImageUrl, + OauthId oauthId + ) { + this.email = email; + this.profileImageUrl = profileImageUrl; + this.oauthId = oauthId; + } + + public static OauthMember of( + String email, + String profileImageUrl, + Long oauthServerId, + OauthServerType oauthServerType + ) { + return new OauthMember(email, profileImageUrl, new OauthId(oauthServerId, oauthServerType)); + } + + public Member toRegisterMember() { + return Member.ofRandomNickname( + email, + profileImageUrl, + Role.USER, + oauthId + ); + } + +} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMemberClient.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMemberClient.java index f76d39914..1a229e38e 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMemberClient.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMemberClient.java @@ -1,11 +1,9 @@ package com.mapbefine.mapbefine.oauth; -import com.mapbefine.mapbefine.member.domain.Member; - public interface OauthMemberClient { OauthServerType supportServer(); - Member fetch(String authCode); + OauthMember fetch(String authCode); } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMemberClientComposite.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMemberClientComposite.java index 863c95ee4..88c2e441c 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMemberClientComposite.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMemberClientComposite.java @@ -3,7 +3,6 @@ import static java.util.function.UnaryOperator.identity; import static java.util.stream.Collectors.toMap; -import com.mapbefine.mapbefine.member.domain.Member; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -22,7 +21,7 @@ public OauthMemberClientComposite(Set clients) { )); } - public Member fetch(OauthServerType oauthServerType, String authCode) { + public OauthMember fetch(OauthServerType oauthServerType, String authCode) { return getClient(oauthServerType).fetch(authCode); } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java index 4afc2b3cc..cb8167195 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java @@ -3,8 +3,8 @@ import com.mapbefine.mapbefine.auth.infrastructure.JwtTokenProvider; import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.member.domain.MemberRepository; -import com.mapbefine.mapbefine.member.domain.OauthId; import com.mapbefine.mapbefine.oauth.AuthCodeRequestUrlProviderComposite; +import com.mapbefine.mapbefine.oauth.OauthMember; import com.mapbefine.mapbefine.oauth.OauthMemberClientComposite; import com.mapbefine.mapbefine.oauth.OauthServerType; import com.mapbefine.mapbefine.oauth.dto.LoginInfoResponse; @@ -35,10 +35,8 @@ public String getAuthCodeRequestUrl(OauthServerType oauthServerType) { } public LoginInfoResponse login(OauthServerType oauthServerType, String code) { - // TODO: 2023/08/11 nickname 카카오에서 받은 값 그대로 쓰지 않고 UUID 사용해 unique 하게 만들기 - Member oauthMember = oauthMemberClientComposite.fetch(oauthServerType, code); - OauthId oauthId = oauthMember.getOauthId(); - Member savedMember = memberRepository.findByOauthId(oauthId) + OauthMember oauthMember = oauthMemberClientComposite.fetch(oauthServerType, code); + Member savedMember = memberRepository.findByOauthId(oauthMember.getOauthId()) .orElseGet(() -> register(oauthMember)); String accessToken = jwtTokenProvider.createToken(String.valueOf(savedMember.getId())); @@ -46,8 +44,9 @@ public LoginInfoResponse login(OauthServerType oauthServerType, String code) { return LoginInfoResponse.of(accessToken, savedMember); } - private Member register(Member member) { - return memberRepository.save(member); + private Member register(OauthMember oauthMember) { + + return memberRepository.save(oauthMember.toRegisterMember()); } } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/KakaoMemberResponse.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/KakaoMemberResponse.java index 4d6dc0f70..1173c611e 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/KakaoMemberResponse.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/KakaoMemberResponse.java @@ -4,9 +4,7 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; import com.fasterxml.jackson.databind.annotation.JsonNaming; -import com.mapbefine.mapbefine.member.domain.Member; -import com.mapbefine.mapbefine.member.domain.OauthId; -import com.mapbefine.mapbefine.member.domain.Role; +import com.mapbefine.mapbefine.oauth.OauthMember; import java.time.LocalDateTime; @JsonNaming(SnakeCaseStrategy.class) @@ -17,13 +15,12 @@ public record KakaoMemberResponse( KakaoAccount kakaoAccount ) { - public Member toDomain() { - return Member.of( - kakaoAccount().profile().nickname(), - kakaoAccount().email(), - kakaoAccount().profile().profileImageUrl(), - Role.USER, - new OauthId(id, KAKAO) + public OauthMember extract() { + return OauthMember.of( + kakaoAccount().email, + kakaoAccount().profile.profileImageUrl, + id, + KAKAO ); } From 0f2baaa6864f442d67174acb2a2f5fc495ef08f9 Mon Sep 17 00:00:00 2001 From: yoondgu Date: Sat, 12 Aug 2023 12:01:32 +0900 Subject: [PATCH 11/35] =?UTF-8?q?rename:=20=ED=81=B4=EB=9E=98=EC=8A=A4?= =?UTF-8?q?=EB=AA=85=20=EC=98=A4=EA=B8=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: kpeel5839 --- ...iderProvider.java => KakaoAuthCodeRequestUrlProvider.java} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename backend/src/main/java/com/mapbefine/mapbefine/oauth/{KakaoAuthCodeRequestUrlProviderProvider.java => KakaoAuthCodeRequestUrlProvider.java} (82%) diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoAuthCodeRequestUrlProviderProvider.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoAuthCodeRequestUrlProvider.java similarity index 82% rename from backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoAuthCodeRequestUrlProviderProvider.java rename to backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoAuthCodeRequestUrlProvider.java index 45dc696ff..36c1cbc72 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoAuthCodeRequestUrlProviderProvider.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoAuthCodeRequestUrlProvider.java @@ -4,11 +4,11 @@ import org.springframework.web.util.UriComponentsBuilder; @Component -public class KakaoAuthCodeRequestUrlProviderProvider implements AuthCodeRequestUrlProvider { +public class KakaoAuthCodeRequestUrlProvider implements AuthCodeRequestUrlProvider { private final KakaoOauthConfig kakaoOauthConfig; - public KakaoAuthCodeRequestUrlProviderProvider(KakaoOauthConfig kakaoOauthConfig) { + public KakaoAuthCodeRequestUrlProvider(KakaoOauthConfig kakaoOauthConfig) { this.kakaoOauthConfig = kakaoOauthConfig; } From 5cba4ba7b3421417be5f74cd798b888dc0c5ffcf Mon Sep 17 00:00:00 2001 From: yoondgu Date: Sat, 12 Aug 2023 12:13:38 +0900 Subject: [PATCH 12/35] =?UTF-8?q?rename:=20oauth=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - OauthServerTypeConverter common 패키지로 이동 - kakao 구현체, dto 패키지 분리 Co-authored-by: kpeel5839 --- .../{oauth => common/config}/HttpInterfaceConfig.java | 3 ++- .../com/mapbefine/mapbefine/common/config/WebConfig.java | 2 +- .../converter}/OauthServerTypeConverter.java | 5 +++-- .../com/mapbefine/mapbefine/member/domain/OauthId.java | 2 +- .../mapbefine/oauth/application/OauthService.java | 8 ++++---- .../oauth/{ => domain}/AuthCodeRequestUrlProvider.java | 2 +- .../AuthCodeRequestUrlProviderComposite.java | 2 +- .../mapbefine/oauth/{ => domain}/OauthMember.java | 2 +- .../mapbefine/oauth/{ => domain}/OauthMemberClient.java | 2 +- .../oauth/{ => domain}/OauthMemberClientComposite.java | 2 +- .../mapbefine/oauth/{ => domain}/OauthServerType.java | 2 +- .../oauth/{ => domain/kakao}/KakaoApiClient.java | 6 +++--- .../kakao}/KakaoAuthCodeRequestUrlProvider.java | 4 +++- .../oauth/{ => domain/kakao}/KakaoMemberClient.java | 9 ++++++--- .../oauth/{ => domain/kakao}/KakaoOauthConfig.java | 2 +- .../{ => domain/kakao}/dto/KakaoMemberResponse.java | 6 +++--- .../oauth/{ => domain/kakao}/dto/KakaoToken.java | 2 +- .../mapbefine/oauth/presentation/OauthController.java | 2 +- .../com/mapbefine/mapbefine/member/MemberFixture.java | 2 +- .../mapbefine/mapbefine/member/domain/MemberTest.java | 2 +- .../member/presentation/MemberIntegrationTest.java | 2 +- 21 files changed, 38 insertions(+), 31 deletions(-) rename backend/src/main/java/com/mapbefine/mapbefine/{oauth => common/config}/HttpInterfaceConfig.java (87%) rename backend/src/main/java/com/mapbefine/mapbefine/{oauth => common/converter}/OauthServerTypeConverter.java (70%) rename backend/src/main/java/com/mapbefine/mapbefine/oauth/{ => domain}/AuthCodeRequestUrlProvider.java (70%) rename backend/src/main/java/com/mapbefine/mapbefine/oauth/{ => domain}/AuthCodeRequestUrlProviderComposite.java (95%) rename backend/src/main/java/com/mapbefine/mapbefine/oauth/{ => domain}/OauthMember.java (95%) rename backend/src/main/java/com/mapbefine/mapbefine/oauth/{ => domain}/OauthMemberClient.java (72%) rename backend/src/main/java/com/mapbefine/mapbefine/oauth/{ => domain}/OauthMemberClientComposite.java (95%) rename backend/src/main/java/com/mapbefine/mapbefine/oauth/{ => domain}/OauthServerType.java (83%) rename backend/src/main/java/com/mapbefine/mapbefine/oauth/{ => domain/kakao}/KakaoApiClient.java (81%) rename backend/src/main/java/com/mapbefine/mapbefine/oauth/{ => domain/kakao}/KakaoAuthCodeRequestUrlProvider.java (84%) rename backend/src/main/java/com/mapbefine/mapbefine/oauth/{ => domain/kakao}/KakaoMemberClient.java (80%) rename backend/src/main/java/com/mapbefine/mapbefine/oauth/{ => domain/kakao}/KakaoOauthConfig.java (83%) rename backend/src/main/java/com/mapbefine/mapbefine/oauth/{ => domain/kakao}/dto/KakaoMemberResponse.java (90%) rename backend/src/main/java/com/mapbefine/mapbefine/oauth/{ => domain/kakao}/dto/KakaoToken.java (87%) diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/HttpInterfaceConfig.java b/backend/src/main/java/com/mapbefine/mapbefine/common/config/HttpInterfaceConfig.java similarity index 87% rename from backend/src/main/java/com/mapbefine/mapbefine/oauth/HttpInterfaceConfig.java rename to backend/src/main/java/com/mapbefine/mapbefine/common/config/HttpInterfaceConfig.java index 0bfefd990..90a0188ac 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/HttpInterfaceConfig.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/common/config/HttpInterfaceConfig.java @@ -1,5 +1,6 @@ -package com.mapbefine.mapbefine.oauth; +package com.mapbefine.mapbefine.common.config; +import com.mapbefine.mapbefine.oauth.domain.kakao.KakaoApiClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.reactive.function.client.WebClient; diff --git a/backend/src/main/java/com/mapbefine/mapbefine/common/config/WebConfig.java b/backend/src/main/java/com/mapbefine/mapbefine/common/config/WebConfig.java index faa1a1bc2..635d99ae7 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/common/config/WebConfig.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/common/config/WebConfig.java @@ -1,6 +1,6 @@ package com.mapbefine.mapbefine.common.config; -import com.mapbefine.mapbefine.oauth.OauthServerTypeConverter; +import com.mapbefine.mapbefine.common.converter.OauthServerTypeConverter; import org.springframework.context.annotation.Configuration; import org.springframework.format.FormatterRegistry; import org.springframework.web.servlet.config.annotation.CorsRegistry; diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthServerTypeConverter.java b/backend/src/main/java/com/mapbefine/mapbefine/common/converter/OauthServerTypeConverter.java similarity index 70% rename from backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthServerTypeConverter.java rename to backend/src/main/java/com/mapbefine/mapbefine/common/converter/OauthServerTypeConverter.java index ce39272d0..7855d11a9 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthServerTypeConverter.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/common/converter/OauthServerTypeConverter.java @@ -1,5 +1,6 @@ -package com.mapbefine.mapbefine.oauth; +package com.mapbefine.mapbefine.common.converter; +import com.mapbefine.mapbefine.oauth.domain.OauthServerType; import org.springframework.core.convert.converter.Converter; public class OauthServerTypeConverter implements Converter { @@ -9,4 +10,4 @@ public OauthServerType convert(String source) { return OauthServerType.fromName(source); } -} \ No newline at end of file +} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/OauthId.java b/backend/src/main/java/com/mapbefine/mapbefine/member/domain/OauthId.java index 0fcd42686..61f22fea7 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/OauthId.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/member/domain/OauthId.java @@ -2,7 +2,7 @@ import static lombok.AccessLevel.PROTECTED; -import com.mapbefine.mapbefine.oauth.OauthServerType; +import com.mapbefine.mapbefine.oauth.domain.OauthServerType; import jakarta.persistence.Column; import jakarta.persistence.Embeddable; import jakarta.persistence.EnumType; diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java index cb8167195..d75526a0e 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/application/OauthService.java @@ -3,10 +3,10 @@ import com.mapbefine.mapbefine.auth.infrastructure.JwtTokenProvider; import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.member.domain.MemberRepository; -import com.mapbefine.mapbefine.oauth.AuthCodeRequestUrlProviderComposite; -import com.mapbefine.mapbefine.oauth.OauthMember; -import com.mapbefine.mapbefine.oauth.OauthMemberClientComposite; -import com.mapbefine.mapbefine.oauth.OauthServerType; +import com.mapbefine.mapbefine.oauth.domain.AuthCodeRequestUrlProviderComposite; +import com.mapbefine.mapbefine.oauth.domain.OauthMember; +import com.mapbefine.mapbefine.oauth.domain.OauthMemberClientComposite; +import com.mapbefine.mapbefine.oauth.domain.OauthServerType; import com.mapbefine.mapbefine.oauth.dto.LoginInfoResponse; import org.springframework.stereotype.Service; diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/AuthCodeRequestUrlProvider.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/AuthCodeRequestUrlProvider.java similarity index 70% rename from backend/src/main/java/com/mapbefine/mapbefine/oauth/AuthCodeRequestUrlProvider.java rename to backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/AuthCodeRequestUrlProvider.java index 62fc08ca3..93638b891 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/AuthCodeRequestUrlProvider.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/AuthCodeRequestUrlProvider.java @@ -1,4 +1,4 @@ -package com.mapbefine.mapbefine.oauth; +package com.mapbefine.mapbefine.oauth.domain; public interface AuthCodeRequestUrlProvider { diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/AuthCodeRequestUrlProviderComposite.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/AuthCodeRequestUrlProviderComposite.java similarity index 95% rename from backend/src/main/java/com/mapbefine/mapbefine/oauth/AuthCodeRequestUrlProviderComposite.java rename to backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/AuthCodeRequestUrlProviderComposite.java index c940bdce7..117eb7be2 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/AuthCodeRequestUrlProviderComposite.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/AuthCodeRequestUrlProviderComposite.java @@ -1,4 +1,4 @@ -package com.mapbefine.mapbefine.oauth; +package com.mapbefine.mapbefine.oauth.domain; import static java.util.function.UnaryOperator.identity; import static java.util.stream.Collectors.toMap; diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMember.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/OauthMember.java similarity index 95% rename from backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMember.java rename to backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/OauthMember.java index 9e6acb85c..9599b9d8d 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMember.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/OauthMember.java @@ -1,4 +1,4 @@ -package com.mapbefine.mapbefine.oauth; +package com.mapbefine.mapbefine.oauth.domain; import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.member.domain.OauthId; diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMemberClient.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/OauthMemberClient.java similarity index 72% rename from backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMemberClient.java rename to backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/OauthMemberClient.java index 1a229e38e..eff82552d 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMemberClient.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/OauthMemberClient.java @@ -1,4 +1,4 @@ -package com.mapbefine.mapbefine.oauth; +package com.mapbefine.mapbefine.oauth.domain; public interface OauthMemberClient { diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMemberClientComposite.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/OauthMemberClientComposite.java similarity index 95% rename from backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMemberClientComposite.java rename to backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/OauthMemberClientComposite.java index 88c2e441c..c556a011c 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthMemberClientComposite.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/OauthMemberClientComposite.java @@ -1,4 +1,4 @@ -package com.mapbefine.mapbefine.oauth; +package com.mapbefine.mapbefine.oauth.domain; import static java.util.function.UnaryOperator.identity; import static java.util.stream.Collectors.toMap; diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthServerType.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/OauthServerType.java similarity index 83% rename from backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthServerType.java rename to backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/OauthServerType.java index 66288d58c..ac15172ea 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/OauthServerType.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/OauthServerType.java @@ -1,4 +1,4 @@ -package com.mapbefine.mapbefine.oauth; +package com.mapbefine.mapbefine.oauth.domain; import static java.util.Locale.ENGLISH; diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoApiClient.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoApiClient.java similarity index 81% rename from backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoApiClient.java rename to backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoApiClient.java index e092edc28..b05612436 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoApiClient.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoApiClient.java @@ -1,10 +1,10 @@ -package com.mapbefine.mapbefine.oauth; +package com.mapbefine.mapbefine.oauth.domain.kakao; import static org.springframework.http.HttpHeaders.AUTHORIZATION; import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; -import com.mapbefine.mapbefine.oauth.dto.KakaoMemberResponse; -import com.mapbefine.mapbefine.oauth.dto.KakaoToken; +import com.mapbefine.mapbefine.oauth.domain.kakao.dto.KakaoMemberResponse; +import com.mapbefine.mapbefine.oauth.domain.kakao.dto.KakaoToken; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoAuthCodeRequestUrlProvider.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoAuthCodeRequestUrlProvider.java similarity index 84% rename from backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoAuthCodeRequestUrlProvider.java rename to backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoAuthCodeRequestUrlProvider.java index 36c1cbc72..7ae2d404f 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoAuthCodeRequestUrlProvider.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoAuthCodeRequestUrlProvider.java @@ -1,5 +1,7 @@ -package com.mapbefine.mapbefine.oauth; +package com.mapbefine.mapbefine.oauth.domain.kakao; +import com.mapbefine.mapbefine.oauth.domain.AuthCodeRequestUrlProvider; +import com.mapbefine.mapbefine.oauth.domain.OauthServerType; import org.springframework.stereotype.Component; import org.springframework.web.util.UriComponentsBuilder; diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoMemberClient.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoMemberClient.java similarity index 80% rename from backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoMemberClient.java rename to backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoMemberClient.java index 22813ede6..84354a459 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoMemberClient.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoMemberClient.java @@ -1,7 +1,10 @@ -package com.mapbefine.mapbefine.oauth; +package com.mapbefine.mapbefine.oauth.domain.kakao; -import com.mapbefine.mapbefine.oauth.dto.KakaoMemberResponse; -import com.mapbefine.mapbefine.oauth.dto.KakaoToken; +import com.mapbefine.mapbefine.oauth.domain.OauthMember; +import com.mapbefine.mapbefine.oauth.domain.OauthMemberClient; +import com.mapbefine.mapbefine.oauth.domain.OauthServerType; +import com.mapbefine.mapbefine.oauth.domain.kakao.dto.KakaoMemberResponse; +import com.mapbefine.mapbefine.oauth.domain.kakao.dto.KakaoToken; import org.springframework.stereotype.Component; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoOauthConfig.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoOauthConfig.java similarity index 83% rename from backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoOauthConfig.java rename to backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoOauthConfig.java index 89d2cddff..a391ee832 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/KakaoOauthConfig.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoOauthConfig.java @@ -1,4 +1,4 @@ -package com.mapbefine.mapbefine.oauth; +package com.mapbefine.mapbefine.oauth.domain.kakao; import org.springframework.boot.context.properties.ConfigurationProperties; diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/KakaoMemberResponse.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/dto/KakaoMemberResponse.java similarity index 90% rename from backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/KakaoMemberResponse.java rename to backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/dto/KakaoMemberResponse.java index 1173c611e..d4f9dcd14 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/KakaoMemberResponse.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/dto/KakaoMemberResponse.java @@ -1,10 +1,10 @@ -package com.mapbefine.mapbefine.oauth.dto; +package com.mapbefine.mapbefine.oauth.domain.kakao.dto; -import static com.mapbefine.mapbefine.oauth.OauthServerType.KAKAO; +import static com.mapbefine.mapbefine.oauth.domain.OauthServerType.KAKAO; import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; import com.fasterxml.jackson.databind.annotation.JsonNaming; -import com.mapbefine.mapbefine.oauth.OauthMember; +import com.mapbefine.mapbefine.oauth.domain.OauthMember; import java.time.LocalDateTime; @JsonNaming(SnakeCaseStrategy.class) diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/KakaoToken.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/dto/KakaoToken.java similarity index 87% rename from backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/KakaoToken.java rename to backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/dto/KakaoToken.java index 1af105ef2..c96df5f7f 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/dto/KakaoToken.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/dto/KakaoToken.java @@ -1,4 +1,4 @@ -package com.mapbefine.mapbefine.oauth.dto; +package com.mapbefine.mapbefine.oauth.domain.kakao.dto; import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; import com.fasterxml.jackson.databind.annotation.JsonNaming; diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java index 50644845c..4748d4305 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java @@ -1,6 +1,6 @@ package com.mapbefine.mapbefine.oauth.presentation; -import com.mapbefine.mapbefine.oauth.OauthServerType; +import com.mapbefine.mapbefine.oauth.domain.OauthServerType; import com.mapbefine.mapbefine.oauth.application.OauthService; import com.mapbefine.mapbefine.oauth.dto.LoginInfoResponse; import jakarta.servlet.http.HttpServletResponse; diff --git a/backend/src/test/java/com/mapbefine/mapbefine/member/MemberFixture.java b/backend/src/test/java/com/mapbefine/mapbefine/member/MemberFixture.java index cd163b558..d6943a997 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/member/MemberFixture.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/member/MemberFixture.java @@ -5,7 +5,7 @@ import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.member.domain.OauthId; import com.mapbefine.mapbefine.member.domain.Role; -import com.mapbefine.mapbefine.oauth.OauthServerType; +import com.mapbefine.mapbefine.oauth.domain.OauthServerType; import com.mapbefine.mapbefine.topic.domain.Topic; public class MemberFixture { diff --git a/backend/src/test/java/com/mapbefine/mapbefine/member/domain/MemberTest.java b/backend/src/test/java/com/mapbefine/mapbefine/member/domain/MemberTest.java index 80ea71215..0ee9b697e 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/member/domain/MemberTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/member/domain/MemberTest.java @@ -2,7 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; -import com.mapbefine.mapbefine.oauth.OauthServerType; +import com.mapbefine.mapbefine.oauth.domain.OauthServerType; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberIntegrationTest.java b/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberIntegrationTest.java index 95fa5ab72..6b844690a 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberIntegrationTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberIntegrationTest.java @@ -1,6 +1,6 @@ package com.mapbefine.mapbefine.member.presentation; -import static com.mapbefine.mapbefine.oauth.OauthServerType.KAKAO; +import static com.mapbefine.mapbefine.oauth.domain.OauthServerType.KAKAO; import static io.restassured.RestAssured.*; import static org.apache.http.HttpHeaders.AUTHORIZATION; import static org.assertj.core.api.Assertions.assertThat; From b127e47a93b9f70c40b5d299e29b4c21e029d76c Mon Sep 17 00:00:00 2001 From: yoondgu Date: Sat, 12 Aug 2023 12:17:46 +0900 Subject: [PATCH 13/35] =?UTF-8?q?rename:=20kakao=20oauth=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=86=8D=EC=84=B1=EA=B0=92=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 다른 Configuration 클래스들 이름과 겹쳐 혼동의 여지가 있어 수정함 Co-authored-by: kpeel5839 --- .../kakao/KakaoAuthCodeRequestUrlProvider.java | 12 ++++++------ .../oauth/domain/kakao/KakaoMemberClient.java | 12 ++++++------ ...kaoOauthConfig.java => KakaoOauthProperties.java} | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) rename backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/{KakaoOauthConfig.java => KakaoOauthProperties.java} (88%) diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoAuthCodeRequestUrlProvider.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoAuthCodeRequestUrlProvider.java index 7ae2d404f..a62ab39bf 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoAuthCodeRequestUrlProvider.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoAuthCodeRequestUrlProvider.java @@ -8,10 +8,10 @@ @Component public class KakaoAuthCodeRequestUrlProvider implements AuthCodeRequestUrlProvider { - private final KakaoOauthConfig kakaoOauthConfig; + private final KakaoOauthProperties kakaoOauthProperties; - public KakaoAuthCodeRequestUrlProvider(KakaoOauthConfig kakaoOauthConfig) { - this.kakaoOauthConfig = kakaoOauthConfig; + public KakaoAuthCodeRequestUrlProvider(KakaoOauthProperties kakaoOauthProperties) { + this.kakaoOauthProperties = kakaoOauthProperties; } @Override @@ -24,9 +24,9 @@ public String provide() { return UriComponentsBuilder .fromUriString("https://kauth.kakao.com/oauth/authorize") .queryParam("response_type", "code") - .queryParam("client_id", kakaoOauthConfig.clientId()) - .queryParam("redirect_uri", kakaoOauthConfig.redirectUri()) - .queryParam("scope", String.join(",", kakaoOauthConfig.scope())) + .queryParam("client_id", kakaoOauthProperties.clientId()) + .queryParam("redirect_uri", kakaoOauthProperties.redirectUri()) + .queryParam("scope", String.join(",", kakaoOauthProperties.scope())) .toUriString(); } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoMemberClient.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoMemberClient.java index 84354a459..92b18d00a 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoMemberClient.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoMemberClient.java @@ -13,14 +13,14 @@ public class KakaoMemberClient implements OauthMemberClient { private KakaoApiClient kakaoApiClient; - private KakaoOauthConfig kakaoOauthConfig; + private KakaoOauthProperties kakaoOauthProperties; public KakaoMemberClient( KakaoApiClient kakaoApiClient, - KakaoOauthConfig kakaoOauthConfig + KakaoOauthProperties kakaoOauthProperties ) { this.kakaoApiClient = kakaoApiClient; - this.kakaoOauthConfig = kakaoOauthConfig; + this.kakaoOauthProperties = kakaoOauthProperties; } @Override @@ -41,10 +41,10 @@ public OauthMember fetch(String authCode) { private MultiValueMap tokenRequestParams(String authCode) { MultiValueMap params = new LinkedMultiValueMap<>(); params.add("grant_type", "authorization_code"); - params.add("client_id", kakaoOauthConfig.clientId()); - params.add("redirect_uri", kakaoOauthConfig.redirectUri()); + params.add("client_id", kakaoOauthProperties.clientId()); + params.add("redirect_uri", kakaoOauthProperties.redirectUri()); params.add("code", authCode); - params.add("client_secret", kakaoOauthConfig.clientSecret()); + params.add("client_secret", kakaoOauthProperties.clientSecret()); return params; } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoOauthConfig.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoOauthProperties.java similarity index 88% rename from backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoOauthConfig.java rename to backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoOauthProperties.java index a391ee832..ff1508721 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoOauthConfig.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoOauthProperties.java @@ -3,7 +3,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix = "oauth.kakao") -public record KakaoOauthConfig( +public record KakaoOauthProperties( String redirectUri, String clientId, String clientSecret, From 5a0936e09bd059f1e12a99a0dd98e926d3c79378 Mon Sep 17 00:00:00 2001 From: yoondgu Date: Sat, 12 Aug 2023 12:43:55 +0900 Subject: [PATCH 14/35] =?UTF-8?q?rename:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=A0=84=EC=9A=A9=20authHeader=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: kpeel5839 --- .../com/mapbefine/mapbefine/common/IntegrationTest.java | 2 +- ...AccessTokenProvider.java => TestAuthHeaderProvider.java} | 6 +++--- .../member/presentation/MemberIntegrationTest.java | 4 ++-- .../com/mapbefine/mapbefine/pin/PinIntegrationTest.java | 2 +- .../com/mapbefine/mapbefine/topic/TopicIntegrationTest.java | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) rename backend/src/test/java/com/mapbefine/mapbefine/common/{TestAccessTokenProvider.java => TestAuthHeaderProvider.java} (74%) diff --git a/backend/src/test/java/com/mapbefine/mapbefine/common/IntegrationTest.java b/backend/src/test/java/com/mapbefine/mapbefine/common/IntegrationTest.java index 5844691fc..e20e5caa6 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/common/IntegrationTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/common/IntegrationTest.java @@ -12,7 +12,7 @@ public class IntegrationTest { @Autowired - protected TestAccessTokenProvider testAccessTokenProvider; + protected TestAuthHeaderProvider testAuthHeaderProvider; @LocalServerPort private int port; diff --git a/backend/src/test/java/com/mapbefine/mapbefine/common/TestAccessTokenProvider.java b/backend/src/test/java/com/mapbefine/mapbefine/common/TestAuthHeaderProvider.java similarity index 74% rename from backend/src/test/java/com/mapbefine/mapbefine/common/TestAccessTokenProvider.java rename to backend/src/test/java/com/mapbefine/mapbefine/common/TestAuthHeaderProvider.java index 9ef1af6a9..8bdc0ae09 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/common/TestAccessTokenProvider.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/common/TestAuthHeaderProvider.java @@ -5,15 +5,15 @@ import org.springframework.stereotype.Component; @Component -public class TestAccessTokenProvider { +public class TestAuthHeaderProvider { private JwtTokenProvider jwtTokenProvider; - public TestAccessTokenProvider(JwtTokenProvider jwtTokenProvider) { + public TestAuthHeaderProvider(JwtTokenProvider jwtTokenProvider) { this.jwtTokenProvider = jwtTokenProvider; } - public String createToken(Member member) { + public String createAuthHeader(Member member) { Long memberId = member.getId(); return "Bearer " + jwtTokenProvider.createToken(String.valueOf(memberId)); } diff --git a/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberIntegrationTest.java b/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberIntegrationTest.java index 6b844690a..42c4af81f 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberIntegrationTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberIntegrationTest.java @@ -91,8 +91,8 @@ public void setUp() { new OauthId(3L, KAKAO) ) ); - creatorAuthHeader = testAccessTokenProvider.createToken(creator); - user1AuthHeader = testAccessTokenProvider.createToken(user1); + creatorAuthHeader = testAuthHeaderProvider.createAuthHeader(creator); + user1AuthHeader = testAuthHeaderProvider.createAuthHeader(user1); } @Test diff --git a/backend/src/test/java/com/mapbefine/mapbefine/pin/PinIntegrationTest.java b/backend/src/test/java/com/mapbefine/mapbefine/pin/PinIntegrationTest.java index a8664ddc5..178383606 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/pin/PinIntegrationTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/pin/PinIntegrationTest.java @@ -52,7 +52,7 @@ class PinIntegrationTest extends IntegrationTest { @BeforeEach void saveTopicAndLocation() { member = memberRepository.save(MemberFixture.create("member", "member@naver.com", Role.ADMIN)); - authHeader = testAccessTokenProvider.createToken(member); + authHeader = testAuthHeaderProvider.createAuthHeader(member); topic = topicRepository.save(TopicFixture.createByName("PinIntegration 토픽", member)); location = locationRepository.save(LocationFixture.createByCoordinate(37.5152933, 127.1029866)); diff --git a/backend/src/test/java/com/mapbefine/mapbefine/topic/TopicIntegrationTest.java b/backend/src/test/java/com/mapbefine/mapbefine/topic/TopicIntegrationTest.java index e33daca02..ea4083147 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/topic/TopicIntegrationTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/topic/TopicIntegrationTest.java @@ -58,7 +58,7 @@ void setMember() { member = memberRepository.save(MemberFixture.create("other", "other@othter.com", Role.ADMIN)); topic = topicRepository.save(TopicFixture.createPublicAndAllMembersTopic(member)); location = locationRepository.save(LocationFixture.create()); - authHeader = testAccessTokenProvider.createToken(member); + authHeader = testAuthHeaderProvider.createAuthHeader(member); } From fe8d2eb6a9784e1c4dde31c034780e652dadb497 Mon Sep 17 00:00:00 2001 From: yoondgu Date: Sat, 12 Aug 2023 15:32:43 +0900 Subject: [PATCH 15/35] =?UTF-8?q?refactor:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=A0=84=EC=9A=A9=20jwt=20secret=20key=20=ED=99=98=EA=B2=BD?= =?UTF-8?q?=EB=B3=80=EC=88=98=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: kpeel5839 --- backend/src/test/resources/application.yml | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/backend/src/test/resources/application.yml b/backend/src/test/resources/application.yml index 3acf2336d..a5fffc643 100644 --- a/backend/src/test/resources/application.yml +++ b/backend/src/test/resources/application.yml @@ -24,15 +24,8 @@ logging: org.hibernate.type: trace org.hibernate.stat: debug -oauth: - kakao: - client_id: ${OAUTH_KAKAO_CLIENT_ID} - redirect_uri: ${OAUTH_KAKAO_REDIRECT_URI} - client_secret: ${OAUTH_KAKAO_CLIENT_SECRET} - scope: ${OAUTH_KAKAO_SCOPE} - security: jwt: token: - secret-key: ${JWT_TOKEN_SECRET_KEY} - expire-length: ${JWT_TOKEN_EXPIRE_LENGTH} + secret-key: ${TEST_JWT_SECRET_KEY} + expire-length: ${TEST_JWT_EXPIRE_LENGTH} From ae3cd44aa35a8d156a74d5c8a01c82a229d029e8 Mon Sep 17 00:00:00 2001 From: jaeyeon kim Date: Thu, 10 Aug 2023 15:07:43 +0900 Subject: [PATCH 16/35] =?UTF-8?q?chore=20:=20cherry=20pick=20=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=B0=98=EC=97=AC=EC=9E=89=20=EB=90=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EB=8A=94=20=EC=82=AC=ED=95=AD=EB=93=A4=EC=9D=84=20?= =?UTF-8?q?=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/MemberCommandService.java | 28 ------- .../mapbefine/member/domain/Member.java | 11 ++- .../member/presentation/MemberController.java | 8 -- .../application/MemberCommandServiceTest.java | 74 ------------------- .../presentation/MemberControllerTest.java | 22 ------ backend/src/test/resources/application.yml | 7 ++ 6 files changed, 15 insertions(+), 135 deletions(-) diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/application/MemberCommandService.java b/backend/src/main/java/com/mapbefine/mapbefine/member/application/MemberCommandService.java index 6aed8af7f..d5a3a0c4e 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/member/application/MemberCommandService.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/member/application/MemberCommandService.java @@ -5,7 +5,6 @@ import com.mapbefine.mapbefine.member.domain.MemberRepository; import com.mapbefine.mapbefine.member.domain.MemberTopicPermission; import com.mapbefine.mapbefine.member.domain.MemberTopicPermissionRepository; -import com.mapbefine.mapbefine.member.dto.request.MemberCreateRequest; import com.mapbefine.mapbefine.member.dto.request.MemberTopicPermissionCreateRequest; import com.mapbefine.mapbefine.topic.domain.Topic; import com.mapbefine.mapbefine.topic.domain.TopicRepository; @@ -31,33 +30,6 @@ public MemberCommandService( this.memberTopicPermissionRepository = memberTopicPermissionRepository; } - public Long save(MemberCreateRequest request) { - validateUniqueNickName(request.nickName()); - validateUniqueEmail(request.email()); - - Member member = Member.of( - request.nickName(), - request.email(), - request.imageUrl(), - request.role() - ); - - return memberRepository.save(member) - .getId(); - } - - private void validateUniqueNickName(String nickName) { - if (memberRepository.existsByMemberInfoNickName(nickName)) { - throw new IllegalArgumentException("이미 존재하는 닉네임입니다."); - } - } - - private void validateUniqueEmail(String email) { - if (memberRepository.existsByMemberInfoEmail(email)) { - throw new IllegalArgumentException("이미 존재하는 이메일입니다."); - } - } - public Long saveMemberTopicPermission(AuthMember authMember, MemberTopicPermissionCreateRequest request) { Member member = memberRepository.findById(request.memberId()) .orElseThrow(NoSuchElementException::new); diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/Member.java b/backend/src/main/java/com/mapbefine/mapbefine/member/domain/Member.java index 8ceea7652..c82759538 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/Member.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/member/domain/Member.java @@ -32,6 +32,9 @@ public class Member extends BaseTimeEntity { @Embedded private MemberInfo memberInfo; + @Embedded + private OauthId oauthId; + @OneToMany(mappedBy = "creator") private List createdTopics = new ArrayList<>(); @@ -41,15 +44,17 @@ public class Member extends BaseTimeEntity { @OneToMany(mappedBy = "member") private List topicsWithPermissions = new ArrayList<>(); - private Member(MemberInfo memberInfo) { + private Member(MemberInfo memberInfo, OauthId oauthId) { this.memberInfo = memberInfo; + this.oauthId = oauthId; } public static Member of( String nickName, String email, String imageUrl, - Role role + Role role, + OauthId oauthId ) { MemberInfo memberInfo = MemberInfo.of( nickName, @@ -58,7 +63,7 @@ public static Member of( role ); - return new Member(memberInfo); + return new Member(memberInfo, oauthId); } public static Member ofRandomNickname( diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/presentation/MemberController.java b/backend/src/main/java/com/mapbefine/mapbefine/member/presentation/MemberController.java index 5cb391ce0..7a189e309 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/member/presentation/MemberController.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/member/presentation/MemberController.java @@ -4,7 +4,6 @@ import com.mapbefine.mapbefine.common.interceptor.LoginRequired; import com.mapbefine.mapbefine.member.application.MemberCommandService; import com.mapbefine.mapbefine.member.application.MemberQueryService; -import com.mapbefine.mapbefine.member.dto.request.MemberCreateRequest; import com.mapbefine.mapbefine.member.dto.request.MemberTopicPermissionCreateRequest; import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; import com.mapbefine.mapbefine.member.dto.response.MemberResponse; @@ -38,13 +37,6 @@ public MemberController( this.memberQueryService = memberQueryService; } - @PostMapping - public ResponseEntity add(@RequestBody MemberCreateRequest request) { - Long savedId = memberCommandService.save(request); - - return ResponseEntity.created(URI.create("/members/" + savedId)).build(); - } - @LoginRequired @PostMapping("/permissions") public ResponseEntity addMemberTopicPermission( diff --git a/backend/src/test/java/com/mapbefine/mapbefine/member/application/MemberCommandServiceTest.java b/backend/src/test/java/com/mapbefine/mapbefine/member/application/MemberCommandServiceTest.java index 563e06d2c..4e697d050 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/member/application/MemberCommandServiceTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/member/application/MemberCommandServiceTest.java @@ -282,80 +282,6 @@ void deleteMemberTopicPermissionByCreator_whenNoneExistsPermission_thenFail() { .isInstanceOf(NoSuchElementException.class); } - @Test - @DisplayName("유저를 저장한다.") - void save() { - // given - Member member = MemberFixture.create( - "member", - "member@naver.com", - Role.USER - ); - MemberInfo memberInfo = member.getMemberInfo(); - MemberCreateRequest memberCreateRequest = new MemberCreateRequest( - memberInfo.getNickName(), - memberInfo.getEmail(), - memberInfo.getImageUrl(), - memberInfo.getRole() - ); - - // when - Long savedId = memberCommandService.save(memberCreateRequest); - Member savedResult = memberRepository.findById(savedId) - .orElseThrow(NoSuchElementException::new); - - // then - assertThat(savedResult).usingRecursiveComparison() - .ignoringFields("id", "createdAt", "updatedAt") - .isEqualTo(member); - } - - @Test - @DisplayName("이미 존재하는 이름으로 유저를 저장할 때 예외가 발생한다.") - void save_whenDuplicateName_thenFail() { - // given - Member member = MemberFixture.create( - "member", - "member@naver.com", - Role.USER - ); - memberRepository.save(member); - MemberInfo memberInfo = member.getMemberInfo(); - MemberCreateRequest memberCreateRequest = new MemberCreateRequest( - memberInfo.getNickName(), - "memberr@naver.com", - memberInfo.getImageUrl(), - memberInfo.getRole() - ); - - // when - assertThatThrownBy(() -> memberCommandService.save(memberCreateRequest)) - .isInstanceOf(IllegalArgumentException.class); - } - - @Test - @DisplayName("이미 존재하는 이메일로 유저를 저장할 때 예외가 발생한다.") - void save_whenDuplicateEmail_thenFail() { - // given - Member member = MemberFixture.create( - "member", - "member@naver.com", - Role.USER - ); - memberRepository.save(member); - MemberInfo memberInfo = member.getMemberInfo(); - MemberCreateRequest memberCreateRequest = new MemberCreateRequest( - "memberr", - memberInfo.getEmail(), - memberInfo.getImageUrl(), - memberInfo.getRole() - ); - - // when - assertThatThrownBy(() -> memberCommandService.save(memberCreateRequest)) - .isInstanceOf(IllegalArgumentException.class); - } - private List getTopicsWithPermission(Member member) { return member.getTopicsWithPermissions() .stream() diff --git a/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberControllerTest.java b/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberControllerTest.java index 527f8a125..8d59d65d9 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberControllerTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberControllerTest.java @@ -10,7 +10,6 @@ import com.mapbefine.mapbefine.member.application.MemberQueryService; import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.member.domain.Role; -import com.mapbefine.mapbefine.member.dto.request.MemberCreateRequest; import com.mapbefine.mapbefine.member.dto.request.MemberTopicPermissionCreateRequest; import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; import com.mapbefine.mapbefine.member.dto.response.MemberResponse; @@ -65,8 +64,6 @@ void deleteMemberTopicPermission() throws Exception { ("Basic " + member.getMemberInfo().getEmail()).getBytes() ); - given(memberCommandService.save(any())).willReturn(1L); - mockMvc.perform( MockMvcRequestBuilders.delete("/members/permissions/1") .header(AUTHORIZATION, authHeader) @@ -132,25 +129,6 @@ void findMemberTopicPermissionById() throws Exception { ).andDo(restDocs.document()); } - @Test - @DisplayName("유저 생성") - void add() throws Exception { - MemberCreateRequest request = new MemberCreateRequest( - "member", - "member@naver.com", - "https://map-befine-official.github.io/favicon.png", - Role.USER - ); - - given(memberCommandService.save(any())).willReturn(1L); - - mockMvc.perform( - MockMvcRequestBuilders.post("/members") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(request)) - ).andDo(restDocs.document()); - } - @Test @DisplayName("유저 목록 조회") void findAllMember() throws Exception { diff --git a/backend/src/test/resources/application.yml b/backend/src/test/resources/application.yml index a5fffc643..2bd7641e9 100644 --- a/backend/src/test/resources/application.yml +++ b/backend/src/test/resources/application.yml @@ -24,6 +24,13 @@ logging: org.hibernate.type: trace org.hibernate.stat: debug +oauth: + kakao: + client_id: ${OAUTH_KAKAO_CLIENT_ID} + redirect_uri: ${OAUTH_KAKAO_REDIRECT_URI} + client_secret: ${OAUTH_KAKAO_CLIENT_SECRET} + scope: ${OAUTH_KAKAO_SCOPE} + security: jwt: token: From a197be9fc39f942e4011895d1257db8ecf52d6de Mon Sep 17 00:00:00 2001 From: jaeyeon kim Date: Sun, 13 Aug 2023 16:43:32 +0900 Subject: [PATCH 17/35] =?UTF-8?q?test=20:=20Kakao=20Redirect=20Url=20?= =?UTF-8?q?=EB=B0=98=ED=99=98=EC=9D=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/annotation/ServiceTest.java | 7 +-- .../common/config/MockBeansConfig.java | 5 +- .../oauth/application/OauthServiceTest.java | 46 +++++++++++++++++++ 3 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java diff --git a/backend/src/test/java/com/mapbefine/mapbefine/common/annotation/ServiceTest.java b/backend/src/test/java/com/mapbefine/mapbefine/common/annotation/ServiceTest.java index a071eae93..33016bbbf 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/common/annotation/ServiceTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/common/annotation/ServiceTest.java @@ -1,6 +1,5 @@ package com.mapbefine.mapbefine.common.annotation; -import com.mapbefine.mapbefine.common.config.MockBeansConfig; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -8,7 +7,6 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.FilterType; -import org.springframework.context.annotation.Import; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -18,8 +16,11 @@ @DataJpaTest( includeFilters = @Filter( type = FilterType.ANNOTATION, value = Service.class + ), + excludeFilters = @Filter( + type = FilterType.REGEX, + pattern = "com.mapbefine.mapbefine.oauth.application.*" ) ) -@Import(MockBeansConfig.class) public @interface ServiceTest { } diff --git a/backend/src/test/java/com/mapbefine/mapbefine/common/config/MockBeansConfig.java b/backend/src/test/java/com/mapbefine/mapbefine/common/config/MockBeansConfig.java index dc4ebd1d8..d930797c8 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/common/config/MockBeansConfig.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/common/config/MockBeansConfig.java @@ -7,6 +7,7 @@ @Configuration public class MockBeansConfig { - @MockBean - private OauthService oauthService; +// @MockBean +// private OauthService oauthService; + } diff --git a/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java b/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java new file mode 100644 index 000000000..30d0efe88 --- /dev/null +++ b/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java @@ -0,0 +1,46 @@ +package com.mapbefine.mapbefine.oauth.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; + +import com.mapbefine.mapbefine.oauth.domain.OauthServerType; +import com.mapbefine.mapbefine.oauth.domain.kakao.KakaoOauthProperties; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; + +@SpringBootTest +class OauthServiceTest { + + @Autowired + private OauthService oauthService; + + @MockBean + private KakaoOauthProperties kakaoOauthProperties; + + @BeforeEach + void beforeEach() { + given(kakaoOauthProperties.clientId()).willReturn("774"); + given(kakaoOauthProperties.scope()).willReturn(new String[] {"profile_nickname", "account_email"}); + given(kakaoOauthProperties.redirectUri()).willReturn("http://localhost:3000/oauth/redirected/kakao"); + given(kakaoOauthProperties.clientSecret()).willReturn("4521"); + } + + @Test + @DisplayName("Kakao 의 로그인 페이지 url 을 반환한다.") + void getAuthCodeRequestUrl_success() { + // when + String url = oauthService.getAuthCodeRequestUrl(OauthServerType.KAKAO); + + // then + assertThat(url).isEqualTo("https://kauth.kakao.com/oauth/authorize?" + + "response_type=code" + + "&client_id=" + kakaoOauthProperties.clientId() + + "&redirect_uri=" + kakaoOauthProperties.redirectUri() + + "&scope=" + String.join(",", kakaoOauthProperties.scope())); + } + +} From 0bef02cb5d14b4c6cbfdebcc34e8b0bbc1ee87bc Mon Sep 17 00:00:00 2001 From: jaeyeon kim Date: Sun, 13 Aug 2023 18:04:20 +0900 Subject: [PATCH 18/35] =?UTF-8?q?test=20:=20OauthService=20=EC=9D=98=20Log?= =?UTF-8?q?in=20=EC=9D=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/domain/kakao/KakaoMemberClient.java | 2 +- backend/src/main/resources/application.yml | 4 +- .../oauth/application/OauthServiceTest.java | 49 ++++++++++++++++++- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoMemberClient.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoMemberClient.java index 92b18d00a..5048b37c1 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoMemberClient.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/domain/kakao/KakaoMemberClient.java @@ -30,7 +30,7 @@ public OauthServerType supportServer() { @Override public OauthMember fetch(String authCode) { - KakaoToken kakaoToken = kakaoApiClient.fetchToken(tokenRequestParams(authCode)); + KakaoToken kakaoToken = kakaoApiClient.fetchToken(tokenRequestParams(authCode)); // kakaoApiClient 는 ?? 그냥 kakaoToken 을 반환하고 KakaoMemberResponse kakaoMemberResponse = kakaoApiClient.fetchMember( kakaoToken.tokenType() + " " + kakaoToken.accessToken() ); diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 3a75b6ddf..bc55efa1a 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -32,5 +32,5 @@ oauth: security: jwt: token: - secret-key: ${JWT_TOKEN_SECRET_KEY} - expire-length: ${JWT_TOKEN_EXPIRE_LENGTH} + secret-key: ${JWT_SECRET_KEY} + expire-length: ${JWT_EXPIRE_LENGTH} diff --git a/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java b/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java index 30d0efe88..69bb7b6e3 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java @@ -1,10 +1,17 @@ package com.mapbefine.mapbefine.oauth.application; +import static com.mapbefine.mapbefine.oauth.domain.OauthServerType.KAKAO; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; +import com.mapbefine.mapbefine.oauth.domain.OauthMember; import com.mapbefine.mapbefine.oauth.domain.OauthServerType; +import com.mapbefine.mapbefine.oauth.domain.kakao.KakaoApiClient; import com.mapbefine.mapbefine.oauth.domain.kakao.KakaoOauthProperties; +import com.mapbefine.mapbefine.oauth.domain.kakao.dto.KakaoMemberResponse; +import com.mapbefine.mapbefine.oauth.domain.kakao.dto.KakaoToken; +import com.mapbefine.mapbefine.oauth.dto.LoginInfoResponse; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -15,24 +22,49 @@ @SpringBootTest class OauthServiceTest { + private static final OauthMember oauthMember = OauthMember.of( + "yshert@naver.com", + "https://map-befine-official.github.io/favicon.png", + Long.MAX_VALUE, + KAKAO + ); + @Autowired private OauthService oauthService; + @MockBean + private KakaoApiClient kakaoApiClient; + @MockBean private KakaoOauthProperties kakaoOauthProperties; + @MockBean + private KakaoToken kakaoToken; + + @MockBean + private KakaoMemberResponse kakaoMemberResponse; + + @BeforeEach void beforeEach() { given(kakaoOauthProperties.clientId()).willReturn("774"); given(kakaoOauthProperties.scope()).willReturn(new String[] {"profile_nickname", "account_email"}); given(kakaoOauthProperties.redirectUri()).willReturn("http://localhost:3000/oauth/redirected/kakao"); given(kakaoOauthProperties.clientSecret()).willReturn("4521"); + + given(kakaoToken.tokenType()).willReturn("tokenType"); + given(kakaoToken.accessToken()).willReturn("accessToken"); + + given(kakaoMemberResponse.extract()).willReturn(oauthMember); + + given(kakaoApiClient.fetchToken(any())).willReturn(kakaoToken); + given(kakaoApiClient.fetchMember("tokenType accessToken")).willReturn(kakaoMemberResponse); } @Test @DisplayName("Kakao 의 로그인 페이지 url 을 반환한다.") void getAuthCodeRequestUrl_success() { - // when + // given when String url = oauthService.getAuthCodeRequestUrl(OauthServerType.KAKAO); // then @@ -42,5 +74,20 @@ void getAuthCodeRequestUrl_success() { + "&redirect_uri=" + kakaoOauthProperties.redirectUri() + "&scope=" + String.join(",", kakaoOauthProperties.scope())); } + + @Test + @DisplayName("Kakao 로 로그인 하는 경우 사용자의 로그인 정보를 반환한다.") + void login() { + // given when + LoginInfoResponse response = oauthService.login(KAKAO, "auth"); + + // then + assertThat(response.accessToken()).isNotNull(); + assertThat(response.member().email()).isEqualTo("yshert@naver.com"); + assertThat(response.member().imageUrl()).isEqualTo( + "https://map-befine-official.github.io/favicon.png" + ); + assertThat(response.member().nickName()).startsWith("모험가"); + } } From bb0a6130b8db911e8085807d14ebf222e11de2c9 Mon Sep 17 00:00:00 2001 From: jaeyeon kim Date: Sun, 13 Aug 2023 18:14:52 +0900 Subject: [PATCH 19/35] =?UTF-8?q?docs=20:=20/oauth/{oauthServerType}=20API?= =?UTF-8?q?=20=EB=AA=85=EC=84=B8=EC=84=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mapbefine/common/RestDocsIntegration.java | 2 +- .../presentation/OauthControllerTest.java | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 backend/src/test/java/com/mapbefine/mapbefine/oauth/application/presentation/OauthControllerTest.java diff --git a/backend/src/test/java/com/mapbefine/mapbefine/common/RestDocsIntegration.java b/backend/src/test/java/com/mapbefine/mapbefine/common/RestDocsIntegration.java index 3bf037791..a6ecf542e 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/common/RestDocsIntegration.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/common/RestDocsIntegration.java @@ -44,7 +44,7 @@ void beforeEach( final RestDocumentationContextProvider provider ) throws Exception { given(authInterceptor.preHandle(any(), any(), any())).willReturn(true); - this.restDocs = MockMvcRestDocumentation.document("{class-nickName}/{method-nickName}"); + this.restDocs = MockMvcRestDocumentation.document("{class-name}/{method-name}"); this.mockMvc = MockMvcBuilders.webAppContextSetup(context) .apply( MockMvcRestDocumentation.documentationConfiguration(provider) diff --git a/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/presentation/OauthControllerTest.java b/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/presentation/OauthControllerTest.java new file mode 100644 index 000000000..b39e9b167 --- /dev/null +++ b/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/presentation/OauthControllerTest.java @@ -0,0 +1,50 @@ +package com.mapbefine.mapbefine.oauth.application.presentation; + +import static org.mockito.BDDMockito.given; + +import com.mapbefine.mapbefine.common.RestDocsIntegration; +import com.mapbefine.mapbefine.oauth.application.OauthService; +import com.mapbefine.mapbefine.oauth.domain.kakao.KakaoOauthProperties; +import com.mapbefine.mapbefine.oauth.domain.kakao.dto.KakaoMemberResponse; +import com.mapbefine.mapbefine.oauth.domain.kakao.dto.KakaoToken; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +class OauthControllerTest extends RestDocsIntegration { + + @Autowired + private OauthService oauthService; + + @MockBean + private KakaoOauthProperties kakaoOauthProperties; + + @MockBean + private KakaoToken kakaoToken; + + @MockBean + private KakaoMemberResponse kakaoMemberResponse; + + @BeforeEach + void beforeEach() { + given(kakaoOauthProperties.clientId()).willReturn("[client_id]"); + given(kakaoOauthProperties.scope()).willReturn(new String[] {"[scope]"}); + given(kakaoOauthProperties.redirectUri()).willReturn("[redirection_uri]"); + + given(kakaoToken.tokenType()).willReturn("tokenType"); + given(kakaoToken.accessToken()).willReturn("accessToken"); + } + + @Test + @DisplayName("Kakao Redirection Url 요청") + void redirection() throws Exception { + // given when then + mockMvc.perform( + MockMvcRequestBuilders.get("/oauth/kakao") + ).andDo(restDocs.document()); + } + +} From 59402b3a97df8d52fe2dd3cfcdde529c005b50e7 Mon Sep 17 00:00:00 2001 From: jaeyeon kim Date: Sun, 13 Aug 2023 19:03:47 +0900 Subject: [PATCH 20/35] =?UTF-8?q?docs=20:=20/oauth/login/{oauthServerType}?= =?UTF-8?q?=20API=20=EB=AA=85=EC=84=B8=EC=84=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/presentation/OauthController.java | 2 +- .../mapbefine/common/RestDocsIntegration.java | 3 + .../common/TestAuthHeaderProvider.java | 8 +++ .../oauth/application/OauthServiceTest.java | 1 + .../presentation/OauthControllerTest.java | 67 +++++++++++-------- 5 files changed, 53 insertions(+), 28 deletions(-) diff --git a/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java b/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java index 4748d4305..410697c9b 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/oauth/presentation/OauthController.java @@ -1,7 +1,7 @@ package com.mapbefine.mapbefine.oauth.presentation; -import com.mapbefine.mapbefine.oauth.domain.OauthServerType; import com.mapbefine.mapbefine.oauth.application.OauthService; +import com.mapbefine.mapbefine.oauth.domain.OauthServerType; import com.mapbefine.mapbefine.oauth.dto.LoginInfoResponse; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; diff --git a/backend/src/test/java/com/mapbefine/mapbefine/common/RestDocsIntegration.java b/backend/src/test/java/com/mapbefine/mapbefine/common/RestDocsIntegration.java index a6ecf542e..633c38766 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/common/RestDocsIntegration.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/common/RestDocsIntegration.java @@ -31,6 +31,9 @@ public abstract class RestDocsIntegration { @Autowired protected ObjectMapper objectMapper; + @Autowired + protected TestAuthHeaderProvider testAuthHeaderProvider; + protected RestDocumentationResultHandler restDocs; protected MockMvc mockMvc; diff --git a/backend/src/test/java/com/mapbefine/mapbefine/common/TestAuthHeaderProvider.java b/backend/src/test/java/com/mapbefine/mapbefine/common/TestAuthHeaderProvider.java index 8bdc0ae09..ed2bc6330 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/common/TestAuthHeaderProvider.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/common/TestAuthHeaderProvider.java @@ -15,6 +15,14 @@ public TestAuthHeaderProvider(JwtTokenProvider jwtTokenProvider) { public String createAuthHeader(Member member) { Long memberId = member.getId(); + return generateToken(memberId); + } + + public String createAuthHeaderById(Long id) { + return generateToken(id); + } + + private String generateToken(Long memberId) { return "Bearer " + jwtTokenProvider.createToken(String.valueOf(memberId)); } diff --git a/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java b/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java index 69bb7b6e3..9c8caf432 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java @@ -80,6 +80,7 @@ void getAuthCodeRequestUrl_success() { void login() { // given when LoginInfoResponse response = oauthService.login(KAKAO, "auth"); + System.out.println(response); // then assertThat(response.accessToken()).isNotNull(); diff --git a/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/presentation/OauthControllerTest.java b/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/presentation/OauthControllerTest.java index b39e9b167..7151139a9 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/presentation/OauthControllerTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/presentation/OauthControllerTest.java @@ -1,50 +1,63 @@ package com.mapbefine.mapbefine.oauth.application.presentation; +import static com.mapbefine.mapbefine.oauth.domain.OauthServerType.KAKAO; import static org.mockito.BDDMockito.given; import com.mapbefine.mapbefine.common.RestDocsIntegration; +import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; import com.mapbefine.mapbefine.oauth.application.OauthService; -import com.mapbefine.mapbefine.oauth.domain.kakao.KakaoOauthProperties; -import com.mapbefine.mapbefine.oauth.domain.kakao.dto.KakaoMemberResponse; -import com.mapbefine.mapbefine.oauth.domain.kakao.dto.KakaoToken; -import org.junit.jupiter.api.BeforeEach; +import com.mapbefine.mapbefine.oauth.dto.LoginInfoResponse; +import java.time.LocalDateTime; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; class OauthControllerTest extends RestDocsIntegration { - @Autowired - private OauthService oauthService; - - @MockBean - private KakaoOauthProperties kakaoOauthProperties; - @MockBean - private KakaoToken kakaoToken; - - @MockBean - private KakaoMemberResponse kakaoMemberResponse; - - @BeforeEach - void beforeEach() { - given(kakaoOauthProperties.clientId()).willReturn("[client_id]"); - given(kakaoOauthProperties.scope()).willReturn(new String[] {"[scope]"}); - given(kakaoOauthProperties.redirectUri()).willReturn("[redirection_uri]"); - - given(kakaoToken.tokenType()).willReturn("tokenType"); - given(kakaoToken.accessToken()).willReturn("accessToken"); - } + private OauthService oauthService; @Test - @DisplayName("Kakao Redirection Url 요청") + @DisplayName("kakao 소셜 로그인 Redirection Url 반환") void redirection() throws Exception { - // given when then + // given + given(oauthService.getAuthCodeRequestUrl(KAKAO)).willReturn( + "https://kauth.kakao.com/oauth/authorize?" + + "response_type=code" + + "&client_id={client_id}" + + "&redirect_uri={redirection_uri}" + + "&scope={scope}" + ); + + // when then mockMvc.perform( MockMvcRequestBuilders.get("/oauth/kakao") ).andDo(restDocs.document()); } + @Test + @DisplayName("소셜 로그인 성공시 로그인한 유저 정보 반환") + void login() throws Exception { + // given + String code = "auth_code"; + LoginInfoResponse response = new LoginInfoResponse( + testAuthHeaderProvider.createAuthHeaderById(Long.MAX_VALUE), + new MemberDetailResponse( + Long.MAX_VALUE, + "모험가03fcb0d", + "yshert@naver.com", + "https://map-befine-official.github.io/favicon.png", + LocalDateTime.now() + ) + ); + given(oauthService.login(KAKAO, code)).willReturn(response); + + // when then + mockMvc.perform( + MockMvcRequestBuilders.get("/oauth/login/kakao") + .param("code", code) + ).andDo(restDocs.document()); + } + } From e747f959db513eea91de55bd38b79e3ee8804b2f Mon Sep 17 00:00:00 2001 From: jaeyeon kim Date: Sun, 13 Aug 2023 19:18:41 +0900 Subject: [PATCH 21/35] =?UTF-8?q?test=20:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=EC=9D=B4=20=EC=A4=91=EB=B3=B5=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=BC=EC=96=B4=EB=82=98=EC=A7=80=20=EC=95=8A=EC=9D=8C?= =?UTF-8?q?=EC=9D=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mapbefine/member/domain/MemberInfo.java | 2 +- .../oauth/application/OauthServiceTest.java | 45 ++++++++++++++++--- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/MemberInfo.java b/backend/src/main/java/com/mapbefine/mapbefine/member/domain/MemberInfo.java index a5af5cffc..7bce3e921 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/MemberInfo.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/member/domain/MemberInfo.java @@ -20,7 +20,7 @@ public class MemberInfo { private static final int MAX_NICK_NAME_LENGTH = 20; private static final String VALID_EMAIL_URL_REGEX = "^[a-zA-Z0-9]+@[a-zA-Z]+\\.[a-zA-Z]{2,}$"; - @Column(nullable = false, length = 20, unique = true) // Nick Name + @Column(nullable = false, length = 20, unique = true) private String nickName; @Column(nullable = false, unique = true) diff --git a/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java b/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java index 9c8caf432..e84437ff2 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java @@ -2,9 +2,13 @@ import static com.mapbefine.mapbefine.oauth.domain.OauthServerType.KAKAO; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; +import com.mapbefine.mapbefine.DatabaseCleanup; +import com.mapbefine.mapbefine.member.domain.Member; +import com.mapbefine.mapbefine.member.domain.MemberRepository; import com.mapbefine.mapbefine.oauth.domain.OauthMember; import com.mapbefine.mapbefine.oauth.domain.OauthServerType; import com.mapbefine.mapbefine.oauth.domain.kakao.KakaoApiClient; @@ -12,6 +16,9 @@ import com.mapbefine.mapbefine.oauth.domain.kakao.dto.KakaoMemberResponse; import com.mapbefine.mapbefine.oauth.domain.kakao.dto.KakaoToken; import com.mapbefine.mapbefine.oauth.dto.LoginInfoResponse; +import java.util.NoSuchElementException; +import java.util.Optional; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -32,6 +39,12 @@ class OauthServiceTest { @Autowired private OauthService oauthService; + @Autowired + private DatabaseCleanup databaseCleanup; + + @Autowired + private MemberRepository memberRepository; + @MockBean private KakaoApiClient kakaoApiClient; @@ -46,7 +59,7 @@ class OauthServiceTest { @BeforeEach - void beforeEach() { + void setUp() { given(kakaoOauthProperties.clientId()).willReturn("774"); given(kakaoOauthProperties.scope()).willReturn(new String[] {"profile_nickname", "account_email"}); given(kakaoOauthProperties.redirectUri()).willReturn("http://localhost:3000/oauth/redirected/kakao"); @@ -61,10 +74,15 @@ void beforeEach() { given(kakaoApiClient.fetchMember("tokenType accessToken")).willReturn(kakaoMemberResponse); } + @AfterEach + void tearDown() { + databaseCleanup.execute(); + } + @Test @DisplayName("Kakao 의 로그인 페이지 url 을 반환한다.") void getAuthCodeRequestUrl_success() { - // given when + // when String url = oauthService.getAuthCodeRequestUrl(OauthServerType.KAKAO); // then @@ -76,11 +94,12 @@ void getAuthCodeRequestUrl_success() { } @Test - @DisplayName("Kakao 로 로그인 하는 경우 사용자의 로그인 정보를 반환한다.") - void login() { - // given when + @DisplayName("Kakao 로 로그인 처음 하는 경우 사용자의 정보를 저장하고 사용자의 로그인 정보를 반환한다.") + void loginAndRegister_success() { + // when LoginInfoResponse response = oauthService.login(KAKAO, "auth"); - System.out.println(response); + Member savedMember = memberRepository.findByMemberInfoEmail("yshert@naver.com") + .orElseThrow(NoSuchElementException::new); // then assertThat(response.accessToken()).isNotNull(); @@ -89,6 +108,20 @@ void login() { "https://map-befine-official.github.io/favicon.png" ); assertThat(response.member().nickName()).startsWith("모험가"); + assertThat(savedMember.getId()).isEqualTo(response.member().id()); + } + + @Test + @DisplayName("Kakao 로 로그인 처음이 아닌 경우 사용자의 정보를 저장하지 않고 사용자의 로그인 정보를 반환한다.") + void login() { + // given + oauthService.login(KAKAO, "auth"); + + // then + // 중복으로 저장되지 않는다는 것을 assertDoesNotThrow 로 표현해봤어요.. + // findByMemberInfoEmail 했을 때 size 가 2가 아닌지 확인하는 것을 고려해봤지만 + // 현재로서는 반환 타입이 Optional 라서 검증하지 못했네용.. + assertDoesNotThrow(() -> oauthService.login(KAKAO, "auth")); } } From 9d8107b34c3193ff81c0872965e6029aa3e201f9 Mon Sep 17 00:00:00 2001 From: jaeyeon kim Date: Sun, 13 Aug 2023 19:52:32 +0900 Subject: [PATCH 22/35] =?UTF-8?q?chore=20:=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mapbefine/oauth/application/OauthServiceTest.java | 4 ---- .../{application => }/presentation/OauthControllerTest.java | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) rename backend/src/test/java/com/mapbefine/mapbefine/oauth/{application => }/presentation/OauthControllerTest.java (97%) diff --git a/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java b/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java index e84437ff2..5f0eeb213 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java @@ -17,7 +17,6 @@ import com.mapbefine.mapbefine.oauth.domain.kakao.dto.KakaoToken; import com.mapbefine.mapbefine.oauth.dto.LoginInfoResponse; import java.util.NoSuchElementException; -import java.util.Optional; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -118,9 +117,6 @@ void login() { oauthService.login(KAKAO, "auth"); // then - // 중복으로 저장되지 않는다는 것을 assertDoesNotThrow 로 표현해봤어요.. - // findByMemberInfoEmail 했을 때 size 가 2가 아닌지 확인하는 것을 고려해봤지만 - // 현재로서는 반환 타입이 Optional 라서 검증하지 못했네용.. assertDoesNotThrow(() -> oauthService.login(KAKAO, "auth")); } diff --git a/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/presentation/OauthControllerTest.java b/backend/src/test/java/com/mapbefine/mapbefine/oauth/presentation/OauthControllerTest.java similarity index 97% rename from backend/src/test/java/com/mapbefine/mapbefine/oauth/application/presentation/OauthControllerTest.java rename to backend/src/test/java/com/mapbefine/mapbefine/oauth/presentation/OauthControllerTest.java index 7151139a9..a540cb8f8 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/presentation/OauthControllerTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/oauth/presentation/OauthControllerTest.java @@ -1,4 +1,4 @@ -package com.mapbefine.mapbefine.oauth.application.presentation; +package com.mapbefine.mapbefine.oauth.presentation; import static com.mapbefine.mapbefine.oauth.domain.OauthServerType.KAKAO; import static org.mockito.BDDMockito.given; From 9a83e11f8648da507b6ffe2d17ed6533165de726 Mon Sep 17 00:00:00 2001 From: jaeyeon kim Date: Sun, 13 Aug 2023 19:56:54 +0900 Subject: [PATCH 23/35] =?UTF-8?q?docs=20:=20oauth.adoc=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=20=EB=B0=8F=20=EB=8B=A4=EB=A5=B8=20adoc=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EA=B2=BD=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/docs/asciidoc/index.adoc | 1 + backend/src/docs/asciidoc/member.adoc | 4 ---- backend/src/docs/asciidoc/oauth.adoc | 9 +++++++++ backend/src/docs/asciidoc/pin.adoc | 1 + backend/src/docs/asciidoc/topic.adoc | 2 +- 5 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 backend/src/docs/asciidoc/oauth.adoc diff --git a/backend/src/docs/asciidoc/index.adoc b/backend/src/docs/asciidoc/index.adoc index 1294932d7..4cae5b937 100644 --- a/backend/src/docs/asciidoc/index.adoc +++ b/backend/src/docs/asciidoc/index.adoc @@ -11,3 +11,4 @@ toc::[] include::topic.adoc[] include::pin.adoc[] include::member.adoc[] +include::oauth.adoc[] diff --git a/backend/src/docs/asciidoc/member.adoc b/backend/src/docs/asciidoc/member.adoc index 75796870d..8f5d7acca 100644 --- a/backend/src/docs/asciidoc/member.adoc +++ b/backend/src/docs/asciidoc/member.adoc @@ -16,10 +16,6 @@ operation::member-controller-test/find-member-topic-permission-all[snippets='htt operation::member-controller-test/find-member-topic-permission-by-id[snippets='http-request,http-response'] -=== 유저 생성 - -operation::member-controller-test/add[snippets='http-request,http-response'] - === 유저 목록 조회 operation::member-controller-test/find-all-member[snippets='http-request,http-response'] diff --git a/backend/src/docs/asciidoc/oauth.adoc b/backend/src/docs/asciidoc/oauth.adoc new file mode 100644 index 000000000..f6aeec235 --- /dev/null +++ b/backend/src/docs/asciidoc/oauth.adoc @@ -0,0 +1,9 @@ +== 소셜 로그인 + +=== KAKAO 로그인 URL 반환 + +operation::oauth-controller-test/redirection[snippets='http-request,http-response'] + +=== KAKAO 로그인 + +operation::oauth-controller-test/login[snippets='http-request,http-response'] diff --git a/backend/src/docs/asciidoc/pin.adoc b/backend/src/docs/asciidoc/pin.adoc index ac0a84499..a16023f13 100644 --- a/backend/src/docs/asciidoc/pin.adoc +++ b/backend/src/docs/asciidoc/pin.adoc @@ -25,4 +25,5 @@ operation::pin-controller-test/delete[snippets='http-request,http-response'] operation::pin-controller-test/add-image[snippets='http-request,http-response'] === 핀 이미지 삭제 + operation::pin-controller-test/remove-image[snippets='http-request,http-response'] diff --git a/backend/src/docs/asciidoc/topic.adoc b/backend/src/docs/asciidoc/topic.adoc index c634e6935..b62df9b45 100644 --- a/backend/src/docs/asciidoc/topic.adoc +++ b/backend/src/docs/asciidoc/topic.adoc @@ -6,7 +6,7 @@ operation::topic-controller-test/find-all[snippets='http-request,http-response'] === 토픽 인기 목록 조회 -operation::topic-controller-test/find-bests[snippets='http-request,http-response'] +operation::location-controller-test/find-nearby-topics-sorted-by-pin-count[snippets='http-request,http-response'] === 토픽 상세 조회 From d8c4ee55a0f70210804f01ca886bcbf2dc0466ba Mon Sep 17 00:00:00 2001 From: jaeyeon kim Date: Sun, 13 Aug 2023 20:01:12 +0900 Subject: [PATCH 24/35] =?UTF-8?q?refactor=20:=20=EC=9E=AC=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=B3=B4?= =?UTF-8?q?=EC=99=84=20=EB=B0=8F=20=ED=95=84=EC=9A=94=EC=97=86=EB=8A=94=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mapbefine/oauth/application/OauthServiceTest.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java b/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java index 5f0eeb213..69fbbffcb 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/oauth/application/OauthServiceTest.java @@ -2,7 +2,6 @@ import static com.mapbefine.mapbefine.oauth.domain.OauthServerType.KAKAO; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; @@ -106,7 +105,6 @@ void loginAndRegister_success() { assertThat(response.member().imageUrl()).isEqualTo( "https://map-befine-official.github.io/favicon.png" ); - assertThat(response.member().nickName()).startsWith("모험가"); assertThat(savedMember.getId()).isEqualTo(response.member().id()); } @@ -114,10 +112,15 @@ void loginAndRegister_success() { @DisplayName("Kakao 로 로그인 처음이 아닌 경우 사용자의 정보를 저장하지 않고 사용자의 로그인 정보를 반환한다.") void login() { // given - oauthService.login(KAKAO, "auth"); + LoginInfoResponse firstLogin = oauthService.login(KAKAO, "auth"); + Member savedMember = memberRepository.findByMemberInfoEmail(firstLogin.member().email()) + .orElseThrow(NoSuchElementException::new); + + // when + LoginInfoResponse secondLogin = oauthService.login(KAKAO, "auth"); // then - assertDoesNotThrow(() -> oauthService.login(KAKAO, "auth")); + assertThat(savedMember.getId()).isEqualTo(secondLogin.member().id()); } } From 45bab9cb991b9ff6e5203dd41eed6b1ad65bf983 Mon Sep 17 00:00:00 2001 From: yoondgu Date: Mon, 14 Aug 2023 01:08:21 +0900 Subject: [PATCH 25/35] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=B6=84=EB=A6=AC=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mapbefine/common/interceptor/AuthInterceptor.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/backend/src/main/java/com/mapbefine/mapbefine/common/interceptor/AuthInterceptor.java b/backend/src/main/java/com/mapbefine/mapbefine/common/interceptor/AuthInterceptor.java index 9ac0e34f0..64000b742 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/common/interceptor/AuthInterceptor.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/common/interceptor/AuthInterceptor.java @@ -48,8 +48,8 @@ public boolean preHandle( request.setAttribute("memberId", memberId); if (isLoginRequired((HandlerMethod) handler)) { - // TODO: 2023/08/11 403 반환 - return isMember(memberId); + // TODO: 2023/08/11 isMember false이면 403 반환 + return authService.isMember(memberId); } return true; } @@ -69,11 +69,6 @@ private boolean isLoginRequired(HandlerMethod handlerMethod) { return !Objects.isNull(loginRequired); } - private boolean isMember(Long memberId) { - - return authService.isMember(memberId); - } - private Long extractMemberIdFromToken(HttpServletRequest request) { AuthInfo authInfo = authorizationExtractor.extract(request); if (Objects.isNull(authInfo)) { From 63a92083ad51b8709a1750e0259be27e6620c80c Mon Sep 17 00:00:00 2001 From: yoondgu Date: Mon, 14 Aug 2023 01:09:55 +0900 Subject: [PATCH 26/35] =?UTF-8?q?refactor:=20stream=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=9D=B8=EB=8D=B4=ED=8A=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mapbefine/common/interceptor/AuthInterceptor.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/backend/src/main/java/com/mapbefine/mapbefine/common/interceptor/AuthInterceptor.java b/backend/src/main/java/com/mapbefine/mapbefine/common/interceptor/AuthInterceptor.java index 64000b742..2f7ece05f 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/common/interceptor/AuthInterceptor.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/common/interceptor/AuthInterceptor.java @@ -7,8 +7,8 @@ import com.mapbefine.mapbefine.auth.infrastructure.JwtTokenProvider; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import java.util.Arrays; import java.util.Objects; -import org.springframework.core.MethodParameter; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; @@ -55,12 +55,8 @@ public boolean preHandle( } private boolean isAuthMemberNotRequired(HandlerMethod handlerMethod) { - for (MethodParameter parameter : handlerMethod.getMethodParameters()) { - if (parameter.getParameterType().equals(AuthMember.class)) { - return false; - } - } - return true; + return Arrays.stream(handlerMethod.getMethodParameters()) + .noneMatch(parameter -> parameter.getParameterType().equals(AuthMember.class)); } private boolean isLoginRequired(HandlerMethod handlerMethod) { From 0bca0352d3bd30b1a29869cfaddd1a6fbe5739ba Mon Sep 17 00:00:00 2001 From: yoondgu Date: Mon, 14 Aug 2023 01:12:08 +0900 Subject: [PATCH 27/35] =?UTF-8?q?refactor:=20null=20=EC=97=AC=EB=B6=80=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=20=EB=A9=94=EC=84=9C=EB=93=9C=20=ED=86=B5?= =?UTF-8?q?=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mapbefine/common/resolver/AuthArgumentResolver.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/src/main/java/com/mapbefine/mapbefine/common/resolver/AuthArgumentResolver.java b/backend/src/main/java/com/mapbefine/mapbefine/common/resolver/AuthArgumentResolver.java index a04a773d7..0ae86c591 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/common/resolver/AuthArgumentResolver.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/common/resolver/AuthArgumentResolver.java @@ -4,6 +4,7 @@ import com.mapbefine.mapbefine.auth.domain.AuthMember; import com.mapbefine.mapbefine.auth.domain.member.Guest; import jakarta.servlet.http.HttpServletRequest; +import java.util.Objects; import org.springframework.core.MethodParameter; import org.springframework.stereotype.Component; import org.springframework.web.bind.support.WebDataBinderFactory; @@ -39,14 +40,14 @@ public Object resolveArgument( } private void validateRequest(HttpServletRequest request) { - if (request == null) { + if (Objects.isNull(request)) { throw new IllegalArgumentException("정상적인 요청이 아닙니다."); } } private AuthMember createAuthMember(HttpServletRequest request) { Long memberId = (Long) request.getAttribute("memberId"); - if (memberId == null) { + if (Objects.isNull(memberId)) { return new Guest(); } From bad465f6fab7b46900b5cfc7d82864ecc63f68ae Mon Sep 17 00:00:00 2001 From: yoondgu Date: Mon, 14 Aug 2023 01:14:30 +0900 Subject: [PATCH 28/35] =?UTF-8?q?refactor:=20BearerAuthorizationExtractor?= =?UTF-8?q?=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BearerAuthorizationExtractor.java | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/backend/src/main/java/com/mapbefine/mapbefine/auth/infrastructure/BearerAuthorizationExtractor.java b/backend/src/main/java/com/mapbefine/mapbefine/auth/infrastructure/BearerAuthorizationExtractor.java index 595844700..2dfbfa473 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/auth/infrastructure/BearerAuthorizationExtractor.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/auth/infrastructure/BearerAuthorizationExtractor.java @@ -4,28 +4,36 @@ import com.mapbefine.mapbefine.auth.dto.AuthInfo; import jakarta.servlet.http.HttpServletRequest; -import java.util.Enumeration; +import java.util.Collections; import org.springframework.stereotype.Component; @Component public class BearerAuthorizationExtractor implements AuthorizationExtractor { + private static final String BEARER_TYPE = "Bearer"; @Override public AuthInfo extract(HttpServletRequest request) { - Enumeration headers = request.getHeaders(AUTHORIZATION); - while (headers.hasMoreElements()) { - String value = headers.nextElement(); - if ((value.toLowerCase().startsWith(BEARER_TYPE.toLowerCase()))) { - String authHeaderValue = value.substring(BEARER_TYPE.length()).trim(); - int commaIndex = authHeaderValue.indexOf(','); - if (commaIndex > 0) { - authHeaderValue = authHeaderValue.substring(0, commaIndex); - } - return new AuthInfo(authHeaderValue); - } - } + return Collections.list(request.getHeaders(AUTHORIZATION)) + .stream() + .filter(this::isBearerType) + .map(this::extractAuthHeaderValue) + .findFirst() + .map(AuthInfo::new) + .orElse(null); + } - return null; + private boolean isBearerType(String value) { + return value.toLowerCase().startsWith(BEARER_TYPE.toLowerCase()); } + + private String extractAuthHeaderValue(String value) { + String authHeaderValue = value.substring(BEARER_TYPE.length()).trim(); + int commaIndex = authHeaderValue.indexOf(','); + if (commaIndex > 0) { + return authHeaderValue.substring(0, commaIndex); + } + return authHeaderValue; + } + } From df7123ce9f42ff040fcb862105c6ce4e0d286f35 Mon Sep 17 00:00:00 2001 From: junpakPark Date: Mon, 14 Aug 2023 10:25:49 +0900 Subject: [PATCH 29/35] =?UTF-8?q?refactor:=20Permission=20Enum=20=EB=84=A4?= =?UTF-8?q?=EC=9D=B4=EB=B0=8D=20=EB=B3=80=EA=B2=BD(PermissionType)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/TopicCommandService.java | 6 +-- .../{Permission.java => PermissionType.java} | 4 +- .../mapbefine/topic/domain/Topic.java | 8 ++-- .../mapbefine/topic/domain/TopicStatus.java | 38 +++++++++--------- .../topic/dto/request/TopicCreateRequest.java | 4 +- .../topic/dto/request/TopicMergeRequest.java | 4 +- .../topic/dto/request/TopicUpdateRequest.java | 4 +- .../mapbefine/topic/TopicFixture.java | 14 +++---- .../mapbefine/topic/TopicIntegrationTest.java | 22 +++++----- .../application/TopicCommandServiceTest.java | 6 +-- ...ssionTest.java => PermissionTypeTest.java} | 10 ++--- .../topic/domain/TopicRepositoryTest.java | 4 +- .../topic/domain/TopicStatusTest.java | 40 +++++++++---------- .../mapbefine/topic/domain/TopicTest.java | 8 ++-- .../presentation/TopicControllerTest.java | 8 ++-- 15 files changed, 90 insertions(+), 90 deletions(-) rename backend/src/main/java/com/mapbefine/mapbefine/topic/domain/{Permission.java => PermissionType.java} (85%) rename backend/src/test/java/com/mapbefine/mapbefine/topic/domain/{PermissionTest.java => PermissionTypeTest.java} (82%) diff --git a/backend/src/main/java/com/mapbefine/mapbefine/topic/application/TopicCommandService.java b/backend/src/main/java/com/mapbefine/mapbefine/topic/application/TopicCommandService.java index 96e1d024d..1145a860b 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/topic/application/TopicCommandService.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/topic/application/TopicCommandService.java @@ -56,7 +56,7 @@ private Topic convertToTopic(AuthMember member, TopicCreateRequest request) { request.description(), request.image(), request.publicity(), - request.permission(), + request.permissionType(), creator ); } @@ -126,7 +126,7 @@ private Topic convertToTopic(AuthMember member, TopicMergeRequest request) { request.description(), request.image(), request.publicity(), - request.permission(), + request.permissionType(), creator ); } @@ -168,7 +168,7 @@ public void updateTopicInfo( validateUpdateAuth(member, topic); topic.updateTopicInfo(request.name(), request.description(), request.image()); - topic.updateTopicStatus(request.publicity(), request.permission()); + topic.updateTopicStatus(request.publicity(), request.permissionType()); } private Topic findTopic(Long topicId) { diff --git a/backend/src/main/java/com/mapbefine/mapbefine/topic/domain/Permission.java b/backend/src/main/java/com/mapbefine/mapbefine/topic/domain/PermissionType.java similarity index 85% rename from backend/src/main/java/com/mapbefine/mapbefine/topic/domain/Permission.java rename to backend/src/main/java/com/mapbefine/mapbefine/topic/domain/PermissionType.java index a5f0ac532..aa145d4ad 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/topic/domain/Permission.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/topic/domain/PermissionType.java @@ -3,14 +3,14 @@ import lombok.Getter; @Getter -public enum Permission { +public enum PermissionType { ALL_MEMBERS("모든 회원"), GROUP_ONLY("소속 회원"); private final String title; - Permission(String title) { + PermissionType(String title) { this.title = title; } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/topic/domain/Topic.java b/backend/src/main/java/com/mapbefine/mapbefine/topic/domain/Topic.java index f9d62f9fb..de0a06446 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/topic/domain/Topic.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/topic/domain/Topic.java @@ -66,11 +66,11 @@ public static Topic createTopicAssociatedWithCreator( String description, String imageUrl, Publicity publicity, - Permission permission, + PermissionType permissionType, Member creator ) { TopicInfo topicInfo = TopicInfo.of(name, description, imageUrl); - TopicStatus topicStatus = TopicStatus.of(publicity, permission); + TopicStatus topicStatus = TopicStatus.of(publicity, permissionType); Topic topic = new Topic(topicInfo, topicStatus, creator); creator.addTopic(topic); @@ -86,8 +86,8 @@ public void updateTopicInfo( this.topicInfo = TopicInfo.of(name, description, imageUrl); } - public void updateTopicStatus(Publicity publicity, Permission permission) { - topicStatus.update(publicity, permission); + public void updateTopicStatus(Publicity publicity, PermissionType permissionType) { + topicStatus.update(publicity, permissionType); } public int countPins() { diff --git a/backend/src/main/java/com/mapbefine/mapbefine/topic/domain/TopicStatus.java b/backend/src/main/java/com/mapbefine/mapbefine/topic/domain/TopicStatus.java index 5e79662c0..1232830a1 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/topic/domain/TopicStatus.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/topic/domain/TopicStatus.java @@ -21,50 +21,50 @@ public class TopicStatus { @Enumerated(EnumType.STRING) @Column(nullable = false) - private Permission permission; + private PermissionType permissionType; - private TopicStatus(Publicity publicity, Permission permission) { + private TopicStatus(Publicity publicity, PermissionType permissionType) { this.publicity = publicity; - this.permission = permission; + this.permissionType = permissionType; } - public static TopicStatus of(Publicity publicity, Permission permission) { - validateTopicStatus(publicity, permission); + public static TopicStatus of(Publicity publicity, PermissionType permissionType) { + validateTopicStatus(publicity, permissionType); - return new TopicStatus(publicity, permission); + return new TopicStatus(publicity, permissionType); } - private static void validateTopicStatus(Publicity publicity, Permission permission) { + private static void validateTopicStatus(Publicity publicity, PermissionType permissionType) { if (Objects.isNull(publicity)) { throw new IllegalArgumentException("공개 범위는 null일 수 없습니다."); } - if (Objects.isNull(permission)) { + if (Objects.isNull(permissionType)) { throw new IllegalArgumentException("권한 설정은 null일 수 없습니다."); } - if (publicity.isPrivate() && permission.isAllMembers()) { + if (publicity.isPrivate() && permissionType.isAllMembers()) { throw new IllegalArgumentException("공개 범위가 혼자 볼 지도인 경우, 권한 설정이 소속 회원이어야합니다."); } } - public void update(Publicity publicity, Permission permission) { - validatePublicity(publicity, permission); - validatePermission(permission); + public void update(Publicity publicity, PermissionType permissionType) { + validatePublicity(publicity, permissionType); + validatePermission(permissionType); this.publicity = publicity; - this.permission = permission; + this.permissionType = permissionType; } - private void validatePublicity(Publicity publicity, Permission permission) { - if (publicity.isPrivate() && permission.isAllMembers()) { + private void validatePublicity(Publicity publicity, PermissionType permissionType) { + if (publicity.isPrivate() && permissionType.isAllMembers()) { throw new IllegalArgumentException("권한 범위가 모든 멤버인 경우, 공개 범위를 혼자 볼 지도로 설정할 수 없습니다."); } } // TODO: 2023/08/09 해당 정책으로 인해, TopicStatus는 불변 객체로 만들 수 없을까 ? - private void validatePermission(Permission permission) { - if (this.permission.isAllMembers() && permission.isGroupOnly()) { + private void validatePermission(PermissionType permissionType) { + if (this.permissionType.isAllMembers() && permissionType.isGroupOnly()) { throw new IllegalArgumentException("권한 범위는 줄어들 수 없습니다."); } } @@ -78,11 +78,11 @@ public boolean isPrivate() { } public boolean isAllMembers() { - return permission.isAllMembers(); + return permissionType.isAllMembers(); } public boolean isGroupOnly() { - return permission.isGroupOnly(); + return permissionType.isGroupOnly(); } } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/topic/dto/request/TopicCreateRequest.java b/backend/src/main/java/com/mapbefine/mapbefine/topic/dto/request/TopicCreateRequest.java index 873d46c40..e7dc64c52 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/topic/dto/request/TopicCreateRequest.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/topic/dto/request/TopicCreateRequest.java @@ -1,6 +1,6 @@ package com.mapbefine.mapbefine.topic.dto.request; -import com.mapbefine.mapbefine.topic.domain.Permission; +import com.mapbefine.mapbefine.topic.domain.PermissionType; import com.mapbefine.mapbefine.topic.domain.Publicity; import java.util.List; @@ -9,7 +9,7 @@ public record TopicCreateRequest( String image, String description, Publicity publicity, - Permission permission, + PermissionType permissionType, List pins ) { } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/topic/dto/request/TopicMergeRequest.java b/backend/src/main/java/com/mapbefine/mapbefine/topic/dto/request/TopicMergeRequest.java index 18d468ace..deb14c79b 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/topic/dto/request/TopicMergeRequest.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/topic/dto/request/TopicMergeRequest.java @@ -1,6 +1,6 @@ package com.mapbefine.mapbefine.topic.dto.request; -import com.mapbefine.mapbefine.topic.domain.Permission; +import com.mapbefine.mapbefine.topic.domain.PermissionType; import com.mapbefine.mapbefine.topic.domain.Publicity; import java.util.List; @@ -9,7 +9,7 @@ public record TopicMergeRequest( String image, String description, Publicity publicity, - Permission permission, + PermissionType permissionType, List topics ) { } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/topic/dto/request/TopicUpdateRequest.java b/backend/src/main/java/com/mapbefine/mapbefine/topic/dto/request/TopicUpdateRequest.java index c3d616844..76bd803aa 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/topic/dto/request/TopicUpdateRequest.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/topic/dto/request/TopicUpdateRequest.java @@ -1,6 +1,6 @@ package com.mapbefine.mapbefine.topic.dto.request; -import com.mapbefine.mapbefine.topic.domain.Permission; +import com.mapbefine.mapbefine.topic.domain.PermissionType; import com.mapbefine.mapbefine.topic.domain.Publicity; public record TopicUpdateRequest( @@ -8,7 +8,7 @@ public record TopicUpdateRequest( String image, String description, Publicity publicity, - Permission permission + PermissionType permissionType ) { } diff --git a/backend/src/test/java/com/mapbefine/mapbefine/topic/TopicFixture.java b/backend/src/test/java/com/mapbefine/mapbefine/topic/TopicFixture.java index 5d8f0841c..818e81f3f 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/topic/TopicFixture.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/topic/TopicFixture.java @@ -2,7 +2,7 @@ import com.mapbefine.mapbefine.member.domain.Member; -import com.mapbefine.mapbefine.topic.domain.Permission; +import com.mapbefine.mapbefine.topic.domain.PermissionType; import com.mapbefine.mapbefine.topic.domain.Publicity; import com.mapbefine.mapbefine.topic.domain.Topic; import com.mapbefine.mapbefine.topic.dto.request.TopicCreateRequest; @@ -19,7 +19,7 @@ public static Topic createPrivateAndGroupOnlyTopic(Member member) { "토픽 멤버만 읽을 수 있습니다.", IMAGE_URL, Publicity.PRIVATE, - Permission.GROUP_ONLY, + PermissionType.GROUP_ONLY, member ); } @@ -30,7 +30,7 @@ public static Topic createPublicAndAllMembersTopic(Member member) { "아무나 읽을 수 있습니다.", IMAGE_URL, Publicity.PUBLIC, - Permission.ALL_MEMBERS, + PermissionType.ALL_MEMBERS, member ); } @@ -41,7 +41,7 @@ public static Topic createByName(String name, Member member) { "설명", null, Publicity.PUBLIC, - Permission.ALL_MEMBERS, + PermissionType.ALL_MEMBERS, member ); } @@ -52,7 +52,7 @@ public static Topic createPrivateByName(String name, Member member) { "설명", null, Publicity.PRIVATE, - Permission.GROUP_ONLY, + PermissionType.GROUP_ONLY, member ); } @@ -65,7 +65,7 @@ public static TopicCreateRequest createPublicAndAllMembersCreateRequestWithPins( IMAGE_URL, "아무나 읽을 수 있는 토픽입니다.", Publicity.PUBLIC, - Permission.ALL_MEMBERS, + PermissionType.ALL_MEMBERS, pinIds ); } @@ -78,7 +78,7 @@ public static TopicMergeRequest createPublicAndAllMembersMergeRequestWithTopics( IMAGE_URL, "아무나 읽을 수 있는 토픽입니다.", Publicity.PUBLIC, - Permission.ALL_MEMBERS, + PermissionType.ALL_MEMBERS, topicIds ); } diff --git a/backend/src/test/java/com/mapbefine/mapbefine/topic/TopicIntegrationTest.java b/backend/src/test/java/com/mapbefine/mapbefine/topic/TopicIntegrationTest.java index ea4083147..090dd9efa 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/topic/TopicIntegrationTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/topic/TopicIntegrationTest.java @@ -14,7 +14,7 @@ import com.mapbefine.mapbefine.pin.PinFixture; import com.mapbefine.mapbefine.pin.domain.Pin; import com.mapbefine.mapbefine.pin.domain.PinRepository; -import com.mapbefine.mapbefine.topic.domain.Permission; +import com.mapbefine.mapbefine.topic.domain.PermissionType; import com.mapbefine.mapbefine.topic.domain.Publicity; import com.mapbefine.mapbefine.topic.domain.Topic; import com.mapbefine.mapbefine.topic.domain.TopicRepository; @@ -70,7 +70,7 @@ void createNewTopicWithoutPins_Success() { "https://map-befine-official.github.io/favicon.png", "준팍이 2번 이상 간집 ", Publicity.PUBLIC, - Permission.ALL_MEMBERS, + PermissionType.ALL_MEMBERS, Collections.emptyList() ); @@ -109,7 +109,7 @@ void createNewTopicWithPins_Success() { "https://map-befine-official.github.io/favicon.png", "준팍이 2번 이상 간집 ", Publicity.PUBLIC, - Permission.ALL_MEMBERS, + PermissionType.ALL_MEMBERS, pinIds ); @@ -130,7 +130,7 @@ void createMergeTopic_Success() { "https://map-befine-official.github.io/favicon.png", "준팍이 2번 이상 간집 ", Publicity.PUBLIC, - Permission.ALL_MEMBERS, + PermissionType.ALL_MEMBERS, Collections.emptyList() ); TopicCreateRequest 준팍의_또안간집 = new TopicCreateRequest( @@ -138,7 +138,7 @@ void createMergeTopic_Success() { "https://map-befine-official.github.io/favicon.png", "준팍이 2번 이상 안간집 ", Publicity.PUBLIC, - Permission.ALL_MEMBERS, + PermissionType.ALL_MEMBERS, Collections.emptyList() ); createNewTopic(준팍의_또간집, authHeader); @@ -153,7 +153,7 @@ void createMergeTopic_Success() { "https://map-befine-official.github.io/favicon.png", "맛집과 카페 토픽 합치기", Publicity.PUBLIC, - Permission.ALL_MEMBERS, + PermissionType.ALL_MEMBERS, topicIds); // when @@ -180,7 +180,7 @@ void updateTopic_Success() { "https://map-befine-official.github.io/favicon.png", "준팍이 두번 간집", Publicity.PUBLIC, - Permission.ALL_MEMBERS, + PermissionType.ALL_MEMBERS, Collections.emptyList() ), authHeader @@ -193,7 +193,7 @@ void updateTopic_Success() { "https://map-befine-official.github.io/favicon.png", "수정한 토픽", Publicity.PUBLIC, - Permission.ALL_MEMBERS + PermissionType.ALL_MEMBERS ); ExtractableResponse response = RestAssured .given().log().all() @@ -217,7 +217,7 @@ void deleteTopic_Success() { "https://map-befine-official.github.io/favicon.png", "준팍이 두번 간집 ", Publicity.PUBLIC, - Permission.ALL_MEMBERS, + PermissionType.ALL_MEMBERS, Collections.emptyList() ), authHeader @@ -262,7 +262,7 @@ void findTopicDetail_Success() { "https://map-befine-official.github.io/favicon.png", "description", Publicity.PUBLIC, - Permission.ALL_MEMBERS, + PermissionType.ALL_MEMBERS, Collections.emptyList() ); ExtractableResponse createResponse = createNewTopic(request, authHeader); @@ -291,7 +291,7 @@ void findTopicDetailsByIds_Success() { "https://map-befine-official.github.io/favicon.png", "description", Publicity.PUBLIC, - Permission.ALL_MEMBERS, + PermissionType.ALL_MEMBERS, Collections.emptyList() ); ExtractableResponse createResponse1 = createNewTopic(request, authHeader); diff --git a/backend/src/test/java/com/mapbefine/mapbefine/topic/application/TopicCommandServiceTest.java b/backend/src/test/java/com/mapbefine/mapbefine/topic/application/TopicCommandServiceTest.java index f0bea115a..194de9c41 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/topic/application/TopicCommandServiceTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/topic/application/TopicCommandServiceTest.java @@ -17,7 +17,7 @@ import com.mapbefine.mapbefine.pin.PinFixture; import com.mapbefine.mapbefine.pin.domain.Pin; import com.mapbefine.mapbefine.topic.TopicFixture; -import com.mapbefine.mapbefine.topic.domain.Permission; +import com.mapbefine.mapbefine.topic.domain.PermissionType; import com.mapbefine.mapbefine.topic.domain.Publicity; import com.mapbefine.mapbefine.topic.domain.Topic; import com.mapbefine.mapbefine.topic.domain.TopicRepository; @@ -302,7 +302,7 @@ public void updateTopicInfo_Success() { "https://map-befine-official.github.io/favicon.png", "수정된 설명", Publicity.PRIVATE, - Permission.GROUP_ONLY + PermissionType.GROUP_ONLY ); topicCommandService.updateTopicInfo(user, topic.getId(), request); @@ -338,7 +338,7 @@ public void updateTopicInfo_Fail() { "https://map-befine-official.github.io/favicon.png", "수정된 설명", Publicity.PUBLIC, - Permission.ALL_MEMBERS + PermissionType.ALL_MEMBERS ); assertThatThrownBy(() -> topicCommandService.updateTopicInfo(user, topic.getId(), request)) diff --git a/backend/src/test/java/com/mapbefine/mapbefine/topic/domain/PermissionTest.java b/backend/src/test/java/com/mapbefine/mapbefine/topic/domain/PermissionTypeTest.java similarity index 82% rename from backend/src/test/java/com/mapbefine/mapbefine/topic/domain/PermissionTest.java rename to backend/src/test/java/com/mapbefine/mapbefine/topic/domain/PermissionTypeTest.java index 695d3bed3..c517ab851 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/topic/domain/PermissionTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/topic/domain/PermissionTypeTest.java @@ -6,7 +6,7 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -class PermissionTest { +class PermissionTypeTest { @Nested @DisplayName("isAllMembers 메서드를 호출했을 때 ALL_MEMBER가 ") @@ -16,7 +16,7 @@ class IsAllMembers { @DisplayName("아니면, false를 반환한다.") void fail() { //given - Permission groupOnly = Permission.GROUP_ONLY; + PermissionType groupOnly = PermissionType.GROUP_ONLY; //when //then @@ -27,7 +27,7 @@ void fail() { @DisplayName("맞으면 true를 반환한다.") void success() { //given - Permission allMembers = Permission.ALL_MEMBERS; + PermissionType allMembers = PermissionType.ALL_MEMBERS; //when //then @@ -44,7 +44,7 @@ class IsGroupOnly { @DisplayName("아니면, false를 반환한다.") void fail() { //given - Permission allMembers = Permission.ALL_MEMBERS; + PermissionType allMembers = PermissionType.ALL_MEMBERS; //when //then @@ -55,7 +55,7 @@ void fail() { @DisplayName("맞으면 true를 반환한다.") void success() { //given - Permission groupOnly = Permission.GROUP_ONLY; + PermissionType groupOnly = PermissionType.GROUP_ONLY; //when //then diff --git a/backend/src/test/java/com/mapbefine/mapbefine/topic/domain/TopicRepositoryTest.java b/backend/src/test/java/com/mapbefine/mapbefine/topic/domain/TopicRepositoryTest.java index 7f3876be1..3280df30b 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/topic/domain/TopicRepositoryTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/topic/domain/TopicRepositoryTest.java @@ -38,7 +38,7 @@ void deleteById_Success() { "토픽설명", "https://example.com/image.jpg", Publicity.PUBLIC, - Permission.ALL_MEMBERS, + PermissionType.ALL_MEMBERS, member ); @@ -54,4 +54,4 @@ void deleteById_Success() { assertThat(deletedTopic.isDeleted()).isTrue(); } -} \ No newline at end of file +} diff --git a/backend/src/test/java/com/mapbefine/mapbefine/topic/domain/TopicStatusTest.java b/backend/src/test/java/com/mapbefine/mapbefine/topic/domain/TopicStatusTest.java index 160c46003..f00682e16 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/topic/domain/TopicStatusTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/topic/domain/TopicStatusTest.java @@ -17,11 +17,11 @@ class Validate { void fail() { //given Publicity publicity = Publicity.PRIVATE; - Permission permission = Permission.ALL_MEMBERS; + PermissionType permissionType = PermissionType.ALL_MEMBERS; //when //then - assertThatThrownBy(() -> TopicStatus.of(publicity, permission)) + assertThatThrownBy(() -> TopicStatus.of(publicity, permissionType)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("공개 범위가 혼자 볼 지도인 경우, 권한 설정이 소속 회원이어야합니다."); } @@ -31,10 +31,10 @@ void fail() { void whenPrivateAndGroupOnly_thenSuccess() { //given Publicity publicity = Publicity.PRIVATE; - Permission permission = Permission.GROUP_ONLY; + PermissionType permissionType = PermissionType.GROUP_ONLY; //when - TopicStatus topicStatus = TopicStatus.of(publicity, permission); + TopicStatus topicStatus = TopicStatus.of(publicity, permissionType); //then assertThat(topicStatus).isNotNull(); @@ -47,10 +47,10 @@ void whenPrivateAndGroupOnly_thenSuccess() { void whenPublicAndGroupOnly_thenSuccess() { //given Publicity publicity = Publicity.PUBLIC; - Permission permission = Permission.GROUP_ONLY; + PermissionType permissionType = PermissionType.GROUP_ONLY; //when - TopicStatus topicStatus = TopicStatus.of(publicity, permission); + TopicStatus topicStatus = TopicStatus.of(publicity, permissionType); //then assertThat(topicStatus).isNotNull(); @@ -63,10 +63,10 @@ void whenPublicAndGroupOnly_thenSuccess() { void whenPublicAndAllMembers_thenSuccess() { //given Publicity publicity = Publicity.PUBLIC; - Permission permission = Permission.ALL_MEMBERS; + PermissionType permissionType = PermissionType.ALL_MEMBERS; //when - TopicStatus topicStatus = TopicStatus.of(publicity, permission); + TopicStatus topicStatus = TopicStatus.of(publicity, permissionType); //then assertThat(topicStatus).isNotNull(); @@ -79,10 +79,10 @@ void whenPublicAndAllMembers_thenSuccess() { public void whenPublicityIsNull_Fail() { //given Publicity publicity = null; - Permission permission = Permission.ALL_MEMBERS; + PermissionType permissionType = PermissionType.ALL_MEMBERS; //when //then - assertThatThrownBy(() -> TopicStatus.of(publicity, permission)) + assertThatThrownBy(() -> TopicStatus.of(publicity, permissionType)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("공개 범위는 null일 수 없습니다."); } @@ -92,10 +92,10 @@ public void whenPublicityIsNull_Fail() { public void whenPermissionIsNull_Fail() { //given Publicity publicity = Publicity.PUBLIC; - Permission permission = null; + PermissionType permissionType = null; //when //then - assertThatThrownBy(() -> TopicStatus.of(publicity, permission)) + assertThatThrownBy(() -> TopicStatus.of(publicity, permissionType)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("권한 설정은 null일 수 없습니다."); } @@ -109,11 +109,11 @@ class Update { @DisplayName("권한 범위가 모든 멤버이면, 공개 범위를 혼자 볼 지도로 설정할 때 예외가 발생한다") void whenAllMembersAndPrivate_thenFail() { //given - TopicStatus topicStatus = TopicStatus.of(Publicity.PUBLIC, Permission.ALL_MEMBERS); + TopicStatus topicStatus = TopicStatus.of(Publicity.PUBLIC, PermissionType.ALL_MEMBERS); //when //then - assertThatThrownBy(() -> topicStatus.update(Publicity.PRIVATE, Permission.ALL_MEMBERS)) + assertThatThrownBy(() -> topicStatus.update(Publicity.PRIVATE, PermissionType.ALL_MEMBERS)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("권한 범위가 모든 멤버인 경우, 공개 범위를 혼자 볼 지도로 설정할 수 없습니다."); } @@ -121,11 +121,11 @@ void whenAllMembersAndPrivate_thenFail() { @Test @DisplayName("권한 범위를 GroupOnly로 변경할 경우, 예외가 발생한다") void whenUpdateGroupOnly_thenFail() { - TopicStatus topicStatus = TopicStatus.of(Publicity.PUBLIC, Permission.ALL_MEMBERS); + TopicStatus topicStatus = TopicStatus.of(Publicity.PUBLIC, PermissionType.ALL_MEMBERS); //when //then - assertThatThrownBy(() -> topicStatus.update(Publicity.PUBLIC, Permission.GROUP_ONLY)) + assertThatThrownBy(() -> topicStatus.update(Publicity.PUBLIC, PermissionType.GROUP_ONLY)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("권한 범위는 줄어들 수 없습니다."); } @@ -133,10 +133,10 @@ void whenUpdateGroupOnly_thenFail() { @Test @DisplayName("권한 범위가 GroupOnly일 때 private을 public으로 변경 가능하다") void whenUpdatePublicityToPublic_thenSuccess() { - TopicStatus topicStatus = TopicStatus.of(Publicity.PRIVATE, Permission.GROUP_ONLY); + TopicStatus topicStatus = TopicStatus.of(Publicity.PRIVATE, PermissionType.GROUP_ONLY); //when - topicStatus.update(Publicity.PUBLIC, Permission.GROUP_ONLY); + topicStatus.update(Publicity.PUBLIC, PermissionType.GROUP_ONLY); //then assertThat(topicStatus).isNotNull(); @@ -147,10 +147,10 @@ void whenUpdatePublicityToPublic_thenSuccess() { @Test @DisplayName("권한 범위가 GroupOnly일 때 public을 private으로 변경 가능하다") void whenUpdatePublicityToPrivate_thenSuccess() { - TopicStatus topicStatus = TopicStatus.of(Publicity.PUBLIC, Permission.GROUP_ONLY); + TopicStatus topicStatus = TopicStatus.of(Publicity.PUBLIC, PermissionType.GROUP_ONLY); //when - topicStatus.update(Publicity.PRIVATE, Permission.GROUP_ONLY); + topicStatus.update(Publicity.PRIVATE, PermissionType.GROUP_ONLY); //then assertThat(topicStatus).isNotNull(); diff --git a/backend/src/test/java/com/mapbefine/mapbefine/topic/domain/TopicTest.java b/backend/src/test/java/com/mapbefine/mapbefine/topic/domain/TopicTest.java index 9d2cdaf7c..0d5b02a44 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/topic/domain/TopicTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/topic/domain/TopicTest.java @@ -26,7 +26,7 @@ void setUp() { "매튜가 엄마 몰래 찾는 산스장", "https://example.com/image.jpg", Publicity.PUBLIC, - Permission.GROUP_ONLY, + PermissionType.GROUP_ONLY, member ); pin = PinFixture.create(LocationFixture.create(), topic, member); @@ -57,18 +57,18 @@ void updateTopicInfo() { void updateTopicStatus() { //given Publicity publicity = Publicity.PRIVATE; - Permission permission = Permission.GROUP_ONLY; + PermissionType permissionType = PermissionType.GROUP_ONLY; //when topic.updateTopicStatus( publicity, - permission + permissionType ); TopicStatus topicStatus = topic.getTopicStatus(); //then assertThat(topicStatus.getPublicity()).isEqualTo(publicity); - assertThat(topicStatus.getPermission()).isEqualTo(permission); + assertThat(topicStatus.getPermissionType()).isEqualTo(permissionType); } @Test diff --git a/backend/src/test/java/com/mapbefine/mapbefine/topic/presentation/TopicControllerTest.java b/backend/src/test/java/com/mapbefine/mapbefine/topic/presentation/TopicControllerTest.java index 03cc13d90..0af3b59a6 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/topic/presentation/TopicControllerTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/topic/presentation/TopicControllerTest.java @@ -11,7 +11,7 @@ import com.mapbefine.mapbefine.pin.dto.response.PinResponse; import com.mapbefine.mapbefine.topic.application.TopicCommandService; import com.mapbefine.mapbefine.topic.application.TopicQueryService; -import com.mapbefine.mapbefine.topic.domain.Permission; +import com.mapbefine.mapbefine.topic.domain.PermissionType; import com.mapbefine.mapbefine.topic.domain.Publicity; import com.mapbefine.mapbefine.topic.dto.request.TopicCreateRequest; import com.mapbefine.mapbefine.topic.dto.request.TopicMergeRequest; @@ -53,7 +53,7 @@ void create() throws Exception { "https://map-befine-official.github.io/favicon.png", "준팍이 두번 다시 안갈집", Publicity.PUBLIC, - Permission.ALL_MEMBERS, + PermissionType.ALL_MEMBERS, List.of(1L, 2L, 3L) ); @@ -77,7 +77,7 @@ void mergeAndCreate() throws Exception { "https://map-befine-official.github.io/favicon.png", "준팍이 두번 다시 안갈집", Publicity.PUBLIC, - Permission.ALL_MEMBERS, + PermissionType.ALL_MEMBERS, List.of(1L, 2L, 3L) ); @@ -100,7 +100,7 @@ void update() throws Exception { "https://map-befine-official.github.io/favicon.png", "준팍이 두번 다시 안갈집", Publicity.PUBLIC, - Permission.ALL_MEMBERS + PermissionType.ALL_MEMBERS ); mockMvc.perform( From cef6353d7b3fddc4f2cfc3e61ecb2b208a80c250 Mon Sep 17 00:00:00 2001 From: junpakPark Date: Mon, 14 Aug 2023 10:34:36 +0900 Subject: [PATCH 30/35] =?UTF-8?q?refactor:=20MemberTopicPermission=20?= =?UTF-8?q?=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EB=B3=80=EA=B2=BD(Permission)=20?= =?UTF-8?q?=EB=B0=8F=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/MemberCommandService.java | 32 +++++------ .../application/MemberQueryService.java | 26 ++++----- .../mapbefine/member/domain/Member.java | 9 ++-- .../MemberTopicPermissionCreateRequest.java | 7 --- .../MemberTopicPermissionDetailResponse.java | 20 ------- .../MemberTopicPermissionResponse.java | 17 ------ .../member/presentation/MemberController.java | 16 +++--- .../domain/Permission.java} | 17 +++--- .../domain/PermissionRepository.java} | 6 +-- .../dto/request/PermissionCreateRequest.java | 7 +++ .../response/PermissionDetailResponse.java | 21 ++++++++ .../dto/response/PermissionResponse.java | 18 +++++++ .../mapbefine/topic/domain/Topic.java | 8 +-- .../application/MemberCommandServiceTest.java | 54 +++++++++---------- .../application/MemberQueryServiceTest.java | 38 ++++++------- .../presentation/MemberControllerTest.java | 24 ++++----- .../presentation/MemberIntegrationTest.java | 54 +++++++++---------- .../domain/PermissionTest.java} | 28 +++++----- 18 files changed, 203 insertions(+), 199 deletions(-) delete mode 100644 backend/src/main/java/com/mapbefine/mapbefine/member/dto/request/MemberTopicPermissionCreateRequest.java delete mode 100644 backend/src/main/java/com/mapbefine/mapbefine/member/dto/response/MemberTopicPermissionDetailResponse.java delete mode 100644 backend/src/main/java/com/mapbefine/mapbefine/member/dto/response/MemberTopicPermissionResponse.java rename backend/src/main/java/com/mapbefine/mapbefine/{member/domain/MemberTopicPermission.java => permission/domain/Permission.java} (63%) rename backend/src/main/java/com/mapbefine/mapbefine/{member/domain/MemberTopicPermissionRepository.java => permission/domain/PermissionRepository.java} (50%) create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/permission/dto/request/PermissionCreateRequest.java create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/permission/dto/response/PermissionDetailResponse.java create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/permission/dto/response/PermissionResponse.java rename backend/src/test/java/com/mapbefine/mapbefine/{member/domain/MemberTopicPermissionTest.java => permission/domain/PermissionTest.java} (65%) diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/application/MemberCommandService.java b/backend/src/main/java/com/mapbefine/mapbefine/member/application/MemberCommandService.java index d5a3a0c4e..c2242cead 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/member/application/MemberCommandService.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/member/application/MemberCommandService.java @@ -3,9 +3,9 @@ import com.mapbefine.mapbefine.auth.domain.AuthMember; import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.member.domain.MemberRepository; -import com.mapbefine.mapbefine.member.domain.MemberTopicPermission; -import com.mapbefine.mapbefine.member.domain.MemberTopicPermissionRepository; -import com.mapbefine.mapbefine.member.dto.request.MemberTopicPermissionCreateRequest; +import com.mapbefine.mapbefine.permission.domain.Permission; +import com.mapbefine.mapbefine.permission.domain.PermissionRepository; +import com.mapbefine.mapbefine.permission.dto.request.PermissionCreateRequest; import com.mapbefine.mapbefine.topic.domain.Topic; import com.mapbefine.mapbefine.topic.domain.TopicRepository; import java.util.NoSuchElementException; @@ -18,19 +18,19 @@ public class MemberCommandService { private final MemberRepository memberRepository; private final TopicRepository topicRepository; - private final MemberTopicPermissionRepository memberTopicPermissionRepository; + private final PermissionRepository permissionRepository; public MemberCommandService( MemberRepository memberRepository, TopicRepository topicRepository, - MemberTopicPermissionRepository memberTopicPermissionRepository + PermissionRepository permissionRepository ) { this.memberRepository = memberRepository; this.topicRepository = topicRepository; - this.memberTopicPermissionRepository = memberTopicPermissionRepository; + this.permissionRepository = permissionRepository; } - public Long saveMemberTopicPermission(AuthMember authMember, MemberTopicPermissionCreateRequest request) { + public Long saveMemberTopicPermission(AuthMember authMember, PermissionCreateRequest request) { Member member = memberRepository.findById(request.memberId()) .orElseThrow(NoSuchElementException::new); Topic topic = topicRepository.findById(request.topicId()) @@ -38,15 +38,15 @@ public Long saveMemberTopicPermission(AuthMember authMember, MemberTopicPermissi validateSaveMemberTopicPermission(authMember, request, member, topic); - MemberTopicPermission memberTopicPermission = - MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic, member); + Permission permission = + Permission.createPermissionAssociatedWithTopicAndMember(topic, member); - return memberTopicPermissionRepository.save(memberTopicPermission).getId(); + return permissionRepository.save(permission).getId(); } private void validateSaveMemberTopicPermission( AuthMember authMember, - MemberTopicPermissionCreateRequest request, + PermissionCreateRequest request, Member member, Topic topic ) { @@ -65,7 +65,7 @@ private void validateMemberCanTopicUpdate(AuthMember authMember, Topic topic) { private void validateSelfPermission( AuthMember authMember, - MemberTopicPermissionCreateRequest request + PermissionCreateRequest request ) { if (authMember.getMemberId().equals(request.memberId())) { throw new IllegalArgumentException("본인에게 권한을 줄 수 없습니다."); @@ -73,18 +73,18 @@ private void validateSelfPermission( } private void validateDuplicatePermission(Long topicId, Long memberId) { - if (memberTopicPermissionRepository.existsByTopicIdAndMemberId(topicId, memberId)) { + if (permissionRepository.existsByTopicIdAndMemberId(topicId, memberId)) { throw new IllegalArgumentException("권한은 중복으로 줄 수 없습니다."); } } public void deleteMemberTopicPermission(AuthMember authMember, Long permissionId) { - MemberTopicPermission memberTopicPermission = memberTopicPermissionRepository.findById(permissionId) + Permission permission = permissionRepository.findById(permissionId) .orElseThrow(NoSuchElementException::new); - validateMemberCanTopicUpdate(authMember, memberTopicPermission.getTopic()); + validateMemberCanTopicUpdate(authMember, permission.getTopic()); - memberTopicPermissionRepository.delete(memberTopicPermission); + permissionRepository.delete(permission); } } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/application/MemberQueryService.java b/backend/src/main/java/com/mapbefine/mapbefine/member/application/MemberQueryService.java index fc6515b67..1d844a5f3 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/member/application/MemberQueryService.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/member/application/MemberQueryService.java @@ -3,12 +3,12 @@ import com.mapbefine.mapbefine.auth.domain.AuthMember; import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.member.domain.MemberRepository; -import com.mapbefine.mapbefine.member.domain.MemberTopicPermission; -import com.mapbefine.mapbefine.member.domain.MemberTopicPermissionRepository; +import com.mapbefine.mapbefine.permission.domain.Permission; +import com.mapbefine.mapbefine.permission.domain.PermissionRepository; import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; import com.mapbefine.mapbefine.member.dto.response.MemberResponse; -import com.mapbefine.mapbefine.member.dto.response.MemberTopicPermissionDetailResponse; -import com.mapbefine.mapbefine.member.dto.response.MemberTopicPermissionResponse; +import com.mapbefine.mapbefine.permission.dto.response.PermissionDetailResponse; +import com.mapbefine.mapbefine.permission.dto.response.PermissionResponse; import com.mapbefine.mapbefine.pin.domain.Pin; import com.mapbefine.mapbefine.pin.domain.PinRepository; import com.mapbefine.mapbefine.pin.dto.response.PinResponse; @@ -28,18 +28,18 @@ public class MemberQueryService { private final MemberRepository memberRepository; private final TopicRepository topicRepository; private final PinRepository pinRepository; - private final MemberTopicPermissionRepository memberTopicPermissionRepository; + private final PermissionRepository permissionRepository; public MemberQueryService( MemberRepository memberRepository, TopicRepository topicRepository, PinRepository pinRepository, - MemberTopicPermissionRepository memberTopicPermissionRepository + PermissionRepository permissionRepository ) { this.memberRepository = memberRepository; this.topicRepository = topicRepository; this.pinRepository = pinRepository; - this.memberTopicPermissionRepository = memberTopicPermissionRepository; + this.permissionRepository = permissionRepository; } public MemberDetailResponse findById(Long id) { @@ -80,21 +80,21 @@ public void validateNonExistsMember(Long memberId) { } } - public List findAllWithPermission(Long topicId) { + public List findAllWithPermission(Long topicId) { Topic topic = topicRepository.findById(topicId) .orElseThrow(NoSuchElementException::new); - return memberTopicPermissionRepository.findAllByTopic(topic) + return permissionRepository.findAllByTopic(topic) .stream() - .map(MemberTopicPermissionResponse::from) + .map(PermissionResponse::from) .toList(); } - public MemberTopicPermissionDetailResponse findMemberTopicPermissionById(Long permissionId) { - MemberTopicPermission memberTopicPermission = memberTopicPermissionRepository.findById(permissionId) + public PermissionDetailResponse findMemberTopicPermissionById(Long permissionId) { + Permission permission = permissionRepository.findById(permissionId) .orElseThrow(NoSuchElementException::new); - return MemberTopicPermissionDetailResponse.from(memberTopicPermission); + return PermissionDetailResponse.from(permission); } } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/Member.java b/backend/src/main/java/com/mapbefine/mapbefine/member/domain/Member.java index c82759538..8a67118d4 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/Member.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/member/domain/Member.java @@ -4,6 +4,7 @@ import static lombok.AccessLevel.PROTECTED; import com.mapbefine.mapbefine.common.entity.BaseTimeEntity; +import com.mapbefine.mapbefine.permission.domain.Permission; import com.mapbefine.mapbefine.pin.domain.Pin; import com.mapbefine.mapbefine.topic.domain.Topic; import jakarta.persistence.Embedded; @@ -42,7 +43,7 @@ public class Member extends BaseTimeEntity { private List createdPins = new ArrayList<>(); @OneToMany(mappedBy = "member") - private List topicsWithPermissions = new ArrayList<>(); + private List topicsWithPermissions = new ArrayList<>(); private Member(MemberInfo memberInfo, OauthId oauthId) { this.memberInfo = memberInfo; @@ -105,8 +106,8 @@ public void addPin(Pin pin) { createdPins.add(pin); } - public void addMemberTopicPermission(MemberTopicPermission memberTopicPermission) { - topicsWithPermissions.add(memberTopicPermission); + public void addMemberTopicPermission(Permission permission) { + topicsWithPermissions.add(permission); } public String getRoleKey() { @@ -122,7 +123,7 @@ public boolean isUser() { public List getTopicsWithPermissions() { return topicsWithPermissions.stream() - .map(MemberTopicPermission::getTopic) + .map(Permission::getTopic) .toList(); } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/dto/request/MemberTopicPermissionCreateRequest.java b/backend/src/main/java/com/mapbefine/mapbefine/member/dto/request/MemberTopicPermissionCreateRequest.java deleted file mode 100644 index 55b3ea7d1..000000000 --- a/backend/src/main/java/com/mapbefine/mapbefine/member/dto/request/MemberTopicPermissionCreateRequest.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.mapbefine.mapbefine.member.dto.request; - -public record MemberTopicPermissionCreateRequest( - Long topicId, - Long memberId -) { -} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/dto/response/MemberTopicPermissionDetailResponse.java b/backend/src/main/java/com/mapbefine/mapbefine/member/dto/response/MemberTopicPermissionDetailResponse.java deleted file mode 100644 index 50c554681..000000000 --- a/backend/src/main/java/com/mapbefine/mapbefine/member/dto/response/MemberTopicPermissionDetailResponse.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.mapbefine.mapbefine.member.dto.response; - -import com.mapbefine.mapbefine.member.domain.MemberTopicPermission; -import java.time.LocalDateTime; - -public record MemberTopicPermissionDetailResponse( - Long id, - LocalDateTime updatedAt, - MemberDetailResponse memberDetailResponse -) { - - public static MemberTopicPermissionDetailResponse from(MemberTopicPermission memberTopicPermission) { - return new MemberTopicPermissionDetailResponse( - memberTopicPermission.getId(), - memberTopicPermission.getUpdatedAt(), - MemberDetailResponse.from(memberTopicPermission.getMember()) - ); - } - -} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/dto/response/MemberTopicPermissionResponse.java b/backend/src/main/java/com/mapbefine/mapbefine/member/dto/response/MemberTopicPermissionResponse.java deleted file mode 100644 index 0e0dc6daa..000000000 --- a/backend/src/main/java/com/mapbefine/mapbefine/member/dto/response/MemberTopicPermissionResponse.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.mapbefine.mapbefine.member.dto.response; - -import com.mapbefine.mapbefine.member.domain.MemberTopicPermission; - -public record MemberTopicPermissionResponse( - Long id, - MemberResponse memberResponse -) { - - public static MemberTopicPermissionResponse from(MemberTopicPermission memberTopicPermission) { - return new MemberTopicPermissionResponse( - memberTopicPermission.getId(), - MemberResponse.from(memberTopicPermission.getMember()) - ); - } - -} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/presentation/MemberController.java b/backend/src/main/java/com/mapbefine/mapbefine/member/presentation/MemberController.java index 7a189e309..9e31e78dd 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/member/presentation/MemberController.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/member/presentation/MemberController.java @@ -4,11 +4,11 @@ import com.mapbefine.mapbefine.common.interceptor.LoginRequired; import com.mapbefine.mapbefine.member.application.MemberCommandService; import com.mapbefine.mapbefine.member.application.MemberQueryService; -import com.mapbefine.mapbefine.member.dto.request.MemberTopicPermissionCreateRequest; +import com.mapbefine.mapbefine.permission.dto.request.PermissionCreateRequest; import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; import com.mapbefine.mapbefine.member.dto.response.MemberResponse; -import com.mapbefine.mapbefine.member.dto.response.MemberTopicPermissionDetailResponse; -import com.mapbefine.mapbefine.member.dto.response.MemberTopicPermissionResponse; +import com.mapbefine.mapbefine.permission.dto.response.PermissionDetailResponse; +import com.mapbefine.mapbefine.permission.dto.response.PermissionResponse; import com.mapbefine.mapbefine.pin.dto.response.PinResponse; import com.mapbefine.mapbefine.topic.dto.response.TopicResponse; import java.net.URI; @@ -41,7 +41,7 @@ public MemberController( @PostMapping("/permissions") public ResponseEntity addMemberTopicPermission( AuthMember authMember, - @RequestBody MemberTopicPermissionCreateRequest request + @RequestBody PermissionCreateRequest request ) { Long savedId = memberCommandService.saveMemberTopicPermission(authMember, request); @@ -82,20 +82,20 @@ public ResponseEntity> findPinsByMember(AuthMember authMember) @LoginRequired @GetMapping("/permissions/topics/{topicId}") - public ResponseEntity> findMemberTopicPermissionAll( + public ResponseEntity> findMemberTopicPermissionAll( @PathVariable Long topicId ) { - List responses = memberQueryService.findAllWithPermission(topicId); + List responses = memberQueryService.findAllWithPermission(topicId); return ResponseEntity.ok(responses); } @LoginRequired @GetMapping("/permissions/{permissionId}") - public ResponseEntity findMemberTopicPermissionById( + public ResponseEntity findMemberTopicPermissionById( @PathVariable Long permissionId ) { - MemberTopicPermissionDetailResponse response = memberQueryService.findMemberTopicPermissionById(permissionId); + PermissionDetailResponse response = memberQueryService.findMemberTopicPermissionById(permissionId); return ResponseEntity.ok(response); } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/MemberTopicPermission.java b/backend/src/main/java/com/mapbefine/mapbefine/permission/domain/Permission.java similarity index 63% rename from backend/src/main/java/com/mapbefine/mapbefine/member/domain/MemberTopicPermission.java rename to backend/src/main/java/com/mapbefine/mapbefine/permission/domain/Permission.java index 2cd41de02..df3fe9ec2 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/MemberTopicPermission.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/permission/domain/Permission.java @@ -1,8 +1,9 @@ -package com.mapbefine.mapbefine.member.domain; +package com.mapbefine.mapbefine.permission.domain; import static lombok.AccessLevel.PROTECTED; import com.mapbefine.mapbefine.common.entity.BaseTimeEntity; +import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.topic.domain.Topic; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; @@ -16,7 +17,7 @@ @Entity @NoArgsConstructor(access = PROTECTED) @Getter -public class MemberTopicPermission extends BaseTimeEntity { +public class Permission extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -30,20 +31,20 @@ public class MemberTopicPermission extends BaseTimeEntity { @JoinColumn(name = "member_id", nullable = false) private Member member; - private MemberTopicPermission(Topic topic, Member member) { + private Permission(Topic topic, Member member) { this.topic = topic; this.member = member; } - public static MemberTopicPermission createPermissionAssociatedWithTopicAndMember( + public static Permission createPermissionAssociatedWithTopicAndMember( Topic topic, Member member ) { - MemberTopicPermission memberTopicPermission = new MemberTopicPermission(topic, member); - topic.addMemberTopicPermission(memberTopicPermission); - member.addMemberTopicPermission(memberTopicPermission); + Permission permission = new Permission(topic, member); + topic.addMemberTopicPermission(permission); + member.addMemberTopicPermission(permission); - return memberTopicPermission; + return permission; } } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/MemberTopicPermissionRepository.java b/backend/src/main/java/com/mapbefine/mapbefine/permission/domain/PermissionRepository.java similarity index 50% rename from backend/src/main/java/com/mapbefine/mapbefine/member/domain/MemberTopicPermissionRepository.java rename to backend/src/main/java/com/mapbefine/mapbefine/permission/domain/PermissionRepository.java index 0ab5dde24..be3775e49 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/member/domain/MemberTopicPermissionRepository.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/permission/domain/PermissionRepository.java @@ -1,12 +1,12 @@ -package com.mapbefine.mapbefine.member.domain; +package com.mapbefine.mapbefine.permission.domain; import com.mapbefine.mapbefine.topic.domain.Topic; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; -public interface MemberTopicPermissionRepository extends JpaRepository { +public interface PermissionRepository extends JpaRepository { - List findAllByTopic(Topic topic); + List findAllByTopic(Topic topic); boolean existsByTopicIdAndMemberId(Long topicId, Long memberId); diff --git a/backend/src/main/java/com/mapbefine/mapbefine/permission/dto/request/PermissionCreateRequest.java b/backend/src/main/java/com/mapbefine/mapbefine/permission/dto/request/PermissionCreateRequest.java new file mode 100644 index 000000000..c7a925032 --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/permission/dto/request/PermissionCreateRequest.java @@ -0,0 +1,7 @@ +package com.mapbefine.mapbefine.permission.dto.request; + +public record PermissionCreateRequest( + Long topicId, + Long memberId +) { +} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/permission/dto/response/PermissionDetailResponse.java b/backend/src/main/java/com/mapbefine/mapbefine/permission/dto/response/PermissionDetailResponse.java new file mode 100644 index 000000000..967fa8eb5 --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/permission/dto/response/PermissionDetailResponse.java @@ -0,0 +1,21 @@ +package com.mapbefine.mapbefine.permission.dto.response; + +import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; +import com.mapbefine.mapbefine.permission.domain.Permission; +import java.time.LocalDateTime; + +public record PermissionDetailResponse( + Long id, + LocalDateTime updatedAt, + MemberDetailResponse memberDetailResponse +) { + + public static PermissionDetailResponse from(Permission permission) { + return new PermissionDetailResponse( + permission.getId(), + permission.getUpdatedAt(), + MemberDetailResponse.from(permission.getMember()) + ); + } + +} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/permission/dto/response/PermissionResponse.java b/backend/src/main/java/com/mapbefine/mapbefine/permission/dto/response/PermissionResponse.java new file mode 100644 index 000000000..9c4f23689 --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/permission/dto/response/PermissionResponse.java @@ -0,0 +1,18 @@ +package com.mapbefine.mapbefine.permission.dto.response; + +import com.mapbefine.mapbefine.member.dto.response.MemberResponse; +import com.mapbefine.mapbefine.permission.domain.Permission; + +public record PermissionResponse( + Long id, + MemberResponse memberResponse +) { + + public static PermissionResponse from(Permission permission) { + return new PermissionResponse( + permission.getId(), + MemberResponse.from(permission.getMember()) + ); + } + +} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/topic/domain/Topic.java b/backend/src/main/java/com/mapbefine/mapbefine/topic/domain/Topic.java index de0a06446..ba6f9ec3e 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/topic/domain/Topic.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/topic/domain/Topic.java @@ -4,7 +4,7 @@ import com.mapbefine.mapbefine.common.entity.BaseTimeEntity; import com.mapbefine.mapbefine.member.domain.Member; -import com.mapbefine.mapbefine.member.domain.MemberTopicPermission; +import com.mapbefine.mapbefine.permission.domain.Permission; import com.mapbefine.mapbefine.pin.domain.Pin; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; @@ -42,7 +42,7 @@ public class Topic extends BaseTimeEntity { private Member creator; @OneToMany(mappedBy = "topic") - private List memberTopicPermissions = new ArrayList<>(); + private List permissions = new ArrayList<>(); @OneToMany(mappedBy = "topic", cascade = CascadeType.PERSIST) private List pins = new ArrayList<>(); @@ -98,8 +98,8 @@ public void addPin(Pin pin) { pins.add(pin); } - public void addMemberTopicPermission(MemberTopicPermission memberTopicPermission) { - memberTopicPermissions.add(memberTopicPermission); + public void addMemberTopicPermission(Permission permission) { + permissions.add(permission); } } diff --git a/backend/src/test/java/com/mapbefine/mapbefine/member/application/MemberCommandServiceTest.java b/backend/src/test/java/com/mapbefine/mapbefine/member/application/MemberCommandServiceTest.java index 4e697d050..885b2d612 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/member/application/MemberCommandServiceTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/member/application/MemberCommandServiceTest.java @@ -10,13 +10,11 @@ import com.mapbefine.mapbefine.common.annotation.ServiceTest; import com.mapbefine.mapbefine.member.MemberFixture; import com.mapbefine.mapbefine.member.domain.Member; -import com.mapbefine.mapbefine.member.domain.MemberInfo; import com.mapbefine.mapbefine.member.domain.MemberRepository; -import com.mapbefine.mapbefine.member.domain.MemberTopicPermission; -import com.mapbefine.mapbefine.member.domain.MemberTopicPermissionRepository; +import com.mapbefine.mapbefine.permission.domain.Permission; +import com.mapbefine.mapbefine.permission.domain.PermissionRepository; import com.mapbefine.mapbefine.member.domain.Role; -import com.mapbefine.mapbefine.member.dto.request.MemberCreateRequest; -import com.mapbefine.mapbefine.member.dto.request.MemberTopicPermissionCreateRequest; +import com.mapbefine.mapbefine.permission.dto.request.PermissionCreateRequest; import com.mapbefine.mapbefine.topic.TopicFixture; import com.mapbefine.mapbefine.topic.domain.Topic; import com.mapbefine.mapbefine.topic.domain.TopicRepository; @@ -39,7 +37,7 @@ class MemberCommandServiceTest { private MemberRepository memberRepository; @Autowired - private MemberTopicPermissionRepository memberTopicPermissionRepository; + private PermissionRepository permissionRepository; @Test @DisplayName("Admin 이 권한을 주는 경우 정상적으로 권한이 주어진다.") @@ -49,16 +47,16 @@ void saveMemberTopicPermissionByAdmin() { Member member = memberRepository.save(MemberFixture.create("members", "members@naver.com", Role.USER)); Topic topic = topicRepository.save(TopicFixture.createByName("topic", admin)); AuthMember authAdmin = new Admin(admin.getId()); - MemberTopicPermissionCreateRequest request = new MemberTopicPermissionCreateRequest( + PermissionCreateRequest request = new PermissionCreateRequest( topic.getId(), member.getId() ); // when Long savedId = memberCommandService.saveMemberTopicPermission(authAdmin, request); - MemberTopicPermission memberTopicPermission = memberTopicPermissionRepository.findById(savedId) + Permission permission = permissionRepository.findById(savedId) .orElseThrow(NoSuchElementException::new); - Member memberWithPermission = memberTopicPermission.getMember(); + Member memberWithPermission = permission.getMember(); // then assertThat(member).usingRecursiveComparison() @@ -78,16 +76,16 @@ void saveMemberTopicPermissionByCreator() { getCreatedTopics(creator), getTopicsWithPermission(creator) ); - MemberTopicPermissionCreateRequest request = new MemberTopicPermissionCreateRequest( + PermissionCreateRequest request = new PermissionCreateRequest( topic.getId(), member.getId() ); // when Long savedId = memberCommandService.saveMemberTopicPermission(authCreator, request); - MemberTopicPermission memberTopicPermission = memberTopicPermissionRepository.findById(savedId) + Permission permission = permissionRepository.findById(savedId) .orElseThrow(NoSuchElementException::new); - Member memberWithPermission = memberTopicPermission.getMember(); + Member memberWithPermission = permission.getMember(); // then assertThat(member).usingRecursiveComparison() @@ -108,7 +106,7 @@ void saveMemberTopicPermissionByUser() { getCreatedTopics(notCreator), getTopicsWithPermission(notCreator) ); - MemberTopicPermissionCreateRequest request = new MemberTopicPermissionCreateRequest( + PermissionCreateRequest request = new PermissionCreateRequest( topic.getId(), member.getId() ); @@ -126,7 +124,7 @@ void saveMemberTopicPermissionByGuest() { Member member = memberRepository.save(MemberFixture.create("memberss", "memberss@naver.com", Role.USER)); Topic topic = topicRepository.save(TopicFixture.createByName("topic", creator)); AuthMember guest = new Guest(); - MemberTopicPermissionCreateRequest request = new MemberTopicPermissionCreateRequest( + PermissionCreateRequest request = new PermissionCreateRequest( topic.getId(), member.getId() ); @@ -147,7 +145,7 @@ void saveMemberTopicPermissionByCreator_whenSelf_thenFail() { getCreatedTopics(creator), getTopicsWithPermission(creator) ); - MemberTopicPermissionCreateRequest request = new MemberTopicPermissionCreateRequest( + PermissionCreateRequest request = new PermissionCreateRequest( topic.getId(), creator.getId() ); @@ -176,15 +174,15 @@ void saveMemberTopicPermissionByCreator_whenDuplicate_thenFail() { ) ); Topic topic = topicRepository.save(TopicFixture.createByName("topic", creator)); - MemberTopicPermission memberTopicPermission = - MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic, member); - memberTopicPermissionRepository.save(memberTopicPermission); + Permission permission = + Permission.createPermissionAssociatedWithTopicAndMember(topic, member); + permissionRepository.save(permission); AuthMember authCreator = new User( creator.getId(), getCreatedTopics(creator), getTopicsWithPermission(creator) ); - MemberTopicPermissionCreateRequest request = new MemberTopicPermissionCreateRequest( + PermissionCreateRequest request = new PermissionCreateRequest( topic.getId(), member.getId() ); @@ -204,9 +202,9 @@ void deleteMemberTopicPermissionByAdmin() { AuthMember authAdmin = new Admin(admin.getId()); // when - MemberTopicPermission memberTopicPermission = - MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic, member); - Long savedId = memberTopicPermissionRepository.save(memberTopicPermission).getId(); + Permission permission = + Permission.createPermissionAssociatedWithTopicAndMember(topic, member); + Long savedId = permissionRepository.save(permission).getId(); memberCommandService.deleteMemberTopicPermission(authAdmin, savedId); // then @@ -227,9 +225,9 @@ void deleteMemberTopicPermissionByCreator() { ); // when - MemberTopicPermission memberTopicPermission = - MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic, member); - Long savedId = memberTopicPermissionRepository.save(memberTopicPermission).getId(); + Permission permission = + Permission.createPermissionAssociatedWithTopicAndMember(topic, member); + Long savedId = permissionRepository.save(permission).getId(); memberCommandService.deleteMemberTopicPermission(authCreator, savedId); // then @@ -251,9 +249,9 @@ void deleteMemberTopicPermissionByUser() { ); // when - MemberTopicPermission memberTopicPermission = - MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic, member); - Long savedId = memberTopicPermissionRepository.save(memberTopicPermission).getId(); + Permission permission = + Permission.createPermissionAssociatedWithTopicAndMember(topic, member); + Long savedId = permissionRepository.save(permission).getId(); // then assertThatThrownBy(() -> memberCommandService.deleteMemberTopicPermission(authNonCreator, savedId)) diff --git a/backend/src/test/java/com/mapbefine/mapbefine/member/application/MemberQueryServiceTest.java b/backend/src/test/java/com/mapbefine/mapbefine/member/application/MemberQueryServiceTest.java index db7757efe..9d64114b4 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/member/application/MemberQueryServiceTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/member/application/MemberQueryServiceTest.java @@ -13,13 +13,13 @@ import com.mapbefine.mapbefine.member.MemberFixture; import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.member.domain.MemberRepository; -import com.mapbefine.mapbefine.member.domain.MemberTopicPermission; -import com.mapbefine.mapbefine.member.domain.MemberTopicPermissionRepository; +import com.mapbefine.mapbefine.permission.domain.Permission; +import com.mapbefine.mapbefine.permission.domain.PermissionRepository; import com.mapbefine.mapbefine.member.domain.Role; import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; import com.mapbefine.mapbefine.member.dto.response.MemberResponse; -import com.mapbefine.mapbefine.member.dto.response.MemberTopicPermissionDetailResponse; -import com.mapbefine.mapbefine.member.dto.response.MemberTopicPermissionResponse; +import com.mapbefine.mapbefine.permission.dto.response.PermissionDetailResponse; +import com.mapbefine.mapbefine.permission.dto.response.PermissionResponse; import com.mapbefine.mapbefine.pin.PinFixture; import com.mapbefine.mapbefine.pin.domain.Pin; import com.mapbefine.mapbefine.pin.domain.PinRepository; @@ -47,7 +47,7 @@ class MemberQueryServiceTest { private MemberRepository memberRepository; @Autowired - private MemberTopicPermissionRepository memberTopicPermissionRepository; + private PermissionRepository permissionRepository; @Autowired private LocationRepository locationRepository; @@ -70,24 +70,24 @@ void findAllWithPermission() { ); Topic topic1 = topicRepository.save(TopicFixture.createByName("topic1", member3InTopic2)); Topic topic2 = topicRepository.save(TopicFixture.createByName("topic2", member1InTopic1)); - memberTopicPermissionRepository.save( - MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic1, member1InTopic1) + permissionRepository.save( + Permission.createPermissionAssociatedWithTopicAndMember(topic1, member1InTopic1) ); - memberTopicPermissionRepository.save( - MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic1, member2InTopic1) + permissionRepository.save( + Permission.createPermissionAssociatedWithTopicAndMember(topic1, member2InTopic1) ); - memberTopicPermissionRepository.save( - MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic2, member3InTopic2) + permissionRepository.save( + Permission.createPermissionAssociatedWithTopicAndMember(topic2, member3InTopic2) ); // when - List memberTopicPermissionResponses = memberQueryService.findAllWithPermission(topic1.getId()); + List permissionRespons = memberQueryService.findAllWithPermission(topic1.getId()); MemberResponse memberResponse1 = MemberResponse.from(member1InTopic1); MemberResponse memberResponse2 = MemberResponse.from(member2InTopic1); // then - assertThat(memberTopicPermissionResponses).hasSize(2) - .extracting(MemberTopicPermissionResponse::memberResponse) + assertThat(permissionRespons).hasSize(2) + .extracting(PermissionResponse::memberResponse) .usingRecursiveComparison() .isEqualTo(List.of(memberResponse1, memberResponse2)); } @@ -103,18 +103,18 @@ void findMemberTopicPermissionById() { MemberFixture.create("members", "members@naver.com", Role.USER) ); Topic topic = topicRepository.save(TopicFixture.createByName("topic", creator)); - Long savedId = memberTopicPermissionRepository.save( - MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic, permissionUser) + Long savedId = permissionRepository.save( + Permission.createPermissionAssociatedWithTopicAndMember(topic, permissionUser) ).getId(); // when - MemberTopicPermissionDetailResponse memberTopicPermissionDetailResponse = + PermissionDetailResponse permissionDetailResponse = memberQueryService.findMemberTopicPermissionById(savedId); MemberDetailResponse permissionUserResponse = MemberDetailResponse.from(permissionUser); // then - assertThat(memberTopicPermissionDetailResponse) - .extracting(MemberTopicPermissionDetailResponse::memberDetailResponse) + assertThat(permissionDetailResponse) + .extracting(PermissionDetailResponse::memberDetailResponse) .usingRecursiveComparison() .isEqualTo(permissionUserResponse); } diff --git a/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberControllerTest.java b/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberControllerTest.java index 8d59d65d9..eb8a5410b 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberControllerTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberControllerTest.java @@ -10,11 +10,11 @@ import com.mapbefine.mapbefine.member.application.MemberQueryService; import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.member.domain.Role; -import com.mapbefine.mapbefine.member.dto.request.MemberTopicPermissionCreateRequest; +import com.mapbefine.mapbefine.permission.dto.request.PermissionCreateRequest; import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; import com.mapbefine.mapbefine.member.dto.response.MemberResponse; -import com.mapbefine.mapbefine.member.dto.response.MemberTopicPermissionDetailResponse; -import com.mapbefine.mapbefine.member.dto.response.MemberTopicPermissionResponse; +import com.mapbefine.mapbefine.permission.dto.response.PermissionDetailResponse; +import com.mapbefine.mapbefine.permission.dto.response.PermissionResponse; import com.mapbefine.mapbefine.pin.dto.response.PinResponse; import com.mapbefine.mapbefine.topic.dto.response.TopicResponse; import java.time.LocalDateTime; @@ -38,7 +38,7 @@ class MemberControllerTest extends RestDocsIntegration { @DisplayName("권한 추가") void addMemberTopicPermission() throws Exception { Member member = MemberFixture.create("member", "member@naver.com", Role.ADMIN); - MemberTopicPermissionCreateRequest request = new MemberTopicPermissionCreateRequest( + PermissionCreateRequest request = new PermissionCreateRequest( 1L, 2L ); @@ -73,8 +73,8 @@ void deleteMemberTopicPermission() throws Exception { @Test @DisplayName("권한이 있는 자들 모두 조회") void findMemberTopicPermissionAll() throws Exception { - List memberTopicPermissionResponses = List.of( - new MemberTopicPermissionResponse( + List permissionRespons = List.of( + new PermissionResponse( 1L, new MemberResponse( 1L, @@ -82,7 +82,7 @@ void findMemberTopicPermissionAll() throws Exception { "member@naver.com" ) ), - new MemberTopicPermissionResponse( + new PermissionResponse( 1L, new MemberResponse( 2L, @@ -92,10 +92,10 @@ void findMemberTopicPermissionAll() throws Exception { ) ); String authHeader = Base64.encodeBase64String( - ("Basic " + memberTopicPermissionResponses.get(0).memberResponse().email()).getBytes() + ("Basic " + permissionRespons.get(0).memberResponse().email()).getBytes() ); - given(memberQueryService.findAllWithPermission(any())).willReturn(memberTopicPermissionResponses); + given(memberQueryService.findAllWithPermission(any())).willReturn(permissionRespons); mockMvc.perform( MockMvcRequestBuilders.get("/members/permissions/topics/1") @@ -106,7 +106,7 @@ void findMemberTopicPermissionAll() throws Exception { @Test @DisplayName("권한이 있는 자들 모두 조회") void findMemberTopicPermissionById() throws Exception { - MemberTopicPermissionDetailResponse memberTopicPermissionDetailResponse = new MemberTopicPermissionDetailResponse( + PermissionDetailResponse permissionDetailResponse = new PermissionDetailResponse( 1L, LocalDateTime.now(), new MemberDetailResponse( @@ -118,10 +118,10 @@ void findMemberTopicPermissionById() throws Exception { ) ); String authHeader = Base64.encodeBase64String( - ("Basic " + memberTopicPermissionDetailResponse.memberDetailResponse().email()).getBytes() + ("Basic " + permissionDetailResponse.memberDetailResponse().email()).getBytes() ); - given(memberQueryService.findMemberTopicPermissionById(any())).willReturn(memberTopicPermissionDetailResponse); + given(memberQueryService.findMemberTopicPermissionById(any())).willReturn(permissionDetailResponse); mockMvc.perform( MockMvcRequestBuilders.get("/members/permissions/1") diff --git a/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberIntegrationTest.java b/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberIntegrationTest.java index 42c4af81f..df2c5bc23 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberIntegrationTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberIntegrationTest.java @@ -12,15 +12,15 @@ import com.mapbefine.mapbefine.member.MemberFixture; import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.member.domain.MemberRepository; -import com.mapbefine.mapbefine.member.domain.MemberTopicPermission; -import com.mapbefine.mapbefine.member.domain.MemberTopicPermissionRepository; +import com.mapbefine.mapbefine.permission.domain.Permission; +import com.mapbefine.mapbefine.permission.domain.PermissionRepository; import com.mapbefine.mapbefine.member.domain.OauthId; import com.mapbefine.mapbefine.member.domain.Role; -import com.mapbefine.mapbefine.member.dto.request.MemberTopicPermissionCreateRequest; +import com.mapbefine.mapbefine.permission.dto.request.PermissionCreateRequest; import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; import com.mapbefine.mapbefine.member.dto.response.MemberResponse; -import com.mapbefine.mapbefine.member.dto.response.MemberTopicPermissionDetailResponse; -import com.mapbefine.mapbefine.member.dto.response.MemberTopicPermissionResponse; +import com.mapbefine.mapbefine.permission.dto.response.PermissionDetailResponse; +import com.mapbefine.mapbefine.permission.dto.response.PermissionResponse; import com.mapbefine.mapbefine.pin.PinFixture; import com.mapbefine.mapbefine.pin.domain.Pin; import com.mapbefine.mapbefine.pin.domain.PinRepository; @@ -55,7 +55,7 @@ class MemberIntegrationTest extends IntegrationTest { private LocationRepository locationRepository; @Autowired - private MemberTopicPermissionRepository memberTopicPermissionRepository; + private PermissionRepository permissionRepository; private Member creator; private Member user1; @@ -102,7 +102,7 @@ void addMemberTopicPermission() { Topic topic = topicRepository.save(TopicFixture.createByName("topicName", creator)); // when - MemberTopicPermissionCreateRequest request = new MemberTopicPermissionCreateRequest( + PermissionCreateRequest request = new PermissionCreateRequest( topic.getId(), user1.getId() ); @@ -124,9 +124,9 @@ void addMemberTopicPermission() { void deleteMemberTopicPermission() { // given Topic topic = topicRepository.save(TopicFixture.createByName("topicName", creator)); - MemberTopicPermission memberTopicPermission = - MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic, user1); - Long savedId = memberTopicPermissionRepository.save(memberTopicPermission).getId(); + Permission permission = + Permission.createPermissionAssociatedWithTopicAndMember(topic, user1); + Long savedId = permissionRepository.save(permission).getId(); // when ExtractableResponse response = given().log().all() @@ -145,12 +145,12 @@ void deleteMemberTopicPermission() { void findMemberTopicPermissionAll() { // given Topic topic = topicRepository.save(TopicFixture.createByName("topicName", creator)); - MemberTopicPermission memberTopicPermission1 = - MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic, user1); - MemberTopicPermission memberTopicPermission2 = - MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic, user2); - memberTopicPermissionRepository.save(memberTopicPermission1); - memberTopicPermissionRepository.save(memberTopicPermission2); + Permission permission1 = + Permission.createPermissionAssociatedWithTopicAndMember(topic, user1); + Permission permission2 = + Permission.createPermissionAssociatedWithTopicAndMember(topic, user2); + permissionRepository.save(permission1); + permissionRepository.save(permission2); // when ExtractableResponse response = given().log().all() @@ -160,13 +160,13 @@ void findMemberTopicPermissionAll() { .extract(); // then - List memberTopicPermissionResponses = response.as(new TypeRef<>() { + List permissionRespons = response.as(new TypeRef<>() { }); assertThat(response.statusCode()) .isEqualTo(HttpStatus.OK.value()); - assertThat(memberTopicPermissionResponses) + assertThat(permissionRespons) .hasSize(2) - .extracting(MemberTopicPermissionResponse::memberResponse) + .extracting(PermissionResponse::memberResponse) .usingRecursiveComparison() .isEqualTo(List.of(MemberResponse.from(user1), MemberResponse.from(user2))); } @@ -176,24 +176,24 @@ void findMemberTopicPermissionAll() { void findMemberTopicPermissionById() { // given Topic topic = topicRepository.save(TopicFixture.createByName("topicName", creator)); - MemberTopicPermission memberTopicPermission = - MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic, user1); - memberTopicPermission = memberTopicPermissionRepository.save(memberTopicPermission); + Permission permission = + Permission.createPermissionAssociatedWithTopicAndMember(topic, user1); + permission = permissionRepository.save(permission); // when ExtractableResponse response = given().log().all() .header(AUTHORIZATION, creatorAuthHeader) - .when().get("/members/permissions/" + memberTopicPermission.getId()) + .when().get("/members/permissions/" + permission.getId()) .then().log().all() .extract(); // then - MemberTopicPermissionDetailResponse memberTopicPermissionDetailResponse = response.as( - MemberTopicPermissionDetailResponse.class); + PermissionDetailResponse permissionDetailResponse = response.as( + PermissionDetailResponse.class); assertThat(response.statusCode()) .isEqualTo(HttpStatus.OK.value()); - assertThat(memberTopicPermissionDetailResponse) - .extracting(MemberTopicPermissionDetailResponse::memberDetailResponse) + assertThat(permissionDetailResponse) + .extracting(PermissionDetailResponse::memberDetailResponse) .usingRecursiveComparison() .ignoringFieldsOfTypes(LocalDateTime.class) .isEqualTo(MemberDetailResponse.from(user1)); diff --git a/backend/src/test/java/com/mapbefine/mapbefine/member/domain/MemberTopicPermissionTest.java b/backend/src/test/java/com/mapbefine/mapbefine/permission/domain/PermissionTest.java similarity index 65% rename from backend/src/test/java/com/mapbefine/mapbefine/member/domain/MemberTopicPermissionTest.java rename to backend/src/test/java/com/mapbefine/mapbefine/permission/domain/PermissionTest.java index ec058f00a..d2778835b 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/member/domain/MemberTopicPermissionTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/permission/domain/PermissionTest.java @@ -1,19 +1,21 @@ -package com.mapbefine.mapbefine.member.domain; +package com.mapbefine.mapbefine.permission.domain; import static org.assertj.core.api.Assertions.assertThat; import com.mapbefine.mapbefine.member.MemberFixture; +import com.mapbefine.mapbefine.member.domain.Member; +import com.mapbefine.mapbefine.member.domain.Role; import com.mapbefine.mapbefine.topic.TopicFixture; import com.mapbefine.mapbefine.topic.domain.Topic; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -class MemberTopicPermissionTest { +class PermissionTest { @Test @DisplayName("정상적인 값을 입력하면 객체가 생성된다.") - void createMemberTopicPermission() { + void createPermission() { // given Member member = MemberFixture.create( "member", @@ -23,14 +25,14 @@ void createMemberTopicPermission() { Topic topic = TopicFixture.createByName("topic", member); // when - MemberTopicPermission memberTopicPermission = - MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic, member); + Permission permission = + Permission.createPermissionAssociatedWithTopicAndMember(topic, member); // then - assertThat(memberTopicPermission.getMember()).usingRecursiveComparison() + assertThat(permission.getMember()).usingRecursiveComparison() .ignoringFields("createdAt", "updatedAt") .isEqualTo(member); - assertThat(memberTopicPermission.getTopic()).usingRecursiveComparison() + assertThat(permission.getTopic()).usingRecursiveComparison() .ignoringFields("createdAt", "updatedAt") .isEqualTo(topic); } @@ -47,20 +49,20 @@ void createPermissionAssociatedWithTopicAndMember() { Topic topic = TopicFixture.createByName("topic", member); // when - MemberTopicPermission memberTopicPermission = - MemberTopicPermission.createPermissionAssociatedWithTopicAndMember(topic, member); + Permission permission = + Permission.createPermissionAssociatedWithTopicAndMember(topic, member); List topicsWithPermission = member.getTopicsWithPermissions(); - List memberTopicPermissions = topic.getMemberTopicPermissions(); + List permissions = topic.getPermissions(); // then assertThat(topicsWithPermission).hasSize(1); - assertThat(memberTopicPermissions).hasSize(1); + assertThat(permissions).hasSize(1); assertThat(topicsWithPermission.get(0)).usingRecursiveComparison() .ignoringFields("createdAt", "updatedAt") .isEqualTo(topic); - assertThat(memberTopicPermissions.get(0)).usingRecursiveComparison() + assertThat(permissions.get(0)).usingRecursiveComparison() .ignoringFields("createdAt", "updatedAt") - .isEqualTo(memberTopicPermission); + .isEqualTo(permission); } } From af1416b77a2d307ab8f7606673ea7dfbff7ac53d Mon Sep 17 00:00:00 2001 From: junpakPark Date: Mon, 14 Aug 2023 12:36:35 +0900 Subject: [PATCH 31/35] =?UTF-8?q?refactor:=20Service=20=EB=B0=8F=20Control?= =?UTF-8?q?ler=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/MemberQueryService.java | 33 +--- .../member/presentation/MemberController.java | 62 +----- .../PermissionCommandService.java} | 72 +++---- .../application/PermissionQueryService.java | 35 ++++ .../domain/PermissionRepository.java | 3 +- ...ateRequest.java => PermissionRequest.java} | 2 +- .../presentation/PermissionController.java | 68 +++++++ .../application/MemberQueryServiceTest.java | 80 -------- .../presentation/MemberControllerTest.java | 106 ---------- .../presentation/MemberIntegrationTest.java | 112 ----------- .../permission/PermissionIntegrationTest.java | 185 ++++++++++++++++++ .../PermissionCommandServiceTest.java} | 42 ++-- .../PermissionQueryServiceTest.java | 112 +++++++++++ .../PermissionControllerTest.java | 126 ++++++++++++ 14 files changed, 599 insertions(+), 439 deletions(-) rename backend/src/main/java/com/mapbefine/mapbefine/{member/application/MemberCommandService.java => permission/application/PermissionCommandService.java} (62%) create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/permission/application/PermissionQueryService.java rename backend/src/main/java/com/mapbefine/mapbefine/permission/dto/request/{PermissionCreateRequest.java => PermissionRequest.java} (73%) create mode 100644 backend/src/main/java/com/mapbefine/mapbefine/permission/presentation/PermissionController.java create mode 100644 backend/src/test/java/com/mapbefine/mapbefine/permission/PermissionIntegrationTest.java rename backend/src/test/java/com/mapbefine/mapbefine/{member/application/MemberCommandServiceTest.java => permission/application/PermissionCommandServiceTest.java} (87%) create mode 100644 backend/src/test/java/com/mapbefine/mapbefine/permission/application/PermissionQueryServiceTest.java create mode 100644 backend/src/test/java/com/mapbefine/mapbefine/permission/presentation/PermissionControllerTest.java diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/application/MemberQueryService.java b/backend/src/main/java/com/mapbefine/mapbefine/member/application/MemberQueryService.java index 1d844a5f3..6614e6dd6 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/member/application/MemberQueryService.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/member/application/MemberQueryService.java @@ -3,12 +3,8 @@ import com.mapbefine.mapbefine.auth.domain.AuthMember; import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.member.domain.MemberRepository; -import com.mapbefine.mapbefine.permission.domain.Permission; -import com.mapbefine.mapbefine.permission.domain.PermissionRepository; import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; import com.mapbefine.mapbefine.member.dto.response.MemberResponse; -import com.mapbefine.mapbefine.permission.dto.response.PermissionDetailResponse; -import com.mapbefine.mapbefine.permission.dto.response.PermissionResponse; import com.mapbefine.mapbefine.pin.domain.Pin; import com.mapbefine.mapbefine.pin.domain.PinRepository; import com.mapbefine.mapbefine.pin.dto.response.PinResponse; @@ -28,18 +24,15 @@ public class MemberQueryService { private final MemberRepository memberRepository; private final TopicRepository topicRepository; private final PinRepository pinRepository; - private final PermissionRepository permissionRepository; public MemberQueryService( MemberRepository memberRepository, TopicRepository topicRepository, - PinRepository pinRepository, - PermissionRepository permissionRepository + PinRepository pinRepository ) { this.memberRepository = memberRepository; this.topicRepository = topicRepository; this.pinRepository = pinRepository; - this.permissionRepository = permissionRepository; } public MemberDetailResponse findById(Long id) { @@ -49,6 +42,7 @@ public MemberDetailResponse findById(Long id) { return MemberDetailResponse.from(member); } + // TODO: 2023/08/14 해당 메서드는 ADMIN만 접근 가능하게 리팩터링 하기 public List findAll() { return memberRepository.findAll() .stream() @@ -56,6 +50,7 @@ public List findAll() { .toList(); } + // TODO: 2023/08/14 해당 메서드는 TopicQueryService로 옮기기 public List findTopicsByMember(AuthMember authMember) { validateNonExistsMember(authMember.getMemberId()); List topicsByCreator = topicRepository.findByCreatorId(authMember.getMemberId()); @@ -65,6 +60,7 @@ public List findTopicsByMember(AuthMember authMember) { .toList(); } + // TODO: 2023/08/14 해당 메서드는 PinQueryService로 옮기기 public List findPinsByMember(AuthMember authMember) { validateNonExistsMember(authMember.getMemberId()); List pinsByCreator = pinRepository.findByCreatorId(authMember.getMemberId()); @@ -73,28 +69,11 @@ public List findPinsByMember(AuthMember authMember) { .map(PinResponse::from) .toList(); } - - public void validateNonExistsMember(Long memberId) { + + private void validateNonExistsMember(Long memberId) { if (Objects.isNull(memberId)) { throw new IllegalArgumentException("존재하지 않는 유저입니다."); } } - public List findAllWithPermission(Long topicId) { - Topic topic = topicRepository.findById(topicId) - .orElseThrow(NoSuchElementException::new); - - return permissionRepository.findAllByTopic(topic) - .stream() - .map(PermissionResponse::from) - .toList(); - } - - public PermissionDetailResponse findMemberTopicPermissionById(Long permissionId) { - Permission permission = permissionRepository.findById(permissionId) - .orElseThrow(NoSuchElementException::new); - - return PermissionDetailResponse.from(permission); - } - } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/presentation/MemberController.java b/backend/src/main/java/com/mapbefine/mapbefine/member/presentation/MemberController.java index 9e31e78dd..b2165c32a 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/member/presentation/MemberController.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/member/presentation/MemberController.java @@ -2,23 +2,15 @@ import com.mapbefine.mapbefine.auth.domain.AuthMember; import com.mapbefine.mapbefine.common.interceptor.LoginRequired; -import com.mapbefine.mapbefine.member.application.MemberCommandService; import com.mapbefine.mapbefine.member.application.MemberQueryService; -import com.mapbefine.mapbefine.permission.dto.request.PermissionCreateRequest; import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; import com.mapbefine.mapbefine.member.dto.response.MemberResponse; -import com.mapbefine.mapbefine.permission.dto.response.PermissionDetailResponse; -import com.mapbefine.mapbefine.permission.dto.response.PermissionResponse; import com.mapbefine.mapbefine.pin.dto.response.PinResponse; import com.mapbefine.mapbefine.topic.dto.response.TopicResponse; -import java.net.URI; import java.util.List; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; 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; @@ -26,26 +18,18 @@ @RequestMapping("/members") public class MemberController { - private final MemberCommandService memberCommandService; private final MemberQueryService memberQueryService; - public MemberController( - MemberCommandService memberCommandService, - MemberQueryService memberQueryService - ) { - this.memberCommandService = memberCommandService; + public MemberController(MemberQueryService memberQueryService) { this.memberQueryService = memberQueryService; } @LoginRequired - @PostMapping("/permissions") - public ResponseEntity addMemberTopicPermission( - AuthMember authMember, - @RequestBody PermissionCreateRequest request - ) { - Long savedId = memberCommandService.saveMemberTopicPermission(authMember, request); + @GetMapping + public ResponseEntity> findAllMember() { + List responses = memberQueryService.findAll(); - return ResponseEntity.created(URI.create("/members/permissions/" + savedId)).build(); + return ResponseEntity.ok(responses); } @LoginRequired @@ -56,14 +40,6 @@ public ResponseEntity findMemberById(@PathVariable Long me return ResponseEntity.ok(response); } - @LoginRequired - @GetMapping - public ResponseEntity> findAllMember() { - List responses = memberQueryService.findAll(); - - return ResponseEntity.ok(responses); - } - @LoginRequired @GetMapping("/topics") public ResponseEntity> findTopicsByMember(AuthMember authMember) { @@ -80,32 +56,4 @@ public ResponseEntity> findPinsByMember(AuthMember authMember) return ResponseEntity.ok(responses); } - @LoginRequired - @GetMapping("/permissions/topics/{topicId}") - public ResponseEntity> findMemberTopicPermissionAll( - @PathVariable Long topicId - ) { - List responses = memberQueryService.findAllWithPermission(topicId); - - return ResponseEntity.ok(responses); - } - - @LoginRequired - @GetMapping("/permissions/{permissionId}") - public ResponseEntity findMemberTopicPermissionById( - @PathVariable Long permissionId - ) { - PermissionDetailResponse response = memberQueryService.findMemberTopicPermissionById(permissionId); - - return ResponseEntity.ok(response); - } - - @LoginRequired - @DeleteMapping("/permissions/{permissionId}") - public ResponseEntity deleteMemberTopicPermission(AuthMember authMember, @PathVariable Long permissionId) { - memberCommandService.deleteMemberTopicPermission(authMember, permissionId); - - return ResponseEntity.noContent().build(); - } - } diff --git a/backend/src/main/java/com/mapbefine/mapbefine/member/application/MemberCommandService.java b/backend/src/main/java/com/mapbefine/mapbefine/permission/application/PermissionCommandService.java similarity index 62% rename from backend/src/main/java/com/mapbefine/mapbefine/member/application/MemberCommandService.java rename to backend/src/main/java/com/mapbefine/mapbefine/permission/application/PermissionCommandService.java index c2242cead..2db9f8dc8 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/member/application/MemberCommandService.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/permission/application/PermissionCommandService.java @@ -1,26 +1,27 @@ -package com.mapbefine.mapbefine.member.application; +package com.mapbefine.mapbefine.permission.application; import com.mapbefine.mapbefine.auth.domain.AuthMember; import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.member.domain.MemberRepository; import com.mapbefine.mapbefine.permission.domain.Permission; import com.mapbefine.mapbefine.permission.domain.PermissionRepository; -import com.mapbefine.mapbefine.permission.dto.request.PermissionCreateRequest; +import com.mapbefine.mapbefine.permission.dto.request.PermissionRequest; import com.mapbefine.mapbefine.topic.domain.Topic; import com.mapbefine.mapbefine.topic.domain.TopicRepository; import java.util.NoSuchElementException; +import java.util.Objects; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service @Transactional -public class MemberCommandService { +public class PermissionCommandService { private final MemberRepository memberRepository; private final TopicRepository topicRepository; private final PermissionRepository permissionRepository; - public MemberCommandService( + public PermissionCommandService( MemberRepository memberRepository, TopicRepository topicRepository, PermissionRepository permissionRepository @@ -30,54 +31,59 @@ public MemberCommandService( this.permissionRepository = permissionRepository; } - public Long saveMemberTopicPermission(AuthMember authMember, PermissionCreateRequest request) { - Member member = memberRepository.findById(request.memberId()) - .orElseThrow(NoSuchElementException::new); - Topic topic = topicRepository.findById(request.topicId()) - .orElseThrow(NoSuchElementException::new); + public Long savePermission(AuthMember authMember, PermissionRequest request) { + validateNull(authMember); + validateSelfPermission(authMember, request); + validateDuplicatePermission(request); - validateSaveMemberTopicPermission(authMember, request, member, topic); + Topic topic = getTopic(request); + validateMemberCanTopicUpdate(authMember, topic); + Member member = getMember(request); Permission permission = Permission.createPermissionAssociatedWithTopicAndMember(topic, member); return permissionRepository.save(permission).getId(); } - private void validateSaveMemberTopicPermission( - AuthMember authMember, - PermissionCreateRequest request, - Member member, - Topic topic - ) { - validateMemberCanTopicUpdate(authMember, topic); - validateSelfPermission(authMember, request); - validateDuplicatePermission(topic.getId(), member.getId()); - } - - private void validateMemberCanTopicUpdate(AuthMember authMember, Topic topic) { - if (authMember.canTopicUpdate(topic)) { - return; + private void validateNull(AuthMember authMember) { + if (Objects.isNull(authMember.getMemberId())) { + throw new IllegalArgumentException(); } - - throw new IllegalArgumentException("해당 유저는 해당 토픽에서 다른 유저에게 권한을 줄 수 없습니다."); } - private void validateSelfPermission( - AuthMember authMember, - PermissionCreateRequest request - ) { - if (authMember.getMemberId().equals(request.memberId())) { + private void validateSelfPermission(AuthMember authMember, PermissionRequest request) { + Long sourceMemberId = authMember.getMemberId(); + Long targetMemberId = request.memberId(); + + if (sourceMemberId.equals(targetMemberId)) { throw new IllegalArgumentException("본인에게 권한을 줄 수 없습니다."); } } - private void validateDuplicatePermission(Long topicId, Long memberId) { - if (permissionRepository.existsByTopicIdAndMemberId(topicId, memberId)) { + private void validateDuplicatePermission(PermissionRequest request) { + if (permissionRepository.existsByTopicIdAndMemberId(request.topicId(), request.memberId())) { throw new IllegalArgumentException("권한은 중복으로 줄 수 없습니다."); } } + private Topic getTopic(PermissionRequest request) { + return topicRepository.findById(request.topicId()) + .orElseThrow(NoSuchElementException::new); + } + + private void validateMemberCanTopicUpdate(AuthMember authMember, Topic topic) { + if (authMember.canTopicUpdate(topic)) { + return; + } + throw new IllegalArgumentException("해당 지도에서 다른 유저에게 권한을 줄 수 없습니다."); + } + + private Member getMember(PermissionRequest request) { + return memberRepository.findById(request.memberId()) + .orElseThrow(NoSuchElementException::new); + } + public void deleteMemberTopicPermission(AuthMember authMember, Long permissionId) { Permission permission = permissionRepository.findById(permissionId) .orElseThrow(NoSuchElementException::new); diff --git a/backend/src/main/java/com/mapbefine/mapbefine/permission/application/PermissionQueryService.java b/backend/src/main/java/com/mapbefine/mapbefine/permission/application/PermissionQueryService.java new file mode 100644 index 000000000..5ca53ba2f --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/permission/application/PermissionQueryService.java @@ -0,0 +1,35 @@ +package com.mapbefine.mapbefine.permission.application; + +import com.mapbefine.mapbefine.permission.domain.Permission; +import com.mapbefine.mapbefine.permission.domain.PermissionRepository; +import com.mapbefine.mapbefine.permission.dto.response.PermissionDetailResponse; +import com.mapbefine.mapbefine.permission.dto.response.PermissionResponse; +import java.util.List; +import java.util.NoSuchElementException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +public class PermissionQueryService { + + private final PermissionRepository permissionRepository; + + public PermissionQueryService(PermissionRepository permissionRepository) { + this.permissionRepository = permissionRepository; + } + + public List findAllTopicPermissions(Long topicId) { + return permissionRepository.findAllByTopicId(topicId) + .stream() + .map(PermissionResponse::from) + .toList(); + } + + public PermissionDetailResponse findPermissionById(Long permissionId) { + Permission permission = permissionRepository.findById(permissionId) + .orElseThrow(NoSuchElementException::new); + + return PermissionDetailResponse.from(permission); + } +} diff --git a/backend/src/main/java/com/mapbefine/mapbefine/permission/domain/PermissionRepository.java b/backend/src/main/java/com/mapbefine/mapbefine/permission/domain/PermissionRepository.java index be3775e49..da8dca9b9 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/permission/domain/PermissionRepository.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/permission/domain/PermissionRepository.java @@ -1,12 +1,11 @@ package com.mapbefine.mapbefine.permission.domain; -import com.mapbefine.mapbefine.topic.domain.Topic; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; public interface PermissionRepository extends JpaRepository { - List findAllByTopic(Topic topic); + List findAllByTopicId(Long topicId); boolean existsByTopicIdAndMemberId(Long topicId, Long memberId); diff --git a/backend/src/main/java/com/mapbefine/mapbefine/permission/dto/request/PermissionCreateRequest.java b/backend/src/main/java/com/mapbefine/mapbefine/permission/dto/request/PermissionRequest.java similarity index 73% rename from backend/src/main/java/com/mapbefine/mapbefine/permission/dto/request/PermissionCreateRequest.java rename to backend/src/main/java/com/mapbefine/mapbefine/permission/dto/request/PermissionRequest.java index c7a925032..a0dd1f421 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/permission/dto/request/PermissionCreateRequest.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/permission/dto/request/PermissionRequest.java @@ -1,6 +1,6 @@ package com.mapbefine.mapbefine.permission.dto.request; -public record PermissionCreateRequest( +public record PermissionRequest( Long topicId, Long memberId ) { diff --git a/backend/src/main/java/com/mapbefine/mapbefine/permission/presentation/PermissionController.java b/backend/src/main/java/com/mapbefine/mapbefine/permission/presentation/PermissionController.java new file mode 100644 index 000000000..2cd732809 --- /dev/null +++ b/backend/src/main/java/com/mapbefine/mapbefine/permission/presentation/PermissionController.java @@ -0,0 +1,68 @@ +package com.mapbefine.mapbefine.permission.presentation; + +import com.mapbefine.mapbefine.auth.domain.AuthMember; +import com.mapbefine.mapbefine.common.interceptor.LoginRequired; +import com.mapbefine.mapbefine.permission.application.PermissionCommandService; +import com.mapbefine.mapbefine.permission.application.PermissionQueryService; +import com.mapbefine.mapbefine.permission.dto.request.PermissionRequest; +import com.mapbefine.mapbefine.permission.dto.response.PermissionDetailResponse; +import com.mapbefine.mapbefine.permission.dto.response.PermissionResponse; +import java.net.URI; +import java.util.List; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +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; + +@RestController +@RequestMapping("/permissions") +public class PermissionController { + + private final PermissionCommandService permissionCommandService; + private final PermissionQueryService permissionQueryService; + + public PermissionController( + PermissionCommandService permissionCommandService, + PermissionQueryService permissionQueryService + ) { + this.permissionCommandService = permissionCommandService; + this.permissionQueryService = permissionQueryService; + } + + @LoginRequired + @PostMapping + public ResponseEntity addPermission(AuthMember authMember, @RequestBody PermissionRequest request) { + Long savedId = permissionCommandService.savePermission(authMember, request); + + return ResponseEntity.created(URI.create("/permissions/" + savedId)).build(); + } + + @LoginRequired + @DeleteMapping("/{permissionId}") + public ResponseEntity deleteMemberTopicPermission(AuthMember authMember, @PathVariable Long permissionId) { + permissionCommandService.deleteMemberTopicPermission(authMember, permissionId); + + return ResponseEntity.noContent().build(); + } + + @LoginRequired + @GetMapping("/topics/{topicId}") + public ResponseEntity> findAllTopicPermissions(@PathVariable Long topicId) { + List responses = permissionQueryService.findAllTopicPermissions(topicId); + + return ResponseEntity.ok(responses); + } + + @LoginRequired + @GetMapping("/{permissionId}") + public ResponseEntity findPermissionById(@PathVariable Long permissionId) { + PermissionDetailResponse response = permissionQueryService.findPermissionById(permissionId); + + return ResponseEntity.ok(response); + } + +} diff --git a/backend/src/test/java/com/mapbefine/mapbefine/member/application/MemberQueryServiceTest.java b/backend/src/test/java/com/mapbefine/mapbefine/member/application/MemberQueryServiceTest.java index 9d64114b4..db54086c0 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/member/application/MemberQueryServiceTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/member/application/MemberQueryServiceTest.java @@ -13,13 +13,9 @@ import com.mapbefine.mapbefine.member.MemberFixture; import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.member.domain.MemberRepository; -import com.mapbefine.mapbefine.permission.domain.Permission; -import com.mapbefine.mapbefine.permission.domain.PermissionRepository; import com.mapbefine.mapbefine.member.domain.Role; import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; import com.mapbefine.mapbefine.member.dto.response.MemberResponse; -import com.mapbefine.mapbefine.permission.dto.response.PermissionDetailResponse; -import com.mapbefine.mapbefine.permission.dto.response.PermissionResponse; import com.mapbefine.mapbefine.pin.PinFixture; import com.mapbefine.mapbefine.pin.domain.Pin; import com.mapbefine.mapbefine.pin.domain.PinRepository; @@ -46,88 +42,12 @@ class MemberQueryServiceTest { @Autowired private MemberRepository memberRepository; - @Autowired - private PermissionRepository permissionRepository; - @Autowired private LocationRepository locationRepository; @Autowired private PinRepository pinRepository; - @Test - @DisplayName("Topic 에 권한이 있는자들을 모두 조회한다.") // creator 는 권한이 있는자들을 조회할 때 조회되어야 할 것인가?? - void findAllWithPermission() { - // given - Member member1InTopic1 = memberRepository.save( - MemberFixture.create("member", "member@naver.com", Role.USER) - ); - Member member2InTopic1 = memberRepository.save( - MemberFixture.create("members", "members@naver.com", Role.USER) - ); - Member member3InTopic2 = memberRepository.save( - MemberFixture.create("memberss", "memberss@naver.com", Role.USER) - ); - Topic topic1 = topicRepository.save(TopicFixture.createByName("topic1", member3InTopic2)); - Topic topic2 = topicRepository.save(TopicFixture.createByName("topic2", member1InTopic1)); - permissionRepository.save( - Permission.createPermissionAssociatedWithTopicAndMember(topic1, member1InTopic1) - ); - permissionRepository.save( - Permission.createPermissionAssociatedWithTopicAndMember(topic1, member2InTopic1) - ); - permissionRepository.save( - Permission.createPermissionAssociatedWithTopicAndMember(topic2, member3InTopic2) - ); - - // when - List permissionRespons = memberQueryService.findAllWithPermission(topic1.getId()); - MemberResponse memberResponse1 = MemberResponse.from(member1InTopic1); - MemberResponse memberResponse2 = MemberResponse.from(member2InTopic1); - - // then - assertThat(permissionRespons).hasSize(2) - .extracting(PermissionResponse::memberResponse) - .usingRecursiveComparison() - .isEqualTo(List.of(memberResponse1, memberResponse2)); - } - - @Test - @DisplayName("ID 를 통해서 토픽에 권한이 있는자를 조회한다.") - void findMemberTopicPermissionById() { - // given - Member creator = memberRepository.save( - MemberFixture.create("member", "member@naver.com", Role.USER) - ); - Member permissionUser = memberRepository.save( - MemberFixture.create("members", "members@naver.com", Role.USER) - ); - Topic topic = topicRepository.save(TopicFixture.createByName("topic", creator)); - Long savedId = permissionRepository.save( - Permission.createPermissionAssociatedWithTopicAndMember(topic, permissionUser) - ).getId(); - - // when - PermissionDetailResponse permissionDetailResponse = - memberQueryService.findMemberTopicPermissionById(savedId); - MemberDetailResponse permissionUserResponse = MemberDetailResponse.from(permissionUser); - - // then - assertThat(permissionDetailResponse) - .extracting(PermissionDetailResponse::memberDetailResponse) - .usingRecursiveComparison() - .isEqualTo(permissionUserResponse); - } - - @Test - @DisplayName("ID 를 통해서 토픽에 권한이 있는자를 조회하려 할 때, 결과가 존재하지 않을 때 예외가 발생한다.") - void findMemberTopicPermissionById_whenNoneExistsPermission_thenFail() { - // given when then - assertThatThrownBy(() -> memberQueryService.findMemberTopicPermissionById(Long.MAX_VALUE)) - .isInstanceOf(NoSuchElementException.class); - } - - @Test @DisplayName("유저 목록을 조회한다.") void findAllMember() { diff --git a/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberControllerTest.java b/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberControllerTest.java index eb8a5410b..f92455c1d 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberControllerTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberControllerTest.java @@ -5,16 +5,9 @@ import static org.mockito.BDDMockito.given; import com.mapbefine.mapbefine.common.RestDocsIntegration; -import com.mapbefine.mapbefine.member.MemberFixture; -import com.mapbefine.mapbefine.member.application.MemberCommandService; import com.mapbefine.mapbefine.member.application.MemberQueryService; -import com.mapbefine.mapbefine.member.domain.Member; -import com.mapbefine.mapbefine.member.domain.Role; -import com.mapbefine.mapbefine.permission.dto.request.PermissionCreateRequest; import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; import com.mapbefine.mapbefine.member.dto.response.MemberResponse; -import com.mapbefine.mapbefine.permission.dto.response.PermissionDetailResponse; -import com.mapbefine.mapbefine.permission.dto.response.PermissionResponse; import com.mapbefine.mapbefine.pin.dto.response.PinResponse; import com.mapbefine.mapbefine.topic.dto.response.TopicResponse; import java.time.LocalDateTime; @@ -23,112 +16,13 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.MediaType; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; class MemberControllerTest extends RestDocsIntegration { - @MockBean - private MemberCommandService memberCommandService; - @MockBean private MemberQueryService memberQueryService; - @Test - @DisplayName("권한 추가") - void addMemberTopicPermission() throws Exception { - Member member = MemberFixture.create("member", "member@naver.com", Role.ADMIN); - PermissionCreateRequest request = new PermissionCreateRequest( - 1L, - 2L - ); - String authHeader = Base64.encodeBase64String( - ("Basic " + member.getMemberInfo().getEmail()).getBytes() - ); - - given(memberCommandService.saveMemberTopicPermission(any(), any())).willReturn(1L); - - mockMvc.perform( - MockMvcRequestBuilders.post("/members/permissions") - .header(AUTHORIZATION, authHeader) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(request)) - ).andDo(restDocs.document()); - } - - @Test - @DisplayName("권한 삭제") - void deleteMemberTopicPermission() throws Exception { - Member member = MemberFixture.create("member", "member@naver.com", Role.ADMIN); - String authHeader = Base64.encodeBase64String( - ("Basic " + member.getMemberInfo().getEmail()).getBytes() - ); - - mockMvc.perform( - MockMvcRequestBuilders.delete("/members/permissions/1") - .header(AUTHORIZATION, authHeader) - ).andDo(restDocs.document()); - } - - @Test - @DisplayName("권한이 있는 자들 모두 조회") - void findMemberTopicPermissionAll() throws Exception { - List permissionRespons = List.of( - new PermissionResponse( - 1L, - new MemberResponse( - 1L, - "member", - "member@naver.com" - ) - ), - new PermissionResponse( - 1L, - new MemberResponse( - 2L, - "memberr", - "memberr@naver.com" - ) - ) - ); - String authHeader = Base64.encodeBase64String( - ("Basic " + permissionRespons.get(0).memberResponse().email()).getBytes() - ); - - given(memberQueryService.findAllWithPermission(any())).willReturn(permissionRespons); - - mockMvc.perform( - MockMvcRequestBuilders.get("/members/permissions/topics/1") - .header(AUTHORIZATION, authHeader) - ).andDo(restDocs.document()); - } - - @Test - @DisplayName("권한이 있는 자들 모두 조회") - void findMemberTopicPermissionById() throws Exception { - PermissionDetailResponse permissionDetailResponse = new PermissionDetailResponse( - 1L, - LocalDateTime.now(), - new MemberDetailResponse( - 1L, - "member", - "member@naver.com", - "https://map-befine-official.github.io/favicon.png", - LocalDateTime.now() - ) - ); - String authHeader = Base64.encodeBase64String( - ("Basic " + permissionDetailResponse.memberDetailResponse().email()).getBytes() - ); - - given(memberQueryService.findMemberTopicPermissionById(any())).willReturn(permissionDetailResponse); - - mockMvc.perform( - MockMvcRequestBuilders.get("/members/permissions/1") - .header(AUTHORIZATION, authHeader) - ).andDo(restDocs.document()); - } - @Test @DisplayName("유저 목록 조회") void findAllMember() throws Exception { diff --git a/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberIntegrationTest.java b/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberIntegrationTest.java index df2c5bc23..edd2fdb3d 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberIntegrationTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/member/presentation/MemberIntegrationTest.java @@ -12,15 +12,10 @@ import com.mapbefine.mapbefine.member.MemberFixture; import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.member.domain.MemberRepository; -import com.mapbefine.mapbefine.permission.domain.Permission; -import com.mapbefine.mapbefine.permission.domain.PermissionRepository; import com.mapbefine.mapbefine.member.domain.OauthId; import com.mapbefine.mapbefine.member.domain.Role; -import com.mapbefine.mapbefine.permission.dto.request.PermissionCreateRequest; import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; import com.mapbefine.mapbefine.member.dto.response.MemberResponse; -import com.mapbefine.mapbefine.permission.dto.response.PermissionDetailResponse; -import com.mapbefine.mapbefine.permission.dto.response.PermissionResponse; import com.mapbefine.mapbefine.pin.PinFixture; import com.mapbefine.mapbefine.pin.domain.Pin; import com.mapbefine.mapbefine.pin.domain.PinRepository; @@ -54,9 +49,6 @@ class MemberIntegrationTest extends IntegrationTest { @Autowired private LocationRepository locationRepository; - @Autowired - private PermissionRepository permissionRepository; - private Member creator; private Member user1; private Member user2; @@ -95,110 +87,6 @@ public void setUp() { user1AuthHeader = testAuthHeaderProvider.createAuthHeader(user1); } - @Test - @DisplayName("Topic 을 만든자가 특정 유저에게 권한을 준다.") - void addMemberTopicPermission() { - // given - Topic topic = topicRepository.save(TopicFixture.createByName("topicName", creator)); - - // when - PermissionCreateRequest request = new PermissionCreateRequest( - topic.getId(), - user1.getId() - ); - ExtractableResponse response = given().log().all() - .header(AUTHORIZATION, creatorAuthHeader) - .contentType(MediaType.APPLICATION_JSON_VALUE) - .body(request) - .when().post("/members/permissions") - .then().log().all() - .extract(); - - // then - assertThat(response.header("Location")).isNotBlank(); - assertThat(response.statusCode()).isEqualTo(HttpStatus.CREATED.value()); - } - - @Test - @DisplayName("Topic 을 만든자가 특정 유저에게 권한을 삭제한다.") - void deleteMemberTopicPermission() { - // given - Topic topic = topicRepository.save(TopicFixture.createByName("topicName", creator)); - Permission permission = - Permission.createPermissionAssociatedWithTopicAndMember(topic, user1); - Long savedId = permissionRepository.save(permission).getId(); - - // when - ExtractableResponse response = given().log().all() - .header(AUTHORIZATION, creatorAuthHeader) - .when().delete("/members/permissions/" + savedId) - .then().log().all() - .extract(); - - // then - assertThat(response.statusCode()) - .isEqualTo(HttpStatus.NO_CONTENT.value()); - } - - @Test - @DisplayName("Topic 에 권한을 가진 자들을 모두 조회한다.") - void findMemberTopicPermissionAll() { - // given - Topic topic = topicRepository.save(TopicFixture.createByName("topicName", creator)); - Permission permission1 = - Permission.createPermissionAssociatedWithTopicAndMember(topic, user1); - Permission permission2 = - Permission.createPermissionAssociatedWithTopicAndMember(topic, user2); - permissionRepository.save(permission1); - permissionRepository.save(permission2); - - // when - ExtractableResponse response = given().log().all() - .header(AUTHORIZATION, creatorAuthHeader) - .when().get("/members/permissions/topics/" + topic.getId()) - .then().log().all() - .extract(); - - // then - List permissionRespons = response.as(new TypeRef<>() { - }); - assertThat(response.statusCode()) - .isEqualTo(HttpStatus.OK.value()); - assertThat(permissionRespons) - .hasSize(2) - .extracting(PermissionResponse::memberResponse) - .usingRecursiveComparison() - .isEqualTo(List.of(MemberResponse.from(user1), MemberResponse.from(user2))); - } - - @Test - @DisplayName("Topic 에 권한을 가진 자를 조회한다.") - void findMemberTopicPermissionById() { - // given - Topic topic = topicRepository.save(TopicFixture.createByName("topicName", creator)); - Permission permission = - Permission.createPermissionAssociatedWithTopicAndMember(topic, user1); - permission = permissionRepository.save(permission); - - // when - ExtractableResponse response = given().log().all() - .header(AUTHORIZATION, creatorAuthHeader) - .when().get("/members/permissions/" + permission.getId()) - .then().log().all() - .extract(); - - // then - PermissionDetailResponse permissionDetailResponse = response.as( - PermissionDetailResponse.class); - assertThat(response.statusCode()) - .isEqualTo(HttpStatus.OK.value()); - assertThat(permissionDetailResponse) - .extracting(PermissionDetailResponse::memberDetailResponse) - .usingRecursiveComparison() - .ignoringFieldsOfTypes(LocalDateTime.class) - .isEqualTo(MemberDetailResponse.from(user1)); - } - @Test @DisplayName("유저 목록을 조회한다.") void findAllMember() { diff --git a/backend/src/test/java/com/mapbefine/mapbefine/permission/PermissionIntegrationTest.java b/backend/src/test/java/com/mapbefine/mapbefine/permission/PermissionIntegrationTest.java new file mode 100644 index 000000000..008532a00 --- /dev/null +++ b/backend/src/test/java/com/mapbefine/mapbefine/permission/PermissionIntegrationTest.java @@ -0,0 +1,185 @@ +package com.mapbefine.mapbefine.permission; + +import static com.mapbefine.mapbefine.oauth.domain.OauthServerType.KAKAO; +import static io.restassured.RestAssured.*; +import static org.apache.http.HttpHeaders.AUTHORIZATION; +import static org.assertj.core.api.Assertions.assertThat; + +import com.mapbefine.mapbefine.common.IntegrationTest; +import com.mapbefine.mapbefine.member.MemberFixture; +import com.mapbefine.mapbefine.member.domain.Member; +import com.mapbefine.mapbefine.member.domain.MemberRepository; +import com.mapbefine.mapbefine.member.domain.OauthId; +import com.mapbefine.mapbefine.member.domain.Role; +import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; +import com.mapbefine.mapbefine.member.dto.response.MemberResponse; +import com.mapbefine.mapbefine.permission.domain.Permission; +import com.mapbefine.mapbefine.permission.domain.PermissionRepository; +import com.mapbefine.mapbefine.permission.dto.request.PermissionRequest; +import com.mapbefine.mapbefine.permission.dto.response.PermissionDetailResponse; +import com.mapbefine.mapbefine.permission.dto.response.PermissionResponse; +import com.mapbefine.mapbefine.topic.TopicFixture; +import com.mapbefine.mapbefine.topic.domain.Topic; +import com.mapbefine.mapbefine.topic.domain.TopicRepository; +import io.restassured.common.mapper.*; +import io.restassured.response.*; +import java.time.LocalDateTime; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +public class PermissionIntegrationTest extends IntegrationTest { + + @Autowired + private MemberRepository memberRepository; + @Autowired + private TopicRepository topicRepository; + @Autowired + private PermissionRepository permissionRepository; + + private Member creator; + private Member user1; + private Member user2; + private String creatorAuthHeader; + + @Override + @BeforeEach + public void setUp() { + super.setUp(); + creator = memberRepository.save( + MemberFixture.createWithOauthId( + "creator", + "creator@naver.com", + Role.USER, + new OauthId(1L, KAKAO) + ) + ); + user1 = memberRepository.save( + MemberFixture.createWithOauthId( + "user1", + "user1@naver.com", + Role.USER, + new OauthId(2L, KAKAO) + ) + ); + user2 = memberRepository.save( + MemberFixture.createWithOauthId( + "user2", + "user2@naver.com", + Role.USER, + new OauthId(3L, KAKAO) + ) + ); + creatorAuthHeader = testAuthHeaderProvider.createAuthHeader(creator); + } + + @Test + @DisplayName("Topic 을 만든자가 특정 유저에게 권한을 준다.") + void addPermission() { + // given + Topic topic = topicRepository.save(TopicFixture.createByName("topicName", creator)); + + // when + PermissionRequest request = new PermissionRequest( + topic.getId(), + user1.getId() + ); + ExtractableResponse response = given().log().all() + .header(AUTHORIZATION, creatorAuthHeader) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .body(request) + .when().post("/members/permissions") + .then().log().all() + .extract(); + + // then + assertThat(response.header("Location")).isNotBlank(); + assertThat(response.statusCode()).isEqualTo(HttpStatus.CREATED.value()); + } + + @Test + @DisplayName("Topic 을 만든자가 특정 유저에게 권한을 삭제한다.") + void deletePermission() { + // given + Topic topic = topicRepository.save(TopicFixture.createByName("topicName", creator)); + Permission permission = + Permission.createPermissionAssociatedWithTopicAndMember(topic, user1); + Long savedId = permissionRepository.save(permission).getId(); + + // when + ExtractableResponse response = given().log().all() + .header(AUTHORIZATION, creatorAuthHeader) + .when().delete("/members/permissions/" + savedId) + .then().log().all() + .extract(); + + // then + assertThat(response.statusCode()) + .isEqualTo(HttpStatus.NO_CONTENT.value()); + } + + @Test + @DisplayName("Topic 에 권한을 가진 자들을 모두 조회한다.") + void findMemberTopicPermissionAll() { + // given + Topic topic = topicRepository.save(TopicFixture.createByName("topicName", creator)); + Permission permission1 = + Permission.createPermissionAssociatedWithTopicAndMember(topic, user1); + Permission permission2 = + Permission.createPermissionAssociatedWithTopicAndMember(topic, user2); + permissionRepository.save(permission1); + permissionRepository.save(permission2); + + // when + ExtractableResponse response = given().log().all() + .header(AUTHORIZATION, creatorAuthHeader) + .when().get("/members/permissions/topics/" + topic.getId()) + .then().log().all() + .extract(); + + // then + List permissionRespons = response.as(new TypeRef<>() { + }); + assertThat(response.statusCode()) + .isEqualTo(HttpStatus.OK.value()); + assertThat(permissionRespons) + .hasSize(2) + .extracting(PermissionResponse::memberResponse) + .usingRecursiveComparison() + .isEqualTo(List.of(MemberResponse.from(user1), MemberResponse.from(user2))); + } + + @Test + @DisplayName("Topic 에 권한을 가진 자를 조회한다.") + void findMemberTopicPermissionById() { + // given + Topic topic = topicRepository.save(TopicFixture.createByName("topicName", creator)); + Permission permission = + Permission.createPermissionAssociatedWithTopicAndMember(topic, user1); + permission = permissionRepository.save(permission); + + // when + ExtractableResponse response = given().log().all() + .header(AUTHORIZATION, creatorAuthHeader) + .when().get("/members/permissions/" + permission.getId()) + .then().log().all() + .extract(); + + // then + PermissionDetailResponse permissionDetailResponse = response.as( + PermissionDetailResponse.class); + assertThat(response.statusCode()) + .isEqualTo(HttpStatus.OK.value()); + assertThat(permissionDetailResponse) + .extracting(PermissionDetailResponse::memberDetailResponse) + .usingRecursiveComparison() + .ignoringFieldsOfTypes(LocalDateTime.class) + .isEqualTo(MemberDetailResponse.from(user1)); + } + + +} diff --git a/backend/src/test/java/com/mapbefine/mapbefine/member/application/MemberCommandServiceTest.java b/backend/src/test/java/com/mapbefine/mapbefine/permission/application/PermissionCommandServiceTest.java similarity index 87% rename from backend/src/test/java/com/mapbefine/mapbefine/member/application/MemberCommandServiceTest.java rename to backend/src/test/java/com/mapbefine/mapbefine/permission/application/PermissionCommandServiceTest.java index 885b2d612..4d7352762 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/member/application/MemberCommandServiceTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/permission/application/PermissionCommandServiceTest.java @@ -1,4 +1,4 @@ -package com.mapbefine.mapbefine.member.application; +package com.mapbefine.mapbefine.permission.application; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -11,10 +11,10 @@ import com.mapbefine.mapbefine.member.MemberFixture; import com.mapbefine.mapbefine.member.domain.Member; import com.mapbefine.mapbefine.member.domain.MemberRepository; +import com.mapbefine.mapbefine.member.domain.Role; import com.mapbefine.mapbefine.permission.domain.Permission; import com.mapbefine.mapbefine.permission.domain.PermissionRepository; -import com.mapbefine.mapbefine.member.domain.Role; -import com.mapbefine.mapbefine.permission.dto.request.PermissionCreateRequest; +import com.mapbefine.mapbefine.permission.dto.request.PermissionRequest; import com.mapbefine.mapbefine.topic.TopicFixture; import com.mapbefine.mapbefine.topic.domain.Topic; import com.mapbefine.mapbefine.topic.domain.TopicRepository; @@ -25,10 +25,10 @@ import org.springframework.beans.factory.annotation.Autowired; @ServiceTest -class MemberCommandServiceTest { +class PermissionCommandServiceTest { @Autowired - private MemberCommandService memberCommandService; + private PermissionCommandService permissionCommandService; @Autowired private TopicRepository topicRepository; @@ -47,13 +47,13 @@ void saveMemberTopicPermissionByAdmin() { Member member = memberRepository.save(MemberFixture.create("members", "members@naver.com", Role.USER)); Topic topic = topicRepository.save(TopicFixture.createByName("topic", admin)); AuthMember authAdmin = new Admin(admin.getId()); - PermissionCreateRequest request = new PermissionCreateRequest( + PermissionRequest request = new PermissionRequest( topic.getId(), member.getId() ); // when - Long savedId = memberCommandService.saveMemberTopicPermission(authAdmin, request); + Long savedId = permissionCommandService.savePermission(authAdmin, request); Permission permission = permissionRepository.findById(savedId) .orElseThrow(NoSuchElementException::new); Member memberWithPermission = permission.getMember(); @@ -76,13 +76,13 @@ void saveMemberTopicPermissionByCreator() { getCreatedTopics(creator), getTopicsWithPermission(creator) ); - PermissionCreateRequest request = new PermissionCreateRequest( + PermissionRequest request = new PermissionRequest( topic.getId(), member.getId() ); // when - Long savedId = memberCommandService.saveMemberTopicPermission(authCreator, request); + Long savedId = permissionCommandService.savePermission(authCreator, request); Permission permission = permissionRepository.findById(savedId) .orElseThrow(NoSuchElementException::new); Member memberWithPermission = permission.getMember(); @@ -106,13 +106,13 @@ void saveMemberTopicPermissionByUser() { getCreatedTopics(notCreator), getTopicsWithPermission(notCreator) ); - PermissionCreateRequest request = new PermissionCreateRequest( + PermissionRequest request = new PermissionRequest( topic.getId(), member.getId() ); // when then - assertThatThrownBy(() -> memberCommandService.saveMemberTopicPermission(authNotCreator, request)) + assertThatThrownBy(() -> permissionCommandService.savePermission(authNotCreator, request)) .isInstanceOf(IllegalArgumentException.class); } @@ -124,13 +124,13 @@ void saveMemberTopicPermissionByGuest() { Member member = memberRepository.save(MemberFixture.create("memberss", "memberss@naver.com", Role.USER)); Topic topic = topicRepository.save(TopicFixture.createByName("topic", creator)); AuthMember guest = new Guest(); - PermissionCreateRequest request = new PermissionCreateRequest( + PermissionRequest request = new PermissionRequest( topic.getId(), member.getId() ); // when then - assertThatThrownBy(() -> memberCommandService.saveMemberTopicPermission(guest, request)) + assertThatThrownBy(() -> permissionCommandService.savePermission(guest, request)) .isInstanceOf(IllegalArgumentException.class); } @@ -145,13 +145,13 @@ void saveMemberTopicPermissionByCreator_whenSelf_thenFail() { getCreatedTopics(creator), getTopicsWithPermission(creator) ); - PermissionCreateRequest request = new PermissionCreateRequest( + PermissionRequest request = new PermissionRequest( topic.getId(), creator.getId() ); // when then - assertThatThrownBy(() -> memberCommandService.saveMemberTopicPermission(authCreator, request)) + assertThatThrownBy(() -> permissionCommandService.savePermission(authCreator, request)) .isInstanceOf(IllegalArgumentException.class); } @@ -182,13 +182,13 @@ void saveMemberTopicPermissionByCreator_whenDuplicate_thenFail() { getCreatedTopics(creator), getTopicsWithPermission(creator) ); - PermissionCreateRequest request = new PermissionCreateRequest( + PermissionRequest request = new PermissionRequest( topic.getId(), member.getId() ); // when then - assertThatThrownBy(() -> memberCommandService.saveMemberTopicPermission(authCreator, request)) + assertThatThrownBy(() -> permissionCommandService.savePermission(authCreator, request)) .isInstanceOf(IllegalArgumentException.class); } @@ -205,7 +205,7 @@ void deleteMemberTopicPermissionByAdmin() { Permission permission = Permission.createPermissionAssociatedWithTopicAndMember(topic, member); Long savedId = permissionRepository.save(permission).getId(); - memberCommandService.deleteMemberTopicPermission(authAdmin, savedId); + permissionCommandService.deleteMemberTopicPermission(authAdmin, savedId); // then assertThat(memberRepository.existsById(savedId)).isFalse(); @@ -228,7 +228,7 @@ void deleteMemberTopicPermissionByCreator() { Permission permission = Permission.createPermissionAssociatedWithTopicAndMember(topic, member); Long savedId = permissionRepository.save(permission).getId(); - memberCommandService.deleteMemberTopicPermission(authCreator, savedId); + permissionCommandService.deleteMemberTopicPermission(authCreator, savedId); // then assertThat(memberRepository.existsById(savedId)).isFalse(); @@ -254,7 +254,7 @@ void deleteMemberTopicPermissionByUser() { Long savedId = permissionRepository.save(permission).getId(); // then - assertThatThrownBy(() -> memberCommandService.deleteMemberTopicPermission(authNonCreator, savedId)) + assertThatThrownBy(() -> permissionCommandService.deleteMemberTopicPermission(authNonCreator, savedId)) .isInstanceOf(IllegalArgumentException.class); } @@ -276,7 +276,7 @@ void deleteMemberTopicPermissionByCreator_whenNoneExistsPermission_thenFail() { ); // when then - assertThatThrownBy(() -> memberCommandService.deleteMemberTopicPermission(authCreator, Long.MAX_VALUE)) + assertThatThrownBy(() -> permissionCommandService.deleteMemberTopicPermission(authCreator, Long.MAX_VALUE)) .isInstanceOf(NoSuchElementException.class); } diff --git a/backend/src/test/java/com/mapbefine/mapbefine/permission/application/PermissionQueryServiceTest.java b/backend/src/test/java/com/mapbefine/mapbefine/permission/application/PermissionQueryServiceTest.java new file mode 100644 index 000000000..ba66c1229 --- /dev/null +++ b/backend/src/test/java/com/mapbefine/mapbefine/permission/application/PermissionQueryServiceTest.java @@ -0,0 +1,112 @@ +package com.mapbefine.mapbefine.permission.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.mapbefine.mapbefine.common.annotation.ServiceTest; +import com.mapbefine.mapbefine.member.MemberFixture; +import com.mapbefine.mapbefine.member.domain.Member; +import com.mapbefine.mapbefine.member.domain.MemberRepository; +import com.mapbefine.mapbefine.member.domain.Role; +import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; +import com.mapbefine.mapbefine.member.dto.response.MemberResponse; +import com.mapbefine.mapbefine.permission.domain.Permission; +import com.mapbefine.mapbefine.permission.domain.PermissionRepository; +import com.mapbefine.mapbefine.permission.dto.response.PermissionDetailResponse; +import com.mapbefine.mapbefine.permission.dto.response.PermissionResponse; +import com.mapbefine.mapbefine.topic.TopicFixture; +import com.mapbefine.mapbefine.topic.domain.Topic; +import com.mapbefine.mapbefine.topic.domain.TopicRepository; +import java.util.List; +import java.util.NoSuchElementException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +@ServiceTest +class PermissionQueryServiceTest { + + @Autowired + private MemberRepository memberRepository; + @Autowired + private TopicRepository topicRepository; + @Autowired + private PermissionRepository permissionRepository; + @Autowired + private PermissionQueryService permissionQueryService; + + @Test + @DisplayName("Topic 에 권한이 있는자들을 모두 조회한다.") + // creator 는 권한이 있는자들을 조회할 때 조회되어야 할 것인가?? + void findAllWithPermission() { + // given + Member member1InTopic1 = memberRepository.save( + MemberFixture.create("member", "member@naver.com", Role.USER) + ); + Member member2InTopic1 = memberRepository.save( + MemberFixture.create("members", "members@naver.com", Role.USER) + ); + Member member3InTopic2 = memberRepository.save( + MemberFixture.create("memberss", "memberss@naver.com", Role.USER) + ); + Topic topic1 = topicRepository.save(TopicFixture.createByName("topic1", member3InTopic2)); + Topic topic2 = topicRepository.save(TopicFixture.createByName("topic2", member1InTopic1)); + permissionRepository.save( + Permission.createPermissionAssociatedWithTopicAndMember(topic1, member1InTopic1) + ); + permissionRepository.save( + Permission.createPermissionAssociatedWithTopicAndMember(topic1, member2InTopic1) + ); + permissionRepository.save( + Permission.createPermissionAssociatedWithTopicAndMember(topic2, member3InTopic2) + ); + + // when + List permissionRespons = permissionQueryService.findAllTopicPermissions(topic1.getId()); + MemberResponse memberResponse1 = MemberResponse.from(member1InTopic1); + MemberResponse memberResponse2 = MemberResponse.from(member2InTopic1); + + // then + assertThat(permissionRespons).hasSize(2) + .extracting(PermissionResponse::memberResponse) + .usingRecursiveComparison() + .isEqualTo(List.of(memberResponse1, memberResponse2)); + } + + @Test + @DisplayName("ID 를 통해서 토픽에 권한이 있는자를 조회한다.") + void findMemberTopicPermissionById() { + // given + Member creator = memberRepository.save( + MemberFixture.create("member", "member@naver.com", Role.USER) + ); + Member permissionUser = memberRepository.save( + MemberFixture.create("members", "members@naver.com", Role.USER) + ); + Topic topic = topicRepository.save(TopicFixture.createByName("topic", creator)); + Long savedId = permissionRepository.save( + Permission.createPermissionAssociatedWithTopicAndMember(topic, permissionUser) + ).getId(); + + // when + PermissionDetailResponse permissionDetailResponse = + permissionQueryService.findPermissionById(savedId); + MemberDetailResponse permissionUserResponse = MemberDetailResponse.from(permissionUser); + + // then + assertThat(permissionDetailResponse) + .extracting(PermissionDetailResponse::memberDetailResponse) + .usingRecursiveComparison() + .isEqualTo(permissionUserResponse); + } + + @Test + @DisplayName("ID 를 통해서 토픽에 권한이 있는자를 조회하려 할 때, 결과가 존재하지 않을 때 예외가 발생한다.") + void findMemberTopicPermissionById_whenNoneExistsPermission_thenFail() { + // given when then + assertThatThrownBy(() -> permissionQueryService.findPermissionById(Long.MAX_VALUE)) + .isInstanceOf(NoSuchElementException.class); + } + + +} diff --git a/backend/src/test/java/com/mapbefine/mapbefine/permission/presentation/PermissionControllerTest.java b/backend/src/test/java/com/mapbefine/mapbefine/permission/presentation/PermissionControllerTest.java new file mode 100644 index 000000000..2db0f7363 --- /dev/null +++ b/backend/src/test/java/com/mapbefine/mapbefine/permission/presentation/PermissionControllerTest.java @@ -0,0 +1,126 @@ +package com.mapbefine.mapbefine.permission.presentation; + +import static org.apache.http.HttpHeaders.AUTHORIZATION; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; + +import com.mapbefine.mapbefine.common.RestDocsIntegration; +import com.mapbefine.mapbefine.member.MemberFixture; +import com.mapbefine.mapbefine.member.domain.Member; +import com.mapbefine.mapbefine.member.domain.Role; +import com.mapbefine.mapbefine.member.dto.response.MemberDetailResponse; +import com.mapbefine.mapbefine.member.dto.response.MemberResponse; +import com.mapbefine.mapbefine.permission.application.PermissionCommandService; +import com.mapbefine.mapbefine.permission.application.PermissionQueryService; +import com.mapbefine.mapbefine.permission.dto.request.PermissionRequest; +import com.mapbefine.mapbefine.permission.dto.response.PermissionDetailResponse; +import com.mapbefine.mapbefine.permission.dto.response.PermissionResponse; +import java.time.LocalDateTime; +import java.util.List; +import org.apache.tomcat.util.codec.binary.Base64; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +class PermissionControllerTest extends RestDocsIntegration { + + @MockBean + private PermissionCommandService permissionCommandService; + @MockBean + private PermissionQueryService permissionQueryService; + + @Test + @DisplayName("권한 추가") + void addMemberTopicPermission() throws Exception { + Member member = MemberFixture.create("member", "member@naver.com", Role.ADMIN); + PermissionRequest request = new PermissionRequest(1L, 2L); + String authHeader = Base64.encodeBase64String( + ("Basic " + member.getMemberInfo().getEmail()).getBytes() + ); + + given(permissionCommandService.savePermission(any(), any())).willReturn(1L); + + mockMvc.perform( + MockMvcRequestBuilders.post("/members/permissions") + .header(AUTHORIZATION, authHeader) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request)) + ).andDo(restDocs.document()); + } + + @Test + @DisplayName("권한 삭제") + void deleteMemberTopicPermission() throws Exception { + Member member = MemberFixture.create("member", "member@naver.com", Role.ADMIN); + String authHeader = Base64.encodeBase64String( + ("Basic " + member.getMemberInfo().getEmail()).getBytes() + ); + + mockMvc.perform( + MockMvcRequestBuilders.delete("/members/permissions/1") + .header(AUTHORIZATION, authHeader) + ).andDo(restDocs.document()); + } + + @Test + @DisplayName("권한이 있는 자들 모두 조회") + void findMemberTopicPermissionAll() throws Exception { + List permissionRespons = List.of( + new PermissionResponse( + 1L, + new MemberResponse( + 1L, + "member", + "member@naver.com" + ) + ), + new PermissionResponse( + 1L, + new MemberResponse( + 2L, + "memberr", + "memberr@naver.com" + ) + ) + ); + String authHeader = Base64.encodeBase64String( + ("Basic " + permissionRespons.get(0).memberResponse().email()).getBytes() + ); + + given(permissionQueryService.findAllTopicPermissions(any())).willReturn(permissionRespons); + + mockMvc.perform( + MockMvcRequestBuilders.get("/members/permissions/topics/1") + .header(AUTHORIZATION, authHeader) + ).andDo(restDocs.document()); + } + + @Test + @DisplayName("권한이 있는 자들 모두 조회") + void findMemberTopicPermissionById() throws Exception { + PermissionDetailResponse permissionDetailResponse = new PermissionDetailResponse( + 1L, + LocalDateTime.now(), + new MemberDetailResponse( + 1L, + "member", + "member@naver.com", + "https://map-befine-official.github.io/favicon.png", + LocalDateTime.now() + ) + ); + String authHeader = Base64.encodeBase64String( + ("Basic " + permissionDetailResponse.memberDetailResponse().email()).getBytes() + ); + + given(permissionQueryService.findPermissionById(any())).willReturn(permissionDetailResponse); + + mockMvc.perform( + MockMvcRequestBuilders.get("/members/permissions/1") + .header(AUTHORIZATION, authHeader) + ).andDo(restDocs.document()); + } + +} From d77c3a5e8a8c05e68a1dc96bb0249d7f1b075c29 Mon Sep 17 00:00:00 2001 From: junpakPark Date: Mon, 14 Aug 2023 12:45:36 +0900 Subject: [PATCH 32/35] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../permission/PermissionIntegrationTest.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/backend/src/test/java/com/mapbefine/mapbefine/permission/PermissionIntegrationTest.java b/backend/src/test/java/com/mapbefine/mapbefine/permission/PermissionIntegrationTest.java index 008532a00..12e82ae9c 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/permission/PermissionIntegrationTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/permission/PermissionIntegrationTest.java @@ -84,15 +84,13 @@ void addPermission() { Topic topic = topicRepository.save(TopicFixture.createByName("topicName", creator)); // when - PermissionRequest request = new PermissionRequest( - topic.getId(), - user1.getId() - ); + PermissionRequest request = new PermissionRequest(topic.getId(), user1.getId()); + ExtractableResponse response = given().log().all() .header(AUTHORIZATION, creatorAuthHeader) .contentType(MediaType.APPLICATION_JSON_VALUE) .body(request) - .when().post("/members/permissions") + .when().post("/permissions") .then().log().all() .extract(); @@ -113,7 +111,7 @@ void deletePermission() { // when ExtractableResponse response = given().log().all() .header(AUTHORIZATION, creatorAuthHeader) - .when().delete("/members/permissions/" + savedId) + .when().delete("/permissions/" + savedId) .then().log().all() .extract(); @@ -137,16 +135,16 @@ void findMemberTopicPermissionAll() { // when ExtractableResponse response = given().log().all() .header(AUTHORIZATION, creatorAuthHeader) - .when().get("/members/permissions/topics/" + topic.getId()) + .when().get("/permissions/topics/" + topic.getId()) .then().log().all() .extract(); // then - List permissionRespons = response.as(new TypeRef<>() { + List permissionResponse = response.as(new TypeRef<>() { }); assertThat(response.statusCode()) .isEqualTo(HttpStatus.OK.value()); - assertThat(permissionRespons) + assertThat(permissionResponse) .hasSize(2) .extracting(PermissionResponse::memberResponse) .usingRecursiveComparison() @@ -165,7 +163,7 @@ void findMemberTopicPermissionById() { // when ExtractableResponse response = given().log().all() .header(AUTHORIZATION, creatorAuthHeader) - .when().get("/members/permissions/" + permission.getId()) + .when().get("/permissions/" + permission.getId()) .then().log().all() .extract(); From 05b0ea6197a1b1f94babeb18a7b9f7dfc98479cf Mon Sep 17 00:00:00 2001 From: junpakPark Date: Mon, 14 Aug 2023 13:28:05 +0900 Subject: [PATCH 33/35] =?UTF-8?q?refactor:=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=20=EB=84=A4=EC=9E=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../permission/application/PermissionCommandService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/src/main/java/com/mapbefine/mapbefine/permission/application/PermissionCommandService.java b/backend/src/main/java/com/mapbefine/mapbefine/permission/application/PermissionCommandService.java index 2db9f8dc8..8359fe919 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/permission/application/PermissionCommandService.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/permission/application/PermissionCommandService.java @@ -36,10 +36,10 @@ public Long savePermission(AuthMember authMember, PermissionRequest request) { validateSelfPermission(authMember, request); validateDuplicatePermission(request); - Topic topic = getTopic(request); + Topic topic = findTopic(request); validateMemberCanTopicUpdate(authMember, topic); - Member member = getMember(request); + Member member = findMember(request); Permission permission = Permission.createPermissionAssociatedWithTopicAndMember(topic, member); @@ -67,7 +67,7 @@ private void validateDuplicatePermission(PermissionRequest request) { } } - private Topic getTopic(PermissionRequest request) { + private Topic findTopic(PermissionRequest request) { return topicRepository.findById(request.topicId()) .orElseThrow(NoSuchElementException::new); } @@ -79,7 +79,7 @@ private void validateMemberCanTopicUpdate(AuthMember authMember, Topic topic) { throw new IllegalArgumentException("해당 지도에서 다른 유저에게 권한을 줄 수 없습니다."); } - private Member getMember(PermissionRequest request) { + private Member findMember(PermissionRequest request) { return memberRepository.findById(request.memberId()) .orElseThrow(NoSuchElementException::new); } From 38d78e1efacf17a857231058f8f0246df8e1786d Mon Sep 17 00:00:00 2001 From: junpakPark Date: Mon, 14 Aug 2023 13:39:32 +0900 Subject: [PATCH 34/35] =?UTF-8?q?docs:=20restDocs=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/docs/asciidoc/index.adoc | 1 + backend/src/docs/asciidoc/member.adoc | 16 -------------- backend/src/docs/asciidoc/permission.adoc | 17 ++++++++++++++ .../PermissionControllerTest.java | 22 +++++++++---------- 4 files changed, 29 insertions(+), 27 deletions(-) create mode 100644 backend/src/docs/asciidoc/permission.adoc diff --git a/backend/src/docs/asciidoc/index.adoc b/backend/src/docs/asciidoc/index.adoc index 4cae5b937..b6cbd853d 100644 --- a/backend/src/docs/asciidoc/index.adoc +++ b/backend/src/docs/asciidoc/index.adoc @@ -11,4 +11,5 @@ toc::[] include::topic.adoc[] include::pin.adoc[] include::member.adoc[] +include::permission.adoc[] include::oauth.adoc[] diff --git a/backend/src/docs/asciidoc/member.adoc b/backend/src/docs/asciidoc/member.adoc index 8f5d7acca..fc40578c3 100644 --- a/backend/src/docs/asciidoc/member.adoc +++ b/backend/src/docs/asciidoc/member.adoc @@ -1,21 +1,5 @@ == 유저 -=== 유저 권한 부여 - -operation::member-controller-test/add-member-topic-permission[snippets='http-request,http-response'] - -=== 유저 권한 삭제 - -operation::member-controller-test/delete-member-topic-permission[snippets='http-request,http-response'] - -=== 토픽에 권한을 가진 유저 목록 조회 - -operation::member-controller-test/find-member-topic-permission-all[snippets='http-request,http-response'] - -=== 토픽에 권한을 가진 유저 단일 조회 - -operation::member-controller-test/find-member-topic-permission-by-id[snippets='http-request,http-response'] - === 유저 목록 조회 operation::member-controller-test/find-all-member[snippets='http-request,http-response'] diff --git a/backend/src/docs/asciidoc/permission.adoc b/backend/src/docs/asciidoc/permission.adoc new file mode 100644 index 000000000..c704d7ed3 --- /dev/null +++ b/backend/src/docs/asciidoc/permission.adoc @@ -0,0 +1,17 @@ +== 권한 + +=== 권한 부여 + +operation::permission-controller-test/add-permission[snippets='http-request,http-response'] + +=== 권한 삭제 + +operation::permission-controller-test/delete-permission[snippets='http-request,http-response'] + +=== 토픽에 권한을 가진 유저 목록 조회 + +operation::permission-controller-test/find-all-topic-permissions[snippets='http-request,http-response'] + +=== 토픽에 권한을 가진 유저 단일 조회 + +operation::permission-controller-test/find-permission-by-id[snippets='http-request,http-response'] diff --git a/backend/src/test/java/com/mapbefine/mapbefine/permission/presentation/PermissionControllerTest.java b/backend/src/test/java/com/mapbefine/mapbefine/permission/presentation/PermissionControllerTest.java index 2db0f7363..aa9b1db6c 100644 --- a/backend/src/test/java/com/mapbefine/mapbefine/permission/presentation/PermissionControllerTest.java +++ b/backend/src/test/java/com/mapbefine/mapbefine/permission/presentation/PermissionControllerTest.java @@ -33,7 +33,7 @@ class PermissionControllerTest extends RestDocsIntegration { @Test @DisplayName("권한 추가") - void addMemberTopicPermission() throws Exception { + void addPermission() throws Exception { Member member = MemberFixture.create("member", "member@naver.com", Role.ADMIN); PermissionRequest request = new PermissionRequest(1L, 2L); String authHeader = Base64.encodeBase64String( @@ -43,7 +43,7 @@ void addMemberTopicPermission() throws Exception { given(permissionCommandService.savePermission(any(), any())).willReturn(1L); mockMvc.perform( - MockMvcRequestBuilders.post("/members/permissions") + MockMvcRequestBuilders.post("/permissions") .header(AUTHORIZATION, authHeader) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request)) @@ -52,22 +52,22 @@ void addMemberTopicPermission() throws Exception { @Test @DisplayName("권한 삭제") - void deleteMemberTopicPermission() throws Exception { + void deletePermission() throws Exception { Member member = MemberFixture.create("member", "member@naver.com", Role.ADMIN); String authHeader = Base64.encodeBase64String( ("Basic " + member.getMemberInfo().getEmail()).getBytes() ); mockMvc.perform( - MockMvcRequestBuilders.delete("/members/permissions/1") + MockMvcRequestBuilders.delete("/permissions/1") .header(AUTHORIZATION, authHeader) ).andDo(restDocs.document()); } @Test @DisplayName("권한이 있는 자들 모두 조회") - void findMemberTopicPermissionAll() throws Exception { - List permissionRespons = List.of( + void findAllTopicPermissions() throws Exception { + List permissionResponses = List.of( new PermissionResponse( 1L, new MemberResponse( @@ -86,20 +86,20 @@ void findMemberTopicPermissionAll() throws Exception { ) ); String authHeader = Base64.encodeBase64String( - ("Basic " + permissionRespons.get(0).memberResponse().email()).getBytes() + ("Basic " + permissionResponses.get(0).memberResponse().email()).getBytes() ); - given(permissionQueryService.findAllTopicPermissions(any())).willReturn(permissionRespons); + given(permissionQueryService.findAllTopicPermissions(any())).willReturn(permissionResponses); mockMvc.perform( - MockMvcRequestBuilders.get("/members/permissions/topics/1") + MockMvcRequestBuilders.get("/permissions/topics/1") .header(AUTHORIZATION, authHeader) ).andDo(restDocs.document()); } @Test @DisplayName("권한이 있는 자들 모두 조회") - void findMemberTopicPermissionById() throws Exception { + void findPermissionById() throws Exception { PermissionDetailResponse permissionDetailResponse = new PermissionDetailResponse( 1L, LocalDateTime.now(), @@ -118,7 +118,7 @@ void findMemberTopicPermissionById() throws Exception { given(permissionQueryService.findPermissionById(any())).willReturn(permissionDetailResponse); mockMvc.perform( - MockMvcRequestBuilders.get("/members/permissions/1") + MockMvcRequestBuilders.get("/permissions/1") .header(AUTHORIZATION, authHeader) ).andDo(restDocs.document()); } From eee9ff534879322857751d35b5a755dc3fa9aa19 Mon Sep 17 00:00:00 2001 From: junpakPark Date: Mon, 14 Aug 2023 14:45:00 +0900 Subject: [PATCH 35/35] =?UTF-8?q?refactor:=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../permission/application/PermissionCommandService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/main/java/com/mapbefine/mapbefine/permission/application/PermissionCommandService.java b/backend/src/main/java/com/mapbefine/mapbefine/permission/application/PermissionCommandService.java index 8359fe919..4a64110f6 100644 --- a/backend/src/main/java/com/mapbefine/mapbefine/permission/application/PermissionCommandService.java +++ b/backend/src/main/java/com/mapbefine/mapbefine/permission/application/PermissionCommandService.java @@ -32,7 +32,7 @@ public PermissionCommandService( } public Long savePermission(AuthMember authMember, PermissionRequest request) { - validateNull(authMember); + validateUser(authMember); validateSelfPermission(authMember, request); validateDuplicatePermission(request); @@ -46,9 +46,9 @@ public Long savePermission(AuthMember authMember, PermissionRequest request) { return permissionRepository.save(permission).getId(); } - private void validateNull(AuthMember authMember) { + private void validateUser(AuthMember authMember) { if (Objects.isNull(authMember.getMemberId())) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException("Guest는 권한을 줄 수 없습니다."); } }