From 21bf4e8956cdf782095c4838db7c454fd3a15897 Mon Sep 17 00:00:00 2001 From: wkwon Date: Sat, 11 Nov 2023 17:00:13 +0900 Subject: [PATCH 01/70] =?UTF-8?q?docs:=20README=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3a323585..560ddb3d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,4 @@ -# amazing3-be - -## 커멧 컨벤션 +## 커밋 컨벤션 - `태그(#issue): 내용` - feat : 새로운 기능 추가 - fix : 버그 수정 @@ -8,4 +6,4 @@ - style : 코드 포맷팅, 세미콜론 누락, 코드 변경이 없는 경우 - refactor : 코드 리펙토링 - test : 테스트 코드, 리펙토링 테스트 코드 추가 - - chore : 빌드 업무 수정, 패키지 매니저 수정 \ No newline at end of file + - chore : 빌드 업무 수정, 패키지 매니저 수 \ No newline at end of file From 147acabe0b6dc8eb31cbf557978e441a4846164b Mon Sep 17 00:00:00 2001 From: manhyuk Date: Sat, 11 Nov 2023 18:50:41 +0900 Subject: [PATCH 02/70] feat: add issue template --- .github/ISSUE_TEMPLATE/issue.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/issue.md diff --git a/.github/ISSUE_TEMPLATE/issue.md b/.github/ISSUE_TEMPLATE/issue.md new file mode 100644 index 00000000..3cb6b07f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/issue.md @@ -0,0 +1,14 @@ +--- +name: 티켓 이슈 +about: 티켓 발행을 위한 이슈입니다. +title: '' +labels: enhancement +assignees: '' + +--- + +### ⚠️ Issue +- 이슈 개요를 입력해주세요. + +### ✏️ ToDoList +- [ ] 할 일1 \ No newline at end of file From 3024a4102a5d5801df713511c156fadc59781e73 Mon Sep 17 00:00:00 2001 From: wkwon Date: Sat, 11 Nov 2023 19:05:34 +0900 Subject: [PATCH 03/70] =?UTF-8?q?chore:=20java=20version=2017=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD,=20projectGroup=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../springboot/client/example/ExampleApi.kt | 2 +- .../springboot/client/example/ExampleClient.kt | 4 ++-- .../springboot/client/example/ExampleConfig.kt | 2 +- .../springboot/client/example/ExampleRequestDto.kt | 2 +- .../client/example/ExampleResponseDto.kt | 4 ++-- .../client/example/model/ExampleClientResult.kt | 2 +- .../client/ClientExampleContextTest.kt | 2 +- .../client/ClientExampleTestApplication.kt | 4 ++-- .../springboot/client/example/ExampleClientTest.kt | 6 +++--- .../controller/v1/response/ExampleResponseDto.kt | 5 ----- .../springboot/core/api/support/error/ErrorCode.kt | 5 ----- .../core/api/support/response/ResultType.kt | 5 ----- .../springboot/CoreApiApplication.kt | 2 +- .../springboot/core/api/config/AsyncConfig.kt | 4 ++-- .../core/api/config/AsyncExceptionHandler.kt | 4 ++-- .../core/api/controller/ApiControllerAdvice.kt | 8 ++++---- .../core/api/controller/HealthController.kt | 2 +- .../core/api/controller/v1/ExampleController.kt | 12 ++++++------ .../api/controller/v1/request/ExampleRequestDto.kt | 4 ++-- .../controller/v1/response/ExampleResponseDto.kt | 5 +++++ .../springboot/core/api/domain/ExampleData.kt | 2 +- .../springboot/core/api/domain/ExampleResult.kt | 2 +- .../springboot/core/api/domain/ExampleService.kt | 2 +- .../core/api/support/error/CoreApiException.kt | 2 +- .../springboot/core/api/support/error/ErrorCode.kt | 5 +++++ .../core/api/support/error/ErrorMessage.kt | 2 +- .../springboot/core/api/support/error/ErrorType.kt | 2 +- .../core/api/support/response/ApiResponse.kt | 6 +++--- .../core/api/support/response/ResultType.kt | 5 +++++ .../io/{dodn/springboot => raemian}/ContextTest.kt | 2 +- .../CoreApiApplicationTest.kt | 2 +- .../io/{dodn/springboot => raemian}/DevelopTest.kt | 2 +- .../api/controller/v1/ExampleControllerTest.kt | 14 +++++++------- .../io/dodn/springboot/core/enums/ExampleEnum.kt | 3 --- .../raemian/springboot/core/enums/ExampleEnum.kt | 3 +++ gradle.properties | 4 ++-- .../springboot/storage/db/core/BaseEntity.kt | 2 +- .../springboot/storage/db/core/ExampleEntity.kt | 2 +- .../storage/db/core/ExampleRepository.kt | 2 +- .../storage/db/core/config/CoreDataSourceConfig.kt | 2 +- .../storage/db/core/config/CoreJpaConfig.kt | 6 +++--- .../storage/db/CoreDbContextTest.kt | 2 +- .../storage/db/CoreDbTestApplication.kt | 2 +- .../storage/db/core/ExampleRepositoryIT.kt | 6 ++++-- .../src/main/resources/logback/logback-dev.xml | 2 +- .../src/main/resources/logback/logback-live.xml | 2 +- .../main/resources/logback/logback-local-dev.xml | 2 +- .../src/main/resources/logback/logback-local.xml | 2 +- .../src/main/resources/logback/logback-staging.xml | 2 +- .../springboot/test/api/RestDocsTest.kt | 2 +- .../springboot/test/api/RestDocsUtils.kt | 4 ++-- 51 files changed, 92 insertions(+), 90 deletions(-) rename clients/client-example/src/main/kotlin/io/{dodn => raemian}/springboot/client/example/ExampleApi.kt (93%) rename clients/client-example/src/main/kotlin/io/{dodn => raemian}/springboot/client/example/ExampleClient.kt (75%) rename clients/client-example/src/main/kotlin/io/{dodn => raemian}/springboot/client/example/ExampleConfig.kt (80%) rename clients/client-example/src/main/kotlin/io/{dodn => raemian}/springboot/client/example/ExampleRequestDto.kt (63%) rename clients/client-example/src/main/kotlin/io/{dodn => raemian}/springboot/client/example/ExampleResponseDto.kt (62%) rename clients/client-example/src/main/kotlin/io/{dodn => raemian}/springboot/client/example/model/ExampleClientResult.kt (56%) rename clients/client-example/src/test/kotlin/io/{dodn/springboot => raemian}/client/ClientExampleContextTest.kt (91%) rename clients/client-example/src/test/kotlin/io/{dodn/springboot => raemian}/client/ClientExampleTestApplication.kt (76%) rename clients/client-example/src/test/kotlin/io/{dodn => raemian}/springboot/client/example/ExampleClientTest.kt (74%) delete mode 100644 core/core-api/src/main/kotlin/io/dodn/springboot/core/api/controller/v1/response/ExampleResponseDto.kt delete mode 100644 core/core-api/src/main/kotlin/io/dodn/springboot/core/api/support/error/ErrorCode.kt delete mode 100644 core/core-api/src/main/kotlin/io/dodn/springboot/core/api/support/response/ResultType.kt rename core/core-api/src/main/kotlin/io/{dodn => raemian}/springboot/CoreApiApplication.kt (92%) rename core/core-api/src/main/kotlin/io/{dodn => raemian}/springboot/core/api/config/AsyncConfig.kt (89%) rename core/core-api/src/main/kotlin/io/{dodn => raemian}/springboot/core/api/config/AsyncExceptionHandler.kt (88%) rename core/core-api/src/main/kotlin/io/{dodn => raemian}/springboot/core/api/controller/ApiControllerAdvice.kt (83%) rename core/core-api/src/main/kotlin/io/{dodn => raemian}/springboot/core/api/controller/HealthController.kt (89%) rename core/core-api/src/main/kotlin/io/{dodn => raemian}/springboot/core/api/controller/v1/ExampleController.kt (74%) rename core/core-api/src/main/kotlin/io/{dodn => raemian}/springboot/core/api/controller/v1/request/ExampleRequestDto.kt (56%) create mode 100644 core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/v1/response/ExampleResponseDto.kt rename core/core-api/src/main/kotlin/io/{dodn => raemian}/springboot/core/api/domain/ExampleData.kt (62%) rename core/core-api/src/main/kotlin/io/{dodn => raemian}/springboot/core/api/domain/ExampleResult.kt (54%) rename core/core-api/src/main/kotlin/io/{dodn => raemian}/springboot/core/api/domain/ExampleService.kt (82%) rename core/core-api/src/main/kotlin/io/{dodn => raemian}/springboot/core/api/support/error/CoreApiException.kt (70%) create mode 100644 core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/error/ErrorCode.kt rename core/core-api/src/main/kotlin/io/{dodn => raemian}/springboot/core/api/support/error/ErrorMessage.kt (85%) rename core/core-api/src/main/kotlin/io/{dodn => raemian}/springboot/core/api/support/error/ErrorType.kt (86%) rename core/core-api/src/main/kotlin/io/{dodn => raemian}/springboot/core/api/support/response/ApiResponse.kt (77%) create mode 100644 core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/response/ResultType.kt rename core/core-api/src/test/kotlin/io/{dodn/springboot => raemian}/ContextTest.kt (91%) rename core/core-api/src/test/kotlin/io/{dodn/springboot => raemian}/CoreApiApplicationTest.kt (86%) rename core/core-api/src/test/kotlin/io/{dodn/springboot => raemian}/DevelopTest.kt (91%) rename core/core-api/src/test/kotlin/io/{dodn/springboot => raemian}/core/api/controller/v1/ExampleControllerTest.kt (88%) delete mode 100644 core/core-enum/src/main/kotlin/io/dodn/springboot/core/enums/ExampleEnum.kt create mode 100644 core/core-enum/src/main/kotlin/io/raemian/springboot/core/enums/ExampleEnum.kt rename storage/db-core/src/main/kotlin/io/{dodn => raemian}/springboot/storage/db/core/BaseEntity.kt (93%) rename storage/db-core/src/main/kotlin/io/{dodn => raemian}/springboot/storage/db/core/ExampleEntity.kt (77%) rename storage/db-core/src/main/kotlin/io/{dodn => raemian}/springboot/storage/db/core/ExampleRepository.kt (73%) rename storage/db-core/src/main/kotlin/io/{dodn => raemian}/springboot/storage/db/core/config/CoreDataSourceConfig.kt (92%) rename storage/db-core/src/main/kotlin/io/{dodn => raemian}/springboot/storage/db/core/config/CoreJpaConfig.kt (64%) rename storage/db-core/src/test/kotlin/io/{dodn/springboot => raemian}/storage/db/CoreDbContextTest.kt (90%) rename storage/db-core/src/test/kotlin/io/{dodn/springboot => raemian}/storage/db/CoreDbTestApplication.kt (90%) rename storage/db-core/src/test/kotlin/io/{dodn/springboot => raemian}/storage/db/core/ExampleRepositoryIT.kt (71%) rename tests/api-docs/src/main/kotlin/io/{dodn => raemian}/springboot/test/api/RestDocsTest.kt (98%) rename tests/api-docs/src/main/kotlin/io/{dodn => raemian}/springboot/test/api/RestDocsUtils.kt (90%) diff --git a/clients/client-example/src/main/kotlin/io/dodn/springboot/client/example/ExampleApi.kt b/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleApi.kt similarity index 93% rename from clients/client-example/src/main/kotlin/io/dodn/springboot/client/example/ExampleApi.kt rename to clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleApi.kt index 1bbfe399..4dc31e58 100644 --- a/clients/client-example/src/main/kotlin/io/dodn/springboot/client/example/ExampleApi.kt +++ b/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleApi.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.client.example +package io.raemian.springboot.client.example import org.springframework.cloud.openfeign.FeignClient import org.springframework.http.MediaType diff --git a/clients/client-example/src/main/kotlin/io/dodn/springboot/client/example/ExampleClient.kt b/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleClient.kt similarity index 75% rename from clients/client-example/src/main/kotlin/io/dodn/springboot/client/example/ExampleClient.kt rename to clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleClient.kt index cffa9e0f..f73570ad 100644 --- a/clients/client-example/src/main/kotlin/io/dodn/springboot/client/example/ExampleClient.kt +++ b/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleClient.kt @@ -1,6 +1,6 @@ -package io.dodn.springboot.client.example +package io.raemian.springboot.client.example -import io.dodn.springboot.client.example.model.ExampleClientResult +import io.raemian.springboot.client.example.model.ExampleClientResult import org.springframework.stereotype.Component @Component diff --git a/clients/client-example/src/main/kotlin/io/dodn/springboot/client/example/ExampleConfig.kt b/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleConfig.kt similarity index 80% rename from clients/client-example/src/main/kotlin/io/dodn/springboot/client/example/ExampleConfig.kt rename to clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleConfig.kt index 9da21878..292ca7ec 100644 --- a/clients/client-example/src/main/kotlin/io/dodn/springboot/client/example/ExampleConfig.kt +++ b/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleConfig.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.client.example +package io.raemian.springboot.client.example import org.springframework.cloud.openfeign.EnableFeignClients import org.springframework.context.annotation.Configuration diff --git a/clients/client-example/src/main/kotlin/io/dodn/springboot/client/example/ExampleRequestDto.kt b/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleRequestDto.kt similarity index 63% rename from clients/client-example/src/main/kotlin/io/dodn/springboot/client/example/ExampleRequestDto.kt rename to clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleRequestDto.kt index 24d12d92..c1575518 100644 --- a/clients/client-example/src/main/kotlin/io/dodn/springboot/client/example/ExampleRequestDto.kt +++ b/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleRequestDto.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.client.example +package io.raemian.springboot.client.example internal data class ExampleRequestDto( val exampleRequestValue: String, diff --git a/clients/client-example/src/main/kotlin/io/dodn/springboot/client/example/ExampleResponseDto.kt b/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleResponseDto.kt similarity index 62% rename from clients/client-example/src/main/kotlin/io/dodn/springboot/client/example/ExampleResponseDto.kt rename to clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleResponseDto.kt index eb510559..d530d0e6 100644 --- a/clients/client-example/src/main/kotlin/io/dodn/springboot/client/example/ExampleResponseDto.kt +++ b/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleResponseDto.kt @@ -1,6 +1,6 @@ -package io.dodn.springboot.client.example +package io.raemian.springboot.client.example -import io.dodn.springboot.client.example.model.ExampleClientResult +import io.raemian.springboot.client.example.model.ExampleClientResult internal data class ExampleResponseDto( val exampleResponseValue: String, diff --git a/clients/client-example/src/main/kotlin/io/dodn/springboot/client/example/model/ExampleClientResult.kt b/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/model/ExampleClientResult.kt similarity index 56% rename from clients/client-example/src/main/kotlin/io/dodn/springboot/client/example/model/ExampleClientResult.kt rename to clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/model/ExampleClientResult.kt index b5e425bc..a68d489c 100644 --- a/clients/client-example/src/main/kotlin/io/dodn/springboot/client/example/model/ExampleClientResult.kt +++ b/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/model/ExampleClientResult.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.client.example.model +package io.raemian.springboot.client.example.model data class ExampleClientResult( val exampleResult: String, diff --git a/clients/client-example/src/test/kotlin/io/dodn/springboot/client/ClientExampleContextTest.kt b/clients/client-example/src/test/kotlin/io/raemian/client/ClientExampleContextTest.kt similarity index 91% rename from clients/client-example/src/test/kotlin/io/dodn/springboot/client/ClientExampleContextTest.kt rename to clients/client-example/src/test/kotlin/io/raemian/client/ClientExampleContextTest.kt index 8a35630b..2142d52e 100644 --- a/clients/client-example/src/test/kotlin/io/dodn/springboot/client/ClientExampleContextTest.kt +++ b/clients/client-example/src/test/kotlin/io/raemian/client/ClientExampleContextTest.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.client +package io.raemian.client import org.junit.jupiter.api.Tag import org.springframework.boot.test.context.SpringBootTest diff --git a/clients/client-example/src/test/kotlin/io/dodn/springboot/client/ClientExampleTestApplication.kt b/clients/client-example/src/test/kotlin/io/raemian/client/ClientExampleTestApplication.kt similarity index 76% rename from clients/client-example/src/test/kotlin/io/dodn/springboot/client/ClientExampleTestApplication.kt rename to clients/client-example/src/test/kotlin/io/raemian/client/ClientExampleTestApplication.kt index ae7142e0..118fb5e6 100644 --- a/clients/client-example/src/test/kotlin/io/dodn/springboot/client/ClientExampleTestApplication.kt +++ b/clients/client-example/src/test/kotlin/io/raemian/client/ClientExampleTestApplication.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.client +package io.raemian.client import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.context.properties.ConfigurationPropertiesScan @@ -9,5 +9,5 @@ import org.springframework.boot.runApplication class ClientExampleTestApplication fun main(args: Array) { - runApplication(*args) + runApplication(*args) } diff --git a/clients/client-example/src/test/kotlin/io/dodn/springboot/client/example/ExampleClientTest.kt b/clients/client-example/src/test/kotlin/io/raemian/springboot/client/example/ExampleClientTest.kt similarity index 74% rename from clients/client-example/src/test/kotlin/io/dodn/springboot/client/example/ExampleClientTest.kt rename to clients/client-example/src/test/kotlin/io/raemian/springboot/client/example/ExampleClientTest.kt index 1039fde1..19710d16 100644 --- a/clients/client-example/src/test/kotlin/io/dodn/springboot/client/example/ExampleClientTest.kt +++ b/clients/client-example/src/test/kotlin/io/raemian/springboot/client/example/ExampleClientTest.kt @@ -1,13 +1,13 @@ -package io.dodn.springboot.client.example +package io.raemian.springboot.client.example import feign.RetryableException -import io.dodn.springboot.client.ClientExampleContextTest +import io.raemian.client.ClientExampleContextTest import org.assertj.core.api.Assertions import org.junit.jupiter.api.Test class ExampleClientTest( val exampleClient: ExampleClient, -) : ClientExampleContextTest() { +) : io.raemian.client.ClientExampleContextTest() { @Test fun shouldBeThrownExceptionWhenExample() { try { diff --git a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/controller/v1/response/ExampleResponseDto.kt b/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/controller/v1/response/ExampleResponseDto.kt deleted file mode 100644 index e9a75381..00000000 --- a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/controller/v1/response/ExampleResponseDto.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.dodn.springboot.core.api.controller.v1.response - -data class ExampleResponseDto( - val result: String, -) diff --git a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/support/error/ErrorCode.kt b/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/support/error/ErrorCode.kt deleted file mode 100644 index 90b51664..00000000 --- a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/support/error/ErrorCode.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.dodn.springboot.core.api.support.error - -enum class ErrorCode { - E500, -} diff --git a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/support/response/ResultType.kt b/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/support/response/ResultType.kt deleted file mode 100644 index 3f4574dc..00000000 --- a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/support/response/ResultType.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.dodn.springboot.core.api.support.response - -enum class ResultType { - SUCCESS, ERROR -} diff --git a/core/core-api/src/main/kotlin/io/dodn/springboot/CoreApiApplication.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/CoreApiApplication.kt similarity index 92% rename from core/core-api/src/main/kotlin/io/dodn/springboot/CoreApiApplication.kt rename to core/core-api/src/main/kotlin/io/raemian/springboot/CoreApiApplication.kt index 5e1ecf20..56be2fad 100644 --- a/core/core-api/src/main/kotlin/io/dodn/springboot/CoreApiApplication.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/CoreApiApplication.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot +package io.raemian.springboot import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.context.properties.ConfigurationPropertiesScan diff --git a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/config/AsyncConfig.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/config/AsyncConfig.kt similarity index 89% rename from core/core-api/src/main/kotlin/io/dodn/springboot/core/api/config/AsyncConfig.kt rename to core/core-api/src/main/kotlin/io/raemian/springboot/core/api/config/AsyncConfig.kt index 81e08015..d7a996a2 100644 --- a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/config/AsyncConfig.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/config/AsyncConfig.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.core.api.config +package io.raemian.core.api.config import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler import org.springframework.context.annotation.Configuration @@ -22,6 +22,6 @@ class AsyncConfig : AsyncConfigurer { } override fun getAsyncUncaughtExceptionHandler(): AsyncUncaughtExceptionHandler { - return AsyncExceptionHandler() + return io.raemian.core.api.config.AsyncExceptionHandler() } } diff --git a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/config/AsyncExceptionHandler.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/config/AsyncExceptionHandler.kt similarity index 88% rename from core/core-api/src/main/kotlin/io/dodn/springboot/core/api/config/AsyncExceptionHandler.kt rename to core/core-api/src/main/kotlin/io/raemian/springboot/core/api/config/AsyncExceptionHandler.kt index 0fe1905c..4358a45d 100644 --- a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/config/AsyncExceptionHandler.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/config/AsyncExceptionHandler.kt @@ -1,6 +1,6 @@ -package io.dodn.springboot.core.api.config +package io.raemian.core.api.config -import io.dodn.springboot.core.api.support.error.CoreApiException +import io.raemian.core.api.support.error.CoreApiException import org.slf4j.LoggerFactory import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler import org.springframework.boot.logging.LogLevel diff --git a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/controller/ApiControllerAdvice.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/ApiControllerAdvice.kt similarity index 83% rename from core/core-api/src/main/kotlin/io/dodn/springboot/core/api/controller/ApiControllerAdvice.kt rename to core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/ApiControllerAdvice.kt index 946f4974..f382ca34 100644 --- a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/controller/ApiControllerAdvice.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/ApiControllerAdvice.kt @@ -1,8 +1,8 @@ -package io.dodn.springboot.core.api.controller +package io.raemian.core.api.controller -import io.dodn.springboot.core.api.support.error.CoreApiException -import io.dodn.springboot.core.api.support.error.ErrorType -import io.dodn.springboot.core.api.support.response.ApiResponse +import io.raemian.core.api.support.error.CoreApiException +import io.raemian.core.api.support.error.ErrorType +import io.raemian.core.api.support.response.ApiResponse import org.slf4j.Logger import org.slf4j.LoggerFactory import org.springframework.boot.logging.LogLevel diff --git a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/controller/HealthController.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/HealthController.kt similarity index 89% rename from core/core-api/src/main/kotlin/io/dodn/springboot/core/api/controller/HealthController.kt rename to core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/HealthController.kt index 9eaf8de3..c69d1380 100644 --- a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/controller/HealthController.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/HealthController.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.core.api.controller +package io.raemian.core.api.controller import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity diff --git a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/controller/v1/ExampleController.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/v1/ExampleController.kt similarity index 74% rename from core/core-api/src/main/kotlin/io/dodn/springboot/core/api/controller/v1/ExampleController.kt rename to core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/v1/ExampleController.kt index 51e9c7c3..cc193759 100644 --- a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/controller/v1/ExampleController.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/v1/ExampleController.kt @@ -1,10 +1,10 @@ -package io.dodn.springboot.core.api.controller.v1 +package io.raemian.core.api.controller.v1 -import io.dodn.springboot.core.api.controller.v1.request.ExampleRequestDto -import io.dodn.springboot.core.api.controller.v1.response.ExampleResponseDto -import io.dodn.springboot.core.api.domain.ExampleData -import io.dodn.springboot.core.api.domain.ExampleService -import io.dodn.springboot.core.api.support.response.ApiResponse +import io.raemian.core.api.controller.v1.request.ExampleRequestDto +import io.raemian.core.api.controller.v1.response.ExampleResponseDto +import io.raemian.core.api.domain.ExampleData +import io.raemian.core.api.domain.ExampleService +import io.raemian.core.api.support.response.ApiResponse import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.PostMapping diff --git a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/controller/v1/request/ExampleRequestDto.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/v1/request/ExampleRequestDto.kt similarity index 56% rename from core/core-api/src/main/kotlin/io/dodn/springboot/core/api/controller/v1/request/ExampleRequestDto.kt rename to core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/v1/request/ExampleRequestDto.kt index 27da470a..089d1d4b 100644 --- a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/controller/v1/request/ExampleRequestDto.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/v1/request/ExampleRequestDto.kt @@ -1,6 +1,6 @@ -package io.dodn.springboot.core.api.controller.v1.request +package io.raemian.core.api.controller.v1.request -import io.dodn.springboot.core.api.domain.ExampleData +import io.raemian.core.api.domain.ExampleData data class ExampleRequestDto( val data: String, diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/v1/response/ExampleResponseDto.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/v1/response/ExampleResponseDto.kt new file mode 100644 index 00000000..4e429eeb --- /dev/null +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/v1/response/ExampleResponseDto.kt @@ -0,0 +1,5 @@ +package io.raemian.core.api.controller.v1.response + +data class ExampleResponseDto( + val result: String, +) diff --git a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/domain/ExampleData.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/domain/ExampleData.kt similarity index 62% rename from core/core-api/src/main/kotlin/io/dodn/springboot/core/api/domain/ExampleData.kt rename to core/core-api/src/main/kotlin/io/raemian/springboot/core/api/domain/ExampleData.kt index 8a5ff284..5482676e 100644 --- a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/domain/ExampleData.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/domain/ExampleData.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.core.api.domain +package io.raemian.core.api.domain data class ExampleData( val value: String, diff --git a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/domain/ExampleResult.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/domain/ExampleResult.kt similarity index 54% rename from core/core-api/src/main/kotlin/io/dodn/springboot/core/api/domain/ExampleResult.kt rename to core/core-api/src/main/kotlin/io/raemian/springboot/core/api/domain/ExampleResult.kt index a8be81ae..d9f4f34c 100644 --- a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/domain/ExampleResult.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/domain/ExampleResult.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.core.api.domain +package io.raemian.core.api.domain data class ExampleResult( val data: String, diff --git a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/domain/ExampleService.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/domain/ExampleService.kt similarity index 82% rename from core/core-api/src/main/kotlin/io/dodn/springboot/core/api/domain/ExampleService.kt rename to core/core-api/src/main/kotlin/io/raemian/springboot/core/api/domain/ExampleService.kt index d900f7ff..b6afd807 100644 --- a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/domain/ExampleService.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/domain/ExampleService.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.core.api.domain +package io.raemian.core.api.domain import org.springframework.stereotype.Service diff --git a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/support/error/CoreApiException.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/error/CoreApiException.kt similarity index 70% rename from core/core-api/src/main/kotlin/io/dodn/springboot/core/api/support/error/CoreApiException.kt rename to core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/error/CoreApiException.kt index 6815b19a..bb2aed30 100644 --- a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/support/error/CoreApiException.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/error/CoreApiException.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.core.api.support.error +package io.raemian.core.api.support.error class CoreApiException( val errorType: ErrorType, diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/error/ErrorCode.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/error/ErrorCode.kt new file mode 100644 index 00000000..76837a2b --- /dev/null +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/error/ErrorCode.kt @@ -0,0 +1,5 @@ +package io.raemian.core.api.support.error + +enum class ErrorCode { + E500, +} diff --git a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/support/error/ErrorMessage.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/error/ErrorMessage.kt similarity index 85% rename from core/core-api/src/main/kotlin/io/dodn/springboot/core/api/support/error/ErrorMessage.kt rename to core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/error/ErrorMessage.kt index 656b5de4..635eb134 100644 --- a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/support/error/ErrorMessage.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/error/ErrorMessage.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.core.api.support.error +package io.raemian.core.api.support.error data class ErrorMessage private constructor( val code: String, diff --git a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/support/error/ErrorType.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/error/ErrorType.kt similarity index 86% rename from core/core-api/src/main/kotlin/io/dodn/springboot/core/api/support/error/ErrorType.kt rename to core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/error/ErrorType.kt index 2fc96e27..d48bf16c 100644 --- a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/support/error/ErrorType.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/error/ErrorType.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.core.api.support.error +package io.raemian.core.api.support.error import org.springframework.boot.logging.LogLevel import org.springframework.http.HttpStatus diff --git a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/support/response/ApiResponse.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/response/ApiResponse.kt similarity index 77% rename from core/core-api/src/main/kotlin/io/dodn/springboot/core/api/support/response/ApiResponse.kt rename to core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/response/ApiResponse.kt index 821dfd0d..c76a2fec 100644 --- a/core/core-api/src/main/kotlin/io/dodn/springboot/core/api/support/response/ApiResponse.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/response/ApiResponse.kt @@ -1,7 +1,7 @@ -package io.dodn.springboot.core.api.support.response +package io.raemian.core.api.support.response -import io.dodn.springboot.core.api.support.error.ErrorMessage -import io.dodn.springboot.core.api.support.error.ErrorType +import io.raemian.core.api.support.error.ErrorMessage +import io.raemian.core.api.support.error.ErrorType data class ApiResponse private constructor( val result: ResultType, diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/response/ResultType.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/response/ResultType.kt new file mode 100644 index 00000000..9431b844 --- /dev/null +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/response/ResultType.kt @@ -0,0 +1,5 @@ +package io.raemian.core.api.support.response + +enum class ResultType { + SUCCESS, ERROR +} diff --git a/core/core-api/src/test/kotlin/io/dodn/springboot/ContextTest.kt b/core/core-api/src/test/kotlin/io/raemian/ContextTest.kt similarity index 91% rename from core/core-api/src/test/kotlin/io/dodn/springboot/ContextTest.kt rename to core/core-api/src/test/kotlin/io/raemian/ContextTest.kt index 59f92274..d090951c 100644 --- a/core/core-api/src/test/kotlin/io/dodn/springboot/ContextTest.kt +++ b/core/core-api/src/test/kotlin/io/raemian/ContextTest.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot +package io.raemian import org.junit.jupiter.api.Tag import org.springframework.boot.test.context.SpringBootTest diff --git a/core/core-api/src/test/kotlin/io/dodn/springboot/CoreApiApplicationTest.kt b/core/core-api/src/test/kotlin/io/raemian/CoreApiApplicationTest.kt similarity index 86% rename from core/core-api/src/test/kotlin/io/dodn/springboot/CoreApiApplicationTest.kt rename to core/core-api/src/test/kotlin/io/raemian/CoreApiApplicationTest.kt index 6c32dc03..65f02181 100644 --- a/core/core-api/src/test/kotlin/io/dodn/springboot/CoreApiApplicationTest.kt +++ b/core/core-api/src/test/kotlin/io/raemian/CoreApiApplicationTest.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot +package io.raemian import org.junit.jupiter.api.Test diff --git a/core/core-api/src/test/kotlin/io/dodn/springboot/DevelopTest.kt b/core/core-api/src/test/kotlin/io/raemian/DevelopTest.kt similarity index 91% rename from core/core-api/src/test/kotlin/io/dodn/springboot/DevelopTest.kt rename to core/core-api/src/test/kotlin/io/raemian/DevelopTest.kt index 9da6b45f..22e1fb15 100644 --- a/core/core-api/src/test/kotlin/io/dodn/springboot/DevelopTest.kt +++ b/core/core-api/src/test/kotlin/io/raemian/DevelopTest.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot +package io.raemian import org.junit.jupiter.api.Tag import org.springframework.boot.test.context.SpringBootTest diff --git a/core/core-api/src/test/kotlin/io/dodn/springboot/core/api/controller/v1/ExampleControllerTest.kt b/core/core-api/src/test/kotlin/io/raemian/core/api/controller/v1/ExampleControllerTest.kt similarity index 88% rename from core/core-api/src/test/kotlin/io/dodn/springboot/core/api/controller/v1/ExampleControllerTest.kt rename to core/core-api/src/test/kotlin/io/raemian/core/api/controller/v1/ExampleControllerTest.kt index 07ab7a08..819350f3 100644 --- a/core/core-api/src/test/kotlin/io/dodn/springboot/core/api/controller/v1/ExampleControllerTest.kt +++ b/core/core-api/src/test/kotlin/io/raemian/core/api/controller/v1/ExampleControllerTest.kt @@ -1,11 +1,11 @@ -package io.dodn.springboot.core.api.controller.v1 +package io.raemian.core.api.controller.v1 -import io.dodn.springboot.core.api.controller.v1.request.ExampleRequestDto -import io.dodn.springboot.core.api.domain.ExampleResult -import io.dodn.springboot.core.api.domain.ExampleService -import io.dodn.springboot.test.api.RestDocsTest -import io.dodn.springboot.test.api.RestDocsUtils.requestPreprocessor -import io.dodn.springboot.test.api.RestDocsUtils.responsePreprocessor +import io.raemian.core.api.controller.v1.request.ExampleRequestDto +import io.raemian.core.api.domain.ExampleResult +import io.raemian.core.api.domain.ExampleService +import io.raemian.springboot.test.api.RestDocsTest +import io.raemian.springboot.test.api.RestDocsUtils.requestPreprocessor +import io.raemian.springboot.test.api.RestDocsUtils.responsePreprocessor import io.mockk.every import io.mockk.mockk import io.restassured.http.ContentType diff --git a/core/core-enum/src/main/kotlin/io/dodn/springboot/core/enums/ExampleEnum.kt b/core/core-enum/src/main/kotlin/io/dodn/springboot/core/enums/ExampleEnum.kt deleted file mode 100644 index 2bb23b1c..00000000 --- a/core/core-enum/src/main/kotlin/io/dodn/springboot/core/enums/ExampleEnum.kt +++ /dev/null @@ -1,3 +0,0 @@ -package io.dodn.springboot.core.enums - -enum class ExampleEnum diff --git a/core/core-enum/src/main/kotlin/io/raemian/springboot/core/enums/ExampleEnum.kt b/core/core-enum/src/main/kotlin/io/raemian/springboot/core/enums/ExampleEnum.kt new file mode 100644 index 00000000..caba3010 --- /dev/null +++ b/core/core-enum/src/main/kotlin/io/raemian/springboot/core/enums/ExampleEnum.kt @@ -0,0 +1,3 @@ +package io.raemian.springboot.core.enums + +enum class ExampleEnum diff --git a/gradle.properties b/gradle.properties index eda29bd8..1186a712 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,11 +2,11 @@ applicationVersion=0.0.1-SNAPSHOT ### Project configs ### -projectGroup=io.dodn.springboot +projectGroup=io.raemian.springboot ### Project depdency versions ### kotlinVersion=1.9.20 -javaVersion=21 +javaVersion=17 ### Plugin depdency versions ### asciidoctorConvertVersion=3.3.2 diff --git a/storage/db-core/src/main/kotlin/io/dodn/springboot/storage/db/core/BaseEntity.kt b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/BaseEntity.kt similarity index 93% rename from storage/db-core/src/main/kotlin/io/dodn/springboot/storage/db/core/BaseEntity.kt rename to storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/BaseEntity.kt index ce4219f5..1fd34a79 100644 --- a/storage/db-core/src/main/kotlin/io/dodn/springboot/storage/db/core/BaseEntity.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/BaseEntity.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.storage.db.core +package io.raemian.springboot.storage.db.core import jakarta.persistence.Column import jakarta.persistence.GeneratedValue diff --git a/storage/db-core/src/main/kotlin/io/dodn/springboot/storage/db/core/ExampleEntity.kt b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/ExampleEntity.kt similarity index 77% rename from storage/db-core/src/main/kotlin/io/dodn/springboot/storage/db/core/ExampleEntity.kt rename to storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/ExampleEntity.kt index 44495a4c..47f5203b 100644 --- a/storage/db-core/src/main/kotlin/io/dodn/springboot/storage/db/core/ExampleEntity.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/ExampleEntity.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.storage.db.core +package io.raemian.springboot.storage.db.core import jakarta.persistence.Column import jakarta.persistence.Entity diff --git a/storage/db-core/src/main/kotlin/io/dodn/springboot/storage/db/core/ExampleRepository.kt b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/ExampleRepository.kt similarity index 73% rename from storage/db-core/src/main/kotlin/io/dodn/springboot/storage/db/core/ExampleRepository.kt rename to storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/ExampleRepository.kt index 2157634b..8085adbb 100644 --- a/storage/db-core/src/main/kotlin/io/dodn/springboot/storage/db/core/ExampleRepository.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/ExampleRepository.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.storage.db.core +package io.raemian.springboot.storage.db.core import org.springframework.data.jpa.repository.JpaRepository diff --git a/storage/db-core/src/main/kotlin/io/dodn/springboot/storage/db/core/config/CoreDataSourceConfig.kt b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/config/CoreDataSourceConfig.kt similarity index 92% rename from storage/db-core/src/main/kotlin/io/dodn/springboot/storage/db/core/config/CoreDataSourceConfig.kt rename to storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/config/CoreDataSourceConfig.kt index fc7ff80e..abe8d485 100644 --- a/storage/db-core/src/main/kotlin/io/dodn/springboot/storage/db/core/config/CoreDataSourceConfig.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/config/CoreDataSourceConfig.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.storage.db.core.config +package io.raemian.springboot.storage.db.core.config import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource diff --git a/storage/db-core/src/main/kotlin/io/dodn/springboot/storage/db/core/config/CoreJpaConfig.kt b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/config/CoreJpaConfig.kt similarity index 64% rename from storage/db-core/src/main/kotlin/io/dodn/springboot/storage/db/core/config/CoreJpaConfig.kt rename to storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/config/CoreJpaConfig.kt index e5e19c92..e22d62e4 100644 --- a/storage/db-core/src/main/kotlin/io/dodn/springboot/storage/db/core/config/CoreJpaConfig.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/config/CoreJpaConfig.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.storage.db.core.config +package io.raemian.springboot.storage.db.core.config import org.springframework.boot.autoconfigure.domain.EntityScan import org.springframework.context.annotation.Configuration @@ -7,6 +7,6 @@ import org.springframework.transaction.annotation.EnableTransactionManagement @Configuration @EnableTransactionManagement -@EntityScan(basePackages = ["io.dodn.springboot.storage.db.core"]) -@EnableJpaRepositories(basePackages = ["io.dodn.springboot.storage.db.core"]) +@EntityScan(basePackages = ["io.raemian.storage.db.core"]) +@EnableJpaRepositories(basePackages = ["io.raemian.storage.db.core"]) internal class CoreJpaConfig diff --git a/storage/db-core/src/test/kotlin/io/dodn/springboot/storage/db/CoreDbContextTest.kt b/storage/db-core/src/test/kotlin/io/raemian/storage/db/CoreDbContextTest.kt similarity index 90% rename from storage/db-core/src/test/kotlin/io/dodn/springboot/storage/db/CoreDbContextTest.kt rename to storage/db-core/src/test/kotlin/io/raemian/storage/db/CoreDbContextTest.kt index d4065fa1..1fec50be 100644 --- a/storage/db-core/src/test/kotlin/io/dodn/springboot/storage/db/CoreDbContextTest.kt +++ b/storage/db-core/src/test/kotlin/io/raemian/storage/db/CoreDbContextTest.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.storage.db +package io.raemian.storage.db import org.junit.jupiter.api.Tag import org.springframework.boot.test.context.SpringBootTest diff --git a/storage/db-core/src/test/kotlin/io/dodn/springboot/storage/db/CoreDbTestApplication.kt b/storage/db-core/src/test/kotlin/io/raemian/storage/db/CoreDbTestApplication.kt similarity index 90% rename from storage/db-core/src/test/kotlin/io/dodn/springboot/storage/db/CoreDbTestApplication.kt rename to storage/db-core/src/test/kotlin/io/raemian/storage/db/CoreDbTestApplication.kt index 80e4b117..cacc7013 100644 --- a/storage/db-core/src/test/kotlin/io/dodn/springboot/storage/db/CoreDbTestApplication.kt +++ b/storage/db-core/src/test/kotlin/io/raemian/storage/db/CoreDbTestApplication.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.storage.db +package io.raemian.storage.db import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.context.properties.ConfigurationPropertiesScan diff --git a/storage/db-core/src/test/kotlin/io/dodn/springboot/storage/db/core/ExampleRepositoryIT.kt b/storage/db-core/src/test/kotlin/io/raemian/storage/db/core/ExampleRepositoryIT.kt similarity index 71% rename from storage/db-core/src/test/kotlin/io/dodn/springboot/storage/db/core/ExampleRepositoryIT.kt rename to storage/db-core/src/test/kotlin/io/raemian/storage/db/core/ExampleRepositoryIT.kt index e3c564d3..b3e498da 100644 --- a/storage/db-core/src/test/kotlin/io/dodn/springboot/storage/db/core/ExampleRepositoryIT.kt +++ b/storage/db-core/src/test/kotlin/io/raemian/storage/db/core/ExampleRepositoryIT.kt @@ -1,6 +1,8 @@ -package io.dodn.springboot.storage.db.core +package io.raemian.storage.db.core -import io.dodn.springboot.storage.db.CoreDbContextTest +import io.raemian.springboot.storage.db.core.ExampleEntity +import io.raemian.springboot.storage.db.core.ExampleRepository +import io.raemian.storage.db.CoreDbContextTest import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test diff --git a/support/logging/src/main/resources/logback/logback-dev.xml b/support/logging/src/main/resources/logback/logback-dev.xml index 3003dac1..2f11d40e 100644 --- a/support/logging/src/main/resources/logback/logback-dev.xml +++ b/support/logging/src/main/resources/logback/logback-dev.xml @@ -18,7 +18,7 @@ - + diff --git a/support/logging/src/main/resources/logback/logback-live.xml b/support/logging/src/main/resources/logback/logback-live.xml index 3003dac1..2f11d40e 100644 --- a/support/logging/src/main/resources/logback/logback-live.xml +++ b/support/logging/src/main/resources/logback/logback-live.xml @@ -18,7 +18,7 @@ - + diff --git a/support/logging/src/main/resources/logback/logback-local-dev.xml b/support/logging/src/main/resources/logback/logback-local-dev.xml index b5e358fd..378b1a33 100644 --- a/support/logging/src/main/resources/logback/logback-local-dev.xml +++ b/support/logging/src/main/resources/logback/logback-local-dev.xml @@ -10,7 +10,7 @@ - + diff --git a/support/logging/src/main/resources/logback/logback-local.xml b/support/logging/src/main/resources/logback/logback-local.xml index b5e358fd..378b1a33 100644 --- a/support/logging/src/main/resources/logback/logback-local.xml +++ b/support/logging/src/main/resources/logback/logback-local.xml @@ -10,7 +10,7 @@ - + diff --git a/support/logging/src/main/resources/logback/logback-staging.xml b/support/logging/src/main/resources/logback/logback-staging.xml index 3003dac1..2f11d40e 100644 --- a/support/logging/src/main/resources/logback/logback-staging.xml +++ b/support/logging/src/main/resources/logback/logback-staging.xml @@ -18,7 +18,7 @@ - + diff --git a/tests/api-docs/src/main/kotlin/io/dodn/springboot/test/api/RestDocsTest.kt b/tests/api-docs/src/main/kotlin/io/raemian/springboot/test/api/RestDocsTest.kt similarity index 98% rename from tests/api-docs/src/main/kotlin/io/dodn/springboot/test/api/RestDocsTest.kt rename to tests/api-docs/src/main/kotlin/io/raemian/springboot/test/api/RestDocsTest.kt index 3fe9510f..e763c844 100644 --- a/tests/api-docs/src/main/kotlin/io/dodn/springboot/test/api/RestDocsTest.kt +++ b/tests/api-docs/src/main/kotlin/io/raemian/springboot/test/api/RestDocsTest.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.test.api +package io.raemian.springboot.test.api import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.SerializationFeature diff --git a/tests/api-docs/src/main/kotlin/io/dodn/springboot/test/api/RestDocsUtils.kt b/tests/api-docs/src/main/kotlin/io/raemian/springboot/test/api/RestDocsUtils.kt similarity index 90% rename from tests/api-docs/src/main/kotlin/io/dodn/springboot/test/api/RestDocsUtils.kt rename to tests/api-docs/src/main/kotlin/io/raemian/springboot/test/api/RestDocsUtils.kt index 9eb0aaed..cd041518 100644 --- a/tests/api-docs/src/main/kotlin/io/dodn/springboot/test/api/RestDocsUtils.kt +++ b/tests/api-docs/src/main/kotlin/io/raemian/springboot/test/api/RestDocsUtils.kt @@ -1,4 +1,4 @@ -package io.dodn.springboot.test.api +package io.raemian.springboot.test.api import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor @@ -7,7 +7,7 @@ import org.springframework.restdocs.operation.preprocess.Preprocessors object RestDocsUtils { fun requestPreprocessor(): OperationRequestPreprocessor { return Preprocessors.preprocessRequest( - Preprocessors.modifyUris().scheme("http").host("dev.dodn.io").removePort(), + Preprocessors.modifyUris().scheme("http").host("dev.io.raemian").removePort(), Preprocessors.prettyPrint(), ) } From 86ef3f95ce90c8b080880cb2430574b94d5b5322 Mon Sep 17 00:00:00 2001 From: manhyuk Date: Sat, 11 Nov 2023 21:38:36 +0900 Subject: [PATCH 04/70] feat(#1): add spring security config --- core/core-api/build.gradle.kts | 9 ++++ .../core/api/config/SecurityConfig.kt | 42 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 core/core-api/src/main/kotlin/io/raemian/springboot/core/api/config/SecurityConfig.kt diff --git a/core/core-api/build.gradle.kts b/core/core-api/build.gradle.kts index aa85c0c1..6b504130 100644 --- a/core/core-api/build.gradle.kts +++ b/core/core-api/build.gradle.kts @@ -16,4 +16,13 @@ dependencies { testImplementation(project(":tests:api-docs")) implementation("org.springframework.boot:spring-boot-starter-web") + + // security + implementation("org.springframework.boot:spring-boot-starter-security") + + // security-test + testImplementation("org.springframework.security:spring-security-test") + + + } diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/config/SecurityConfig.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/config/SecurityConfig.kt new file mode 100644 index 00000000..d458e813 --- /dev/null +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/config/SecurityConfig.kt @@ -0,0 +1,42 @@ +package io.raemian.springboot.core.api.config + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty +import org.springframework.boot.autoconfigure.security.servlet.PathRequest +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.security.config.annotation.web.builders.HttpSecurity +import org.springframework.security.config.annotation.web.builders.WebSecurity +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity +import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer +import org.springframework.security.web.SecurityFilterChain +import org.springframework.security.web.util.matcher.AntPathRequestMatcher + + +@Configuration +@EnableWebSecurity +class SecurityConfig { + + @Bean + fun filterChain(http: HttpSecurity): SecurityFilterChain { + return http + .csrf { it.disable() } + .formLogin { it.disable() } + .httpBasic { it.disable() } + .authorizeHttpRequests { + it.anyRequest().permitAll() + } + .build() + } + + + @Bean + @ConditionalOnProperty(name = ["spring.h2.console.enabled"], havingValue = "true") + fun configureH2ConsoleEnable(): WebSecurityCustomizer { + return WebSecurityCustomizer { + it + .ignoring() + .requestMatchers(PathRequest.toH2Console()) + } + } + +} From ca9f049d2646faecdf72ee0d45275459f38e18b3 Mon Sep 17 00:00:00 2001 From: manhyuk Date: Sat, 11 Nov 2023 23:57:48 +0900 Subject: [PATCH 05/70] fix(#1): fix typo --- .../{api => auth}/config/SecurityConfig.kt | 23 +++++++++++++++++++ .../core/auth/controller/AuthController.kt | 4 ++++ .../controller/v1/request/SignInRequest.kt | 3 +++ .../controller/v1/request/SignUpRequest.kt | 3 +++ .../core/auth/domain/SecurityUser.kt | 4 ++++ .../core/auth/service/AuthService.kt | 4 ++++ .../storage/db/core/config/CoreJpaConfig.kt | 4 ++-- .../springboot/storage/db/core/user/User.kt | 13 +++++++++++ .../storage/db/core/user/UserRepository.kt | 7 ++++++ 9 files changed, 63 insertions(+), 2 deletions(-) rename core/core-api/src/main/kotlin/io/raemian/springboot/core/{api => auth}/config/SecurityConfig.kt (53%) create mode 100644 core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt create mode 100644 core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignInRequest.kt create mode 100644 core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignUpRequest.kt create mode 100644 core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt create mode 100644 core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt create mode 100644 storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt create mode 100644 storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/UserRepository.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/config/SecurityConfig.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/SecurityConfig.kt similarity index 53% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/api/config/SecurityConfig.kt rename to core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/SecurityConfig.kt index d458e813..0e1aee34 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/config/SecurityConfig.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/SecurityConfig.kt @@ -8,6 +8,12 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.builders.WebSecurity import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository +import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager +import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository import org.springframework.security.web.SecurityFilterChain import org.springframework.security.web.util.matcher.AntPathRequestMatcher @@ -25,10 +31,27 @@ class SecurityConfig { .authorizeHttpRequests { it.anyRequest().permitAll() } + .oauth2Login { } .build() } + @Bean + fun authorizedClientManager( + clientRegistrationRepository: ClientRegistrationRepository, authorizedClientRepository: OAuth2AuthorizedClientRepository + ): OAuth2AuthorizedClientManager { + val authorizedClientProvider: OAuth2AuthorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder() + .authorizationCode() + .refreshToken() + .clientCredentials() + .password() + .build() + val authorizedClientManager = DefaultOAuth2AuthorizedClientManager( + clientRegistrationRepository, authorizedClientRepository) + authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider) + return authorizedClientManager + } + @Bean @ConditionalOnProperty(name = ["spring.h2.console.enabled"], havingValue = "true") fun configureH2ConsoleEnable(): WebSecurityCustomizer { diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt new file mode 100644 index 00000000..e927a7b8 --- /dev/null +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt @@ -0,0 +1,4 @@ +package io.raemian.springboot.core.auth.controller + +class AuthController { +} \ No newline at end of file diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignInRequest.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignInRequest.kt new file mode 100644 index 00000000..fcf30b34 --- /dev/null +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignInRequest.kt @@ -0,0 +1,3 @@ +package io.raemian.springboot.core.auth.controller.v1.request + +data class SignInRequest() diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignUpRequest.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignUpRequest.kt new file mode 100644 index 00000000..d03b71c5 --- /dev/null +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignUpRequest.kt @@ -0,0 +1,3 @@ +package io.raemian.springboot.core.auth.controller.v1.request + +data class SignUpRequest() diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt new file mode 100644 index 00000000..82b68829 --- /dev/null +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt @@ -0,0 +1,4 @@ +package io.raemian.springboot.core.auth.domain + +class SecurityUser { +} \ No newline at end of file diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt new file mode 100644 index 00000000..957b6661 --- /dev/null +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt @@ -0,0 +1,4 @@ +package io.raemian.springboot.core.auth.service + +class AuthService { +} \ No newline at end of file diff --git a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/config/CoreJpaConfig.kt b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/config/CoreJpaConfig.kt index e22d62e4..fbcefe35 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/config/CoreJpaConfig.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/config/CoreJpaConfig.kt @@ -7,6 +7,6 @@ import org.springframework.transaction.annotation.EnableTransactionManagement @Configuration @EnableTransactionManagement -@EntityScan(basePackages = ["io.raemian.storage.db.core"]) -@EnableJpaRepositories(basePackages = ["io.raemian.storage.db.core"]) +@EntityScan(basePackages = ["io.raemian.springboot.storage.db.core"]) +@EnableJpaRepositories(basePackages = ["io.raemian.springboot.storage.db.core"]) internal class CoreJpaConfig diff --git a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt new file mode 100644 index 00000000..0db61a45 --- /dev/null +++ b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt @@ -0,0 +1,13 @@ +package io.raemian.springboot.storage.db.core.member + +import io.raemian.springboot.storage.db.core.BaseEntity +import jakarta.persistence.Column +import jakarta.persistence.Entity + +@Entity +class Member( + @Column + val email: String, + @Column + val password: String +) : BaseEntity() \ No newline at end of file diff --git a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/UserRepository.kt b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/UserRepository.kt new file mode 100644 index 00000000..fdec7d44 --- /dev/null +++ b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/UserRepository.kt @@ -0,0 +1,7 @@ +package io.raemian.springboot.storage.db.core.member + +import org.springframework.data.jpa.repository.JpaRepository + +interface MemberRepository : JpaRepository { + fun findByEmail(email: String): Member? +} \ No newline at end of file From ffb57db64c0ef89b9966f0aadcfbc1432a9d030c Mon Sep 17 00:00:00 2001 From: manhyuk Date: Sat, 11 Nov 2023 23:58:18 +0900 Subject: [PATCH 06/70] chore(#1): fix typo --- .../kotlin/io/raemian/springboot/core/api/config/AsyncConfig.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/config/AsyncConfig.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/config/AsyncConfig.kt index d7a996a2..1857f52a 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/config/AsyncConfig.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/config/AsyncConfig.kt @@ -22,6 +22,6 @@ class AsyncConfig : AsyncConfigurer { } override fun getAsyncUncaughtExceptionHandler(): AsyncUncaughtExceptionHandler { - return io.raemian.core.api.config.AsyncExceptionHandler() + return AsyncExceptionHandler() } } From 7c0c4dddcc3c18acc24bfcafc9c80a27b3799304 Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Sat, 11 Nov 2023 23:59:30 +0900 Subject: [PATCH 07/70] feat(#1): add local sign-up --- core/core-api/build.gradle.kts | 3 +- .../core/auth/config/SecurityConfig.kt | 37 +++++++++++-------- .../core/auth/controller/AuthController.kt | 29 ++++++++++++++- .../controller/v1/request/SignInRequest.kt | 5 ++- .../controller/v1/request/SignUpRequest.kt | 5 ++- .../core/auth/domain/SecurityUser.kt | 16 +++++++- .../core/auth/service/AuthService.kt | 33 ++++++++++++++++- .../springboot/storage/db/core/user/User.kt | 11 ++++-- .../storage/db/core/user/UserRepository.kt | 6 +-- 9 files changed, 117 insertions(+), 28 deletions(-) diff --git a/core/core-api/build.gradle.kts b/core/core-api/build.gradle.kts index 6b504130..a40da298 100644 --- a/core/core-api/build.gradle.kts +++ b/core/core-api/build.gradle.kts @@ -19,7 +19,8 @@ dependencies { // security implementation("org.springframework.boot:spring-boot-starter-security") - + // oauth-client + implementation("org.springframework.boot:spring-boot-starter-oauth2-client") // security-test testImplementation("org.springframework.security:spring-security-test") diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/SecurityConfig.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/SecurityConfig.kt index 0e1aee34..afdf67fc 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/SecurityConfig.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/SecurityConfig.kt @@ -1,13 +1,14 @@ -package io.raemian.springboot.core.api.config +package io.raemian.springboot.core.auth.config import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.boot.autoconfigure.security.servlet.PathRequest import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.security.config.annotation.web.builders.HttpSecurity -import org.springframework.security.config.annotation.web.builders.WebSecurity import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder +import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder @@ -15,7 +16,6 @@ import org.springframework.security.oauth2.client.registration.ClientRegistratio import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository import org.springframework.security.web.SecurityFilterChain -import org.springframework.security.web.util.matcher.AntPathRequestMatcher @Configuration @@ -31,14 +31,28 @@ class SecurityConfig { .authorizeHttpRequests { it.anyRequest().permitAll() } - .oauth2Login { } .build() } + @Bean + @ConditionalOnProperty(name = ["spring.h2.console.enabled"], havingValue = "true") + fun configureH2ConsoleEnable(): WebSecurityCustomizer { + return WebSecurityCustomizer { + it + .ignoring() + .requestMatchers(PathRequest.toH2Console()) + } + } @Bean + fun getPasswordEncoder(): PasswordEncoder { + return BCryptPasswordEncoder() + } + + // @Bean fun authorizedClientManager( - clientRegistrationRepository: ClientRegistrationRepository, authorizedClientRepository: OAuth2AuthorizedClientRepository + clientRegistrationRepository: ClientRegistrationRepository, + authorizedClientRepository: OAuth2AuthorizedClientRepository, ): OAuth2AuthorizedClientManager { val authorizedClientProvider: OAuth2AuthorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder() .authorizationCode() @@ -47,19 +61,10 @@ class SecurityConfig { .password() .build() val authorizedClientManager = DefaultOAuth2AuthorizedClientManager( - clientRegistrationRepository, authorizedClientRepository) + clientRegistrationRepository, authorizedClientRepository, + ) authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider) return authorizedClientManager } - @Bean - @ConditionalOnProperty(name = ["spring.h2.console.enabled"], havingValue = "true") - fun configureH2ConsoleEnable(): WebSecurityCustomizer { - return WebSecurityCustomizer { - it - .ignoring() - .requestMatchers(PathRequest.toH2Console()) - } - } - } diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt index e927a7b8..3ad04bb4 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt @@ -1,4 +1,31 @@ package io.raemian.springboot.core.auth.controller -class AuthController { +import io.raemian.springboot.core.auth.controller.v1.request.SignInRequest +import io.raemian.springboot.core.auth.controller.v1.request.SignUpRequest +import io.raemian.springboot.core.auth.service.AuthService +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RestController + +@RestController +class AuthController( + private val authService: AuthService +) { + + @GetMapping("/kakao") + fun kk(): String { + return "kko" + } + + @PostMapping("/signup") + fun signUp(@RequestBody signUpRequest: SignUpRequest): String { + authService.save(signUpRequest.email, signUpRequest.password) + return "${signUpRequest.email}/${signUpRequest.password}" + } + + @PostMapping("/signin") + fun signIn(@RequestBody signInRequest: SignInRequest) { + authService.signIn(signInRequest.email, signInRequest.password) + } } \ No newline at end of file diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignInRequest.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignInRequest.kt index fcf30b34..ce413aa8 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignInRequest.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignInRequest.kt @@ -1,3 +1,6 @@ package io.raemian.springboot.core.auth.controller.v1.request -data class SignInRequest() +data class SignInRequest( + val email: String, + val password: String +) diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignUpRequest.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignUpRequest.kt index d03b71c5..5636d912 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignUpRequest.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignUpRequest.kt @@ -1,3 +1,6 @@ package io.raemian.springboot.core.auth.controller.v1.request -data class SignUpRequest() +data class SignUpRequest( + val email: String, + val password: String +) diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt index 82b68829..0150fb31 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt @@ -1,4 +1,18 @@ package io.raemian.springboot.core.auth.domain -class SecurityUser { +import org.springframework.security.core.GrantedAuthority +import org.springframework.security.core.userdetails.User + +class SecurityUser( + username: String, + password: String, +) : User(username, password, arrayListOf(SecurityGrantedAuthority())) { + +} + + +class SecurityGrantedAuthority : GrantedAuthority { + override fun getAuthority(): String { + return "USER" + } } \ No newline at end of file diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt index 957b6661..49fd0166 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt @@ -1,4 +1,35 @@ package io.raemian.springboot.core.auth.service -class AuthService { +import io.raemian.springboot.core.auth.domain.SecurityUser +import io.raemian.springboot.storage.db.core.user.User +import io.raemian.springboot.storage.db.core.user.UserRepository +import org.springframework.security.core.userdetails.UserDetails +import org.springframework.security.core.userdetails.UserDetailsService +import org.springframework.security.core.userdetails.UsernameNotFoundException +import org.springframework.security.crypto.password.PasswordEncoder +import org.springframework.stereotype.Service + +@Service +class AuthService( + private val userRepository: UserRepository, + private val passwordEncoder: PasswordEncoder, +) : UserDetailsService { + + fun save(email: String, password: String) { + userRepository.save( + User( + email = email, + password = passwordEncoder.encode(password), + ), + ) + } + + override fun loadUserByUsername(username: String): UserDetails { + val user = userRepository.findByEmail(username) ?: throw UsernameNotFoundException("not found $username") + return SecurityUser(username = user.email, password = user.password) + } + + fun signIn(email: String, password: String) { + + } } \ No newline at end of file diff --git a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt index 0db61a45..bc058d5a 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt @@ -1,13 +1,18 @@ -package io.raemian.springboot.storage.db.core.member +package io.raemian.springboot.storage.db.core.user import io.raemian.springboot.storage.db.core.BaseEntity import jakarta.persistence.Column import jakarta.persistence.Entity @Entity -class Member( +class User( @Column val email: String, @Column val password: String -) : BaseEntity() \ No newline at end of file +) : BaseEntity() + + +enum class Authority { + ROLE_USER, ROLE_ADMIN +} \ No newline at end of file diff --git a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/UserRepository.kt b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/UserRepository.kt index fdec7d44..ef0992e3 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/UserRepository.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/UserRepository.kt @@ -1,7 +1,7 @@ -package io.raemian.springboot.storage.db.core.member +package io.raemian.springboot.storage.db.core.user import org.springframework.data.jpa.repository.JpaRepository -interface MemberRepository : JpaRepository { - fun findByEmail(email: String): Member? +interface UserRepository : JpaRepository { + fun findByEmail(email: String): User? } \ No newline at end of file From 7e918c40260943db4ee127e651ad50a8c747f854 Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Sun, 12 Nov 2023 02:00:00 +0900 Subject: [PATCH 08/70] feat(#1): add jwt login --- core/core-api/build.gradle.kts | 5 + .../springboot/core/auth/config/CorsConfig.kt | 23 ++++ .../core/auth/config/JwtSecurityConfig.kt | 29 +++++ ...SecurityConfig.kt => WebSecurityConfig.kt} | 33 ++++- .../core/auth/controller/AuthController.kt | 19 +-- .../core/auth/domain/SecurityUser.kt | 4 +- .../springboot/core/auth/domain/TokenDTO.kt | 8 ++ .../core/auth/service/AuthService.kt | 20 ++- .../springboot/core/auth/support/JwtFilter.kt | 44 +++++++ .../core/auth/support/SecurityUtil.kt | 16 +++ .../core/auth/support/TokenProvider.kt | 119 ++++++++++++++++++ .../storage/db/core/token/RefreshToken.kt | 12 ++ .../springboot/storage/db/core/user/User.kt | 11 +- 13 files changed, 324 insertions(+), 19 deletions(-) create mode 100644 core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/CorsConfig.kt create mode 100644 core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/JwtSecurityConfig.kt rename core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/{SecurityConfig.kt => WebSecurityConfig.kt} (64%) create mode 100644 core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/TokenDTO.kt create mode 100644 core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/JwtFilter.kt create mode 100644 core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/SecurityUtil.kt create mode 100644 core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/TokenProvider.kt create mode 100644 storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/token/RefreshToken.kt diff --git a/core/core-api/build.gradle.kts b/core/core-api/build.gradle.kts index a40da298..e94875db 100644 --- a/core/core-api/build.gradle.kts +++ b/core/core-api/build.gradle.kts @@ -17,6 +17,11 @@ dependencies { implementation("org.springframework.boot:spring-boot-starter-web") + // jwt + implementation("io.jsonwebtoken:jjwt-api:0.11.5") + runtimeOnly("io.jsonwebtoken:jjwt-impl:0.11.5") + runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.11.5") + // security implementation("org.springframework.boot:spring-boot-starter-security") // oauth-client diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/CorsConfig.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/CorsConfig.kt new file mode 100644 index 00000000..8a79ac47 --- /dev/null +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/CorsConfig.kt @@ -0,0 +1,23 @@ +package io.raemian.springboot.core.auth.config + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.web.cors.CorsConfiguration +import org.springframework.web.cors.UrlBasedCorsConfigurationSource +import org.springframework.web.filter.CorsFilter + + +@Configuration +class CorsConfig { + @Bean + fun corsFilter(): CorsFilter { + val source = UrlBasedCorsConfigurationSource() + val config = CorsConfiguration() + config.allowCredentials = true + config.addAllowedOrigin("*") + config.addAllowedHeader("*") + config.addAllowedMethod("*") + source.registerCorsConfiguration("/api/**", config) + return CorsFilter(source) + } +} \ No newline at end of file diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/JwtSecurityConfig.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/JwtSecurityConfig.kt new file mode 100644 index 00000000..426924f5 --- /dev/null +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/JwtSecurityConfig.kt @@ -0,0 +1,29 @@ +package io.raemian.springboot.core.auth.config + +import io.raemian.springboot.core.auth.support.JwtFilter +import io.raemian.springboot.core.auth.support.TokenProvider +import jakarta.servlet.ServletException +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.springframework.security.config.annotation.SecurityConfigurerAdapter +import org.springframework.security.config.annotation.web.builders.HttpSecurity +import org.springframework.security.core.AuthenticationException +import org.springframework.security.web.AuthenticationEntryPoint +import org.springframework.security.web.DefaultSecurityFilterChain +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter +import org.springframework.stereotype.Component +import org.springframework.security.access.AccessDeniedException +import org.springframework.security.web.access.AccessDeniedHandler + + +class JwtSecurityConfig( + private val tokenProvider: TokenProvider, +) : SecurityConfigurerAdapter() { + + // TokenProvider 를 주입받아서 JwtFilter 를 통해 Security 로직에 필터를 등록 + override fun configure(http: HttpSecurity) { + val customFilter = JwtFilter(tokenProvider) + http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter::class.java) + } +} + diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/SecurityConfig.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/WebSecurityConfig.kt similarity index 64% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/SecurityConfig.kt rename to core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/WebSecurityConfig.kt index afdf67fc..b2cb6dee 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/SecurityConfig.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/WebSecurityConfig.kt @@ -1,5 +1,7 @@ package io.raemian.springboot.core.auth.config +import io.raemian.springboot.core.auth.support.TokenProvider +import jakarta.servlet.http.HttpServletResponse import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.boot.autoconfigure.security.servlet.PathRequest import org.springframework.context.annotation.Bean @@ -7,6 +9,7 @@ import org.springframework.context.annotation.Configuration import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer +import org.springframework.security.config.http.SessionCreationPolicy import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager @@ -16,22 +19,44 @@ import org.springframework.security.oauth2.client.registration.ClientRegistratio import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository import org.springframework.security.web.SecurityFilterChain +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter +import org.springframework.security.web.util.matcher.AntPathRequestMatcher +import org.springframework.web.filter.CorsFilter @Configuration @EnableWebSecurity -class SecurityConfig { +class WebSecurityConfig( + private val corsFilter: CorsFilter, + private val tokenProvider: TokenProvider +) { @Bean fun filterChain(http: HttpSecurity): SecurityFilterChain { - return http + http .csrf { it.disable() } .formLogin { it.disable() } .httpBasic { it.disable() } + .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter::class.java) + .exceptionHandling { + it + .authenticationEntryPoint { request, response, authException -> + // 유효한 자격증명을 제공하지 않고 접근하려 할때 401 + response.sendError(HttpServletResponse.SC_UNAUTHORIZED,) + } + .accessDeniedHandler { request, response, accessDeniedException -> + // 필요한 권한이 없이 접근하려 할때 403 + response.sendError(HttpServletResponse.SC_FORBIDDEN) + } + } .authorizeHttpRequests { - it.anyRequest().permitAll() + it.requestMatchers(AntPathRequestMatcher("/auth/**")).permitAll() + .anyRequest().authenticated() } - .build() + .sessionManagement { it.sessionCreationPolicy(SessionCreationPolicy.STATELESS) } + .apply(JwtSecurityConfig(tokenProvider)) + + return http.build() } @Bean diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt index 3ad04bb4..3025722c 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt @@ -2,6 +2,7 @@ package io.raemian.springboot.core.auth.controller import io.raemian.springboot.core.auth.controller.v1.request.SignInRequest import io.raemian.springboot.core.auth.controller.v1.request.SignUpRequest +import io.raemian.springboot.core.auth.domain.TokenDTO import io.raemian.springboot.core.auth.service.AuthService import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PostMapping @@ -13,19 +14,19 @@ class AuthController( private val authService: AuthService ) { - @GetMapping("/kakao") - fun kk(): String { - return "kko" - } - - @PostMapping("/signup") + @PostMapping("/auth/sign-up") fun signUp(@RequestBody signUpRequest: SignUpRequest): String { authService.save(signUpRequest.email, signUpRequest.password) return "${signUpRequest.email}/${signUpRequest.password}" } - @PostMapping("/signin") - fun signIn(@RequestBody signInRequest: SignInRequest) { - authService.signIn(signInRequest.email, signInRequest.password) + @PostMapping("/auth/sign-in") + fun signIn(@RequestBody signInRequest: SignInRequest): TokenDTO { + return authService.signIn(signInRequest.email, signInRequest.password) + } + + @GetMapping("/auth/my") + fun my() { + } } \ No newline at end of file diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt index 0150fb31..f83651d3 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt @@ -1,12 +1,14 @@ package io.raemian.springboot.core.auth.domain import org.springframework.security.core.GrantedAuthority +import org.springframework.security.core.authority.SimpleGrantedAuthority import org.springframework.security.core.userdetails.User class SecurityUser( username: String, password: String, -) : User(username, password, arrayListOf(SecurityGrantedAuthority())) { + authority: String +) : User(username, password, arrayListOf(SimpleGrantedAuthority(authority))) { } diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/TokenDTO.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/TokenDTO.kt new file mode 100644 index 00000000..7583f2b0 --- /dev/null +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/TokenDTO.kt @@ -0,0 +1,8 @@ +package io.raemian.springboot.core.auth.domain + +data class TokenDTO( + val grantType: String, + val accessToken: String, + val refreshToken: String, + val accessTokenExpiresIn: Long, +) diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt index 49fd0166..b57447f5 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt @@ -1,8 +1,15 @@ package io.raemian.springboot.core.auth.service import io.raemian.springboot.core.auth.domain.SecurityUser +import io.raemian.springboot.core.auth.domain.TokenDTO +import io.raemian.springboot.core.auth.support.TokenProvider +import io.raemian.springboot.storage.db.core.user.Authority import io.raemian.springboot.storage.db.core.user.User import io.raemian.springboot.storage.db.core.user.UserRepository +import org.springframework.security.authentication.AuthenticationManager +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder +import org.springframework.security.core.authority.SimpleGrantedAuthority import org.springframework.security.core.userdetails.UserDetails import org.springframework.security.core.userdetails.UserDetailsService import org.springframework.security.core.userdetails.UsernameNotFoundException @@ -13,6 +20,8 @@ import org.springframework.stereotype.Service class AuthService( private val userRepository: UserRepository, private val passwordEncoder: PasswordEncoder, + private val authenticationManagerBuilder: AuthenticationManagerBuilder, + private val tokenProvider: TokenProvider, ) : UserDetailsService { fun save(email: String, password: String) { @@ -20,16 +29,23 @@ class AuthService( User( email = email, password = passwordEncoder.encode(password), + authority = Authority.USER, ), ) } override fun loadUserByUsername(username: String): UserDetails { val user = userRepository.findByEmail(username) ?: throw UsernameNotFoundException("not found $username") - return SecurityUser(username = user.email, password = user.password) + return SecurityUser(username = user.email, password = user.password, authority = "USER") } - fun signIn(email: String, password: String) { + fun signIn(email: String, password: String): TokenDTO { + val token = UsernamePasswordAuthenticationToken(email, password, arrayListOf(SimpleGrantedAuthority("USER"))) + val authentication = authenticationManagerBuilder.`object`.authenticate(token) + val tokenDTO = tokenProvider.generateTokenDto(authentication) + + + return tokenDTO } } \ No newline at end of file diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/JwtFilter.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/JwtFilter.kt new file mode 100644 index 00000000..2589faae --- /dev/null +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/JwtFilter.kt @@ -0,0 +1,44 @@ +package io.raemian.springboot.core.auth.support + +import jakarta.servlet.FilterChain +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.springframework.security.core.Authentication +import org.springframework.security.core.context.SecurityContextHolder +import org.springframework.util.StringUtils +import org.springframework.web.filter.OncePerRequestFilter + + +class JwtFilter( + private val tokenProvider: TokenProvider, +) : OncePerRequestFilter() { + + + override fun doFilterInternal( + request: HttpServletRequest, + response: HttpServletResponse, + filterChain: FilterChain, + ) { + // 1. Request Header 에서 토큰을 꺼냄 + val jwt: String = resolveToken(request) + + // 2. validateToken 으로 토큰 유효성 검사 + // 정상 토큰이면 해당 토큰으로 Authentication 을 가져와서 SecurityContext 에 저장 + if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) { + val authentication: Authentication = tokenProvider.getAuthentication(jwt) + SecurityContextHolder.getContext().authentication = authentication + } + filterChain.doFilter(request, response) + } + + // Request Header 에서 토큰 정보를 꺼내오기 + private fun resolveToken(request: HttpServletRequest): String { + val AUTHORIZATION_HEADER = "Authorization" + val BEARER_PREFIX = "Bearer " + + val bearerToken = request.getHeader(AUTHORIZATION_HEADER) + return if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(BEARER_PREFIX)) { + bearerToken.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1].trim { it <= ' ' } + } else "" + } +} \ No newline at end of file diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/SecurityUtil.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/SecurityUtil.kt new file mode 100644 index 00000000..d16df2b3 --- /dev/null +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/SecurityUtil.kt @@ -0,0 +1,16 @@ +package io.raemian.springboot.core.auth.support + +import org.springframework.security.core.Authentication +import org.springframework.security.core.context.SecurityContextHolder + + +object SecurityUtil { + // SecurityContext 에 유저 정보가 저장되는 시점 + fun currentMemberId(): Long { + val authentication: Authentication? = SecurityContextHolder.getContext().authentication + if (authentication == null || authentication.name == null) { + throw RuntimeException("Security Context 에 인증 정보가 없습니다.") + } + return authentication.name.toLong() + } +} \ No newline at end of file diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/TokenProvider.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/TokenProvider.kt new file mode 100644 index 00000000..9ebb6a64 --- /dev/null +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/TokenProvider.kt @@ -0,0 +1,119 @@ +package io.raemian.springboot.core.auth.support + +import io.jsonwebtoken.Claims +import io.jsonwebtoken.ExpiredJwtException +import io.jsonwebtoken.Jwts +import io.jsonwebtoken.MalformedJwtException +import io.jsonwebtoken.SignatureAlgorithm +import io.jsonwebtoken.UnsupportedJwtException +import io.jsonwebtoken.io.Decoders +import io.jsonwebtoken.security.Keys +import io.jsonwebtoken.security.SecurityException +import io.raemian.springboot.core.auth.domain.SecurityUser +import io.raemian.springboot.core.auth.domain.TokenDTO +import org.springframework.beans.factory.annotation.Value +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken +import org.springframework.security.core.Authentication +import org.springframework.security.core.GrantedAuthority +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.security.core.userdetails.UserDetails +import org.springframework.stereotype.Component +import java.security.Key +import java.util.Date +import java.util.stream.Collectors + + +@Component +class TokenProvider() { + private val key: Key + + private val secretKey: String = "c3ByaW5nLWJvb3Qtc2VjdXJpdHktand0LXR1dG9yaWFsLWppd29vbi1zcHJpbmctYm9vdC1zZWN1cml0eS1qd3QtdHV0b3JpYWwK" + private val AUTHORITIES_KEY = "auth" + private val BEARER_TYPE = "Bearer" + private val ACCESS_TOKEN_EXPIRE_TIME = (1000 * 60 * 300) // 300분 + private val REFRESH_TOKEN_EXPIRE_TIME = (1000 * 60 * 60 * 24 * 70) // 70일 + + init { + val keyBytes = Decoders.BASE64.decode(secretKey) + key = Keys.hmacShaKeyFor(keyBytes) + } + + fun generateTokenDto(authentication: Authentication): TokenDTO { + // 권한들 가져오기 + val authorities: String = authentication.authorities + .map { obj: GrantedAuthority -> obj.authority } + .joinToString(",") + val now: Long = Date().time + + // Access Token 생성 + val accessTokenExpiresIn = Date(now + ACCESS_TOKEN_EXPIRE_TIME) + val accessToken: String = Jwts.builder() + .setSubject(authentication.getName()) // payload "sub": "name" + .claim(AUTHORITIES_KEY, authorities) // payload "auth": "ROLE_USER" + .setExpiration(accessTokenExpiresIn) // payload "exp": 151621022 (ex) + .signWith(key, SignatureAlgorithm.HS512) // header "alg": "HS512" + .compact() + + // Refresh Token 생성 + val refreshToken: String = Jwts.builder() + .setExpiration(Date(now + REFRESH_TOKEN_EXPIRE_TIME)) + .signWith(key, SignatureAlgorithm.HS512) + .compact() + return TokenDTO( + grantType = BEARER_TYPE, + accessToken = accessToken, + refreshToken = refreshToken, + accessTokenExpiresIn = accessTokenExpiresIn.time, + ) + } + + fun getAuthentication(accessToken: String): Authentication { + // 토큰 복호화 + val claims = parseClaims(accessToken) + if (claims[AUTHORITIES_KEY] == null) { + throw RuntimeException("권한 정보가 없는 토큰입니다.") + } + + claims[AUTHORITIES_KEY].toString().split(",".toRegex()) + // 클레임에서 권한 정보 가져오기 + val authorities: Collection = + claims[AUTHORITIES_KEY].toString().split(",".toRegex()).dropLastWhile { it.isEmpty() } + .toTypedArray() + .map { role: String? -> SimpleGrantedAuthority(role) } + + // UserDetails 객체를 만들어서 Authentication 리턴 + val principal: UserDetails = SecurityUser(claims.subject, "", "USER") + return UsernamePasswordAuthenticationToken(principal, "", authorities) + } + + fun validateToken(token: String?): Boolean { + try { + Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token) + return true + } catch (e: SecurityException) { + // log.info("잘못된 JWT 서명입니다.") + println("securty exception" + e) + } catch (e: MalformedJwtException) { + // log.info("잘못된 JWT 서명입니다.") + println("malformed " + e) + } catch (e: ExpiredJwtException) { + // log.info("만료된 JWT 토큰입니다.") + println("expired token " +e) + } catch (e: UnsupportedJwtException) { + // log.info("지원되지 않는 JWT 토큰입니다.") + println("not supoorted " + e) + } catch (e: IllegalArgumentException) { + // log.info("JWT 토큰이 잘못되었습니다.") + println("illegal " + e) + } + return false + } + + private fun parseClaims(accessToken: String): Claims { + return try { + Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(accessToken).getBody() + } catch (e: ExpiredJwtException) { + e.claims + } + } +} \ No newline at end of file diff --git a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/token/RefreshToken.kt b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/token/RefreshToken.kt new file mode 100644 index 00000000..b7cc405b --- /dev/null +++ b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/token/RefreshToken.kt @@ -0,0 +1,12 @@ +package io.raemian.springboot.storage.db.core.token + +import jakarta.persistence.Entity +import jakarta.persistence.Id + +@Entity +class RefreshToken( + @Id + val id: Long, + val key: String, + val value: String, +) \ No newline at end of file diff --git a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt index bc058d5a..6e6a1252 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt @@ -3,16 +3,21 @@ package io.raemian.springboot.storage.db.core.user import io.raemian.springboot.storage.db.core.BaseEntity import jakarta.persistence.Column import jakarta.persistence.Entity +import jakarta.persistence.EnumType +import jakarta.persistence.Enumerated -@Entity +@Entity(name = "USER_1") class User( @Column val email: String, @Column - val password: String + val password: String, + + @Enumerated(EnumType.STRING) + val authority: Authority ) : BaseEntity() enum class Authority { - ROLE_USER, ROLE_ADMIN + USER, ADMIN } \ No newline at end of file From 02dd51aa1851b64362450b84471c0791c4f32d79 Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Mon, 13 Nov 2023 23:40:46 +0900 Subject: [PATCH 09/70] =?UTF-8?q?feat(#1):=20=EB=A1=9C=EC=BB=AC=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/auth/controller/AuthController.kt | 8 ++-- .../core/auth/domain/SecurityUser.kt | 42 ++++++++++++++----- .../core/auth/service/AuthService.kt | 16 ++++--- .../core/auth/support/TokenProvider.kt | 23 ++++++---- .../springboot/storage/db/core/user/User.kt | 2 +- 5 files changed, 65 insertions(+), 26 deletions(-) diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt index 3025722c..54b284c2 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt @@ -2,8 +2,10 @@ package io.raemian.springboot.core.auth.controller import io.raemian.springboot.core.auth.controller.v1.request.SignInRequest import io.raemian.springboot.core.auth.controller.v1.request.SignUpRequest +import io.raemian.springboot.core.auth.domain.SecurityUser import io.raemian.springboot.core.auth.domain.TokenDTO import io.raemian.springboot.core.auth.service.AuthService +import org.springframework.security.core.annotation.AuthenticationPrincipal import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody @@ -25,8 +27,8 @@ class AuthController( return authService.signIn(signInRequest.email, signInRequest.password) } - @GetMapping("/auth/my") - fun my() { - + @GetMapping("/my") + fun my(@AuthenticationPrincipal user: SecurityUser): SecurityUser { + return user } } \ No newline at end of file diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt index f83651d3..9c3b5df9 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt @@ -3,18 +3,40 @@ package io.raemian.springboot.core.auth.domain import org.springframework.security.core.GrantedAuthority import org.springframework.security.core.authority.SimpleGrantedAuthority import org.springframework.security.core.userdetails.User +import org.springframework.security.core.userdetails.UserDetails -class SecurityUser( - username: String, - password: String, - authority: String -) : User(username, password, arrayListOf(SimpleGrantedAuthority(authority))) { +data class SecurityUser( + val id: Long, + val email: String, + private val password: String, + private val authorities: List = listOf("ROLE_USER"), +) : UserDetails { + + override fun getAuthorities(): MutableCollection { + return authorities.map { + SimpleGrantedAuthority(it) + }.toMutableList() + } + + + override fun getPassword(): String = password + + + override fun getUsername(): String = email + + override fun isAccountNonExpired(): Boolean = true + + override fun isAccountNonLocked(): Boolean = true + + override fun isCredentialsNonExpired(): Boolean = true + + override fun isEnabled(): Boolean = true } -class SecurityGrantedAuthority : GrantedAuthority { - override fun getAuthority(): String { - return "USER" - } -} \ No newline at end of file +// class SecurityGrantedAuthority : GrantedAuthority { +// override fun getAuthority(): String { +// return "ROLE_USER" +// } +// } \ No newline at end of file diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt index b57447f5..1ef35517 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt @@ -15,6 +15,7 @@ import org.springframework.security.core.userdetails.UserDetailsService import org.springframework.security.core.userdetails.UsernameNotFoundException import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.stereotype.Service +import java.lang.IllegalArgumentException @Service class AuthService( @@ -29,22 +30,27 @@ class AuthService( User( email = email, password = passwordEncoder.encode(password), - authority = Authority.USER, + authority = Authority.ROLE_USER, ), ) } override fun loadUserByUsername(username: String): UserDetails { val user = userRepository.findByEmail(username) ?: throw UsernameNotFoundException("not found $username") - return SecurityUser(username = user.email, password = user.password, authority = "USER") + return SecurityUser(id = user.id!!, email = user.email, password = user.password) } fun signIn(email: String, password: String): TokenDTO { - val token = UsernamePasswordAuthenticationToken(email, password, arrayListOf(SimpleGrantedAuthority("USER"))) - val authentication = authenticationManagerBuilder.`object`.authenticate(token) + val user = userRepository.findByEmail(email) ?: throw RuntimeException("아이디 또는 비밀번호 불일치 ") + + if (!passwordEncoder.matches(password, user.password)) { + throw RuntimeException("아이디 또는 비밀번호 불일치 ") + } - val tokenDTO = tokenProvider.generateTokenDto(authentication) + val token = UsernamePasswordAuthenticationToken(email, password, arrayListOf()) + val authentication = authenticationManagerBuilder.`object`.authenticate(token) + val tokenDTO = tokenProvider.generateTokenDto(authentication) return tokenDTO } diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/TokenProvider.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/TokenProvider.kt index 9ebb6a64..e367553d 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/TokenProvider.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/TokenProvider.kt @@ -29,6 +29,8 @@ class TokenProvider() { private val secretKey: String = "c3ByaW5nLWJvb3Qtc2VjdXJpdHktand0LXR1dG9yaWFsLWppd29vbi1zcHJpbmctYm9vdC1zZWN1cml0eS1qd3QtdHV0b3JpYWwK" private val AUTHORITIES_KEY = "auth" + private val EMAIL_KEY = "email" + private val ID_KEY = "id" private val BEARER_TYPE = "Bearer" private val ACCESS_TOKEN_EXPIRE_TIME = (1000 * 60 * 300) // 300분 private val REFRESH_TOKEN_EXPIRE_TIME = (1000 * 60 * 60 * 24 * 70) // 70일 @@ -39,6 +41,7 @@ class TokenProvider() { } fun generateTokenDto(authentication: Authentication): TokenDTO { + val securityUser = authentication.principal as SecurityUser // 권한들 가져오기 val authorities: String = authentication.authorities .map { obj: GrantedAuthority -> obj.authority } @@ -48,8 +51,10 @@ class TokenProvider() { // Access Token 생성 val accessTokenExpiresIn = Date(now + ACCESS_TOKEN_EXPIRE_TIME) val accessToken: String = Jwts.builder() - .setSubject(authentication.getName()) // payload "sub": "name" + .setSubject(authentication.name) // payload "sub": "name" .claim(AUTHORITIES_KEY, authorities) // payload "auth": "ROLE_USER" + .claim(EMAIL_KEY, authentication.name) + .claim(ID_KEY, securityUser.id) .setExpiration(accessTokenExpiresIn) // payload "exp": 151621022 (ex) .signWith(key, SignatureAlgorithm.HS512) // header "alg": "HS512" .compact() @@ -76,14 +81,18 @@ class TokenProvider() { claims[AUTHORITIES_KEY].toString().split(",".toRegex()) // 클레임에서 권한 정보 가져오기 - val authorities: Collection = - claims[AUTHORITIES_KEY].toString().split(",".toRegex()).dropLastWhile { it.isEmpty() } - .toTypedArray() - .map { role: String? -> SimpleGrantedAuthority(role) } + val authorities = claims[AUTHORITIES_KEY] + .toString() + .split(",".toRegex()) + .dropLastWhile { it.isEmpty() } + + val id = claims[ID_KEY] + .toString() + .toLong() // UserDetails 객체를 만들어서 Authentication 리턴 - val principal: UserDetails = SecurityUser(claims.subject, "", "USER") - return UsernamePasswordAuthenticationToken(principal, "", authorities) + val principal = SecurityUser(id = id, claims.subject, "", authorities) + return UsernamePasswordAuthenticationToken(principal, "", principal.authorities) } fun validateToken(token: String?): Boolean { diff --git a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt index 6e6a1252..f0661783 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt @@ -19,5 +19,5 @@ class User( enum class Authority { - USER, ADMIN + ROLE_USER, ROLE_ADMIN } \ No newline at end of file From 53624f7e41c82e066e94a740463820d34028123b Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Mon, 13 Nov 2023 23:42:16 +0900 Subject: [PATCH 10/70] =?UTF-8?q?chore(#1):=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/auth/domain/SecurityUser.kt | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt index 9c3b5df9..2c93bffd 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt @@ -2,7 +2,6 @@ package io.raemian.springboot.core.auth.domain import org.springframework.security.core.GrantedAuthority import org.springframework.security.core.authority.SimpleGrantedAuthority -import org.springframework.security.core.userdetails.User import org.springframework.security.core.userdetails.UserDetails data class SecurityUser( @@ -12,16 +11,14 @@ data class SecurityUser( private val authorities: List = listOf("ROLE_USER"), ) : UserDetails { - override fun getAuthorities(): MutableCollection { - return authorities.map { - SimpleGrantedAuthority(it) - }.toMutableList() - } + override fun getAuthorities(): MutableCollection = + authorities + .map { SimpleGrantedAuthority(it) } + .toMutableList() override fun getPassword(): String = password - override fun getUsername(): String = email override fun isAccountNonExpired(): Boolean = true @@ -32,11 +29,4 @@ data class SecurityUser( override fun isEnabled(): Boolean = true -} - - -// class SecurityGrantedAuthority : GrantedAuthority { -// override fun getAuthority(): String { -// return "ROLE_USER" -// } -// } \ No newline at end of file +} \ No newline at end of file From 27514e39df21bcfa9974bb84a5d62a45df2036f9 Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Mon, 13 Nov 2023 23:53:20 +0900 Subject: [PATCH 11/70] =?UTF-8?q?refact(#1):=20SecurityUser=20->=20Current?= =?UTF-8?q?User=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=9D=B4=EB=A6=84=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/auth/controller/AuthController.kt | 8 ++++---- .../{SecurityUser.kt => CurrentUser.kt} | 2 +- .../core/auth/service/AuthService.kt | 7 ++----- .../core/auth/support/TokenProvider.kt | 19 ++++++++----------- .../springboot/storage/db/core/user/User.kt | 4 ++-- 5 files changed, 17 insertions(+), 23 deletions(-) rename core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/{SecurityUser.kt => CurrentUser.kt} (97%) diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt index 54b284c2..8a005892 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt @@ -2,7 +2,7 @@ package io.raemian.springboot.core.auth.controller import io.raemian.springboot.core.auth.controller.v1.request.SignInRequest import io.raemian.springboot.core.auth.controller.v1.request.SignUpRequest -import io.raemian.springboot.core.auth.domain.SecurityUser +import io.raemian.springboot.core.auth.domain.CurrentUser import io.raemian.springboot.core.auth.domain.TokenDTO import io.raemian.springboot.core.auth.service.AuthService import org.springframework.security.core.annotation.AuthenticationPrincipal @@ -13,7 +13,7 @@ import org.springframework.web.bind.annotation.RestController @RestController class AuthController( - private val authService: AuthService + private val authService: AuthService, ) { @PostMapping("/auth/sign-up") @@ -28,7 +28,7 @@ class AuthController( } @GetMapping("/my") - fun my(@AuthenticationPrincipal user: SecurityUser): SecurityUser { - return user + fun my(@AuthenticationPrincipal currentUser: CurrentUser): CurrentUser { + return currentUser } } \ No newline at end of file diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/CurrentUser.kt similarity index 97% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt rename to core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/CurrentUser.kt index 2c93bffd..84ca38a8 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/SecurityUser.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/CurrentUser.kt @@ -4,7 +4,7 @@ import org.springframework.security.core.GrantedAuthority import org.springframework.security.core.authority.SimpleGrantedAuthority import org.springframework.security.core.userdetails.UserDetails -data class SecurityUser( +data class CurrentUser( val id: Long, val email: String, private val password: String, diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt index 1ef35517..ca0e4679 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt @@ -1,21 +1,18 @@ package io.raemian.springboot.core.auth.service -import io.raemian.springboot.core.auth.domain.SecurityUser +import io.raemian.springboot.core.auth.domain.CurrentUser import io.raemian.springboot.core.auth.domain.TokenDTO import io.raemian.springboot.core.auth.support.TokenProvider import io.raemian.springboot.storage.db.core.user.Authority import io.raemian.springboot.storage.db.core.user.User import io.raemian.springboot.storage.db.core.user.UserRepository -import org.springframework.security.authentication.AuthenticationManager import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder -import org.springframework.security.core.authority.SimpleGrantedAuthority import org.springframework.security.core.userdetails.UserDetails import org.springframework.security.core.userdetails.UserDetailsService import org.springframework.security.core.userdetails.UsernameNotFoundException import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.stereotype.Service -import java.lang.IllegalArgumentException @Service class AuthService( @@ -37,7 +34,7 @@ class AuthService( override fun loadUserByUsername(username: String): UserDetails { val user = userRepository.findByEmail(username) ?: throw UsernameNotFoundException("not found $username") - return SecurityUser(id = user.id!!, email = user.email, password = user.password) + return CurrentUser(id = user.id!!, email = user.email, password = user.password) } fun signIn(email: String, password: String): TokenDTO { diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/TokenProvider.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/TokenProvider.kt index e367553d..a807d279 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/TokenProvider.kt +++ b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/TokenProvider.kt @@ -9,25 +9,22 @@ import io.jsonwebtoken.UnsupportedJwtException import io.jsonwebtoken.io.Decoders import io.jsonwebtoken.security.Keys import io.jsonwebtoken.security.SecurityException -import io.raemian.springboot.core.auth.domain.SecurityUser +import io.raemian.springboot.core.auth.domain.CurrentUser import io.raemian.springboot.core.auth.domain.TokenDTO -import org.springframework.beans.factory.annotation.Value import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.core.Authentication import org.springframework.security.core.GrantedAuthority -import org.springframework.security.core.authority.SimpleGrantedAuthority -import org.springframework.security.core.userdetails.UserDetails import org.springframework.stereotype.Component import java.security.Key import java.util.Date -import java.util.stream.Collectors @Component class TokenProvider() { private val key: Key - private val secretKey: String = "c3ByaW5nLWJvb3Qtc2VjdXJpdHktand0LXR1dG9yaWFsLWppd29vbi1zcHJpbmctYm9vdC1zZWN1cml0eS1qd3QtdHV0b3JpYWwK" + private val secretKey: String = + "c3ByaW5nLWJvb3Qtc2VjdXJpdHktand0LXR1dG9yaWFsLWppd29vbi1zcHJpbmctYm9vdC1zZWN1cml0eS1qd3QtdHV0b3JpYWwK" private val AUTHORITIES_KEY = "auth" private val EMAIL_KEY = "email" private val ID_KEY = "id" @@ -41,7 +38,7 @@ class TokenProvider() { } fun generateTokenDto(authentication: Authentication): TokenDTO { - val securityUser = authentication.principal as SecurityUser + val currentUser = authentication.principal as CurrentUser // 권한들 가져오기 val authorities: String = authentication.authorities .map { obj: GrantedAuthority -> obj.authority } @@ -54,7 +51,7 @@ class TokenProvider() { .setSubject(authentication.name) // payload "sub": "name" .claim(AUTHORITIES_KEY, authorities) // payload "auth": "ROLE_USER" .claim(EMAIL_KEY, authentication.name) - .claim(ID_KEY, securityUser.id) + .claim(ID_KEY, currentUser.id) .setExpiration(accessTokenExpiresIn) // payload "exp": 151621022 (ex) .signWith(key, SignatureAlgorithm.HS512) // header "alg": "HS512" .compact() @@ -91,7 +88,7 @@ class TokenProvider() { .toLong() // UserDetails 객체를 만들어서 Authentication 리턴 - val principal = SecurityUser(id = id, claims.subject, "", authorities) + val principal = CurrentUser(id = id, claims.subject, "", authorities) return UsernamePasswordAuthenticationToken(principal, "", principal.authorities) } @@ -104,10 +101,10 @@ class TokenProvider() { println("securty exception" + e) } catch (e: MalformedJwtException) { // log.info("잘못된 JWT 서명입니다.") - println("malformed " + e) + println("malformed " + e) } catch (e: ExpiredJwtException) { // log.info("만료된 JWT 토큰입니다.") - println("expired token " +e) + println("expired token " + e) } catch (e: UnsupportedJwtException) { // log.info("지원되지 않는 JWT 토큰입니다.") println("not supoorted " + e) diff --git a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt index f0661783..a4ff4856 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt @@ -6,7 +6,7 @@ import jakarta.persistence.Entity import jakarta.persistence.EnumType import jakarta.persistence.Enumerated -@Entity(name = "USER_1") +@Entity(name = "USERS") class User( @Column val email: String, @@ -14,7 +14,7 @@ class User( val password: String, @Enumerated(EnumType.STRING) - val authority: Authority + val authority: Authority, ) : BaseEntity() From 9c6b8165dcce97c844664eedae63b4a92c0f540f Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Mon, 13 Nov 2023 23:59:51 +0900 Subject: [PATCH 12/70] feat(#1): delete ".sprintboot" in path --- .../client/example/ExampleApi.kt | 4 ++-- .../io/raemian/client/example/ExampleClient.kt | 16 ++++++++++++++++ .../client/example/ExampleConfig.kt | 2 +- .../client/example/ExampleRequestDto.kt | 2 +- .../raemian/client/example/ExampleResponseDto.kt | 11 +++++++++++ .../client/example/model/ExampleClientResult.kt | 2 +- .../springboot/client/example/ExampleClient.kt | 16 ---------------- .../client/example/ExampleResponseDto.kt | 11 ----------- .../client/example/ExampleClientTest.kt | 4 ++-- .../{springboot => }/CoreApiApplication.kt | 2 +- .../core/api/config/AsyncConfig.kt | 0 .../core/api/config/AsyncExceptionHandler.kt | 0 .../core/api/controller/ApiControllerAdvice.kt | 0 .../core/api/controller/HealthController.kt | 0 .../core/api/controller/v1/ExampleController.kt | 0 .../controller/v1/request/ExampleRequestDto.kt | 0 .../controller/v1/response/ExampleResponseDto.kt | 0 .../core/api/domain/ExampleData.kt | 0 .../core/api/domain/ExampleResult.kt | 0 .../core/api/domain/ExampleService.kt | 0 .../core/api/support/error/CoreApiException.kt | 0 .../core/api/support/error/ErrorCode.kt | 0 .../core/api/support/error/ErrorMessage.kt | 0 .../core/api/support/error/ErrorType.kt | 0 .../core/api/support/response/ApiResponse.kt | 0 .../core/api/support/response/ResultType.kt | 0 .../core/auth/config/CorsConfig.kt | 2 +- .../core/auth/config/JwtSecurityConfig.kt | 14 +++----------- .../core/auth/config/WebSecurityConfig.kt | 10 +++++----- .../core/auth/controller/AuthController.kt | 12 ++++++------ .../auth/controller/v1/request/SignInRequest.kt | 6 ++++++ .../auth/controller/v1/request/SignUpRequest.kt | 6 ++++++ .../core/auth/domain/CurrentUser.kt | 2 +- .../core/auth/domain/TokenDTO.kt | 2 +- .../core/auth/service/AuthService.kt | 16 ++++++++-------- .../core/auth/support/JwtFilter.kt | 2 +- .../core/auth/support/SecurityUtil.kt | 2 +- .../core/auth/support/TokenProvider.kt | 6 +++--- .../auth/controller/v1/request/SignInRequest.kt | 6 ------ .../auth/controller/v1/request/SignUpRequest.kt | 6 ------ .../kotlin/io/raemian/core/enums/ExampleEnum.kt | 3 +++ .../raemian/springboot/core/enums/ExampleEnum.kt | 3 --- gradle.properties | 2 +- .../storage/db/core/BaseEntity.kt | 2 +- .../storage/db/core/ExampleEntity.kt | 2 +- .../storage/db/core/ExampleRepository.kt | 2 +- .../db/core/config/CoreDataSourceConfig.kt | 2 +- .../storage/db/core/config/CoreJpaConfig.kt | 6 +++--- .../storage/db/core/token/RefreshToken.kt | 2 +- .../storage/db/core/user/User.kt | 4 ++-- .../storage/db/core/user/UserRepository.kt | 2 +- .../{springboot => }/test/api/RestDocsTest.kt | 2 +- .../{springboot => }/test/api/RestDocsUtils.kt | 2 +- 53 files changed, 94 insertions(+), 102 deletions(-) rename clients/client-example/src/main/kotlin/io/raemian/{springboot => }/client/example/ExampleApi.kt (76%) create mode 100644 clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleClient.kt rename clients/client-example/src/main/kotlin/io/raemian/{springboot => }/client/example/ExampleConfig.kt (80%) rename clients/client-example/src/main/kotlin/io/raemian/{springboot => }/client/example/ExampleRequestDto.kt (63%) create mode 100644 clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleResponseDto.kt rename clients/client-example/src/main/kotlin/io/raemian/{springboot => }/client/example/model/ExampleClientResult.kt (56%) delete mode 100644 clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleClient.kt delete mode 100644 clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleResponseDto.kt rename clients/client-example/src/test/kotlin/io/raemian/{springboot => }/client/example/ExampleClientTest.kt (83%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/CoreApiApplication.kt (92%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/api/config/AsyncConfig.kt (100%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/api/config/AsyncExceptionHandler.kt (100%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/api/controller/ApiControllerAdvice.kt (100%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/api/controller/HealthController.kt (100%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/api/controller/v1/ExampleController.kt (100%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/api/controller/v1/request/ExampleRequestDto.kt (100%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/api/controller/v1/response/ExampleResponseDto.kt (100%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/api/domain/ExampleData.kt (100%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/api/domain/ExampleResult.kt (100%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/api/domain/ExampleService.kt (100%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/api/support/error/CoreApiException.kt (100%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/api/support/error/ErrorCode.kt (100%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/api/support/error/ErrorMessage.kt (100%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/api/support/error/ErrorType.kt (100%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/api/support/response/ApiResponse.kt (100%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/api/support/response/ResultType.kt (100%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/auth/config/CorsConfig.kt (93%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/auth/config/JwtSecurityConfig.kt (55%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/auth/config/WebSecurityConfig.kt (95%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/auth/controller/AuthController.kt (72%) create mode 100644 core/core-api/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignInRequest.kt create mode 100644 core/core-api/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignUpRequest.kt rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/auth/domain/CurrentUser.kt (94%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/auth/domain/TokenDTO.kt (75%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/auth/service/AuthService.kt (83%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/auth/support/JwtFilter.kt (97%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/auth/support/SecurityUtil.kt (92%) rename core/core-api/src/main/kotlin/io/raemian/{springboot => }/core/auth/support/TokenProvider.kt (96%) delete mode 100644 core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignInRequest.kt delete mode 100644 core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignUpRequest.kt create mode 100644 core/core-enum/src/main/kotlin/io/raemian/core/enums/ExampleEnum.kt delete mode 100644 core/core-enum/src/main/kotlin/io/raemian/springboot/core/enums/ExampleEnum.kt rename storage/db-core/src/main/kotlin/io/raemian/{springboot => }/storage/db/core/BaseEntity.kt (93%) rename storage/db-core/src/main/kotlin/io/raemian/{springboot => }/storage/db/core/ExampleEntity.kt (77%) rename storage/db-core/src/main/kotlin/io/raemian/{springboot => }/storage/db/core/ExampleRepository.kt (73%) rename storage/db-core/src/main/kotlin/io/raemian/{springboot => }/storage/db/core/config/CoreDataSourceConfig.kt (92%) rename storage/db-core/src/main/kotlin/io/raemian/{springboot => }/storage/db/core/config/CoreJpaConfig.kt (64%) rename storage/db-core/src/main/kotlin/io/raemian/{springboot => }/storage/db/core/token/RefreshToken.kt (76%) rename storage/db-core/src/main/kotlin/io/raemian/{springboot => }/storage/db/core/user/User.kt (78%) rename storage/db-core/src/main/kotlin/io/raemian/{springboot => }/storage/db/core/user/UserRepository.kt (75%) rename tests/api-docs/src/main/kotlin/io/raemian/{springboot => }/test/api/RestDocsTest.kt (98%) rename tests/api-docs/src/main/kotlin/io/raemian/{springboot => }/test/api/RestDocsUtils.kt (94%) diff --git a/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleApi.kt b/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleApi.kt similarity index 76% rename from clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleApi.kt rename to clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleApi.kt index 4dc31e58..e226e60c 100644 --- a/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleApi.kt +++ b/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleApi.kt @@ -1,4 +1,4 @@ -package io.raemian.springboot.client.example +package io.raemian.client.example import org.springframework.cloud.openfeign.FeignClient import org.springframework.http.MediaType @@ -13,5 +13,5 @@ internal interface ExampleApi { value = ["/example/example-api"], consumes = [MediaType.APPLICATION_JSON_VALUE], ) - fun example(@RequestBody request: ExampleRequestDto): ExampleResponseDto + fun example(@RequestBody request: io.raemian.client.example.ExampleRequestDto): io.raemian.client.example.ExampleResponseDto } diff --git a/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleClient.kt b/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleClient.kt new file mode 100644 index 00000000..92a5413b --- /dev/null +++ b/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleClient.kt @@ -0,0 +1,16 @@ +package io.raemian.client.example + +import io.raemian.client.example.model.ExampleClientResult +import org.springframework.stereotype.Component + +@Component +class ExampleClient internal constructor( + private val exampleApi: io.raemian.client.example.ExampleApi, +) { + fun example( + exampleParameter: String, + ): io.raemian.client.example.model.ExampleClientResult { + val request = io.raemian.client.example.ExampleRequestDto(exampleParameter) + return exampleApi.example(request).toResult() + } +} diff --git a/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleConfig.kt b/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleConfig.kt similarity index 80% rename from clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleConfig.kt rename to clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleConfig.kt index 292ca7ec..6c5842fc 100644 --- a/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleConfig.kt +++ b/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleConfig.kt @@ -1,4 +1,4 @@ -package io.raemian.springboot.client.example +package io.raemian.client.example import org.springframework.cloud.openfeign.EnableFeignClients import org.springframework.context.annotation.Configuration diff --git a/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleRequestDto.kt b/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleRequestDto.kt similarity index 63% rename from clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleRequestDto.kt rename to clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleRequestDto.kt index c1575518..cab3cf49 100644 --- a/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleRequestDto.kt +++ b/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleRequestDto.kt @@ -1,4 +1,4 @@ -package io.raemian.springboot.client.example +package io.raemian.client.example internal data class ExampleRequestDto( val exampleRequestValue: String, diff --git a/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleResponseDto.kt b/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleResponseDto.kt new file mode 100644 index 00000000..330b7835 --- /dev/null +++ b/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleResponseDto.kt @@ -0,0 +1,11 @@ +package io.raemian.client.example + +import io.raemian.client.example.model.ExampleClientResult + +internal data class ExampleResponseDto( + val exampleResponseValue: String, +) { + fun toResult(): io.raemian.client.example.model.ExampleClientResult { + return io.raemian.client.example.model.ExampleClientResult(exampleResponseValue) + } +} diff --git a/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/model/ExampleClientResult.kt b/clients/client-example/src/main/kotlin/io/raemian/client/example/model/ExampleClientResult.kt similarity index 56% rename from clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/model/ExampleClientResult.kt rename to clients/client-example/src/main/kotlin/io/raemian/client/example/model/ExampleClientResult.kt index a68d489c..5fb74da1 100644 --- a/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/model/ExampleClientResult.kt +++ b/clients/client-example/src/main/kotlin/io/raemian/client/example/model/ExampleClientResult.kt @@ -1,4 +1,4 @@ -package io.raemian.springboot.client.example.model +package io.raemian.client.example.model data class ExampleClientResult( val exampleResult: String, diff --git a/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleClient.kt b/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleClient.kt deleted file mode 100644 index f73570ad..00000000 --- a/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleClient.kt +++ /dev/null @@ -1,16 +0,0 @@ -package io.raemian.springboot.client.example - -import io.raemian.springboot.client.example.model.ExampleClientResult -import org.springframework.stereotype.Component - -@Component -class ExampleClient internal constructor( - private val exampleApi: ExampleApi, -) { - fun example( - exampleParameter: String, - ): ExampleClientResult { - val request = ExampleRequestDto(exampleParameter) - return exampleApi.example(request).toResult() - } -} diff --git a/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleResponseDto.kt b/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleResponseDto.kt deleted file mode 100644 index d530d0e6..00000000 --- a/clients/client-example/src/main/kotlin/io/raemian/springboot/client/example/ExampleResponseDto.kt +++ /dev/null @@ -1,11 +0,0 @@ -package io.raemian.springboot.client.example - -import io.raemian.springboot.client.example.model.ExampleClientResult - -internal data class ExampleResponseDto( - val exampleResponseValue: String, -) { - fun toResult(): ExampleClientResult { - return ExampleClientResult(exampleResponseValue) - } -} diff --git a/clients/client-example/src/test/kotlin/io/raemian/springboot/client/example/ExampleClientTest.kt b/clients/client-example/src/test/kotlin/io/raemian/client/example/ExampleClientTest.kt similarity index 83% rename from clients/client-example/src/test/kotlin/io/raemian/springboot/client/example/ExampleClientTest.kt rename to clients/client-example/src/test/kotlin/io/raemian/client/example/ExampleClientTest.kt index 19710d16..9e2628cd 100644 --- a/clients/client-example/src/test/kotlin/io/raemian/springboot/client/example/ExampleClientTest.kt +++ b/clients/client-example/src/test/kotlin/io/raemian/client/example/ExampleClientTest.kt @@ -1,4 +1,4 @@ -package io.raemian.springboot.client.example +package io.raemian.client.example import feign.RetryableException import io.raemian.client.ClientExampleContextTest @@ -6,7 +6,7 @@ import org.assertj.core.api.Assertions import org.junit.jupiter.api.Test class ExampleClientTest( - val exampleClient: ExampleClient, + val exampleClient: io.raemian.client.example.ExampleClient, ) : io.raemian.client.ClientExampleContextTest() { @Test fun shouldBeThrownExceptionWhenExample() { diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/CoreApiApplication.kt b/core/core-api/src/main/kotlin/io/raemian/CoreApiApplication.kt similarity index 92% rename from core/core-api/src/main/kotlin/io/raemian/springboot/CoreApiApplication.kt rename to core/core-api/src/main/kotlin/io/raemian/CoreApiApplication.kt index 56be2fad..7a6daa8f 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/CoreApiApplication.kt +++ b/core/core-api/src/main/kotlin/io/raemian/CoreApiApplication.kt @@ -1,4 +1,4 @@ -package io.raemian.springboot +package io.raemian import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.context.properties.ConfigurationPropertiesScan diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/config/AsyncConfig.kt b/core/core-api/src/main/kotlin/io/raemian/core/api/config/AsyncConfig.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/api/config/AsyncConfig.kt rename to core/core-api/src/main/kotlin/io/raemian/core/api/config/AsyncConfig.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/config/AsyncExceptionHandler.kt b/core/core-api/src/main/kotlin/io/raemian/core/api/config/AsyncExceptionHandler.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/api/config/AsyncExceptionHandler.kt rename to core/core-api/src/main/kotlin/io/raemian/core/api/config/AsyncExceptionHandler.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/ApiControllerAdvice.kt b/core/core-api/src/main/kotlin/io/raemian/core/api/controller/ApiControllerAdvice.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/ApiControllerAdvice.kt rename to core/core-api/src/main/kotlin/io/raemian/core/api/controller/ApiControllerAdvice.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/HealthController.kt b/core/core-api/src/main/kotlin/io/raemian/core/api/controller/HealthController.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/HealthController.kt rename to core/core-api/src/main/kotlin/io/raemian/core/api/controller/HealthController.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/v1/ExampleController.kt b/core/core-api/src/main/kotlin/io/raemian/core/api/controller/v1/ExampleController.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/v1/ExampleController.kt rename to core/core-api/src/main/kotlin/io/raemian/core/api/controller/v1/ExampleController.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/v1/request/ExampleRequestDto.kt b/core/core-api/src/main/kotlin/io/raemian/core/api/controller/v1/request/ExampleRequestDto.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/v1/request/ExampleRequestDto.kt rename to core/core-api/src/main/kotlin/io/raemian/core/api/controller/v1/request/ExampleRequestDto.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/v1/response/ExampleResponseDto.kt b/core/core-api/src/main/kotlin/io/raemian/core/api/controller/v1/response/ExampleResponseDto.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/api/controller/v1/response/ExampleResponseDto.kt rename to core/core-api/src/main/kotlin/io/raemian/core/api/controller/v1/response/ExampleResponseDto.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/domain/ExampleData.kt b/core/core-api/src/main/kotlin/io/raemian/core/api/domain/ExampleData.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/api/domain/ExampleData.kt rename to core/core-api/src/main/kotlin/io/raemian/core/api/domain/ExampleData.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/domain/ExampleResult.kt b/core/core-api/src/main/kotlin/io/raemian/core/api/domain/ExampleResult.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/api/domain/ExampleResult.kt rename to core/core-api/src/main/kotlin/io/raemian/core/api/domain/ExampleResult.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/domain/ExampleService.kt b/core/core-api/src/main/kotlin/io/raemian/core/api/domain/ExampleService.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/api/domain/ExampleService.kt rename to core/core-api/src/main/kotlin/io/raemian/core/api/domain/ExampleService.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/error/CoreApiException.kt b/core/core-api/src/main/kotlin/io/raemian/core/api/support/error/CoreApiException.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/error/CoreApiException.kt rename to core/core-api/src/main/kotlin/io/raemian/core/api/support/error/CoreApiException.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/error/ErrorCode.kt b/core/core-api/src/main/kotlin/io/raemian/core/api/support/error/ErrorCode.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/error/ErrorCode.kt rename to core/core-api/src/main/kotlin/io/raemian/core/api/support/error/ErrorCode.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/error/ErrorMessage.kt b/core/core-api/src/main/kotlin/io/raemian/core/api/support/error/ErrorMessage.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/error/ErrorMessage.kt rename to core/core-api/src/main/kotlin/io/raemian/core/api/support/error/ErrorMessage.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/error/ErrorType.kt b/core/core-api/src/main/kotlin/io/raemian/core/api/support/error/ErrorType.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/error/ErrorType.kt rename to core/core-api/src/main/kotlin/io/raemian/core/api/support/error/ErrorType.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/response/ApiResponse.kt b/core/core-api/src/main/kotlin/io/raemian/core/api/support/response/ApiResponse.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/response/ApiResponse.kt rename to core/core-api/src/main/kotlin/io/raemian/core/api/support/response/ApiResponse.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/response/ResultType.kt b/core/core-api/src/main/kotlin/io/raemian/core/api/support/response/ResultType.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/api/support/response/ResultType.kt rename to core/core-api/src/main/kotlin/io/raemian/core/api/support/response/ResultType.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/CorsConfig.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt similarity index 93% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/CorsConfig.kt rename to core/core-api/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt index 8a79ac47..14b70ebe 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/CorsConfig.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt @@ -1,4 +1,4 @@ -package io.raemian.springboot.core.auth.config +package io.raemian.core.auth.config import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/JwtSecurityConfig.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/config/JwtSecurityConfig.kt similarity index 55% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/JwtSecurityConfig.kt rename to core/core-api/src/main/kotlin/io/raemian/core/auth/config/JwtSecurityConfig.kt index 426924f5..7ca9a6e6 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/JwtSecurityConfig.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/config/JwtSecurityConfig.kt @@ -1,19 +1,11 @@ -package io.raemian.springboot.core.auth.config +package io.raemian.core.auth.config -import io.raemian.springboot.core.auth.support.JwtFilter -import io.raemian.springboot.core.auth.support.TokenProvider -import jakarta.servlet.ServletException -import jakarta.servlet.http.HttpServletRequest -import jakarta.servlet.http.HttpServletResponse +import io.raemian.core.auth.support.JwtFilter +import io.raemian.core.auth.support.TokenProvider import org.springframework.security.config.annotation.SecurityConfigurerAdapter import org.springframework.security.config.annotation.web.builders.HttpSecurity -import org.springframework.security.core.AuthenticationException -import org.springframework.security.web.AuthenticationEntryPoint import org.springframework.security.web.DefaultSecurityFilterChain import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter -import org.springframework.stereotype.Component -import org.springframework.security.access.AccessDeniedException -import org.springframework.security.web.access.AccessDeniedHandler class JwtSecurityConfig( diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/WebSecurityConfig.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt similarity index 95% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/WebSecurityConfig.kt rename to core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt index b2cb6dee..2f4cb197 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/config/WebSecurityConfig.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt @@ -1,6 +1,6 @@ -package io.raemian.springboot.core.auth.config +package io.raemian.core.auth.config -import io.raemian.springboot.core.auth.support.TokenProvider +import io.raemian.core.auth.support.TokenProvider import jakarta.servlet.http.HttpServletResponse import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.boot.autoconfigure.security.servlet.PathRequest @@ -28,7 +28,7 @@ import org.springframework.web.filter.CorsFilter @EnableWebSecurity class WebSecurityConfig( private val corsFilter: CorsFilter, - private val tokenProvider: TokenProvider + private val tokenProvider: TokenProvider, ) { @Bean @@ -42,7 +42,7 @@ class WebSecurityConfig( it .authenticationEntryPoint { request, response, authException -> // 유효한 자격증명을 제공하지 않고 접근하려 할때 401 - response.sendError(HttpServletResponse.SC_UNAUTHORIZED,) + response.sendError(HttpServletResponse.SC_UNAUTHORIZED) } .accessDeniedHandler { request, response, accessDeniedException -> // 필요한 권한이 없이 접근하려 할때 403 @@ -56,7 +56,7 @@ class WebSecurityConfig( .sessionManagement { it.sessionCreationPolicy(SessionCreationPolicy.STATELESS) } .apply(JwtSecurityConfig(tokenProvider)) - return http.build() + return http.build() } @Bean diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/controller/AuthController.kt similarity index 72% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt rename to core/core-api/src/main/kotlin/io/raemian/core/auth/controller/AuthController.kt index 8a005892..9ee9ee7d 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/AuthController.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/controller/AuthController.kt @@ -1,10 +1,10 @@ -package io.raemian.springboot.core.auth.controller +package io.raemian.core.auth.controller -import io.raemian.springboot.core.auth.controller.v1.request.SignInRequest -import io.raemian.springboot.core.auth.controller.v1.request.SignUpRequest -import io.raemian.springboot.core.auth.domain.CurrentUser -import io.raemian.springboot.core.auth.domain.TokenDTO -import io.raemian.springboot.core.auth.service.AuthService +import io.raemian.core.auth.controller.v1.request.SignInRequest +import io.raemian.core.auth.controller.v1.request.SignUpRequest +import io.raemian.core.auth.domain.CurrentUser +import io.raemian.core.auth.domain.TokenDTO +import io.raemian.core.auth.service.AuthService import org.springframework.security.core.annotation.AuthenticationPrincipal import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PostMapping diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignInRequest.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignInRequest.kt new file mode 100644 index 00000000..1024b3dd --- /dev/null +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignInRequest.kt @@ -0,0 +1,6 @@ +package io.raemian.core.auth.controller.v1.request + +data class SignInRequest( + val email: String, + val password: String, +) diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignUpRequest.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignUpRequest.kt new file mode 100644 index 00000000..26381353 --- /dev/null +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignUpRequest.kt @@ -0,0 +1,6 @@ +package io.raemian.core.auth.controller.v1.request + +data class SignUpRequest( + val email: String, + val password: String, +) diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/CurrentUser.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt similarity index 94% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/CurrentUser.kt rename to core/core-api/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt index 84ca38a8..1d10581a 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/CurrentUser.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt @@ -1,4 +1,4 @@ -package io.raemian.springboot.core.auth.domain +package io.raemian.core.auth.domain import org.springframework.security.core.GrantedAuthority import org.springframework.security.core.authority.SimpleGrantedAuthority diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/TokenDTO.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/domain/TokenDTO.kt similarity index 75% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/TokenDTO.kt rename to core/core-api/src/main/kotlin/io/raemian/core/auth/domain/TokenDTO.kt index 7583f2b0..8caa3a88 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/domain/TokenDTO.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/domain/TokenDTO.kt @@ -1,4 +1,4 @@ -package io.raemian.springboot.core.auth.domain +package io.raemian.core.auth.domain data class TokenDTO( val grantType: String, diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/service/AuthService.kt similarity index 83% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt rename to core/core-api/src/main/kotlin/io/raemian/core/auth/service/AuthService.kt index ca0e4679..5e25da90 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/service/AuthService.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/service/AuthService.kt @@ -1,11 +1,11 @@ -package io.raemian.springboot.core.auth.service - -import io.raemian.springboot.core.auth.domain.CurrentUser -import io.raemian.springboot.core.auth.domain.TokenDTO -import io.raemian.springboot.core.auth.support.TokenProvider -import io.raemian.springboot.storage.db.core.user.Authority -import io.raemian.springboot.storage.db.core.user.User -import io.raemian.springboot.storage.db.core.user.UserRepository +package io.raemian.core.auth.service + +import io.raemian.core.auth.domain.CurrentUser +import io.raemian.core.auth.domain.TokenDTO +import io.raemian.core.auth.support.TokenProvider +import io.raemian.storage.db.core.user.Authority +import io.raemian.storage.db.core.user.User +import io.raemian.storage.db.core.user.UserRepository import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder import org.springframework.security.core.userdetails.UserDetails diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/JwtFilter.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/support/JwtFilter.kt similarity index 97% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/JwtFilter.kt rename to core/core-api/src/main/kotlin/io/raemian/core/auth/support/JwtFilter.kt index 2589faae..9129fa78 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/JwtFilter.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/support/JwtFilter.kt @@ -1,4 +1,4 @@ -package io.raemian.springboot.core.auth.support +package io.raemian.core.auth.support import jakarta.servlet.FilterChain import jakarta.servlet.http.HttpServletRequest diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/SecurityUtil.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/support/SecurityUtil.kt similarity index 92% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/SecurityUtil.kt rename to core/core-api/src/main/kotlin/io/raemian/core/auth/support/SecurityUtil.kt index d16df2b3..b6d63b9f 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/SecurityUtil.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/support/SecurityUtil.kt @@ -1,4 +1,4 @@ -package io.raemian.springboot.core.auth.support +package io.raemian.core.auth.support import org.springframework.security.core.Authentication import org.springframework.security.core.context.SecurityContextHolder diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/TokenProvider.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt similarity index 96% rename from core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/TokenProvider.kt rename to core/core-api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt index a807d279..8bdb592e 100644 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/support/TokenProvider.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt @@ -1,4 +1,4 @@ -package io.raemian.springboot.core.auth.support +package io.raemian.core.auth.support import io.jsonwebtoken.Claims import io.jsonwebtoken.ExpiredJwtException @@ -9,8 +9,8 @@ import io.jsonwebtoken.UnsupportedJwtException import io.jsonwebtoken.io.Decoders import io.jsonwebtoken.security.Keys import io.jsonwebtoken.security.SecurityException -import io.raemian.springboot.core.auth.domain.CurrentUser -import io.raemian.springboot.core.auth.domain.TokenDTO +import io.raemian.core.auth.domain.CurrentUser +import io.raemian.core.auth.domain.TokenDTO import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.core.Authentication import org.springframework.security.core.GrantedAuthority diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignInRequest.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignInRequest.kt deleted file mode 100644 index ce413aa8..00000000 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignInRequest.kt +++ /dev/null @@ -1,6 +0,0 @@ -package io.raemian.springboot.core.auth.controller.v1.request - -data class SignInRequest( - val email: String, - val password: String -) diff --git a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignUpRequest.kt b/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignUpRequest.kt deleted file mode 100644 index 5636d912..00000000 --- a/core/core-api/src/main/kotlin/io/raemian/springboot/core/auth/controller/v1/request/SignUpRequest.kt +++ /dev/null @@ -1,6 +0,0 @@ -package io.raemian.springboot.core.auth.controller.v1.request - -data class SignUpRequest( - val email: String, - val password: String -) diff --git a/core/core-enum/src/main/kotlin/io/raemian/core/enums/ExampleEnum.kt b/core/core-enum/src/main/kotlin/io/raemian/core/enums/ExampleEnum.kt new file mode 100644 index 00000000..d70a270d --- /dev/null +++ b/core/core-enum/src/main/kotlin/io/raemian/core/enums/ExampleEnum.kt @@ -0,0 +1,3 @@ +package io.raemian.core.enums + +enum class ExampleEnum diff --git a/core/core-enum/src/main/kotlin/io/raemian/springboot/core/enums/ExampleEnum.kt b/core/core-enum/src/main/kotlin/io/raemian/springboot/core/enums/ExampleEnum.kt deleted file mode 100644 index caba3010..00000000 --- a/core/core-enum/src/main/kotlin/io/raemian/springboot/core/enums/ExampleEnum.kt +++ /dev/null @@ -1,3 +0,0 @@ -package io.raemian.springboot.core.enums - -enum class ExampleEnum diff --git a/gradle.properties b/gradle.properties index 1186a712..87912b23 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ applicationVersion=0.0.1-SNAPSHOT ### Project configs ### -projectGroup=io.raemian.springboot +projectGroup=io.raemian ### Project depdency versions ### kotlinVersion=1.9.20 diff --git a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/BaseEntity.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/BaseEntity.kt similarity index 93% rename from storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/BaseEntity.kt rename to storage/db-core/src/main/kotlin/io/raemian/storage/db/core/BaseEntity.kt index 1fd34a79..b63d965d 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/BaseEntity.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/BaseEntity.kt @@ -1,4 +1,4 @@ -package io.raemian.springboot.storage.db.core +package io.raemian.storage.db.core import jakarta.persistence.Column import jakarta.persistence.GeneratedValue diff --git a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/ExampleEntity.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/ExampleEntity.kt similarity index 77% rename from storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/ExampleEntity.kt rename to storage/db-core/src/main/kotlin/io/raemian/storage/db/core/ExampleEntity.kt index 47f5203b..ce6e15a9 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/ExampleEntity.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/ExampleEntity.kt @@ -1,4 +1,4 @@ -package io.raemian.springboot.storage.db.core +package io.raemian.storage.db.core import jakarta.persistence.Column import jakarta.persistence.Entity diff --git a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/ExampleRepository.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/ExampleRepository.kt similarity index 73% rename from storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/ExampleRepository.kt rename to storage/db-core/src/main/kotlin/io/raemian/storage/db/core/ExampleRepository.kt index 8085adbb..e0f2ab06 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/ExampleRepository.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/ExampleRepository.kt @@ -1,4 +1,4 @@ -package io.raemian.springboot.storage.db.core +package io.raemian.storage.db.core import org.springframework.data.jpa.repository.JpaRepository diff --git a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/config/CoreDataSourceConfig.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/config/CoreDataSourceConfig.kt similarity index 92% rename from storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/config/CoreDataSourceConfig.kt rename to storage/db-core/src/main/kotlin/io/raemian/storage/db/core/config/CoreDataSourceConfig.kt index abe8d485..580e9610 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/config/CoreDataSourceConfig.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/config/CoreDataSourceConfig.kt @@ -1,4 +1,4 @@ -package io.raemian.springboot.storage.db.core.config +package io.raemian.storage.db.core.config import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource diff --git a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/config/CoreJpaConfig.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/config/CoreJpaConfig.kt similarity index 64% rename from storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/config/CoreJpaConfig.kt rename to storage/db-core/src/main/kotlin/io/raemian/storage/db/core/config/CoreJpaConfig.kt index fbcefe35..07b71fa5 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/config/CoreJpaConfig.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/config/CoreJpaConfig.kt @@ -1,4 +1,4 @@ -package io.raemian.springboot.storage.db.core.config +package io.raemian.storage.db.core.config import org.springframework.boot.autoconfigure.domain.EntityScan import org.springframework.context.annotation.Configuration @@ -7,6 +7,6 @@ import org.springframework.transaction.annotation.EnableTransactionManagement @Configuration @EnableTransactionManagement -@EntityScan(basePackages = ["io.raemian.springboot.storage.db.core"]) -@EnableJpaRepositories(basePackages = ["io.raemian.springboot.storage.db.core"]) +@EntityScan(basePackages = ["io.raemian.storage.db.core"]) +@EnableJpaRepositories(basePackages = ["io.raemian.storage.db.core"]) internal class CoreJpaConfig diff --git a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/token/RefreshToken.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/token/RefreshToken.kt similarity index 76% rename from storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/token/RefreshToken.kt rename to storage/db-core/src/main/kotlin/io/raemian/storage/db/core/token/RefreshToken.kt index b7cc405b..aa8970d7 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/token/RefreshToken.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/token/RefreshToken.kt @@ -1,4 +1,4 @@ -package io.raemian.springboot.storage.db.core.token +package io.raemian.storage.db.core.token import jakarta.persistence.Entity import jakarta.persistence.Id diff --git a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt similarity index 78% rename from storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt rename to storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt index a4ff4856..a4428806 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/User.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt @@ -1,6 +1,6 @@ -package io.raemian.springboot.storage.db.core.user +package io.raemian.storage.db.core.user -import io.raemian.springboot.storage.db.core.BaseEntity +import io.raemian.storage.db.core.BaseEntity import jakarta.persistence.Column import jakarta.persistence.Entity import jakarta.persistence.EnumType diff --git a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/UserRepository.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/UserRepository.kt similarity index 75% rename from storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/UserRepository.kt rename to storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/UserRepository.kt index ef0992e3..01c52467 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/springboot/storage/db/core/user/UserRepository.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/UserRepository.kt @@ -1,4 +1,4 @@ -package io.raemian.springboot.storage.db.core.user +package io.raemian.storage.db.core.user import org.springframework.data.jpa.repository.JpaRepository diff --git a/tests/api-docs/src/main/kotlin/io/raemian/springboot/test/api/RestDocsTest.kt b/tests/api-docs/src/main/kotlin/io/raemian/test/api/RestDocsTest.kt similarity index 98% rename from tests/api-docs/src/main/kotlin/io/raemian/springboot/test/api/RestDocsTest.kt rename to tests/api-docs/src/main/kotlin/io/raemian/test/api/RestDocsTest.kt index e763c844..45982570 100644 --- a/tests/api-docs/src/main/kotlin/io/raemian/springboot/test/api/RestDocsTest.kt +++ b/tests/api-docs/src/main/kotlin/io/raemian/test/api/RestDocsTest.kt @@ -1,4 +1,4 @@ -package io.raemian.springboot.test.api +package io.raemian.test.api import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.SerializationFeature diff --git a/tests/api-docs/src/main/kotlin/io/raemian/springboot/test/api/RestDocsUtils.kt b/tests/api-docs/src/main/kotlin/io/raemian/test/api/RestDocsUtils.kt similarity index 94% rename from tests/api-docs/src/main/kotlin/io/raemian/springboot/test/api/RestDocsUtils.kt rename to tests/api-docs/src/main/kotlin/io/raemian/test/api/RestDocsUtils.kt index cd041518..00832701 100644 --- a/tests/api-docs/src/main/kotlin/io/raemian/springboot/test/api/RestDocsUtils.kt +++ b/tests/api-docs/src/main/kotlin/io/raemian/test/api/RestDocsUtils.kt @@ -1,4 +1,4 @@ -package io.raemian.springboot.test.api +package io.raemian.test.api import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor From 9302cdd51053dc37aa915d0b004d9a9821bae8d2 Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Tue, 14 Nov 2023 01:59:44 +0900 Subject: [PATCH 13/70] feat(#1): add oauth2 --- .../core/api/controller/FaviconController.kt | 14 ++++ .../io/raemian/core/auth/config/CorsConfig.kt | 2 +- .../core/auth/config/WebSecurityConfig.kt | 24 +++++- .../core/auth/controller/AuthController.kt | 1 + .../raemian/core/auth/domain/CurrentUser.kt | 7 +- .../core/auth/service/OAuth2UserService.kt | 76 +++++++++++++++++++ .../core/auth/support/TokenProvider.kt | 30 ++++++++ .../src/main/resources/application.yml | 38 ++++++++++ .../controller/v1/ExampleControllerTest.kt | 10 +-- .../storage/db/core/user/UserRepository.kt | 1 + 10 files changed, 195 insertions(+), 8 deletions(-) create mode 100644 core/core-api/src/main/kotlin/io/raemian/core/api/controller/FaviconController.kt create mode 100644 core/core-api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/api/controller/FaviconController.kt b/core/core-api/src/main/kotlin/io/raemian/core/api/controller/FaviconController.kt new file mode 100644 index 00000000..8024768d --- /dev/null +++ b/core/core-api/src/main/kotlin/io/raemian/core/api/controller/FaviconController.kt @@ -0,0 +1,14 @@ +package io.raemian.core.api.controller + +import org.springframework.stereotype.Controller +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.ResponseBody + + +@Controller +class FaviconController { + @GetMapping("favicon.ico") + @ResponseBody + fun returnNoFavicon() { + } +} \ No newline at end of file diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt index 14b70ebe..12bfab95 100644 --- a/core/core-api/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt @@ -17,7 +17,7 @@ class CorsConfig { config.addAllowedOrigin("*") config.addAllowedHeader("*") config.addAllowedMethod("*") - source.registerCorsConfiguration("/api/**", config) + source.registerCorsConfiguration("/**", config) return CorsFilter(source) } } \ No newline at end of file diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt index 2f4cb197..0ad176ab 100644 --- a/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt @@ -1,11 +1,14 @@ package io.raemian.core.auth.config +import io.raemian.core.auth.domain.CurrentUser +import io.raemian.core.auth.service.OAuth2UserService import io.raemian.core.auth.support.TokenProvider import jakarta.servlet.http.HttpServletResponse import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.boot.autoconfigure.security.servlet.PathRequest import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration +import org.springframework.http.MediaType import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer @@ -22,6 +25,7 @@ import org.springframework.security.web.SecurityFilterChain import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter import org.springframework.security.web.util.matcher.AntPathRequestMatcher import org.springframework.web.filter.CorsFilter +import java.nio.charset.StandardCharsets @Configuration @@ -29,6 +33,7 @@ import org.springframework.web.filter.CorsFilter class WebSecurityConfig( private val corsFilter: CorsFilter, private val tokenProvider: TokenProvider, + private val oAuth2UserService: OAuth2UserService, ) { @Bean @@ -51,7 +56,23 @@ class WebSecurityConfig( } .authorizeHttpRequests { it.requestMatchers(AntPathRequestMatcher("/auth/**")).permitAll() - .anyRequest().authenticated() + .anyRequest().permitAll() + } + .oauth2Login { + it.userInfoEndpoint { endpoint -> endpoint.userService(oAuth2UserService) } + it.successHandler { request, response, authentication -> + val user = authentication.principal as CurrentUser + response.contentType = MediaType.APPLICATION_JSON_VALUE + response.characterEncoding = StandardCharsets.UTF_8.name() + + val tokenDTO = tokenProvider.generateTokenDtoV2(user) + response.addHeader("x-token", tokenDTO.accessToken) + } + it.failureHandler { request, response, exception -> + println("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + exception) + response.addHeader("x-token", "ccc") + } + } .sessionManagement { it.sessionCreationPolicy(SessionCreationPolicy.STATELESS) } .apply(JwtSecurityConfig(tokenProvider)) @@ -66,6 +87,7 @@ class WebSecurityConfig( it .ignoring() .requestMatchers(PathRequest.toH2Console()) + .requestMatchers(AntPathRequestMatcher("/favicon.ico")) } } diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/controller/AuthController.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/controller/AuthController.kt index 9ee9ee7d..d32f7dbd 100644 --- a/core/core-api/src/main/kotlin/io/raemian/core/auth/controller/AuthController.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/controller/AuthController.kt @@ -31,4 +31,5 @@ class AuthController( fun my(@AuthenticationPrincipal currentUser: CurrentUser): CurrentUser { return currentUser } + } \ No newline at end of file diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt index 1d10581a..5cf61828 100644 --- a/core/core-api/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt @@ -3,13 +3,18 @@ package io.raemian.core.auth.domain import org.springframework.security.core.GrantedAuthority import org.springframework.security.core.authority.SimpleGrantedAuthority import org.springframework.security.core.userdetails.UserDetails +import org.springframework.security.oauth2.core.user.OAuth2User data class CurrentUser( val id: Long, val email: String, private val password: String, private val authorities: List = listOf("ROLE_USER"), -) : UserDetails { +) : UserDetails, OAuth2User { + + override fun getName(): String = email + + override fun getAttributes(): MutableMap = mutableMapOf() override fun getAuthorities(): MutableCollection = authorities diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt new file mode 100644 index 00000000..aba4bb2f --- /dev/null +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt @@ -0,0 +1,76 @@ +package io.raemian.core.auth.service + +import io.raemian.core.auth.domain.CurrentUser +import io.raemian.core.auth.support.TokenProvider +import io.raemian.storage.db.core.user.Authority +import io.raemian.storage.db.core.user.User +import io.raemian.storage.db.core.user.UserRepository +import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService +import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest +import org.springframework.security.oauth2.core.user.OAuth2User +import org.springframework.stereotype.Service + +@Service +class OAuth2UserService( + private val userRepository: UserRepository, + private val tokenProvider: TokenProvider, + // private val authenticationManagerBuilder: AuthenticationManagerBuilder, +) : DefaultOAuth2UserService() { + override fun loadUser(userRequest: OAuth2UserRequest): OAuth2User { + val oAuth2User = super.loadUser(userRequest) + val usernameAttributeName = userRequest.clientRegistration + .providerDetails + .userInfoEndpoint + .userNameAttributeName + return when (userRequest.clientRegistration.registrationId) { + "google" -> { + val email = oAuth2User.attributes["email"]?.toString() ?: throw RuntimeException("이메일이없음") + val name = oAuth2User.attributes["name"] + val user = userRepository.findByEmail(email) + if (user == null) { + val created = userRepository.save( + User( + email = email, + password = "", + authority = Authority.ROLE_USER, + ), + ) + return CurrentUser( + id = created.id!!, + email = created.email, + password = "", + authorities = listOf(), + ) + } + return CurrentUser(id = user.id!!, email, "", listOf()) + } + + "naver" -> { + val userInfo = oAuth2User.attributes[usernameAttributeName] as Map + val email = userInfo["email"] ?: throw RuntimeException("이메일없음") + val user = userRepository.findByEmail(email) + if (user == null) { + val created = userRepository.save( + User( + email = email, + password = "", + authority = Authority.ROLE_USER, + ), + ) + return CurrentUser( + id = created.id!!, + email = created.email, + password = "", + authorities = listOf(), + ) + } + return CurrentUser(user.id!!, email, "", listOf()) + } + + else -> throw RuntimeException("errrr") + } + + + // userRepository.findByEmail() + } +} \ No newline at end of file diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt index 8bdb592e..508bf141 100644 --- a/core/core-api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt @@ -37,6 +37,36 @@ class TokenProvider() { key = Keys.hmacShaKeyFor(keyBytes) } + fun generateTokenDtoV2(currentUser: CurrentUser): TokenDTO { + val authorities: String = currentUser.authorities + .map { obj: GrantedAuthority -> obj.authority } + .joinToString(",") + val now: Long = Date().time + + // Access Token 생성 + val accessTokenExpiresIn = Date(now + ACCESS_TOKEN_EXPIRE_TIME) + val accessToken: String = Jwts.builder() + .setSubject(currentUser.email) // payload "sub": "name" + .claim(AUTHORITIES_KEY, authorities) // payload "auth": "ROLE_USER" + .claim(EMAIL_KEY, currentUser.email) + .claim(ID_KEY, currentUser.id) + .setExpiration(accessTokenExpiresIn) // payload "exp": 151621022 (ex) + .signWith(key, SignatureAlgorithm.HS512) // header "alg": "HS512" + .compact() + + // Refresh Token 생성 + val refreshToken: String = Jwts.builder() + .setExpiration(Date(now + REFRESH_TOKEN_EXPIRE_TIME)) + .signWith(key, SignatureAlgorithm.HS512) + .compact() + return TokenDTO( + grantType = BEARER_TYPE, + accessToken = accessToken, + refreshToken = refreshToken, + accessTokenExpiresIn = accessTokenExpiresIn.time, + ) + } + fun generateTokenDto(authentication: Authentication): TokenDTO { val currentUser = authentication.principal as CurrentUser // 권한들 가져오기 diff --git a/core/core-api/src/main/resources/application.yml b/core/core-api/src/main/resources/application.yml index 4cede0ff..0c7b770e 100644 --- a/core/core-api/src/main/resources/application.yml +++ b/core/core-api/src/main/resources/application.yml @@ -10,6 +10,44 @@ spring: - client-example.yml mvc.throw-exception-if-no-handler-found: true web.resources.add-mappings: false + security: + oauth2: + client: + provider: + kakao: + authorization-uri: https://kauth.kakao.com/oauth/authorize + token-uri: https://kauth.kakao.com/oauth/token + user-info-uri: https://kapi.kakao.com/v2/user/me + user-name-attribute: id + naver: + authorization_uri: https://nid.naver.com/oauth2.0/authorize + token_uri: https://nid.naver.com/oauth2.0/token + user-info-uri: https://openapi.naver.com/v1/nid/me + user_name_attribute: response + registration: + kakao: + client-id: 303a910470dcf31025f848d901654bb8 + client-secret: dNF4uFxE5PdlSJWOqrx52ywVO5DeuXoP + client-authentication-method: client_secret_post + redirect-uri: http://localhost:8080/login/oauth2/code/kakao + authorization-grant-type: authorization_code + client-name: kakao + scope: + - profile_nickname +# - account_email + naver: + client-id: f0Y2iXBYxDsBPH699BkC + client-secret: xxOOW3Nr6X + redirect-uri: http://localhost:8080/login/oauth2/code/naver + authorization-grant-type: authorization_code + scope: name, email + client-name: naver + google: + client-id: 1007090557425-sk34pslk4o74bn9nc0oi4hrt77o30o7k.apps.googleusercontent.com + client-secret: U9PXLzkdKmdqUzuyGN-kyHa9 + scope: + - email + - profile --- spring.config.activate.on-profile: local diff --git a/core/core-api/src/test/kotlin/io/raemian/core/api/controller/v1/ExampleControllerTest.kt b/core/core-api/src/test/kotlin/io/raemian/core/api/controller/v1/ExampleControllerTest.kt index 819350f3..db839bdc 100644 --- a/core/core-api/src/test/kotlin/io/raemian/core/api/controller/v1/ExampleControllerTest.kt +++ b/core/core-api/src/test/kotlin/io/raemian/core/api/controller/v1/ExampleControllerTest.kt @@ -1,13 +1,13 @@ package io.raemian.core.api.controller.v1 +import io.mockk.every +import io.mockk.mockk import io.raemian.core.api.controller.v1.request.ExampleRequestDto import io.raemian.core.api.domain.ExampleResult import io.raemian.core.api.domain.ExampleService -import io.raemian.springboot.test.api.RestDocsTest -import io.raemian.springboot.test.api.RestDocsUtils.requestPreprocessor -import io.raemian.springboot.test.api.RestDocsUtils.responsePreprocessor -import io.mockk.every -import io.mockk.mockk +import io.raemian.test.api.RestDocsTest +import io.raemian.test.api.RestDocsUtils.requestPreprocessor +import io.raemian.test.api.RestDocsUtils.responsePreprocessor import io.restassured.http.ContentType import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/UserRepository.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/UserRepository.kt index 01c52467..d35eda34 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/UserRepository.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/UserRepository.kt @@ -4,4 +4,5 @@ import org.springframework.data.jpa.repository.JpaRepository interface UserRepository : JpaRepository { fun findByEmail(email: String): User? + fun existsByEmail(email: String): Boolean } \ No newline at end of file From 064b44941751ec1ea7dac807c1b987ff0dc58b00 Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Tue, 14 Nov 2023 21:47:39 +0900 Subject: [PATCH 14/70] =?UTF-8?q?feat(#1):=20oauth2=20=EC=B9=B4=EC=B9=B4?= =?UTF-8?q?=EC=98=A4=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application.yml | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/core/core-api/src/main/resources/application.yml b/core/core-api/src/main/resources/application.yml index 0c7b770e..bf914850 100644 --- a/core/core-api/src/main/resources/application.yml +++ b/core/core-api/src/main/resources/application.yml @@ -14,33 +14,20 @@ spring: oauth2: client: provider: - kakao: - authorization-uri: https://kauth.kakao.com/oauth/authorize - token-uri: https://kauth.kakao.com/oauth/token - user-info-uri: https://kapi.kakao.com/v2/user/me - user-name-attribute: id naver: authorization_uri: https://nid.naver.com/oauth2.0/authorize token_uri: https://nid.naver.com/oauth2.0/token user-info-uri: https://openapi.naver.com/v1/nid/me user_name_attribute: response registration: - kakao: - client-id: 303a910470dcf31025f848d901654bb8 - client-secret: dNF4uFxE5PdlSJWOqrx52ywVO5DeuXoP - client-authentication-method: client_secret_post - redirect-uri: http://localhost:8080/login/oauth2/code/kakao - authorization-grant-type: authorization_code - client-name: kakao - scope: - - profile_nickname -# - account_email naver: client-id: f0Y2iXBYxDsBPH699BkC client-secret: xxOOW3Nr6X redirect-uri: http://localhost:8080/login/oauth2/code/naver authorization-grant-type: authorization_code - scope: name, email + scope: + - email + - name client-name: naver google: client-id: 1007090557425-sk34pslk4o74bn9nc0oi4hrt77o30o7k.apps.googleusercontent.com From 2760e918b5e3897ad9cf9355b8c0a4b1425b560e Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Tue, 14 Nov 2023 22:18:34 +0900 Subject: [PATCH 15/70] chore(#1): edit println -> logger --- .../core/auth/config/WebSecurityConfig.kt | 30 +++---------------- .../core/auth/support/TokenProvider.kt | 19 ++++++------ 2 files changed, 13 insertions(+), 36 deletions(-) diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt index 0ad176ab..c3d8efff 100644 --- a/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt @@ -4,6 +4,7 @@ import io.raemian.core.auth.domain.CurrentUser import io.raemian.core.auth.service.OAuth2UserService import io.raemian.core.auth.support.TokenProvider import jakarta.servlet.http.HttpServletResponse +import org.slf4j.LoggerFactory import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.boot.autoconfigure.security.servlet.PathRequest import org.springframework.context.annotation.Bean @@ -15,12 +16,6 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur import org.springframework.security.config.http.SessionCreationPolicy import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder import org.springframework.security.crypto.password.PasswordEncoder -import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager -import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider -import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder -import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository -import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager -import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository import org.springframework.security.web.SecurityFilterChain import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter import org.springframework.security.web.util.matcher.AntPathRequestMatcher @@ -36,6 +31,8 @@ class WebSecurityConfig( private val oAuth2UserService: OAuth2UserService, ) { + private val log = LoggerFactory.getLogger(javaClass) + @Bean fun filterChain(http: HttpSecurity): SecurityFilterChain { http @@ -69,7 +66,7 @@ class WebSecurityConfig( response.addHeader("x-token", tokenDTO.accessToken) } it.failureHandler { request, response, exception -> - println("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + exception) + log.info("eeeeeeeeeeeeeeeeeeee + ${exception.message}") response.addHeader("x-token", "ccc") } @@ -95,23 +92,4 @@ class WebSecurityConfig( fun getPasswordEncoder(): PasswordEncoder { return BCryptPasswordEncoder() } - - // @Bean - fun authorizedClientManager( - clientRegistrationRepository: ClientRegistrationRepository, - authorizedClientRepository: OAuth2AuthorizedClientRepository, - ): OAuth2AuthorizedClientManager { - val authorizedClientProvider: OAuth2AuthorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder() - .authorizationCode() - .refreshToken() - .clientCredentials() - .password() - .build() - val authorizedClientManager = DefaultOAuth2AuthorizedClientManager( - clientRegistrationRepository, authorizedClientRepository, - ) - authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider) - return authorizedClientManager - } - } diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt index 508bf141..acf0eefa 100644 --- a/core/core-api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt @@ -11,6 +11,7 @@ import io.jsonwebtoken.security.Keys import io.jsonwebtoken.security.SecurityException import io.raemian.core.auth.domain.CurrentUser import io.raemian.core.auth.domain.TokenDTO +import org.slf4j.LoggerFactory import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.core.Authentication import org.springframework.security.core.GrantedAuthority @@ -21,6 +22,9 @@ import java.util.Date @Component class TokenProvider() { + + private val log = LoggerFactory.getLogger(javaClass) + private val key: Key private val secretKey: String = @@ -127,20 +131,15 @@ class TokenProvider() { Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token) return true } catch (e: SecurityException) { - // log.info("잘못된 JWT 서명입니다.") - println("securty exception" + e) + log.info("잘못된 JWT 서명입니다.") } catch (e: MalformedJwtException) { - // log.info("잘못된 JWT 서명입니다.") - println("malformed " + e) + log.info("잘못된 JWT 서명입니다.") } catch (e: ExpiredJwtException) { - // log.info("만료된 JWT 토큰입니다.") - println("expired token " + e) + log.info("만료된 JWT 토큰입니다.") } catch (e: UnsupportedJwtException) { - // log.info("지원되지 않는 JWT 토큰입니다.") - println("not supoorted " + e) + log.info("지원되지 않는 JWT 토큰입니다.") } catch (e: IllegalArgumentException) { - // log.info("JWT 토큰이 잘못되었습니다.") - println("illegal " + e) + log.info("JWT 토큰이 잘못되었습니다.") } return false } From 90ff6acf0f03fe4c4af62c267cfff832c7635b30 Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Tue, 14 Nov 2023 22:24:25 +0900 Subject: [PATCH 16/70] =?UTF-8?q?refact(#1):=20loadUser=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/auth/service/OAuth2UserService.kt | 44 ++++--------------- 1 file changed, 8 insertions(+), 36 deletions(-) diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt index aba4bb2f..211c1532 100644 --- a/core/core-api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt @@ -26,51 +26,23 @@ class OAuth2UserService( "google" -> { val email = oAuth2User.attributes["email"]?.toString() ?: throw RuntimeException("이메일이없음") val name = oAuth2User.attributes["name"] - val user = userRepository.findByEmail(email) - if (user == null) { - val created = userRepository.save( - User( - email = email, - password = "", - authority = Authority.ROLE_USER, - ), - ) - return CurrentUser( - id = created.id!!, - email = created.email, - password = "", - authorities = listOf(), - ) - } - return CurrentUser(id = user.id!!, email, "", listOf()) + val user = upsert(email) + CurrentUser(id = user.id!!, email, "", listOf()) } "naver" -> { val userInfo = oAuth2User.attributes[usernameAttributeName] as Map val email = userInfo["email"] ?: throw RuntimeException("이메일없음") - val user = userRepository.findByEmail(email) - if (user == null) { - val created = userRepository.save( - User( - email = email, - password = "", - authority = Authority.ROLE_USER, - ), - ) - return CurrentUser( - id = created.id!!, - email = created.email, - password = "", - authorities = listOf(), - ) - } - return CurrentUser(user.id!!, email, "", listOf()) + val user = upsert(email) + CurrentUser(user.id!!, email, "", listOf()) } else -> throw RuntimeException("errrr") } + } - - // userRepository.findByEmail() + private fun upsert(email: String): User { + return userRepository.findByEmail(email) + ?: return userRepository.save(User(email = email, password = "", authority = Authority.ROLE_USER)) } } \ No newline at end of file From 3e65e4c6b0efcb15b34f767b4ae71e836b6857b2 Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Wed, 15 Nov 2023 00:26:02 +0900 Subject: [PATCH 17/70] =?UTF-8?q?chore(#1):=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/auth/config/JwtSecurityConfig.kt | 2 +- .../core/auth/config/WebSecurityConfig.kt | 8 +++-- .../raemian/core/auth/domain/CurrentUser.kt | 1 + .../raemian/core/auth/domain/OAuthProvider.kt | 5 +++ .../raemian/core/auth/service/AuthService.kt | 9 +++-- .../core/auth/service/OAuth2UserService.kt | 34 +++++++++++++------ .../core/auth/support/TokenProvider.kt | 5 +-- 7 files changed, 44 insertions(+), 20 deletions(-) create mode 100644 core/core-api/src/main/kotlin/io/raemian/core/auth/domain/OAuthProvider.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/config/JwtSecurityConfig.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/config/JwtSecurityConfig.kt index 7ca9a6e6..5a9613bf 100644 --- a/core/core-api/src/main/kotlin/io/raemian/core/auth/config/JwtSecurityConfig.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/config/JwtSecurityConfig.kt @@ -10,7 +10,7 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic class JwtSecurityConfig( private val tokenProvider: TokenProvider, -) : SecurityConfigurerAdapter() { +) : SecurityConfigurerAdapter() { // TokenProvider 를 주입받아서 JwtFilter 를 통해 Security 로직에 필터를 등록 override fun configure(http: HttpSecurity) { diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt index c3d8efff..f8f8a76d 100644 --- a/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt @@ -53,7 +53,9 @@ class WebSecurityConfig( } .authorizeHttpRequests { it.requestMatchers(AntPathRequestMatcher("/auth/**")).permitAll() - .anyRequest().permitAll() + .requestMatchers(AntPathRequestMatcher("/oauth2/**")).permitAll() + .requestMatchers(AntPathRequestMatcher("/login/**")).permitAll() + .anyRequest().authenticated() } .oauth2Login { it.userInfoEndpoint { endpoint -> endpoint.userService(oAuth2UserService) } @@ -62,12 +64,12 @@ class WebSecurityConfig( response.contentType = MediaType.APPLICATION_JSON_VALUE response.characterEncoding = StandardCharsets.UTF_8.name() - val tokenDTO = tokenProvider.generateTokenDtoV2(user) + val tokenDTO = tokenProvider.generateTokenDto(user) response.addHeader("x-token", tokenDTO.accessToken) } it.failureHandler { request, response, exception -> log.info("eeeeeeeeeeeeeeeeeeee + ${exception.message}") - response.addHeader("x-token", "ccc") + response.addHeader("x-token", exception.message) } } diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt index 5cf61828..cb480e27 100644 --- a/core/core-api/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt @@ -8,6 +8,7 @@ import org.springframework.security.oauth2.core.user.OAuth2User data class CurrentUser( val id: Long, val email: String, + val provider: String? = null, private val password: String, private val authorities: List = listOf("ROLE_USER"), ) : UserDetails, OAuth2User { diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/domain/OAuthProvider.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/domain/OAuthProvider.kt new file mode 100644 index 00000000..9139da2a --- /dev/null +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/domain/OAuthProvider.kt @@ -0,0 +1,5 @@ +package io.raemian.core.auth.domain + +enum class OAuthProvider { + GOOGLE, NAVER +} \ No newline at end of file diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/service/AuthService.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/service/AuthService.kt index 5e25da90..5cc66dc6 100644 --- a/core/core-api/src/main/kotlin/io/raemian/core/auth/service/AuthService.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/service/AuthService.kt @@ -34,17 +34,20 @@ class AuthService( override fun loadUserByUsername(username: String): UserDetails { val user = userRepository.findByEmail(username) ?: throw UsernameNotFoundException("not found $username") - return CurrentUser(id = user.id!!, email = user.email, password = user.password) + return CurrentUser( + id = user.id!!, + email = user.email, + password = user.password, + authorities = listOf(), + ) } fun signIn(email: String, password: String): TokenDTO { val user = userRepository.findByEmail(email) ?: throw RuntimeException("아이디 또는 비밀번호 불일치 ") - if (!passwordEncoder.matches(password, user.password)) { throw RuntimeException("아이디 또는 비밀번호 불일치 ") } - val token = UsernamePasswordAuthenticationToken(email, password, arrayListOf()) val authentication = authenticationManagerBuilder.`object`.authenticate(token) val tokenDTO = tokenProvider.generateTokenDto(authentication) diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt index 211c1532..4911c045 100644 --- a/core/core-api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt @@ -1,6 +1,7 @@ package io.raemian.core.auth.service import io.raemian.core.auth.domain.CurrentUser +import io.raemian.core.auth.domain.OAuthProvider import io.raemian.core.auth.support.TokenProvider import io.raemian.storage.db.core.user.Authority import io.raemian.storage.db.core.user.User @@ -14,7 +15,6 @@ import org.springframework.stereotype.Service class OAuth2UserService( private val userRepository: UserRepository, private val tokenProvider: TokenProvider, - // private val authenticationManagerBuilder: AuthenticationManagerBuilder, ) : DefaultOAuth2UserService() { override fun loadUser(userRequest: OAuth2UserRequest): OAuth2User { val oAuth2User = super.loadUser(userRequest) @@ -22,26 +22,38 @@ class OAuth2UserService( .providerDetails .userInfoEndpoint .userNameAttributeName - return when (userRequest.clientRegistration.registrationId) { - "google" -> { + + val provider = OAuthProvider.valueOf(userRequest.clientRegistration.registrationId.uppercase()) + return when (provider) { + OAuthProvider.GOOGLE -> { val email = oAuth2User.attributes["email"]?.toString() ?: throw RuntimeException("이메일이없음") val name = oAuth2User.attributes["name"] - val user = upsert(email) - CurrentUser(id = user.id!!, email, "", listOf()) + val user = upsert(email, OAuthProvider.GOOGLE) + CurrentUser( + id = user.id!!, + email = email, + provider = provider.name, + password = "", + authorities = listOf(), + ) } - "naver" -> { + OAuthProvider.NAVER -> { val userInfo = oAuth2User.attributes[usernameAttributeName] as Map val email = userInfo["email"] ?: throw RuntimeException("이메일없음") - val user = upsert(email) - CurrentUser(user.id!!, email, "", listOf()) + val user = upsert(email, OAuthProvider.NAVER) + CurrentUser( + id = user.id!!, + email = email, + provider = provider.name, + password = "", + authorities = listOf(), + ) } - - else -> throw RuntimeException("errrr") } } - private fun upsert(email: String): User { + private fun upsert(email: String, oAuthProvider: OAuthProvider): User { return userRepository.findByEmail(email) ?: return userRepository.save(User(email = email, password = "", authority = Authority.ROLE_USER)) } diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt index acf0eefa..3fa655c0 100644 --- a/core/core-api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt @@ -41,7 +41,7 @@ class TokenProvider() { key = Keys.hmacShaKeyFor(keyBytes) } - fun generateTokenDtoV2(currentUser: CurrentUser): TokenDTO { + fun generateTokenDto(currentUser: CurrentUser): TokenDTO { val authorities: String = currentUser.authorities .map { obj: GrantedAuthority -> obj.authority } .joinToString(",") @@ -122,7 +122,8 @@ class TokenProvider() { .toLong() // UserDetails 객체를 만들어서 Authentication 리턴 - val principal = CurrentUser(id = id, claims.subject, "", authorities) + val principal = + CurrentUser(id = id, email = claims.subject, password = "", provider = null, authorities = authorities) return UsernamePasswordAuthenticationToken(principal, "", principal.authorities) } From 7498447a8612300766d5448167170e148c8c4d0c Mon Sep 17 00:00:00 2001 From: binary_ho Date: Thu, 16 Nov 2023 23:45:52 +0900 Subject: [PATCH 18/70] =?UTF-8?q?docs=20:=20PR=EC=9D=84=20open,=20synchron?= =?UTF-8?q?ize,=20closed=20=ED=95=A0=20=EB=95=8C=EB=A7=88=EB=8B=A4=20?= =?UTF-8?q?=EB=B9=8C=EB=93=9C=ED=95=98=EA=B8=B0=20=EC=9C=84=ED=95=9C=20git?= =?UTF-8?q?hub=20workflows=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1=20(#6?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pull-request-gradle-build-test.yml | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 .github/workflows/pull-request-gradle-build-test.yml diff --git a/.github/workflows/pull-request-gradle-build-test.yml b/.github/workflows/pull-request-gradle-build-test.yml new file mode 100644 index 00000000..e6082998 --- /dev/null +++ b/.github/workflows/pull-request-gradle-build-test.yml @@ -0,0 +1,41 @@ +name : Pull Request Gradle Build Test + +on: + pull_request: + types: [opened, synchronize, closed] + +permissions: read-all + +jobs: + build-test: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + steps: + - name: Git Checkout + uses: actions/checkout@v3.0.2 + + - uses: dorny/paths-filter@v2 + id: changes + with: + filters: | + application: + - 'build.gradle.kts' + - '**/src/**' + + - name: JDK 설치 + if: steps.changes.outputs.application == 'true' + uses: actions/setup-java@v3 + with: + distribution: zulu + java-version: 17 + cache: 'gradle' + + - name: gradlew 권한 부여 + run: chmod +x ./gradlew + + - name: Gradle Build + if: steps.changes.outputs.application == 'true' + run: | + ./gradlew build --no-build-cache From b8c2d73008d5b25184f3f64ae6feb84120ddee25 Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Sat, 18 Nov 2023 00:21:10 +0900 Subject: [PATCH 19/70] =?UTF-8?q?chore(#1):=20=EC=BD=94=EB=93=9C=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/io/raemian/core/auth/support/JwtFilter.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/support/JwtFilter.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/support/JwtFilter.kt index 9129fa78..2a5d70f2 100644 --- a/core/core-api/src/main/kotlin/io/raemian/core/auth/support/JwtFilter.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/support/JwtFilter.kt @@ -13,7 +13,8 @@ class JwtFilter( private val tokenProvider: TokenProvider, ) : OncePerRequestFilter() { - + private val AUTHORIZATION_HEADER = "Authorization" + private val BEARER_PREFIX = "Bearer " override fun doFilterInternal( request: HttpServletRequest, response: HttpServletResponse, @@ -33,9 +34,6 @@ class JwtFilter( // Request Header 에서 토큰 정보를 꺼내오기 private fun resolveToken(request: HttpServletRequest): String { - val AUTHORIZATION_HEADER = "Authorization" - val BEARER_PREFIX = "Bearer " - val bearerToken = request.getHeader(AUTHORIZATION_HEADER) return if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(BEARER_PREFIX)) { bearerToken.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1].trim { it <= ' ' } From 85b3eac0952644a22c839e87cddb7c7e38c00187 Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Sat, 18 Nov 2023 00:27:10 +0900 Subject: [PATCH 20/70] =?UTF-8?q?refact(#1):=20=EC=BD=94=EB=93=9C=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/raemian/core/auth/support/TokenProvider.kt | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt index 3fa655c0..eeae9eb2 100644 --- a/core/core-api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt @@ -17,29 +17,26 @@ import org.springframework.security.core.Authentication import org.springframework.security.core.GrantedAuthority import org.springframework.stereotype.Component import java.security.Key +import java.time.Duration import java.util.Date @Component -class TokenProvider() { +class TokenProvider { private val log = LoggerFactory.getLogger(javaClass) - private val key: Key - private val secretKey: String = "c3ByaW5nLWJvb3Qtc2VjdXJpdHktand0LXR1dG9yaWFsLWppd29vbi1zcHJpbmctYm9vdC1zZWN1cml0eS1qd3QtdHV0b3JpYWwK" + private val key: Key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretKey)) + private val AUTHORITIES_KEY = "auth" private val EMAIL_KEY = "email" private val ID_KEY = "id" private val BEARER_TYPE = "Bearer" - private val ACCESS_TOKEN_EXPIRE_TIME = (1000 * 60 * 300) // 300분 - private val REFRESH_TOKEN_EXPIRE_TIME = (1000 * 60 * 60 * 24 * 70) // 70일 + private val ACCESS_TOKEN_EXPIRE_TIME = Duration.ofMinutes(300).toMillis() // 300분 + private val REFRESH_TOKEN_EXPIRE_TIME = Duration.ofDays(70).toMillis() // 70일 - init { - val keyBytes = Decoders.BASE64.decode(secretKey) - key = Keys.hmacShaKeyFor(keyBytes) - } fun generateTokenDto(currentUser: CurrentUser): TokenDTO { val authorities: String = currentUser.authorities From f4d6351c2027d63a5bbc4e6696d3202a917ec70a Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Sat, 18 Nov 2023 03:15:50 +0900 Subject: [PATCH 21/70] =?UTF-8?q?chore(#1):=20=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt | 4 +++- .../kotlin/io/raemian/core/auth/service/OAuth2UserService.kt | 5 +---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt index f8f8a76d..ffc8e586 100644 --- a/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt @@ -10,12 +10,14 @@ import org.springframework.boot.autoconfigure.security.servlet.PathRequest import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.http.MediaType +import org.springframework.security.config.annotation.SecurityConfigurerAdapter import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer import org.springframework.security.config.http.SessionCreationPolicy import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder import org.springframework.security.crypto.password.PasswordEncoder +import org.springframework.security.web.DefaultSecurityFilterChain import org.springframework.security.web.SecurityFilterChain import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter import org.springframework.security.web.util.matcher.AntPathRequestMatcher @@ -29,7 +31,7 @@ class WebSecurityConfig( private val corsFilter: CorsFilter, private val tokenProvider: TokenProvider, private val oAuth2UserService: OAuth2UserService, -) { +) : SecurityConfigurerAdapter() { private val log = LoggerFactory.getLogger(javaClass) diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt index 4911c045..aa7a9257 100644 --- a/core/core-api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt @@ -2,7 +2,6 @@ package io.raemian.core.auth.service import io.raemian.core.auth.domain.CurrentUser import io.raemian.core.auth.domain.OAuthProvider -import io.raemian.core.auth.support.TokenProvider import io.raemian.storage.db.core.user.Authority import io.raemian.storage.db.core.user.User import io.raemian.storage.db.core.user.UserRepository @@ -14,7 +13,6 @@ import org.springframework.stereotype.Service @Service class OAuth2UserService( private val userRepository: UserRepository, - private val tokenProvider: TokenProvider, ) : DefaultOAuth2UserService() { override fun loadUser(userRequest: OAuth2UserRequest): OAuth2User { val oAuth2User = super.loadUser(userRequest) @@ -23,8 +21,7 @@ class OAuth2UserService( .userInfoEndpoint .userNameAttributeName - val provider = OAuthProvider.valueOf(userRequest.clientRegistration.registrationId.uppercase()) - return when (provider) { + return when (val provider = OAuthProvider.valueOf(userRequest.clientRegistration.registrationId.uppercase())) { OAuthProvider.GOOGLE -> { val email = oAuth2User.attributes["email"]?.toString() ?: throw RuntimeException("이메일이없음") val name = oAuth2User.attributes["name"] From 7c154e01d09cdf2795b47e3fd86cd13f063375b6 Mon Sep 17 00:00:00 2001 From: hanmanhyuk Date: Thu, 23 Nov 2023 22:59:42 +0900 Subject: [PATCH 22/70] feat(#1): edit response token --- .../io/raemian/core/auth/config/CorsConfig.kt | 6 ++--- .../core/auth/config/WebSecurityConfig.kt | 8 ++++++- .../storage/db/core/token/RefreshToken.kt | 24 +++++++++---------- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt index 12bfab95..325fcc04 100644 --- a/core/core-api/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt @@ -14,9 +14,9 @@ class CorsConfig { val source = UrlBasedCorsConfigurationSource() val config = CorsConfiguration() config.allowCredentials = true - config.addAllowedOrigin("*") - config.addAllowedHeader("*") - config.addAllowedMethod("*") + config.allowedOriginPatterns = listOf("*") + config.allowedHeaders = listOf("*") + config.allowedMethods = listOf("*") source.registerCorsConfiguration("/**", config) return CorsFilter(source) } diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt b/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt index ffc8e586..e7ebc0f0 100644 --- a/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt +++ b/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt @@ -3,6 +3,8 @@ package io.raemian.core.auth.config import io.raemian.core.auth.domain.CurrentUser import io.raemian.core.auth.service.OAuth2UserService import io.raemian.core.auth.support.TokenProvider +import jakarta.servlet.http.Cookie +import jakarta.servlet.http.HttpServletRequest import jakarta.servlet.http.HttpServletResponse import org.slf4j.LoggerFactory import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty @@ -17,8 +19,11 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur import org.springframework.security.config.http.SessionCreationPolicy import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder import org.springframework.security.crypto.password.PasswordEncoder +import org.springframework.security.web.DefaultRedirectStrategy import org.springframework.security.web.DefaultSecurityFilterChain +import org.springframework.security.web.RedirectStrategy import org.springframework.security.web.SecurityFilterChain +import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter import org.springframework.security.web.util.matcher.AntPathRequestMatcher import org.springframework.web.filter.CorsFilter @@ -67,7 +72,8 @@ class WebSecurityConfig( response.characterEncoding = StandardCharsets.UTF_8.name() val tokenDTO = tokenProvider.generateTokenDto(user) - response.addHeader("x-token", tokenDTO.accessToken) + // TODO edit redirect url + response.sendRedirect("http://localhost:3000/login/oauth2/code/google?token=${tokenDTO.accessToken}") } it.failureHandler { request, response, exception -> log.info("eeeeeeeeeeeeeeeeeeee + ${exception.message}") diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/token/RefreshToken.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/token/RefreshToken.kt index aa8970d7..70afb820 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/token/RefreshToken.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/token/RefreshToken.kt @@ -1,12 +1,12 @@ -package io.raemian.storage.db.core.token - -import jakarta.persistence.Entity -import jakarta.persistence.Id - -@Entity -class RefreshToken( - @Id - val id: Long, - val key: String, - val value: String, -) \ No newline at end of file +// package io.raemian.storage.db.core.token +// +// import jakarta.persistence.Entity +// import jakarta.persistence.Id +// +// @Entity +// class RefreshToken( +// @Id +// val id: Long, +// val key: String, +// val value: String, +// ) \ No newline at end of file From fae86bc3299b28f37f155507b12204bd4c6a88db Mon Sep 17 00:00:00 2001 From: wkwon Date: Sat, 25 Nov 2023 01:53:27 +0900 Subject: [PATCH 23/70] feat(#9): refactor project architecture --- .../api}/build.gradle.kts | 19 ++++--- .../api}/src/docs/asciidoc/index.adoc | 0 .../kotlin/io/raemian/CoreApiApplication.kt | 0 .../io/raemian/core/api/config/AsyncConfig.kt | 0 .../core/api/config/AsyncExceptionHandler.kt | 0 .../api/controller/ApiControllerAdvice.kt | 0 .../core/api/controller/FaviconController.kt | 0 .../core/api/controller/HealthController.kt | 0 .../api/controller/v1/ExampleController.kt | 0 .../v1/request/ExampleRequestDto.kt | 0 .../v1/response/ExampleResponseDto.kt | 0 .../io/raemian/core/api/domain/ExampleData.kt | 0 .../raemian/core/api/domain/ExampleResult.kt | 0 .../raemian/core/api/domain/ExampleService.kt | 0 .../api/support/error/CoreApiException.kt | 0 .../core/api/support/error/ErrorCode.kt | 0 .../core/api/support/error/ErrorMessage.kt | 0 .../core/api/support/error/ErrorType.kt | 0 .../core/api/support/response/ApiResponse.kt | 0 .../core/api/support/response/ResultType.kt | 0 .../io/raemian/core/auth/config/CorsConfig.kt | 0 .../core/auth/config/JwtSecurityConfig.kt | 0 .../core/auth/config/WebSecurityConfig.kt | 0 .../core/auth/controller/AuthController.kt | 0 .../controller/v1/request/SignInRequest.kt | 0 .../controller/v1/request/SignUpRequest.kt | 0 .../raemian/core/auth/domain/CurrentUser.kt | 0 .../raemian/core/auth/domain/OAuthProvider.kt | 0 .../io/raemian/core/auth/domain/TokenDTO.kt | 0 .../raemian/core/auth/service/AuthService.kt | 0 .../core/auth/service/OAuth2UserService.kt | 0 .../io/raemian/core/auth/support/JwtFilter.kt | 0 .../raemian/core/auth/support/SecurityUtil.kt | 0 .../core/auth/support/TokenProvider.kt | 0 .../api}/src/main/resources/application.yml | 1 - .../src/test/kotlin/io/raemian/ContextTest.kt | 0 .../io/raemian/CoreApiApplicationTest.kt | 0 .../src/test/kotlin/io/raemian/DevelopTest.kt | 0 .../controller/v1/ExampleControllerTest.kt | 0 clients/client-example/build.gradle.kts | 5 -- .../io/raemian/client/example/ExampleApi.kt | 17 ------ .../raemian/client/example/ExampleClient.kt | 16 ------ .../raemian/client/example/ExampleConfig.kt | 8 --- .../client/example/ExampleRequestDto.kt | 5 -- .../client/example/ExampleResponseDto.kt | 11 ---- .../example/model/ExampleClientResult.kt | 5 -- .../src/main/resources/client-example.yml | 35 ------------ .../client/ClientExampleContextTest.kt | 12 ---- .../client/ClientExampleTestApplication.kt | 13 ----- .../client/example/ExampleClientTest.kt | 19 ------- .../src/test/resources/application.yml | 6 -- core/core-enum/build.gradle.kts | 0 .../io/raemian/core/enums/ExampleEnum.kt | 3 - {support => infra}/logging/build.gradle.kts | 0 .../main/resources/logback/logback-dev.xml | 0 .../main/resources/logback/logback-live.xml | 0 .../resources/logback/logback-local-dev.xml | 0 .../main/resources/logback/logback-local.xml | 0 .../resources/logback/logback-staging.xml | 0 .../logging/src/main/resources/logging.yml | 0 .../monitoring/build.gradle.kts | 0 .../src/main/resources/monitoring.yml | 0 settings.gradle.kts | 9 +-- tests/api-docs/build.gradle.kts | 7 --- .../io/raemian/test/api/RestDocsTest.kt | 56 ------------------- .../io/raemian/test/api/RestDocsUtils.kt | 18 ------ 66 files changed, 13 insertions(+), 252 deletions(-) rename {core/core-api => application/api}/build.gradle.kts (61%) rename {core/core-api => application/api}/src/docs/asciidoc/index.adoc (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/CoreApiApplication.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/api/config/AsyncConfig.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/api/config/AsyncExceptionHandler.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/api/controller/ApiControllerAdvice.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/api/controller/FaviconController.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/api/controller/HealthController.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/api/controller/v1/ExampleController.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/api/controller/v1/request/ExampleRequestDto.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/api/controller/v1/response/ExampleResponseDto.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/api/domain/ExampleData.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/api/domain/ExampleResult.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/api/domain/ExampleService.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/api/support/error/CoreApiException.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/api/support/error/ErrorCode.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/api/support/error/ErrorMessage.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/api/support/error/ErrorType.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/api/support/response/ApiResponse.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/api/support/response/ResultType.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/auth/config/JwtSecurityConfig.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/auth/controller/AuthController.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignInRequest.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignUpRequest.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/auth/domain/OAuthProvider.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/auth/domain/TokenDTO.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/auth/service/AuthService.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/auth/support/JwtFilter.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/auth/support/SecurityUtil.kt (100%) rename {core/core-api => application/api}/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt (100%) rename {core/core-api => application/api}/src/main/resources/application.yml (98%) rename {core/core-api => application/api}/src/test/kotlin/io/raemian/ContextTest.kt (100%) rename {core/core-api => application/api}/src/test/kotlin/io/raemian/CoreApiApplicationTest.kt (100%) rename {core/core-api => application/api}/src/test/kotlin/io/raemian/DevelopTest.kt (100%) rename {core/core-api => application/api}/src/test/kotlin/io/raemian/core/api/controller/v1/ExampleControllerTest.kt (100%) delete mode 100644 clients/client-example/build.gradle.kts delete mode 100644 clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleApi.kt delete mode 100644 clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleClient.kt delete mode 100644 clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleConfig.kt delete mode 100644 clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleRequestDto.kt delete mode 100644 clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleResponseDto.kt delete mode 100644 clients/client-example/src/main/kotlin/io/raemian/client/example/model/ExampleClientResult.kt delete mode 100644 clients/client-example/src/main/resources/client-example.yml delete mode 100644 clients/client-example/src/test/kotlin/io/raemian/client/ClientExampleContextTest.kt delete mode 100644 clients/client-example/src/test/kotlin/io/raemian/client/ClientExampleTestApplication.kt delete mode 100644 clients/client-example/src/test/kotlin/io/raemian/client/example/ExampleClientTest.kt delete mode 100644 clients/client-example/src/test/resources/application.yml delete mode 100644 core/core-enum/build.gradle.kts delete mode 100644 core/core-enum/src/main/kotlin/io/raemian/core/enums/ExampleEnum.kt rename {support => infra}/logging/build.gradle.kts (100%) rename {support => infra}/logging/src/main/resources/logback/logback-dev.xml (100%) rename {support => infra}/logging/src/main/resources/logback/logback-live.xml (100%) rename {support => infra}/logging/src/main/resources/logback/logback-local-dev.xml (100%) rename {support => infra}/logging/src/main/resources/logback/logback-local.xml (100%) rename {support => infra}/logging/src/main/resources/logback/logback-staging.xml (100%) rename {support => infra}/logging/src/main/resources/logging.yml (100%) rename {support => infra}/monitoring/build.gradle.kts (100%) rename {support => infra}/monitoring/src/main/resources/monitoring.yml (100%) delete mode 100644 tests/api-docs/build.gradle.kts delete mode 100644 tests/api-docs/src/main/kotlin/io/raemian/test/api/RestDocsTest.kt delete mode 100644 tests/api-docs/src/main/kotlin/io/raemian/test/api/RestDocsUtils.kt diff --git a/core/core-api/build.gradle.kts b/application/api/build.gradle.kts similarity index 61% rename from core/core-api/build.gradle.kts rename to application/api/build.gradle.kts index e94875db..dfd0b0b2 100644 --- a/core/core-api/build.gradle.kts +++ b/application/api/build.gradle.kts @@ -7,13 +7,9 @@ tasks.getByName("jar") { } dependencies { - implementation(project(":core:core-enum")) - implementation(project(":support:monitoring")) - implementation(project(":support:logging")) + implementation(project(":infra:monitoring")) + implementation(project(":infra:logging")) implementation(project(":storage:db-core")) - implementation(project(":clients:client-example")) - - testImplementation(project(":tests:api-docs")) implementation("org.springframework.boot:spring-boot-starter-web") @@ -24,11 +20,16 @@ dependencies { // security implementation("org.springframework.boot:spring-boot-starter-security") + // oauth-client implementation("org.springframework.boot:spring-boot-starter-oauth2-client") - // security-test - testImplementation("org.springframework.security:spring-security-test") - + // web-client + implementation("org.springframework.boot:spring-boot-starter-webflux") + // test + testImplementation("org.springframework.security:spring-security-test") + testImplementation("org.springframework.restdocs:spring-restdocs-mockmvc") + testImplementation("org.springframework.restdocs:spring-restdocs-restassured") + testImplementation("io.rest-assured:spring-mock-mvc") } diff --git a/core/core-api/src/docs/asciidoc/index.adoc b/application/api/src/docs/asciidoc/index.adoc similarity index 100% rename from core/core-api/src/docs/asciidoc/index.adoc rename to application/api/src/docs/asciidoc/index.adoc diff --git a/core/core-api/src/main/kotlin/io/raemian/CoreApiApplication.kt b/application/api/src/main/kotlin/io/raemian/CoreApiApplication.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/CoreApiApplication.kt rename to application/api/src/main/kotlin/io/raemian/CoreApiApplication.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/api/config/AsyncConfig.kt b/application/api/src/main/kotlin/io/raemian/core/api/config/AsyncConfig.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/api/config/AsyncConfig.kt rename to application/api/src/main/kotlin/io/raemian/core/api/config/AsyncConfig.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/api/config/AsyncExceptionHandler.kt b/application/api/src/main/kotlin/io/raemian/core/api/config/AsyncExceptionHandler.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/api/config/AsyncExceptionHandler.kt rename to application/api/src/main/kotlin/io/raemian/core/api/config/AsyncExceptionHandler.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/api/controller/ApiControllerAdvice.kt b/application/api/src/main/kotlin/io/raemian/core/api/controller/ApiControllerAdvice.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/api/controller/ApiControllerAdvice.kt rename to application/api/src/main/kotlin/io/raemian/core/api/controller/ApiControllerAdvice.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/api/controller/FaviconController.kt b/application/api/src/main/kotlin/io/raemian/core/api/controller/FaviconController.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/api/controller/FaviconController.kt rename to application/api/src/main/kotlin/io/raemian/core/api/controller/FaviconController.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/api/controller/HealthController.kt b/application/api/src/main/kotlin/io/raemian/core/api/controller/HealthController.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/api/controller/HealthController.kt rename to application/api/src/main/kotlin/io/raemian/core/api/controller/HealthController.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/api/controller/v1/ExampleController.kt b/application/api/src/main/kotlin/io/raemian/core/api/controller/v1/ExampleController.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/api/controller/v1/ExampleController.kt rename to application/api/src/main/kotlin/io/raemian/core/api/controller/v1/ExampleController.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/api/controller/v1/request/ExampleRequestDto.kt b/application/api/src/main/kotlin/io/raemian/core/api/controller/v1/request/ExampleRequestDto.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/api/controller/v1/request/ExampleRequestDto.kt rename to application/api/src/main/kotlin/io/raemian/core/api/controller/v1/request/ExampleRequestDto.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/api/controller/v1/response/ExampleResponseDto.kt b/application/api/src/main/kotlin/io/raemian/core/api/controller/v1/response/ExampleResponseDto.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/api/controller/v1/response/ExampleResponseDto.kt rename to application/api/src/main/kotlin/io/raemian/core/api/controller/v1/response/ExampleResponseDto.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/api/domain/ExampleData.kt b/application/api/src/main/kotlin/io/raemian/core/api/domain/ExampleData.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/api/domain/ExampleData.kt rename to application/api/src/main/kotlin/io/raemian/core/api/domain/ExampleData.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/api/domain/ExampleResult.kt b/application/api/src/main/kotlin/io/raemian/core/api/domain/ExampleResult.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/api/domain/ExampleResult.kt rename to application/api/src/main/kotlin/io/raemian/core/api/domain/ExampleResult.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/api/domain/ExampleService.kt b/application/api/src/main/kotlin/io/raemian/core/api/domain/ExampleService.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/api/domain/ExampleService.kt rename to application/api/src/main/kotlin/io/raemian/core/api/domain/ExampleService.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/api/support/error/CoreApiException.kt b/application/api/src/main/kotlin/io/raemian/core/api/support/error/CoreApiException.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/api/support/error/CoreApiException.kt rename to application/api/src/main/kotlin/io/raemian/core/api/support/error/CoreApiException.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/api/support/error/ErrorCode.kt b/application/api/src/main/kotlin/io/raemian/core/api/support/error/ErrorCode.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/api/support/error/ErrorCode.kt rename to application/api/src/main/kotlin/io/raemian/core/api/support/error/ErrorCode.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/api/support/error/ErrorMessage.kt b/application/api/src/main/kotlin/io/raemian/core/api/support/error/ErrorMessage.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/api/support/error/ErrorMessage.kt rename to application/api/src/main/kotlin/io/raemian/core/api/support/error/ErrorMessage.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/api/support/error/ErrorType.kt b/application/api/src/main/kotlin/io/raemian/core/api/support/error/ErrorType.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/api/support/error/ErrorType.kt rename to application/api/src/main/kotlin/io/raemian/core/api/support/error/ErrorType.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/api/support/response/ApiResponse.kt b/application/api/src/main/kotlin/io/raemian/core/api/support/response/ApiResponse.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/api/support/response/ApiResponse.kt rename to application/api/src/main/kotlin/io/raemian/core/api/support/response/ApiResponse.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/api/support/response/ResultType.kt b/application/api/src/main/kotlin/io/raemian/core/api/support/response/ResultType.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/api/support/response/ResultType.kt rename to application/api/src/main/kotlin/io/raemian/core/api/support/response/ResultType.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt b/application/api/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt rename to application/api/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/config/JwtSecurityConfig.kt b/application/api/src/main/kotlin/io/raemian/core/auth/config/JwtSecurityConfig.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/auth/config/JwtSecurityConfig.kt rename to application/api/src/main/kotlin/io/raemian/core/auth/config/JwtSecurityConfig.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt b/application/api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt rename to application/api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/controller/AuthController.kt b/application/api/src/main/kotlin/io/raemian/core/auth/controller/AuthController.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/auth/controller/AuthController.kt rename to application/api/src/main/kotlin/io/raemian/core/auth/controller/AuthController.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignInRequest.kt b/application/api/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignInRequest.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignInRequest.kt rename to application/api/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignInRequest.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignUpRequest.kt b/application/api/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignUpRequest.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignUpRequest.kt rename to application/api/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignUpRequest.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt b/application/api/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt rename to application/api/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/domain/OAuthProvider.kt b/application/api/src/main/kotlin/io/raemian/core/auth/domain/OAuthProvider.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/auth/domain/OAuthProvider.kt rename to application/api/src/main/kotlin/io/raemian/core/auth/domain/OAuthProvider.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/domain/TokenDTO.kt b/application/api/src/main/kotlin/io/raemian/core/auth/domain/TokenDTO.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/auth/domain/TokenDTO.kt rename to application/api/src/main/kotlin/io/raemian/core/auth/domain/TokenDTO.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/service/AuthService.kt b/application/api/src/main/kotlin/io/raemian/core/auth/service/AuthService.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/auth/service/AuthService.kt rename to application/api/src/main/kotlin/io/raemian/core/auth/service/AuthService.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt b/application/api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt rename to application/api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/support/JwtFilter.kt b/application/api/src/main/kotlin/io/raemian/core/auth/support/JwtFilter.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/auth/support/JwtFilter.kt rename to application/api/src/main/kotlin/io/raemian/core/auth/support/JwtFilter.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/support/SecurityUtil.kt b/application/api/src/main/kotlin/io/raemian/core/auth/support/SecurityUtil.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/auth/support/SecurityUtil.kt rename to application/api/src/main/kotlin/io/raemian/core/auth/support/SecurityUtil.kt diff --git a/core/core-api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt b/application/api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt similarity index 100% rename from core/core-api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt rename to application/api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt diff --git a/core/core-api/src/main/resources/application.yml b/application/api/src/main/resources/application.yml similarity index 98% rename from core/core-api/src/main/resources/application.yml rename to application/api/src/main/resources/application.yml index bf914850..9d1de362 100644 --- a/core/core-api/src/main/resources/application.yml +++ b/application/api/src/main/resources/application.yml @@ -7,7 +7,6 @@ spring: - monitoring.yml - logging.yml - db-core.yml - - client-example.yml mvc.throw-exception-if-no-handler-found: true web.resources.add-mappings: false security: diff --git a/core/core-api/src/test/kotlin/io/raemian/ContextTest.kt b/application/api/src/test/kotlin/io/raemian/ContextTest.kt similarity index 100% rename from core/core-api/src/test/kotlin/io/raemian/ContextTest.kt rename to application/api/src/test/kotlin/io/raemian/ContextTest.kt diff --git a/core/core-api/src/test/kotlin/io/raemian/CoreApiApplicationTest.kt b/application/api/src/test/kotlin/io/raemian/CoreApiApplicationTest.kt similarity index 100% rename from core/core-api/src/test/kotlin/io/raemian/CoreApiApplicationTest.kt rename to application/api/src/test/kotlin/io/raemian/CoreApiApplicationTest.kt diff --git a/core/core-api/src/test/kotlin/io/raemian/DevelopTest.kt b/application/api/src/test/kotlin/io/raemian/DevelopTest.kt similarity index 100% rename from core/core-api/src/test/kotlin/io/raemian/DevelopTest.kt rename to application/api/src/test/kotlin/io/raemian/DevelopTest.kt diff --git a/core/core-api/src/test/kotlin/io/raemian/core/api/controller/v1/ExampleControllerTest.kt b/application/api/src/test/kotlin/io/raemian/core/api/controller/v1/ExampleControllerTest.kt similarity index 100% rename from core/core-api/src/test/kotlin/io/raemian/core/api/controller/v1/ExampleControllerTest.kt rename to application/api/src/test/kotlin/io/raemian/core/api/controller/v1/ExampleControllerTest.kt diff --git a/clients/client-example/build.gradle.kts b/clients/client-example/build.gradle.kts deleted file mode 100644 index a69d1638..00000000 --- a/clients/client-example/build.gradle.kts +++ /dev/null @@ -1,5 +0,0 @@ -dependencies { - implementation("org.springframework.cloud:spring-cloud-starter-openfeign") - implementation("io.github.openfeign:feign-hc5") - implementation("io.github.openfeign:feign-micrometer") -} diff --git a/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleApi.kt b/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleApi.kt deleted file mode 100644 index e226e60c..00000000 --- a/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleApi.kt +++ /dev/null @@ -1,17 +0,0 @@ -package io.raemian.client.example - -import org.springframework.cloud.openfeign.FeignClient -import org.springframework.http.MediaType -import org.springframework.web.bind.annotation.RequestBody -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RequestMethod - -@FeignClient(value = "example-api", url = "\${example.api.url}") -internal interface ExampleApi { - @RequestMapping( - method = [RequestMethod.POST], - value = ["/example/example-api"], - consumes = [MediaType.APPLICATION_JSON_VALUE], - ) - fun example(@RequestBody request: io.raemian.client.example.ExampleRequestDto): io.raemian.client.example.ExampleResponseDto -} diff --git a/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleClient.kt b/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleClient.kt deleted file mode 100644 index 92a5413b..00000000 --- a/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleClient.kt +++ /dev/null @@ -1,16 +0,0 @@ -package io.raemian.client.example - -import io.raemian.client.example.model.ExampleClientResult -import org.springframework.stereotype.Component - -@Component -class ExampleClient internal constructor( - private val exampleApi: io.raemian.client.example.ExampleApi, -) { - fun example( - exampleParameter: String, - ): io.raemian.client.example.model.ExampleClientResult { - val request = io.raemian.client.example.ExampleRequestDto(exampleParameter) - return exampleApi.example(request).toResult() - } -} diff --git a/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleConfig.kt b/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleConfig.kt deleted file mode 100644 index 6c5842fc..00000000 --- a/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleConfig.kt +++ /dev/null @@ -1,8 +0,0 @@ -package io.raemian.client.example - -import org.springframework.cloud.openfeign.EnableFeignClients -import org.springframework.context.annotation.Configuration - -@EnableFeignClients -@Configuration -internal class ExampleConfig diff --git a/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleRequestDto.kt b/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleRequestDto.kt deleted file mode 100644 index cab3cf49..00000000 --- a/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleRequestDto.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.raemian.client.example - -internal data class ExampleRequestDto( - val exampleRequestValue: String, -) diff --git a/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleResponseDto.kt b/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleResponseDto.kt deleted file mode 100644 index 330b7835..00000000 --- a/clients/client-example/src/main/kotlin/io/raemian/client/example/ExampleResponseDto.kt +++ /dev/null @@ -1,11 +0,0 @@ -package io.raemian.client.example - -import io.raemian.client.example.model.ExampleClientResult - -internal data class ExampleResponseDto( - val exampleResponseValue: String, -) { - fun toResult(): io.raemian.client.example.model.ExampleClientResult { - return io.raemian.client.example.model.ExampleClientResult(exampleResponseValue) - } -} diff --git a/clients/client-example/src/main/kotlin/io/raemian/client/example/model/ExampleClientResult.kt b/clients/client-example/src/main/kotlin/io/raemian/client/example/model/ExampleClientResult.kt deleted file mode 100644 index 5fb74da1..00000000 --- a/clients/client-example/src/main/kotlin/io/raemian/client/example/model/ExampleClientResult.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.raemian.client.example.model - -data class ExampleClientResult( - val exampleResult: String, -) diff --git a/clients/client-example/src/main/resources/client-example.yml b/clients/client-example/src/main/resources/client-example.yml deleted file mode 100644 index 169ee0ed..00000000 --- a/clients/client-example/src/main/resources/client-example.yml +++ /dev/null @@ -1,35 +0,0 @@ -example: - api: - url: https://default.example.example - -spring.cloud.openfeign: - client: - config: - example-api: - connectTimeout: 2100 - readTimeout: 5000 - loggerLevel: full - compression: - response: - enabled: false - httpclient: - max-connections: 2000 - max-connections-per-route: 500 - ---- -spring.config.activate.on-profile: local - ---- -spring.config.activate.on-profile: - - local-dev - - dev - ---- -spring.config.activate.on-profile: - - staging - - live - -example: - api: - url: https://live.example.example - diff --git a/clients/client-example/src/test/kotlin/io/raemian/client/ClientExampleContextTest.kt b/clients/client-example/src/test/kotlin/io/raemian/client/ClientExampleContextTest.kt deleted file mode 100644 index 2142d52e..00000000 --- a/clients/client-example/src/test/kotlin/io/raemian/client/ClientExampleContextTest.kt +++ /dev/null @@ -1,12 +0,0 @@ -package io.raemian.client - -import org.junit.jupiter.api.Tag -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.test.context.ActiveProfiles -import org.springframework.test.context.TestConstructor - -@ActiveProfiles("local") -@Tag("context") -@SpringBootTest -@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL) -abstract class ClientExampleContextTest diff --git a/clients/client-example/src/test/kotlin/io/raemian/client/ClientExampleTestApplication.kt b/clients/client-example/src/test/kotlin/io/raemian/client/ClientExampleTestApplication.kt deleted file mode 100644 index 118fb5e6..00000000 --- a/clients/client-example/src/test/kotlin/io/raemian/client/ClientExampleTestApplication.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.raemian.client - -import org.springframework.boot.autoconfigure.SpringBootApplication -import org.springframework.boot.context.properties.ConfigurationPropertiesScan -import org.springframework.boot.runApplication - -@ConfigurationPropertiesScan -@SpringBootApplication -class ClientExampleTestApplication - -fun main(args: Array) { - runApplication(*args) -} diff --git a/clients/client-example/src/test/kotlin/io/raemian/client/example/ExampleClientTest.kt b/clients/client-example/src/test/kotlin/io/raemian/client/example/ExampleClientTest.kt deleted file mode 100644 index 9e2628cd..00000000 --- a/clients/client-example/src/test/kotlin/io/raemian/client/example/ExampleClientTest.kt +++ /dev/null @@ -1,19 +0,0 @@ -package io.raemian.client.example - -import feign.RetryableException -import io.raemian.client.ClientExampleContextTest -import org.assertj.core.api.Assertions -import org.junit.jupiter.api.Test - -class ExampleClientTest( - val exampleClient: io.raemian.client.example.ExampleClient, -) : io.raemian.client.ClientExampleContextTest() { - @Test - fun shouldBeThrownExceptionWhenExample() { - try { - exampleClient.example("HELLO!") - } catch (e: Exception) { - Assertions.assertThat(e).isExactlyInstanceOf(RetryableException::class.java) - } - } -} diff --git a/clients/client-example/src/test/resources/application.yml b/clients/client-example/src/test/resources/application.yml deleted file mode 100644 index 73319a40..00000000 --- a/clients/client-example/src/test/resources/application.yml +++ /dev/null @@ -1,6 +0,0 @@ -spring.application.name: client-example-test - -spring: - config: - import: - - client-example.yml diff --git a/core/core-enum/build.gradle.kts b/core/core-enum/build.gradle.kts deleted file mode 100644 index e69de29b..00000000 diff --git a/core/core-enum/src/main/kotlin/io/raemian/core/enums/ExampleEnum.kt b/core/core-enum/src/main/kotlin/io/raemian/core/enums/ExampleEnum.kt deleted file mode 100644 index d70a270d..00000000 --- a/core/core-enum/src/main/kotlin/io/raemian/core/enums/ExampleEnum.kt +++ /dev/null @@ -1,3 +0,0 @@ -package io.raemian.core.enums - -enum class ExampleEnum diff --git a/support/logging/build.gradle.kts b/infra/logging/build.gradle.kts similarity index 100% rename from support/logging/build.gradle.kts rename to infra/logging/build.gradle.kts diff --git a/support/logging/src/main/resources/logback/logback-dev.xml b/infra/logging/src/main/resources/logback/logback-dev.xml similarity index 100% rename from support/logging/src/main/resources/logback/logback-dev.xml rename to infra/logging/src/main/resources/logback/logback-dev.xml diff --git a/support/logging/src/main/resources/logback/logback-live.xml b/infra/logging/src/main/resources/logback/logback-live.xml similarity index 100% rename from support/logging/src/main/resources/logback/logback-live.xml rename to infra/logging/src/main/resources/logback/logback-live.xml diff --git a/support/logging/src/main/resources/logback/logback-local-dev.xml b/infra/logging/src/main/resources/logback/logback-local-dev.xml similarity index 100% rename from support/logging/src/main/resources/logback/logback-local-dev.xml rename to infra/logging/src/main/resources/logback/logback-local-dev.xml diff --git a/support/logging/src/main/resources/logback/logback-local.xml b/infra/logging/src/main/resources/logback/logback-local.xml similarity index 100% rename from support/logging/src/main/resources/logback/logback-local.xml rename to infra/logging/src/main/resources/logback/logback-local.xml diff --git a/support/logging/src/main/resources/logback/logback-staging.xml b/infra/logging/src/main/resources/logback/logback-staging.xml similarity index 100% rename from support/logging/src/main/resources/logback/logback-staging.xml rename to infra/logging/src/main/resources/logback/logback-staging.xml diff --git a/support/logging/src/main/resources/logging.yml b/infra/logging/src/main/resources/logging.yml similarity index 100% rename from support/logging/src/main/resources/logging.yml rename to infra/logging/src/main/resources/logging.yml diff --git a/support/monitoring/build.gradle.kts b/infra/monitoring/build.gradle.kts similarity index 100% rename from support/monitoring/build.gradle.kts rename to infra/monitoring/build.gradle.kts diff --git a/support/monitoring/src/main/resources/monitoring.yml b/infra/monitoring/src/main/resources/monitoring.yml similarity index 100% rename from support/monitoring/src/main/resources/monitoring.yml rename to infra/monitoring/src/main/resources/monitoring.yml diff --git a/settings.gradle.kts b/settings.gradle.kts index 97ecbf5a..e71e1ac0 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,13 +1,10 @@ rootProject.name = "one-bailey" include( - "core:core-enum", - "core:core-api", + "application:api", "storage:db-core", - "tests:api-docs", - "support:logging", - "support:monitoring", - "clients:client-example" + "infra:logging", + "infra:monitoring", ) pluginManagement { diff --git a/tests/api-docs/build.gradle.kts b/tests/api-docs/build.gradle.kts deleted file mode 100644 index d8a3f863..00000000 --- a/tests/api-docs/build.gradle.kts +++ /dev/null @@ -1,7 +0,0 @@ -dependencies { - compileOnly("jakarta.servlet:jakarta.servlet-api") - compileOnly("org.springframework.boot:spring-boot-starter-test") - api("org.springframework.restdocs:spring-restdocs-mockmvc") - api("org.springframework.restdocs:spring-restdocs-restassured") - api("io.rest-assured:spring-mock-mvc") -} diff --git a/tests/api-docs/src/main/kotlin/io/raemian/test/api/RestDocsTest.kt b/tests/api-docs/src/main/kotlin/io/raemian/test/api/RestDocsTest.kt deleted file mode 100644 index 45982570..00000000 --- a/tests/api-docs/src/main/kotlin/io/raemian/test/api/RestDocsTest.kt +++ /dev/null @@ -1,56 +0,0 @@ -package io.raemian.test.api - -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.databind.SerializationFeature -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import io.restassured.module.mockmvc.RestAssuredMockMvc -import io.restassured.module.mockmvc.specification.MockMvcRequestSpecification -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Tag -import org.junit.jupiter.api.extension.ExtendWith -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter -import org.springframework.restdocs.RestDocumentationContextProvider -import org.springframework.restdocs.RestDocumentationExtension -import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation -import org.springframework.test.web.servlet.MockMvc -import org.springframework.test.web.servlet.setup.MockMvcBuilders -import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder - -@Tag("restdocs") -@ExtendWith(RestDocumentationExtension::class) -abstract class RestDocsTest { - - lateinit var mockMvc: MockMvcRequestSpecification - private lateinit var restDocumentation: RestDocumentationContextProvider - - @BeforeEach - fun setUp(restDocumentation: RestDocumentationContextProvider) { - this.restDocumentation = restDocumentation - } - - protected fun given(): MockMvcRequestSpecification { - return mockMvc - } - - protected fun mockController(controller: Any): MockMvcRequestSpecification { - val mockMvc = createMockMvc(controller) - return RestAssuredMockMvc.given() - .mockMvc(mockMvc) - } - - private fun createMockMvc(controller: Any): MockMvc { - val converter = MappingJackson2HttpMessageConverter(objectMapper()) - - return MockMvcBuilders.standaloneSetup(controller) - .apply(MockMvcRestDocumentation.documentationConfiguration(restDocumentation)) - .setMessageConverters(converter) - .build() - } - - private fun objectMapper(): ObjectMapper { - return jacksonObjectMapper() - .findAndRegisterModules() - .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) - .disable(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS) - } -} diff --git a/tests/api-docs/src/main/kotlin/io/raemian/test/api/RestDocsUtils.kt b/tests/api-docs/src/main/kotlin/io/raemian/test/api/RestDocsUtils.kt deleted file mode 100644 index 00832701..00000000 --- a/tests/api-docs/src/main/kotlin/io/raemian/test/api/RestDocsUtils.kt +++ /dev/null @@ -1,18 +0,0 @@ -package io.raemian.test.api - -import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor -import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor -import org.springframework.restdocs.operation.preprocess.Preprocessors - -object RestDocsUtils { - fun requestPreprocessor(): OperationRequestPreprocessor { - return Preprocessors.preprocessRequest( - Preprocessors.modifyUris().scheme("http").host("dev.io.raemian").removePort(), - Preprocessors.prettyPrint(), - ) - } - - fun responsePreprocessor(): OperationResponsePreprocessor { - return Preprocessors.preprocessResponse(Preprocessors.prettyPrint()) - } -} From 321081e71743fcca5410052c1a756a11276f471f Mon Sep 17 00:00:00 2001 From: wkwon Date: Sun, 26 Nov 2023 15:12:17 +0900 Subject: [PATCH 24/70] style: apply lint --- .../io/raemian/core/api/controller/FaviconController.kt | 3 +-- .../main/kotlin/io/raemian/core/auth/config/CorsConfig.kt | 3 +-- .../io/raemian/core/auth/config/JwtSecurityConfig.kt | 2 -- .../io/raemian/core/auth/config/WebSecurityConfig.kt | 7 ------- .../io/raemian/core/auth/controller/AuthController.kt | 3 +-- .../main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt | 4 +--- .../kotlin/io/raemian/core/auth/domain/OAuthProvider.kt | 2 +- .../kotlin/io/raemian/core/auth/service/AuthService.kt | 2 +- .../io/raemian/core/auth/service/OAuth2UserService.kt | 2 +- .../main/kotlin/io/raemian/core/auth/support/JwtFilter.kt | 7 ++++--- .../kotlin/io/raemian/core/auth/support/SecurityUtil.kt | 3 +-- .../kotlin/io/raemian/core/auth/support/TokenProvider.kt | 6 ++---- .../io/raemian/storage/db/core/token/RefreshToken.kt | 2 +- .../main/kotlin/io/raemian/storage/db/core/user/User.kt | 3 +-- .../io/raemian/storage/db/core/user/UserRepository.kt | 2 +- 15 files changed, 17 insertions(+), 34 deletions(-) diff --git a/application/api/src/main/kotlin/io/raemian/core/api/controller/FaviconController.kt b/application/api/src/main/kotlin/io/raemian/core/api/controller/FaviconController.kt index 8024768d..449dc94b 100644 --- a/application/api/src/main/kotlin/io/raemian/core/api/controller/FaviconController.kt +++ b/application/api/src/main/kotlin/io/raemian/core/api/controller/FaviconController.kt @@ -4,11 +4,10 @@ import org.springframework.stereotype.Controller import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.ResponseBody - @Controller class FaviconController { @GetMapping("favicon.ico") @ResponseBody fun returnNoFavicon() { } -} \ No newline at end of file +} diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt b/application/api/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt index 325fcc04..5ff20827 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt +++ b/application/api/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt @@ -6,7 +6,6 @@ import org.springframework.web.cors.CorsConfiguration import org.springframework.web.cors.UrlBasedCorsConfigurationSource import org.springframework.web.filter.CorsFilter - @Configuration class CorsConfig { @Bean @@ -20,4 +19,4 @@ class CorsConfig { source.registerCorsConfiguration("/**", config) return CorsFilter(source) } -} \ No newline at end of file +} diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/config/JwtSecurityConfig.kt b/application/api/src/main/kotlin/io/raemian/core/auth/config/JwtSecurityConfig.kt index 5a9613bf..2cf1250b 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/config/JwtSecurityConfig.kt +++ b/application/api/src/main/kotlin/io/raemian/core/auth/config/JwtSecurityConfig.kt @@ -7,7 +7,6 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.web.DefaultSecurityFilterChain import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - class JwtSecurityConfig( private val tokenProvider: TokenProvider, ) : SecurityConfigurerAdapter() { @@ -18,4 +17,3 @@ class JwtSecurityConfig( http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter::class.java) } } - diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt b/application/api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt index e7ebc0f0..c7e8888d 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt +++ b/application/api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt @@ -3,8 +3,6 @@ package io.raemian.core.auth.config import io.raemian.core.auth.domain.CurrentUser import io.raemian.core.auth.service.OAuth2UserService import io.raemian.core.auth.support.TokenProvider -import jakarta.servlet.http.Cookie -import jakarta.servlet.http.HttpServletRequest import jakarta.servlet.http.HttpServletResponse import org.slf4j.LoggerFactory import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty @@ -19,17 +17,13 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur import org.springframework.security.config.http.SessionCreationPolicy import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder import org.springframework.security.crypto.password.PasswordEncoder -import org.springframework.security.web.DefaultRedirectStrategy import org.springframework.security.web.DefaultSecurityFilterChain -import org.springframework.security.web.RedirectStrategy import org.springframework.security.web.SecurityFilterChain -import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter import org.springframework.security.web.util.matcher.AntPathRequestMatcher import org.springframework.web.filter.CorsFilter import java.nio.charset.StandardCharsets - @Configuration @EnableWebSecurity class WebSecurityConfig( @@ -79,7 +73,6 @@ class WebSecurityConfig( log.info("eeeeeeeeeeeeeeeeeeee + ${exception.message}") response.addHeader("x-token", exception.message) } - } .sessionManagement { it.sessionCreationPolicy(SessionCreationPolicy.STATELESS) } .apply(JwtSecurityConfig(tokenProvider)) diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/controller/AuthController.kt b/application/api/src/main/kotlin/io/raemian/core/auth/controller/AuthController.kt index d32f7dbd..da09bd72 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/controller/AuthController.kt +++ b/application/api/src/main/kotlin/io/raemian/core/auth/controller/AuthController.kt @@ -31,5 +31,4 @@ class AuthController( fun my(@AuthenticationPrincipal currentUser: CurrentUser): CurrentUser { return currentUser } - -} \ No newline at end of file +} diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt b/application/api/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt index cb480e27..c9ff741d 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt +++ b/application/api/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt @@ -22,7 +22,6 @@ data class CurrentUser( .map { SimpleGrantedAuthority(it) } .toMutableList() - override fun getPassword(): String = password override fun getUsername(): String = email @@ -34,5 +33,4 @@ data class CurrentUser( override fun isCredentialsNonExpired(): Boolean = true override fun isEnabled(): Boolean = true - -} \ No newline at end of file +} diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/domain/OAuthProvider.kt b/application/api/src/main/kotlin/io/raemian/core/auth/domain/OAuthProvider.kt index 9139da2a..8f8babe3 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/domain/OAuthProvider.kt +++ b/application/api/src/main/kotlin/io/raemian/core/auth/domain/OAuthProvider.kt @@ -2,4 +2,4 @@ package io.raemian.core.auth.domain enum class OAuthProvider { GOOGLE, NAVER -} \ No newline at end of file +} diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/service/AuthService.kt b/application/api/src/main/kotlin/io/raemian/core/auth/service/AuthService.kt index 5cc66dc6..9e59d2fe 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/service/AuthService.kt +++ b/application/api/src/main/kotlin/io/raemian/core/auth/service/AuthService.kt @@ -54,4 +54,4 @@ class AuthService( return tokenDTO } -} \ No newline at end of file +} diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt b/application/api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt index aa7a9257..1c5250d5 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt +++ b/application/api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt @@ -54,4 +54,4 @@ class OAuth2UserService( return userRepository.findByEmail(email) ?: return userRepository.save(User(email = email, password = "", authority = Authority.ROLE_USER)) } -} \ No newline at end of file +} diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/support/JwtFilter.kt b/application/api/src/main/kotlin/io/raemian/core/auth/support/JwtFilter.kt index 2a5d70f2..3e89c202 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/support/JwtFilter.kt +++ b/application/api/src/main/kotlin/io/raemian/core/auth/support/JwtFilter.kt @@ -8,7 +8,6 @@ import org.springframework.security.core.context.SecurityContextHolder import org.springframework.util.StringUtils import org.springframework.web.filter.OncePerRequestFilter - class JwtFilter( private val tokenProvider: TokenProvider, ) : OncePerRequestFilter() { @@ -37,6 +36,8 @@ class JwtFilter( val bearerToken = request.getHeader(AUTHORIZATION_HEADER) return if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(BEARER_PREFIX)) { bearerToken.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1].trim { it <= ' ' } - } else "" + } else { + "" + } } -} \ No newline at end of file +} diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/support/SecurityUtil.kt b/application/api/src/main/kotlin/io/raemian/core/auth/support/SecurityUtil.kt index b6d63b9f..c3cd8ac0 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/support/SecurityUtil.kt +++ b/application/api/src/main/kotlin/io/raemian/core/auth/support/SecurityUtil.kt @@ -3,7 +3,6 @@ package io.raemian.core.auth.support import org.springframework.security.core.Authentication import org.springframework.security.core.context.SecurityContextHolder - object SecurityUtil { // SecurityContext 에 유저 정보가 저장되는 시점 fun currentMemberId(): Long { @@ -13,4 +12,4 @@ object SecurityUtil { } return authentication.name.toLong() } -} \ No newline at end of file +} diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt b/application/api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt index eeae9eb2..3808e91d 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt +++ b/application/api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt @@ -20,7 +20,6 @@ import java.security.Key import java.time.Duration import java.util.Date - @Component class TokenProvider { @@ -34,10 +33,9 @@ class TokenProvider { private val EMAIL_KEY = "email" private val ID_KEY = "id" private val BEARER_TYPE = "Bearer" - private val ACCESS_TOKEN_EXPIRE_TIME = Duration.ofMinutes(300).toMillis() // 300분 + private val ACCESS_TOKEN_EXPIRE_TIME = Duration.ofMinutes(300).toMillis() // 300분 private val REFRESH_TOKEN_EXPIRE_TIME = Duration.ofDays(70).toMillis() // 70일 - fun generateTokenDto(currentUser: CurrentUser): TokenDTO { val authorities: String = currentUser.authorities .map { obj: GrantedAuthority -> obj.authority } @@ -149,4 +147,4 @@ class TokenProvider { e.claims } } -} \ No newline at end of file +} diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/token/RefreshToken.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/token/RefreshToken.kt index 70afb820..d7dd63d6 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/token/RefreshToken.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/token/RefreshToken.kt @@ -9,4 +9,4 @@ // val id: Long, // val key: String, // val value: String, -// ) \ No newline at end of file +// ) diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt index a4428806..7a11114c 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt @@ -17,7 +17,6 @@ class User( val authority: Authority, ) : BaseEntity() - enum class Authority { ROLE_USER, ROLE_ADMIN -} \ No newline at end of file +} diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/UserRepository.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/UserRepository.kt index d35eda34..5d95e378 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/UserRepository.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/UserRepository.kt @@ -5,4 +5,4 @@ import org.springframework.data.jpa.repository.JpaRepository interface UserRepository : JpaRepository { fun findByEmail(email: String): User? fun existsByEmail(email: String): Boolean -} \ No newline at end of file +} From 658b71a2f339cb80e27c3d5321b8b53953906b16 Mon Sep 17 00:00:00 2001 From: wkwon Date: Sun, 26 Nov 2023 15:17:58 +0900 Subject: [PATCH 25/70] fix: fix package path --- .../kotlin/io/raemian/storage/db/core/ExampleRepositoryIT.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/db-core/src/test/kotlin/io/raemian/storage/db/core/ExampleRepositoryIT.kt b/storage/db-core/src/test/kotlin/io/raemian/storage/db/core/ExampleRepositoryIT.kt index b3e498da..3d2d89aa 100644 --- a/storage/db-core/src/test/kotlin/io/raemian/storage/db/core/ExampleRepositoryIT.kt +++ b/storage/db-core/src/test/kotlin/io/raemian/storage/db/core/ExampleRepositoryIT.kt @@ -1,7 +1,7 @@ package io.raemian.storage.db.core -import io.raemian.springboot.storage.db.core.ExampleEntity -import io.raemian.springboot.storage.db.core.ExampleRepository +import io.raemian.storage.db.core.ExampleEntity +import io.raemian.storage.db.core.ExampleRepository import io.raemian.storage.db.CoreDbContextTest import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test From 528b77df46ed73399b754fdb3f481f62471eebff Mon Sep 17 00:00:00 2001 From: wkwon Date: Sun, 26 Nov 2023 15:21:56 +0900 Subject: [PATCH 26/70] style: apply lint --- .../kotlin/io/raemian/storage/db/core/ExampleRepositoryIT.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/storage/db-core/src/test/kotlin/io/raemian/storage/db/core/ExampleRepositoryIT.kt b/storage/db-core/src/test/kotlin/io/raemian/storage/db/core/ExampleRepositoryIT.kt index 3d2d89aa..cb1effbf 100644 --- a/storage/db-core/src/test/kotlin/io/raemian/storage/db/core/ExampleRepositoryIT.kt +++ b/storage/db-core/src/test/kotlin/io/raemian/storage/db/core/ExampleRepositoryIT.kt @@ -1,7 +1,5 @@ package io.raemian.storage.db.core -import io.raemian.storage.db.core.ExampleEntity -import io.raemian.storage.db.core.ExampleRepository import io.raemian.storage.db.CoreDbContextTest import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test From 9c6fe52c83a57e3dac8c5b375b48edcf5c47637b Mon Sep 17 00:00:00 2001 From: wkwon Date: Mon, 27 Nov 2023 23:17:18 +0900 Subject: [PATCH 27/70] delete: delete example test --- .../src/test/kotlin/io/raemian/ContextTest.kt | 10 -- .../io/raemian/CoreApiApplicationTest.kt | 10 -- .../src/test/kotlin/io/raemian/DevelopTest.kt | 10 -- .../controller/v1/ExampleControllerTest.kt | 91 ------------------- 4 files changed, 121 deletions(-) delete mode 100644 application/api/src/test/kotlin/io/raemian/ContextTest.kt delete mode 100644 application/api/src/test/kotlin/io/raemian/CoreApiApplicationTest.kt delete mode 100644 application/api/src/test/kotlin/io/raemian/DevelopTest.kt delete mode 100644 application/api/src/test/kotlin/io/raemian/core/api/controller/v1/ExampleControllerTest.kt diff --git a/application/api/src/test/kotlin/io/raemian/ContextTest.kt b/application/api/src/test/kotlin/io/raemian/ContextTest.kt deleted file mode 100644 index d090951c..00000000 --- a/application/api/src/test/kotlin/io/raemian/ContextTest.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.raemian - -import org.junit.jupiter.api.Tag -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.test.context.TestConstructor - -@Tag("context") -@SpringBootTest -@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL) -abstract class ContextTest diff --git a/application/api/src/test/kotlin/io/raemian/CoreApiApplicationTest.kt b/application/api/src/test/kotlin/io/raemian/CoreApiApplicationTest.kt deleted file mode 100644 index 65f02181..00000000 --- a/application/api/src/test/kotlin/io/raemian/CoreApiApplicationTest.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.raemian - -import org.junit.jupiter.api.Test - -internal class CoreApiApplicationTest : ContextTest() { - @Test - fun shouldBeLoadedContext() { - // it should be passed - } -} diff --git a/application/api/src/test/kotlin/io/raemian/DevelopTest.kt b/application/api/src/test/kotlin/io/raemian/DevelopTest.kt deleted file mode 100644 index 22e1fb15..00000000 --- a/application/api/src/test/kotlin/io/raemian/DevelopTest.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.raemian - -import org.junit.jupiter.api.Tag -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.test.context.TestConstructor - -@Tag("develop") -@SpringBootTest -@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL) -abstract class DevelopTest diff --git a/application/api/src/test/kotlin/io/raemian/core/api/controller/v1/ExampleControllerTest.kt b/application/api/src/test/kotlin/io/raemian/core/api/controller/v1/ExampleControllerTest.kt deleted file mode 100644 index db839bdc..00000000 --- a/application/api/src/test/kotlin/io/raemian/core/api/controller/v1/ExampleControllerTest.kt +++ /dev/null @@ -1,91 +0,0 @@ -package io.raemian.core.api.controller.v1 - -import io.mockk.every -import io.mockk.mockk -import io.raemian.core.api.controller.v1.request.ExampleRequestDto -import io.raemian.core.api.domain.ExampleResult -import io.raemian.core.api.domain.ExampleService -import io.raemian.test.api.RestDocsTest -import io.raemian.test.api.RestDocsUtils.requestPreprocessor -import io.raemian.test.api.RestDocsUtils.responsePreprocessor -import io.restassured.http.ContentType -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.springframework.http.HttpStatus -import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document -import org.springframework.restdocs.payload.JsonFieldType -import org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath -import org.springframework.restdocs.payload.PayloadDocumentation.requestFields -import org.springframework.restdocs.payload.PayloadDocumentation.responseFields -import org.springframework.restdocs.request.RequestDocumentation -import org.springframework.restdocs.request.RequestDocumentation.parameterWithName -import org.springframework.restdocs.request.RequestDocumentation.queryParameters - -class ExampleControllerTest : RestDocsTest() { - private lateinit var exampleService: ExampleService - private lateinit var controller: ExampleController - - @BeforeEach - fun setUp() { - exampleService = mockk() - controller = ExampleController(exampleService) - mockMvc = mockController(controller) - } - - @Test - fun exampleGet() { - every { exampleService.processExample(any()) } returns ExampleResult("BYE") - - given() - .contentType(ContentType.JSON) - .queryParam("exampleParam", "HELLO_PARAM") - .get("/get/{exampleValue}", "HELLO_PATH") - .then() - .status(HttpStatus.OK) - .apply( - document( - "exampleGet", - requestPreprocessor(), - responsePreprocessor(), - RequestDocumentation.pathParameters( - parameterWithName("exampleValue").description("ExampleValue"), - ), - queryParameters( - parameterWithName("exampleParam").description("ExampleParam"), - ), - responseFields( - fieldWithPath("result").type(JsonFieldType.STRING).description("ResultType"), - fieldWithPath("data.result").type(JsonFieldType.STRING).description("Result Date"), - fieldWithPath("error").type(JsonFieldType.NULL).ignored(), - ), - ), - ) - } - - @Test - fun examplePost() { - every { exampleService.processExample(any()) } returns ExampleResult("BYE") - - given() - .contentType(ContentType.JSON) - .body(ExampleRequestDto("HELLO_BODY")) - .post("/post") - .then() - .status(HttpStatus.OK) - .apply( - document( - "examplePost", - requestPreprocessor(), - responsePreprocessor(), - requestFields( - fieldWithPath("data").type(JsonFieldType.STRING).description("ExampleBody Data Field"), - ), - responseFields( - fieldWithPath("result").type(JsonFieldType.STRING).description("ResultType"), - fieldWithPath("data.result").type(JsonFieldType.STRING).description("Result Date"), - fieldWithPath("error").type(JsonFieldType.STRING).ignored(), - ), - ), - ) - } -} From 3ddd4334d16b85b4d773578fbda5f0452c5e1d8e Mon Sep 17 00:00:00 2001 From: wkwon Date: Mon, 27 Nov 2023 23:29:00 +0900 Subject: [PATCH 28/70] =?UTF-8?q?refactor:=20package=20path=20=EC=88=98?= =?UTF-8?q?=EC=A0=95(auth=20=ED=8C=A8=ED=82=A4=EC=A7=80=20api=20=EB=82=B4?= =?UTF-8?q?=EB=B6=80=EB=A1=9C=20=EC=9D=B4=EB=8F=99)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{core/auth => api}/config/CorsConfig.kt | 2 +- .../config/GlobalExceptionHandler.kt} | 10 +++--- .../auth => api}/config/JwtSecurityConfig.kt | 6 ++-- .../auth => api}/config/WebSecurityConfig.kt | 10 +++--- .../controller/auth}/AuthController.kt | 12 +++---- .../controller/auth}/request/SignInRequest.kt | 2 +- .../controller/auth}/request/SignUpRequest.kt | 2 +- .../domain => api/domain/auth}/CurrentUser.kt | 2 +- .../domain/auth}/OAuthProvider.kt | 2 +- .../domain => api/domain/auth}/TokenDTO.kt | 2 +- .../service/auth}/AuthService.kt | 8 ++--- .../service/auth}/OAuth2UserService.kt | 6 ++-- .../{core/auth => api}/support/JwtFilter.kt | 2 +- .../auth => api}/support/SecurityUtil.kt | 2 +- .../auth => api}/support/TokenProvider.kt | 6 ++-- .../api/support/error/CoreApiException.kt | 2 +- .../io/raemian/api/support/error/ErrorCode.kt | 5 +++ .../api/support/error/ErrorMessage.kt | 2 +- .../{core => }/api/support/error/ErrorType.kt | 2 +- .../api/support/response/ApiResponse.kt | 6 ++-- .../api/support/response/ResultType.kt | 2 +- .../io/raemian/core/api/config/AsyncConfig.kt | 27 -------------- .../core/api/config/AsyncExceptionHandler.kt | 23 ------------ .../core/api/controller/FaviconController.kt | 13 ------- .../core/api/controller/HealthController.kt | 14 -------- .../api/controller/v1/ExampleController.kt | 35 ------------------- .../v1/request/ExampleRequestDto.kt | 11 ------ .../v1/response/ExampleResponseDto.kt | 5 --- .../io/raemian/core/api/domain/ExampleData.kt | 6 ---- .../raemian/core/api/domain/ExampleResult.kt | 5 --- .../raemian/core/api/domain/ExampleService.kt | 10 ------ .../core/api/support/error/ErrorCode.kt | 5 --- 32 files changed, 49 insertions(+), 198 deletions(-) rename application/api/src/main/kotlin/io/raemian/{core/auth => api}/config/CorsConfig.kt (95%) rename application/api/src/main/kotlin/io/raemian/{core/api/controller/ApiControllerAdvice.kt => api/config/GlobalExceptionHandler.kt} (83%) rename application/api/src/main/kotlin/io/raemian/{core/auth => api}/config/JwtSecurityConfig.kt (85%) rename application/api/src/main/kotlin/io/raemian/{core/auth => api}/config/WebSecurityConfig.kt (94%) rename application/api/src/main/kotlin/io/raemian/{core/auth/controller => api/controller/auth}/AuthController.kt (75%) rename application/api/src/main/kotlin/io/raemian/{core/auth/controller/v1 => api/controller/auth}/request/SignInRequest.kt (60%) rename application/api/src/main/kotlin/io/raemian/{core/auth/controller/v1 => api/controller/auth}/request/SignUpRequest.kt (60%) rename application/api/src/main/kotlin/io/raemian/{core/auth/domain => api/domain/auth}/CurrentUser.kt (96%) rename application/api/src/main/kotlin/io/raemian/{core/auth/domain => api/domain/auth}/OAuthProvider.kt (57%) rename application/api/src/main/kotlin/io/raemian/{core/auth/domain => api/domain/auth}/TokenDTO.kt (80%) rename application/api/src/main/kotlin/io/raemian/{core/auth/service => api/service/auth}/AuthService.kt (92%) rename application/api/src/main/kotlin/io/raemian/{core/auth/service => api/service/auth}/OAuth2UserService.kt (94%) rename application/api/src/main/kotlin/io/raemian/{core/auth => api}/support/JwtFilter.kt (97%) rename application/api/src/main/kotlin/io/raemian/{core/auth => api}/support/SecurityUtil.kt (93%) rename application/api/src/main/kotlin/io/raemian/{core/auth => api}/support/TokenProvider.kt (97%) rename application/api/src/main/kotlin/io/raemian/{core => }/api/support/error/CoreApiException.kt (74%) create mode 100644 application/api/src/main/kotlin/io/raemian/api/support/error/ErrorCode.kt rename application/api/src/main/kotlin/io/raemian/{core => }/api/support/error/ErrorMessage.kt (87%) rename application/api/src/main/kotlin/io/raemian/{core => }/api/support/error/ErrorType.kt (88%) rename application/api/src/main/kotlin/io/raemian/{core => }/api/support/response/ApiResponse.kt (79%) rename application/api/src/main/kotlin/io/raemian/{core => }/api/support/response/ResultType.kt (50%) delete mode 100644 application/api/src/main/kotlin/io/raemian/core/api/config/AsyncConfig.kt delete mode 100644 application/api/src/main/kotlin/io/raemian/core/api/config/AsyncExceptionHandler.kt delete mode 100644 application/api/src/main/kotlin/io/raemian/core/api/controller/FaviconController.kt delete mode 100644 application/api/src/main/kotlin/io/raemian/core/api/controller/HealthController.kt delete mode 100644 application/api/src/main/kotlin/io/raemian/core/api/controller/v1/ExampleController.kt delete mode 100644 application/api/src/main/kotlin/io/raemian/core/api/controller/v1/request/ExampleRequestDto.kt delete mode 100644 application/api/src/main/kotlin/io/raemian/core/api/controller/v1/response/ExampleResponseDto.kt delete mode 100644 application/api/src/main/kotlin/io/raemian/core/api/domain/ExampleData.kt delete mode 100644 application/api/src/main/kotlin/io/raemian/core/api/domain/ExampleResult.kt delete mode 100644 application/api/src/main/kotlin/io/raemian/core/api/domain/ExampleService.kt delete mode 100644 application/api/src/main/kotlin/io/raemian/core/api/support/error/ErrorCode.kt diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt b/application/api/src/main/kotlin/io/raemian/api/config/CorsConfig.kt similarity index 95% rename from application/api/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt rename to application/api/src/main/kotlin/io/raemian/api/config/CorsConfig.kt index 5ff20827..57bdf97b 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/config/CorsConfig.kt +++ b/application/api/src/main/kotlin/io/raemian/api/config/CorsConfig.kt @@ -1,4 +1,4 @@ -package io.raemian.core.auth.config +package io.raemian.api.config import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration diff --git a/application/api/src/main/kotlin/io/raemian/core/api/controller/ApiControllerAdvice.kt b/application/api/src/main/kotlin/io/raemian/api/config/GlobalExceptionHandler.kt similarity index 83% rename from application/api/src/main/kotlin/io/raemian/core/api/controller/ApiControllerAdvice.kt rename to application/api/src/main/kotlin/io/raemian/api/config/GlobalExceptionHandler.kt index f382ca34..cc0d8090 100644 --- a/application/api/src/main/kotlin/io/raemian/core/api/controller/ApiControllerAdvice.kt +++ b/application/api/src/main/kotlin/io/raemian/api/config/GlobalExceptionHandler.kt @@ -1,8 +1,8 @@ -package io.raemian.core.api.controller +package io.raemian.api.config -import io.raemian.core.api.support.error.CoreApiException -import io.raemian.core.api.support.error.ErrorType -import io.raemian.core.api.support.response.ApiResponse +import io.raemian.api.support.error.CoreApiException +import io.raemian.api.support.error.ErrorType +import io.raemian.api.support.response.ApiResponse import org.slf4j.Logger import org.slf4j.LoggerFactory import org.springframework.boot.logging.LogLevel @@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.web.bind.annotation.RestControllerAdvice @RestControllerAdvice -class ApiControllerAdvice { +class GlobalExceptionHandler { private val log: Logger = LoggerFactory.getLogger(javaClass) @ExceptionHandler(CoreApiException::class) diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/config/JwtSecurityConfig.kt b/application/api/src/main/kotlin/io/raemian/api/config/JwtSecurityConfig.kt similarity index 85% rename from application/api/src/main/kotlin/io/raemian/core/auth/config/JwtSecurityConfig.kt rename to application/api/src/main/kotlin/io/raemian/api/config/JwtSecurityConfig.kt index 2cf1250b..161f6495 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/config/JwtSecurityConfig.kt +++ b/application/api/src/main/kotlin/io/raemian/api/config/JwtSecurityConfig.kt @@ -1,7 +1,7 @@ -package io.raemian.core.auth.config +package io.raemian.api.config -import io.raemian.core.auth.support.JwtFilter -import io.raemian.core.auth.support.TokenProvider +import io.raemian.api.support.JwtFilter +import io.raemian.api.support.TokenProvider import org.springframework.security.config.annotation.SecurityConfigurerAdapter import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.web.DefaultSecurityFilterChain diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt b/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt similarity index 94% rename from application/api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt rename to application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt index c7e8888d..87e4e04d 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/config/WebSecurityConfig.kt +++ b/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt @@ -1,8 +1,8 @@ -package io.raemian.core.auth.config +package io.raemian.api.config -import io.raemian.core.auth.domain.CurrentUser -import io.raemian.core.auth.service.OAuth2UserService -import io.raemian.core.auth.support.TokenProvider +import io.raemian.api.domain.auth.CurrentUser +import io.raemian.api.service.auth.OAuth2UserService +import io.raemian.api.support.TokenProvider import jakarta.servlet.http.HttpServletResponse import org.slf4j.LoggerFactory import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty @@ -75,7 +75,7 @@ class WebSecurityConfig( } } .sessionManagement { it.sessionCreationPolicy(SessionCreationPolicy.STATELESS) } - .apply(JwtSecurityConfig(tokenProvider)) + .apply(io.raemian.api.config.JwtSecurityConfig(tokenProvider)) return http.build() } diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/controller/AuthController.kt b/application/api/src/main/kotlin/io/raemian/api/controller/auth/AuthController.kt similarity index 75% rename from application/api/src/main/kotlin/io/raemian/core/auth/controller/AuthController.kt rename to application/api/src/main/kotlin/io/raemian/api/controller/auth/AuthController.kt index da09bd72..1782f7c2 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/controller/AuthController.kt +++ b/application/api/src/main/kotlin/io/raemian/api/controller/auth/AuthController.kt @@ -1,10 +1,10 @@ -package io.raemian.core.auth.controller +package io.raemian.api.controller.auth -import io.raemian.core.auth.controller.v1.request.SignInRequest -import io.raemian.core.auth.controller.v1.request.SignUpRequest -import io.raemian.core.auth.domain.CurrentUser -import io.raemian.core.auth.domain.TokenDTO -import io.raemian.core.auth.service.AuthService +import io.raemian.api.controller.auth.request.SignInRequest +import io.raemian.api.controller.auth.request.SignUpRequest +import io.raemian.api.domain.auth.CurrentUser +import io.raemian.api.domain.auth.TokenDTO +import io.raemian.api.service.auth.AuthService import org.springframework.security.core.annotation.AuthenticationPrincipal import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PostMapping diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignInRequest.kt b/application/api/src/main/kotlin/io/raemian/api/controller/auth/request/SignInRequest.kt similarity index 60% rename from application/api/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignInRequest.kt rename to application/api/src/main/kotlin/io/raemian/api/controller/auth/request/SignInRequest.kt index 1024b3dd..db1c68d1 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignInRequest.kt +++ b/application/api/src/main/kotlin/io/raemian/api/controller/auth/request/SignInRequest.kt @@ -1,4 +1,4 @@ -package io.raemian.core.auth.controller.v1.request +package io.raemian.api.controller.auth.request data class SignInRequest( val email: String, diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignUpRequest.kt b/application/api/src/main/kotlin/io/raemian/api/controller/auth/request/SignUpRequest.kt similarity index 60% rename from application/api/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignUpRequest.kt rename to application/api/src/main/kotlin/io/raemian/api/controller/auth/request/SignUpRequest.kt index 26381353..e88e50e7 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/controller/v1/request/SignUpRequest.kt +++ b/application/api/src/main/kotlin/io/raemian/api/controller/auth/request/SignUpRequest.kt @@ -1,4 +1,4 @@ -package io.raemian.core.auth.controller.v1.request +package io.raemian.api.controller.auth.request data class SignUpRequest( val email: String, diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt b/application/api/src/main/kotlin/io/raemian/api/domain/auth/CurrentUser.kt similarity index 96% rename from application/api/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt rename to application/api/src/main/kotlin/io/raemian/api/domain/auth/CurrentUser.kt index c9ff741d..dd2c3eba 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/domain/CurrentUser.kt +++ b/application/api/src/main/kotlin/io/raemian/api/domain/auth/CurrentUser.kt @@ -1,4 +1,4 @@ -package io.raemian.core.auth.domain +package io.raemian.api.domain.auth import org.springframework.security.core.GrantedAuthority import org.springframework.security.core.authority.SimpleGrantedAuthority diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/domain/OAuthProvider.kt b/application/api/src/main/kotlin/io/raemian/api/domain/auth/OAuthProvider.kt similarity index 57% rename from application/api/src/main/kotlin/io/raemian/core/auth/domain/OAuthProvider.kt rename to application/api/src/main/kotlin/io/raemian/api/domain/auth/OAuthProvider.kt index 8f8babe3..983d3e74 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/domain/OAuthProvider.kt +++ b/application/api/src/main/kotlin/io/raemian/api/domain/auth/OAuthProvider.kt @@ -1,4 +1,4 @@ -package io.raemian.core.auth.domain +package io.raemian.api.domain.auth enum class OAuthProvider { GOOGLE, NAVER diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/domain/TokenDTO.kt b/application/api/src/main/kotlin/io/raemian/api/domain/auth/TokenDTO.kt similarity index 80% rename from application/api/src/main/kotlin/io/raemian/core/auth/domain/TokenDTO.kt rename to application/api/src/main/kotlin/io/raemian/api/domain/auth/TokenDTO.kt index 8caa3a88..7e2238b9 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/domain/TokenDTO.kt +++ b/application/api/src/main/kotlin/io/raemian/api/domain/auth/TokenDTO.kt @@ -1,4 +1,4 @@ -package io.raemian.core.auth.domain +package io.raemian.api.domain.auth data class TokenDTO( val grantType: String, diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/service/AuthService.kt b/application/api/src/main/kotlin/io/raemian/api/service/auth/AuthService.kt similarity index 92% rename from application/api/src/main/kotlin/io/raemian/core/auth/service/AuthService.kt rename to application/api/src/main/kotlin/io/raemian/api/service/auth/AuthService.kt index 9e59d2fe..bddd4843 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/service/AuthService.kt +++ b/application/api/src/main/kotlin/io/raemian/api/service/auth/AuthService.kt @@ -1,8 +1,8 @@ -package io.raemian.core.auth.service +package io.raemian.api.service.auth -import io.raemian.core.auth.domain.CurrentUser -import io.raemian.core.auth.domain.TokenDTO -import io.raemian.core.auth.support.TokenProvider +import io.raemian.api.domain.auth.CurrentUser +import io.raemian.api.domain.auth.TokenDTO +import io.raemian.api.support.TokenProvider import io.raemian.storage.db.core.user.Authority import io.raemian.storage.db.core.user.User import io.raemian.storage.db.core.user.UserRepository diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt b/application/api/src/main/kotlin/io/raemian/api/service/auth/OAuth2UserService.kt similarity index 94% rename from application/api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt rename to application/api/src/main/kotlin/io/raemian/api/service/auth/OAuth2UserService.kt index 1c5250d5..6d04cc3f 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/service/OAuth2UserService.kt +++ b/application/api/src/main/kotlin/io/raemian/api/service/auth/OAuth2UserService.kt @@ -1,7 +1,7 @@ -package io.raemian.core.auth.service +package io.raemian.api.service.auth -import io.raemian.core.auth.domain.CurrentUser -import io.raemian.core.auth.domain.OAuthProvider +import io.raemian.api.domain.auth.CurrentUser +import io.raemian.api.domain.auth.OAuthProvider import io.raemian.storage.db.core.user.Authority import io.raemian.storage.db.core.user.User import io.raemian.storage.db.core.user.UserRepository diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/support/JwtFilter.kt b/application/api/src/main/kotlin/io/raemian/api/support/JwtFilter.kt similarity index 97% rename from application/api/src/main/kotlin/io/raemian/core/auth/support/JwtFilter.kt rename to application/api/src/main/kotlin/io/raemian/api/support/JwtFilter.kt index 3e89c202..868fbe8c 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/support/JwtFilter.kt +++ b/application/api/src/main/kotlin/io/raemian/api/support/JwtFilter.kt @@ -1,4 +1,4 @@ -package io.raemian.core.auth.support +package io.raemian.api.support import jakarta.servlet.FilterChain import jakarta.servlet.http.HttpServletRequest diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/support/SecurityUtil.kt b/application/api/src/main/kotlin/io/raemian/api/support/SecurityUtil.kt similarity index 93% rename from application/api/src/main/kotlin/io/raemian/core/auth/support/SecurityUtil.kt rename to application/api/src/main/kotlin/io/raemian/api/support/SecurityUtil.kt index c3cd8ac0..9258a157 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/support/SecurityUtil.kt +++ b/application/api/src/main/kotlin/io/raemian/api/support/SecurityUtil.kt @@ -1,4 +1,4 @@ -package io.raemian.core.auth.support +package io.raemian.api.support import org.springframework.security.core.Authentication import org.springframework.security.core.context.SecurityContextHolder diff --git a/application/api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt b/application/api/src/main/kotlin/io/raemian/api/support/TokenProvider.kt similarity index 97% rename from application/api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt rename to application/api/src/main/kotlin/io/raemian/api/support/TokenProvider.kt index 3808e91d..34bcd169 100644 --- a/application/api/src/main/kotlin/io/raemian/core/auth/support/TokenProvider.kt +++ b/application/api/src/main/kotlin/io/raemian/api/support/TokenProvider.kt @@ -1,4 +1,4 @@ -package io.raemian.core.auth.support +package io.raemian.api.support import io.jsonwebtoken.Claims import io.jsonwebtoken.ExpiredJwtException @@ -9,8 +9,8 @@ import io.jsonwebtoken.UnsupportedJwtException import io.jsonwebtoken.io.Decoders import io.jsonwebtoken.security.Keys import io.jsonwebtoken.security.SecurityException -import io.raemian.core.auth.domain.CurrentUser -import io.raemian.core.auth.domain.TokenDTO +import io.raemian.api.domain.auth.CurrentUser +import io.raemian.api.domain.auth.TokenDTO import org.slf4j.LoggerFactory import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.core.Authentication diff --git a/application/api/src/main/kotlin/io/raemian/core/api/support/error/CoreApiException.kt b/application/api/src/main/kotlin/io/raemian/api/support/error/CoreApiException.kt similarity index 74% rename from application/api/src/main/kotlin/io/raemian/core/api/support/error/CoreApiException.kt rename to application/api/src/main/kotlin/io/raemian/api/support/error/CoreApiException.kt index bb2aed30..569f4251 100644 --- a/application/api/src/main/kotlin/io/raemian/core/api/support/error/CoreApiException.kt +++ b/application/api/src/main/kotlin/io/raemian/api/support/error/CoreApiException.kt @@ -1,4 +1,4 @@ -package io.raemian.core.api.support.error +package io.raemian.api.support.error class CoreApiException( val errorType: ErrorType, diff --git a/application/api/src/main/kotlin/io/raemian/api/support/error/ErrorCode.kt b/application/api/src/main/kotlin/io/raemian/api/support/error/ErrorCode.kt new file mode 100644 index 00000000..df31d44f --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/support/error/ErrorCode.kt @@ -0,0 +1,5 @@ +package io.raemian.api.support.error + +enum class ErrorCode { + E500, +} diff --git a/application/api/src/main/kotlin/io/raemian/core/api/support/error/ErrorMessage.kt b/application/api/src/main/kotlin/io/raemian/api/support/error/ErrorMessage.kt similarity index 87% rename from application/api/src/main/kotlin/io/raemian/core/api/support/error/ErrorMessage.kt rename to application/api/src/main/kotlin/io/raemian/api/support/error/ErrorMessage.kt index 635eb134..0859c4d2 100644 --- a/application/api/src/main/kotlin/io/raemian/core/api/support/error/ErrorMessage.kt +++ b/application/api/src/main/kotlin/io/raemian/api/support/error/ErrorMessage.kt @@ -1,4 +1,4 @@ -package io.raemian.core.api.support.error +package io.raemian.api.support.error data class ErrorMessage private constructor( val code: String, diff --git a/application/api/src/main/kotlin/io/raemian/core/api/support/error/ErrorType.kt b/application/api/src/main/kotlin/io/raemian/api/support/error/ErrorType.kt similarity index 88% rename from application/api/src/main/kotlin/io/raemian/core/api/support/error/ErrorType.kt rename to application/api/src/main/kotlin/io/raemian/api/support/error/ErrorType.kt index d48bf16c..e92fdcc6 100644 --- a/application/api/src/main/kotlin/io/raemian/core/api/support/error/ErrorType.kt +++ b/application/api/src/main/kotlin/io/raemian/api/support/error/ErrorType.kt @@ -1,4 +1,4 @@ -package io.raemian.core.api.support.error +package io.raemian.api.support.error import org.springframework.boot.logging.LogLevel import org.springframework.http.HttpStatus diff --git a/application/api/src/main/kotlin/io/raemian/core/api/support/response/ApiResponse.kt b/application/api/src/main/kotlin/io/raemian/api/support/response/ApiResponse.kt similarity index 79% rename from application/api/src/main/kotlin/io/raemian/core/api/support/response/ApiResponse.kt rename to application/api/src/main/kotlin/io/raemian/api/support/response/ApiResponse.kt index c76a2fec..96672385 100644 --- a/application/api/src/main/kotlin/io/raemian/core/api/support/response/ApiResponse.kt +++ b/application/api/src/main/kotlin/io/raemian/api/support/response/ApiResponse.kt @@ -1,7 +1,7 @@ -package io.raemian.core.api.support.response +package io.raemian.api.support.response -import io.raemian.core.api.support.error.ErrorMessage -import io.raemian.core.api.support.error.ErrorType +import io.raemian.api.support.error.ErrorMessage +import io.raemian.api.support.error.ErrorType data class ApiResponse private constructor( val result: ResultType, diff --git a/application/api/src/main/kotlin/io/raemian/core/api/support/response/ResultType.kt b/application/api/src/main/kotlin/io/raemian/api/support/response/ResultType.kt similarity index 50% rename from application/api/src/main/kotlin/io/raemian/core/api/support/response/ResultType.kt rename to application/api/src/main/kotlin/io/raemian/api/support/response/ResultType.kt index 9431b844..b8860a45 100644 --- a/application/api/src/main/kotlin/io/raemian/core/api/support/response/ResultType.kt +++ b/application/api/src/main/kotlin/io/raemian/api/support/response/ResultType.kt @@ -1,4 +1,4 @@ -package io.raemian.core.api.support.response +package io.raemian.api.support.response enum class ResultType { SUCCESS, ERROR diff --git a/application/api/src/main/kotlin/io/raemian/core/api/config/AsyncConfig.kt b/application/api/src/main/kotlin/io/raemian/core/api/config/AsyncConfig.kt deleted file mode 100644 index 1857f52a..00000000 --- a/application/api/src/main/kotlin/io/raemian/core/api/config/AsyncConfig.kt +++ /dev/null @@ -1,27 +0,0 @@ -package io.raemian.core.api.config - -import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler -import org.springframework.context.annotation.Configuration -import org.springframework.scheduling.annotation.AsyncConfigurer -import org.springframework.scheduling.annotation.EnableAsync -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor -import java.util.concurrent.Executor - -@Configuration -@EnableAsync -class AsyncConfig : AsyncConfigurer { - override fun getAsyncExecutor(): Executor { - val executor = ThreadPoolTaskExecutor() - executor.corePoolSize = 10 - executor.maxPoolSize = 10 - executor.queueCapacity = 10000 - executor.setWaitForTasksToCompleteOnShutdown(true) - executor.setAwaitTerminationSeconds(10) - executor.initialize() - return executor - } - - override fun getAsyncUncaughtExceptionHandler(): AsyncUncaughtExceptionHandler { - return AsyncExceptionHandler() - } -} diff --git a/application/api/src/main/kotlin/io/raemian/core/api/config/AsyncExceptionHandler.kt b/application/api/src/main/kotlin/io/raemian/core/api/config/AsyncExceptionHandler.kt deleted file mode 100644 index 4358a45d..00000000 --- a/application/api/src/main/kotlin/io/raemian/core/api/config/AsyncExceptionHandler.kt +++ /dev/null @@ -1,23 +0,0 @@ -package io.raemian.core.api.config - -import io.raemian.core.api.support.error.CoreApiException -import org.slf4j.LoggerFactory -import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler -import org.springframework.boot.logging.LogLevel -import java.lang.reflect.Method - -class AsyncExceptionHandler : AsyncUncaughtExceptionHandler { - private val log = LoggerFactory.getLogger(javaClass) - - override fun handleUncaughtException(e: Throwable, method: Method, vararg params: Any?) { - if (e is CoreApiException) { - when (e.errorType.logLevel) { - LogLevel.ERROR -> log.error("CoreApiException : {}", e.message, e) - LogLevel.WARN -> log.warn("CoreApiException : {}", e.message, e) - else -> log.info("CoreApiException : {}", e.message, e) - } - } else { - log.error("Exception : {}", e.message, e) - } - } -} diff --git a/application/api/src/main/kotlin/io/raemian/core/api/controller/FaviconController.kt b/application/api/src/main/kotlin/io/raemian/core/api/controller/FaviconController.kt deleted file mode 100644 index 449dc94b..00000000 --- a/application/api/src/main/kotlin/io/raemian/core/api/controller/FaviconController.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.raemian.core.api.controller - -import org.springframework.stereotype.Controller -import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.ResponseBody - -@Controller -class FaviconController { - @GetMapping("favicon.ico") - @ResponseBody - fun returnNoFavicon() { - } -} diff --git a/application/api/src/main/kotlin/io/raemian/core/api/controller/HealthController.kt b/application/api/src/main/kotlin/io/raemian/core/api/controller/HealthController.kt deleted file mode 100644 index c69d1380..00000000 --- a/application/api/src/main/kotlin/io/raemian/core/api/controller/HealthController.kt +++ /dev/null @@ -1,14 +0,0 @@ -package io.raemian.core.api.controller - -import org.springframework.http.HttpStatus -import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.RestController - -@RestController -class HealthController { - @GetMapping("/health") - fun health(): ResponseEntity<*> { - return ResponseEntity.status(HttpStatus.OK).build() - } -} diff --git a/application/api/src/main/kotlin/io/raemian/core/api/controller/v1/ExampleController.kt b/application/api/src/main/kotlin/io/raemian/core/api/controller/v1/ExampleController.kt deleted file mode 100644 index cc193759..00000000 --- a/application/api/src/main/kotlin/io/raemian/core/api/controller/v1/ExampleController.kt +++ /dev/null @@ -1,35 +0,0 @@ -package io.raemian.core.api.controller.v1 - -import io.raemian.core.api.controller.v1.request.ExampleRequestDto -import io.raemian.core.api.controller.v1.response.ExampleResponseDto -import io.raemian.core.api.domain.ExampleData -import io.raemian.core.api.domain.ExampleService -import io.raemian.core.api.support.response.ApiResponse -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.RequestParam -import org.springframework.web.bind.annotation.RestController - -@RestController -class ExampleController( - val exampleExampleService: ExampleService, -) { - @GetMapping("/get/{exampleValue}") - fun exampleGet( - @PathVariable exampleValue: String, - @RequestParam exampleParam: String, - ): ApiResponse { - val result = exampleExampleService.processExample(ExampleData(exampleValue, exampleParam)) - return ApiResponse.success(ExampleResponseDto(result.data)) - } - - @PostMapping("/post") - fun examplePost( - @RequestBody request: ExampleRequestDto, - ): ApiResponse { - val result = exampleExampleService.processExample(request.toExampleData()) - return ApiResponse.success(ExampleResponseDto(result.data)) - } -} diff --git a/application/api/src/main/kotlin/io/raemian/core/api/controller/v1/request/ExampleRequestDto.kt b/application/api/src/main/kotlin/io/raemian/core/api/controller/v1/request/ExampleRequestDto.kt deleted file mode 100644 index 089d1d4b..00000000 --- a/application/api/src/main/kotlin/io/raemian/core/api/controller/v1/request/ExampleRequestDto.kt +++ /dev/null @@ -1,11 +0,0 @@ -package io.raemian.core.api.controller.v1.request - -import io.raemian.core.api.domain.ExampleData - -data class ExampleRequestDto( - val data: String, -) { - fun toExampleData(): ExampleData { - return ExampleData(data, data) - } -} diff --git a/application/api/src/main/kotlin/io/raemian/core/api/controller/v1/response/ExampleResponseDto.kt b/application/api/src/main/kotlin/io/raemian/core/api/controller/v1/response/ExampleResponseDto.kt deleted file mode 100644 index 4e429eeb..00000000 --- a/application/api/src/main/kotlin/io/raemian/core/api/controller/v1/response/ExampleResponseDto.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.raemian.core.api.controller.v1.response - -data class ExampleResponseDto( - val result: String, -) diff --git a/application/api/src/main/kotlin/io/raemian/core/api/domain/ExampleData.kt b/application/api/src/main/kotlin/io/raemian/core/api/domain/ExampleData.kt deleted file mode 100644 index 5482676e..00000000 --- a/application/api/src/main/kotlin/io/raemian/core/api/domain/ExampleData.kt +++ /dev/null @@ -1,6 +0,0 @@ -package io.raemian.core.api.domain - -data class ExampleData( - val value: String, - val param: String, -) diff --git a/application/api/src/main/kotlin/io/raemian/core/api/domain/ExampleResult.kt b/application/api/src/main/kotlin/io/raemian/core/api/domain/ExampleResult.kt deleted file mode 100644 index d9f4f34c..00000000 --- a/application/api/src/main/kotlin/io/raemian/core/api/domain/ExampleResult.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.raemian.core.api.domain - -data class ExampleResult( - val data: String, -) diff --git a/application/api/src/main/kotlin/io/raemian/core/api/domain/ExampleService.kt b/application/api/src/main/kotlin/io/raemian/core/api/domain/ExampleService.kt deleted file mode 100644 index b6afd807..00000000 --- a/application/api/src/main/kotlin/io/raemian/core/api/domain/ExampleService.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.raemian.core.api.domain - -import org.springframework.stereotype.Service - -@Service -class ExampleService() { - fun processExample(exampleData: ExampleData): ExampleResult { - return ExampleResult(exampleData.value) - } -} diff --git a/application/api/src/main/kotlin/io/raemian/core/api/support/error/ErrorCode.kt b/application/api/src/main/kotlin/io/raemian/core/api/support/error/ErrorCode.kt deleted file mode 100644 index 76837a2b..00000000 --- a/application/api/src/main/kotlin/io/raemian/core/api/support/error/ErrorCode.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.raemian.core.api.support.error - -enum class ErrorCode { - E500, -} From a5fe8077ba5e76a45332a0c0a858b59dd471aebe Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Tue, 28 Nov 2023 23:54:07 +0900 Subject: [PATCH 29/70] feat(#1): edit package --- .../auth => auth/controller}/AuthController.kt | 12 ++++++------ .../controller}/request/SignInRequest.kt | 2 +- .../controller}/request/SignUpRequest.kt | 2 +- .../api/{domain/auth => auth/domain}/CurrentUser.kt | 2 +- .../{domain/auth => auth/domain}/OAuthProvider.kt | 2 +- .../api/{domain/auth => auth/domain}/TokenDTO.kt | 2 +- .../{service/auth => auth/service}/AuthService.kt | 6 +++--- .../auth => auth/service}/OAuth2UserService.kt | 6 +++--- .../io/raemian/api/config/WebSecurityConfig.kt | 4 ++-- .../kotlin/io/raemian/api/support/TokenProvider.kt | 4 ++-- 10 files changed, 21 insertions(+), 21 deletions(-) rename application/api/src/main/kotlin/io/raemian/api/{controller/auth => auth/controller}/AuthController.kt (76%) rename application/api/src/main/kotlin/io/raemian/api/{controller/auth => auth/controller}/request/SignInRequest.kt (62%) rename application/api/src/main/kotlin/io/raemian/api/{controller/auth => auth/controller}/request/SignUpRequest.kt (62%) rename application/api/src/main/kotlin/io/raemian/api/{domain/auth => auth/domain}/CurrentUser.kt (96%) rename application/api/src/main/kotlin/io/raemian/api/{domain/auth => auth/domain}/OAuthProvider.kt (57%) rename application/api/src/main/kotlin/io/raemian/api/{domain/auth => auth/domain}/TokenDTO.kt (80%) rename application/api/src/main/kotlin/io/raemian/api/{service/auth => auth/service}/AuthService.kt (94%) rename application/api/src/main/kotlin/io/raemian/api/{service/auth => auth/service}/OAuth2UserService.kt (94%) diff --git a/application/api/src/main/kotlin/io/raemian/api/controller/auth/AuthController.kt b/application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt similarity index 76% rename from application/api/src/main/kotlin/io/raemian/api/controller/auth/AuthController.kt rename to application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt index 1782f7c2..fc754031 100644 --- a/application/api/src/main/kotlin/io/raemian/api/controller/auth/AuthController.kt +++ b/application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt @@ -1,10 +1,10 @@ -package io.raemian.api.controller.auth +package io.raemian.api.auth.controller -import io.raemian.api.controller.auth.request.SignInRequest -import io.raemian.api.controller.auth.request.SignUpRequest -import io.raemian.api.domain.auth.CurrentUser -import io.raemian.api.domain.auth.TokenDTO -import io.raemian.api.service.auth.AuthService +import io.raemian.api.auth.controller.request.SignInRequest +import io.raemian.api.auth.controller.request.SignUpRequest +import io.raemian.api.auth.domain.CurrentUser +import io.raemian.api.auth.domain.TokenDTO +import io.raemian.api.auth.service.AuthService import org.springframework.security.core.annotation.AuthenticationPrincipal import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PostMapping diff --git a/application/api/src/main/kotlin/io/raemian/api/controller/auth/request/SignInRequest.kt b/application/api/src/main/kotlin/io/raemian/api/auth/controller/request/SignInRequest.kt similarity index 62% rename from application/api/src/main/kotlin/io/raemian/api/controller/auth/request/SignInRequest.kt rename to application/api/src/main/kotlin/io/raemian/api/auth/controller/request/SignInRequest.kt index db1c68d1..45b6676e 100644 --- a/application/api/src/main/kotlin/io/raemian/api/controller/auth/request/SignInRequest.kt +++ b/application/api/src/main/kotlin/io/raemian/api/auth/controller/request/SignInRequest.kt @@ -1,4 +1,4 @@ -package io.raemian.api.controller.auth.request +package io.raemian.api.auth.controller.request data class SignInRequest( val email: String, diff --git a/application/api/src/main/kotlin/io/raemian/api/controller/auth/request/SignUpRequest.kt b/application/api/src/main/kotlin/io/raemian/api/auth/controller/request/SignUpRequest.kt similarity index 62% rename from application/api/src/main/kotlin/io/raemian/api/controller/auth/request/SignUpRequest.kt rename to application/api/src/main/kotlin/io/raemian/api/auth/controller/request/SignUpRequest.kt index e88e50e7..98a13f63 100644 --- a/application/api/src/main/kotlin/io/raemian/api/controller/auth/request/SignUpRequest.kt +++ b/application/api/src/main/kotlin/io/raemian/api/auth/controller/request/SignUpRequest.kt @@ -1,4 +1,4 @@ -package io.raemian.api.controller.auth.request +package io.raemian.api.auth.controller.request data class SignUpRequest( val email: String, diff --git a/application/api/src/main/kotlin/io/raemian/api/domain/auth/CurrentUser.kt b/application/api/src/main/kotlin/io/raemian/api/auth/domain/CurrentUser.kt similarity index 96% rename from application/api/src/main/kotlin/io/raemian/api/domain/auth/CurrentUser.kt rename to application/api/src/main/kotlin/io/raemian/api/auth/domain/CurrentUser.kt index dd2c3eba..97161a39 100644 --- a/application/api/src/main/kotlin/io/raemian/api/domain/auth/CurrentUser.kt +++ b/application/api/src/main/kotlin/io/raemian/api/auth/domain/CurrentUser.kt @@ -1,4 +1,4 @@ -package io.raemian.api.domain.auth +package io.raemian.api.auth.domain import org.springframework.security.core.GrantedAuthority import org.springframework.security.core.authority.SimpleGrantedAuthority diff --git a/application/api/src/main/kotlin/io/raemian/api/domain/auth/OAuthProvider.kt b/application/api/src/main/kotlin/io/raemian/api/auth/domain/OAuthProvider.kt similarity index 57% rename from application/api/src/main/kotlin/io/raemian/api/domain/auth/OAuthProvider.kt rename to application/api/src/main/kotlin/io/raemian/api/auth/domain/OAuthProvider.kt index 983d3e74..d00f4e42 100644 --- a/application/api/src/main/kotlin/io/raemian/api/domain/auth/OAuthProvider.kt +++ b/application/api/src/main/kotlin/io/raemian/api/auth/domain/OAuthProvider.kt @@ -1,4 +1,4 @@ -package io.raemian.api.domain.auth +package io.raemian.api.auth.domain enum class OAuthProvider { GOOGLE, NAVER diff --git a/application/api/src/main/kotlin/io/raemian/api/domain/auth/TokenDTO.kt b/application/api/src/main/kotlin/io/raemian/api/auth/domain/TokenDTO.kt similarity index 80% rename from application/api/src/main/kotlin/io/raemian/api/domain/auth/TokenDTO.kt rename to application/api/src/main/kotlin/io/raemian/api/auth/domain/TokenDTO.kt index 7e2238b9..b08e4b2d 100644 --- a/application/api/src/main/kotlin/io/raemian/api/domain/auth/TokenDTO.kt +++ b/application/api/src/main/kotlin/io/raemian/api/auth/domain/TokenDTO.kt @@ -1,4 +1,4 @@ -package io.raemian.api.domain.auth +package io.raemian.api.auth.domain data class TokenDTO( val grantType: String, diff --git a/application/api/src/main/kotlin/io/raemian/api/service/auth/AuthService.kt b/application/api/src/main/kotlin/io/raemian/api/auth/service/AuthService.kt similarity index 94% rename from application/api/src/main/kotlin/io/raemian/api/service/auth/AuthService.kt rename to application/api/src/main/kotlin/io/raemian/api/auth/service/AuthService.kt index bddd4843..5f8948cb 100644 --- a/application/api/src/main/kotlin/io/raemian/api/service/auth/AuthService.kt +++ b/application/api/src/main/kotlin/io/raemian/api/auth/service/AuthService.kt @@ -1,7 +1,7 @@ -package io.raemian.api.service.auth +package io.raemian.api.auth.service -import io.raemian.api.domain.auth.CurrentUser -import io.raemian.api.domain.auth.TokenDTO +import io.raemian.api.auth.domain.CurrentUser +import io.raemian.api.auth.domain.TokenDTO import io.raemian.api.support.TokenProvider import io.raemian.storage.db.core.user.Authority import io.raemian.storage.db.core.user.User diff --git a/application/api/src/main/kotlin/io/raemian/api/service/auth/OAuth2UserService.kt b/application/api/src/main/kotlin/io/raemian/api/auth/service/OAuth2UserService.kt similarity index 94% rename from application/api/src/main/kotlin/io/raemian/api/service/auth/OAuth2UserService.kt rename to application/api/src/main/kotlin/io/raemian/api/auth/service/OAuth2UserService.kt index 6d04cc3f..5f89afe8 100644 --- a/application/api/src/main/kotlin/io/raemian/api/service/auth/OAuth2UserService.kt +++ b/application/api/src/main/kotlin/io/raemian/api/auth/service/OAuth2UserService.kt @@ -1,7 +1,7 @@ -package io.raemian.api.service.auth +package io.raemian.api.auth.service -import io.raemian.api.domain.auth.CurrentUser -import io.raemian.api.domain.auth.OAuthProvider +import io.raemian.api.auth.domain.CurrentUser +import io.raemian.api.auth.domain.OAuthProvider import io.raemian.storage.db.core.user.Authority import io.raemian.storage.db.core.user.User import io.raemian.storage.db.core.user.UserRepository diff --git a/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt b/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt index 87e4e04d..f1d1b3fe 100644 --- a/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt +++ b/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt @@ -1,7 +1,7 @@ package io.raemian.api.config -import io.raemian.api.domain.auth.CurrentUser -import io.raemian.api.service.auth.OAuth2UserService +import io.raemian.api.auth.domain.CurrentUser +import io.raemian.api.auth.service.OAuth2UserService import io.raemian.api.support.TokenProvider import jakarta.servlet.http.HttpServletResponse import org.slf4j.LoggerFactory diff --git a/application/api/src/main/kotlin/io/raemian/api/support/TokenProvider.kt b/application/api/src/main/kotlin/io/raemian/api/support/TokenProvider.kt index 34bcd169..c52544bd 100644 --- a/application/api/src/main/kotlin/io/raemian/api/support/TokenProvider.kt +++ b/application/api/src/main/kotlin/io/raemian/api/support/TokenProvider.kt @@ -9,8 +9,8 @@ import io.jsonwebtoken.UnsupportedJwtException import io.jsonwebtoken.io.Decoders import io.jsonwebtoken.security.Keys import io.jsonwebtoken.security.SecurityException -import io.raemian.api.domain.auth.CurrentUser -import io.raemian.api.domain.auth.TokenDTO +import io.raemian.api.auth.domain.CurrentUser +import io.raemian.api.auth.domain.TokenDTO import org.slf4j.LoggerFactory import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.core.Authentication From 610f8a93f6febe0b5dba44b21c7997b5b002c470 Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Sat, 2 Dec 2023 20:52:48 +0900 Subject: [PATCH 30/70] refact(#1): refact oauth login --- .../api/auth/controller/AuthController.kt | 9 +------ .../io/raemian/api/auth/domain/CurrentUser.kt | 8 +++--- .../raemian/api/auth/service/AuthService.kt | 27 +++---------------- .../api/auth/service/OAuth2UserService.kt | 18 +++++++------ .../raemian/api/config/JwtSecurityConfig.kt | 4 +-- .../raemian/api/config/WebSecurityConfig.kt | 8 +++--- .../io/raemian/api/support/TokenProvider.kt | 3 ++- .../api/src/main/resources/application.yml | 4 +-- .../io/raemian/storage/db/core/user/User.kt | 13 ++++++++- .../db/core/user/enums}/OAuthProvider.kt | 2 +- 10 files changed, 42 insertions(+), 54 deletions(-) rename {application/api/src/main/kotlin/io/raemian/api/auth/domain => storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/enums}/OAuthProvider.kt (51%) diff --git a/application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt b/application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt index fc754031..97e04368 100644 --- a/application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt +++ b/application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt @@ -1,7 +1,6 @@ package io.raemian.api.auth.controller import io.raemian.api.auth.controller.request.SignInRequest -import io.raemian.api.auth.controller.request.SignUpRequest import io.raemian.api.auth.domain.CurrentUser import io.raemian.api.auth.domain.TokenDTO import io.raemian.api.auth.service.AuthService @@ -16,15 +15,9 @@ class AuthController( private val authService: AuthService, ) { - @PostMapping("/auth/sign-up") - fun signUp(@RequestBody signUpRequest: SignUpRequest): String { - authService.save(signUpRequest.email, signUpRequest.password) - return "${signUpRequest.email}/${signUpRequest.password}" - } - @PostMapping("/auth/sign-in") fun signIn(@RequestBody signInRequest: SignInRequest): TokenDTO { - return authService.signIn(signInRequest.email, signInRequest.password) + return authService.signIn(signInRequest.email) } @GetMapping("/my") diff --git a/application/api/src/main/kotlin/io/raemian/api/auth/domain/CurrentUser.kt b/application/api/src/main/kotlin/io/raemian/api/auth/domain/CurrentUser.kt index 97161a39..59ca77e9 100644 --- a/application/api/src/main/kotlin/io/raemian/api/auth/domain/CurrentUser.kt +++ b/application/api/src/main/kotlin/io/raemian/api/auth/domain/CurrentUser.kt @@ -8,9 +8,11 @@ import org.springframework.security.oauth2.core.user.OAuth2User data class CurrentUser( val id: Long, val email: String, - val provider: String? = null, - private val password: String, + private val authorities: List = listOf("ROLE_USER"), + + // not use field + private val password: String? = null, ) : UserDetails, OAuth2User { override fun getName(): String = email @@ -22,7 +24,7 @@ data class CurrentUser( .map { SimpleGrantedAuthority(it) } .toMutableList() - override fun getPassword(): String = password + override fun getPassword(): String? = password override fun getUsername(): String = email diff --git a/application/api/src/main/kotlin/io/raemian/api/auth/service/AuthService.kt b/application/api/src/main/kotlin/io/raemian/api/auth/service/AuthService.kt index 5f8948cb..ea4ab74b 100644 --- a/application/api/src/main/kotlin/io/raemian/api/auth/service/AuthService.kt +++ b/application/api/src/main/kotlin/io/raemian/api/auth/service/AuthService.kt @@ -3,55 +3,34 @@ package io.raemian.api.auth.service import io.raemian.api.auth.domain.CurrentUser import io.raemian.api.auth.domain.TokenDTO import io.raemian.api.support.TokenProvider -import io.raemian.storage.db.core.user.Authority -import io.raemian.storage.db.core.user.User import io.raemian.storage.db.core.user.UserRepository import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder import org.springframework.security.core.userdetails.UserDetails import org.springframework.security.core.userdetails.UserDetailsService import org.springframework.security.core.userdetails.UsernameNotFoundException -import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.stereotype.Service @Service class AuthService( private val userRepository: UserRepository, - private val passwordEncoder: PasswordEncoder, private val authenticationManagerBuilder: AuthenticationManagerBuilder, private val tokenProvider: TokenProvider, ) : UserDetailsService { - fun save(email: String, password: String) { - userRepository.save( - User( - email = email, - password = passwordEncoder.encode(password), - authority = Authority.ROLE_USER, - ), - ) - } - override fun loadUserByUsername(username: String): UserDetails { val user = userRepository.findByEmail(username) ?: throw UsernameNotFoundException("not found $username") return CurrentUser( id = user.id!!, email = user.email, - password = user.password, authorities = listOf(), ) } - fun signIn(email: String, password: String): TokenDTO { + fun signIn(email: String): TokenDTO { val user = userRepository.findByEmail(email) ?: throw RuntimeException("아이디 또는 비밀번호 불일치 ") - if (!passwordEncoder.matches(password, user.password)) { - throw RuntimeException("아이디 또는 비밀번호 불일치 ") - } - - val token = UsernamePasswordAuthenticationToken(email, password, arrayListOf()) + val token = UsernamePasswordAuthenticationToken(user.email, "", arrayListOf()) val authentication = authenticationManagerBuilder.`object`.authenticate(token) - val tokenDTO = tokenProvider.generateTokenDto(authentication) - - return tokenDTO + return tokenProvider.generateTokenDto(authentication) } } diff --git a/application/api/src/main/kotlin/io/raemian/api/auth/service/OAuth2UserService.kt b/application/api/src/main/kotlin/io/raemian/api/auth/service/OAuth2UserService.kt index 5f89afe8..d3282561 100644 --- a/application/api/src/main/kotlin/io/raemian/api/auth/service/OAuth2UserService.kt +++ b/application/api/src/main/kotlin/io/raemian/api/auth/service/OAuth2UserService.kt @@ -1,10 +1,10 @@ package io.raemian.api.auth.service import io.raemian.api.auth.domain.CurrentUser -import io.raemian.api.auth.domain.OAuthProvider import io.raemian.storage.db.core.user.Authority import io.raemian.storage.db.core.user.User import io.raemian.storage.db.core.user.UserRepository +import io.raemian.storage.db.core.user.enums.OAuthProvider import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest import org.springframework.security.oauth2.core.user.OAuth2User @@ -17,8 +17,7 @@ class OAuth2UserService( override fun loadUser(userRequest: OAuth2UserRequest): OAuth2User { val oAuth2User = super.loadUser(userRequest) val usernameAttributeName = userRequest.clientRegistration - .providerDetails - .userInfoEndpoint + .providerDetails.userInfoEndpoint .userNameAttributeName return when (val provider = OAuthProvider.valueOf(userRequest.clientRegistration.registrationId.uppercase())) { @@ -29,8 +28,6 @@ class OAuth2UserService( CurrentUser( id = user.id!!, email = email, - provider = provider.name, - password = "", authorities = listOf(), ) } @@ -42,8 +39,6 @@ class OAuth2UserService( CurrentUser( id = user.id!!, email = email, - provider = provider.name, - password = "", authorities = listOf(), ) } @@ -52,6 +47,13 @@ class OAuth2UserService( private fun upsert(email: String, oAuthProvider: OAuthProvider): User { return userRepository.findByEmail(email) - ?: return userRepository.save(User(email = email, password = "", authority = Authority.ROLE_USER)) + ?: return userRepository.save( + User( + email = email, + provider = oAuthProvider, + authority = Authority.ROLE_USER, + ), + ) + } } diff --git a/application/api/src/main/kotlin/io/raemian/api/config/JwtSecurityConfig.kt b/application/api/src/main/kotlin/io/raemian/api/config/JwtSecurityConfig.kt index 161f6495..a0d08fbd 100644 --- a/application/api/src/main/kotlin/io/raemian/api/config/JwtSecurityConfig.kt +++ b/application/api/src/main/kotlin/io/raemian/api/config/JwtSecurityConfig.kt @@ -13,7 +13,7 @@ class JwtSecurityConfig( // TokenProvider 를 주입받아서 JwtFilter 를 통해 Security 로직에 필터를 등록 override fun configure(http: HttpSecurity) { - val customFilter = JwtFilter(tokenProvider) - http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter::class.java) + val jwtFilter = JwtFilter(tokenProvider) + http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter::class.java) } } diff --git a/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt b/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt index f1d1b3fe..ee072c7a 100644 --- a/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt +++ b/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt @@ -66,16 +66,16 @@ class WebSecurityConfig( response.characterEncoding = StandardCharsets.UTF_8.name() val tokenDTO = tokenProvider.generateTokenDto(user) + response.setHeader("x-token", tokenDTO.accessToken) // TODO edit redirect url - response.sendRedirect("http://localhost:3000/login/oauth2/code/google?token=${tokenDTO.accessToken}") + response.sendRedirect("http://localhost:8080/login/oauth2/code/google?token=${tokenDTO.accessToken}&refresh=${tokenDTO.refreshToken}") } it.failureHandler { request, response, exception -> - log.info("eeeeeeeeeeeeeeeeeeee + ${exception.message}") response.addHeader("x-token", exception.message) } } .sessionManagement { it.sessionCreationPolicy(SessionCreationPolicy.STATELESS) } - .apply(io.raemian.api.config.JwtSecurityConfig(tokenProvider)) + .apply(JwtSecurityConfig(tokenProvider)) return http.build() } @@ -87,7 +87,7 @@ class WebSecurityConfig( it .ignoring() .requestMatchers(PathRequest.toH2Console()) - .requestMatchers(AntPathRequestMatcher("/favicon.ico")) + .requestMatchers(AntPathRequestMatcher("/favicon.ico", "**/favicon.ico")) } } diff --git a/application/api/src/main/kotlin/io/raemian/api/support/TokenProvider.kt b/application/api/src/main/kotlin/io/raemian/api/support/TokenProvider.kt index c52544bd..1927ec98 100644 --- a/application/api/src/main/kotlin/io/raemian/api/support/TokenProvider.kt +++ b/application/api/src/main/kotlin/io/raemian/api/support/TokenProvider.kt @@ -33,6 +33,7 @@ class TokenProvider { private val EMAIL_KEY = "email" private val ID_KEY = "id" private val BEARER_TYPE = "Bearer" + private val ACCESS_TOKEN_EXPIRE_TIME = Duration.ofMinutes(300).toMillis() // 300분 private val REFRESH_TOKEN_EXPIRE_TIME = Duration.ofDays(70).toMillis() // 70일 @@ -118,7 +119,7 @@ class TokenProvider { // UserDetails 객체를 만들어서 Authentication 리턴 val principal = - CurrentUser(id = id, email = claims.subject, password = "", provider = null, authorities = authorities) + CurrentUser(id = id, email = claims.subject, password = "", authorities = authorities) return UsernamePasswordAuthenticationToken(principal, "", principal.authorities) } diff --git a/application/api/src/main/resources/application.yml b/application/api/src/main/resources/application.yml index 9d1de362..e26c71e9 100644 --- a/application/api/src/main/resources/application.yml +++ b/application/api/src/main/resources/application.yml @@ -29,8 +29,8 @@ spring: - name client-name: naver google: - client-id: 1007090557425-sk34pslk4o74bn9nc0oi4hrt77o30o7k.apps.googleusercontent.com - client-secret: U9PXLzkdKmdqUzuyGN-kyHa9 + client-id: ${GOOGLE-CLIENT-ID} + client-secret: ${GOOGLE-CLIENT-SECRET} scope: - email - profile diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt index 7a11114c..15684d52 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt @@ -1,18 +1,29 @@ package io.raemian.storage.db.core.user import io.raemian.storage.db.core.BaseEntity +import io.raemian.storage.db.core.user.enums.OAuthProvider import jakarta.persistence.Column import jakarta.persistence.Entity import jakarta.persistence.EnumType import jakarta.persistence.Enumerated +import java.time.LocalDate @Entity(name = "USERS") class User( @Column val email: String, + + @Column + val nickname: String? = null, + @Column - val password: String, + val birth: LocalDate? = null, + @Column + @Enumerated(EnumType.STRING) + val provider: OAuthProvider, + + @Column @Enumerated(EnumType.STRING) val authority: Authority, ) : BaseEntity() diff --git a/application/api/src/main/kotlin/io/raemian/api/auth/domain/OAuthProvider.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/enums/OAuthProvider.kt similarity index 51% rename from application/api/src/main/kotlin/io/raemian/api/auth/domain/OAuthProvider.kt rename to storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/enums/OAuthProvider.kt index d00f4e42..d4ad3945 100644 --- a/application/api/src/main/kotlin/io/raemian/api/auth/domain/OAuthProvider.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/enums/OAuthProvider.kt @@ -1,4 +1,4 @@ -package io.raemian.api.auth.domain +package io.raemian.storage.db.core.user.enums enum class OAuthProvider { GOOGLE, NAVER From 8f2ac3047f2a93c88d86268416249eea8163ad1d Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Sat, 2 Dec 2023 21:57:52 +0900 Subject: [PATCH 31/70] =?UTF-8?q?feat(#1):=20=EC=9C=A0=EC=A0=80=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EC=88=98=EC=A0=95=20api=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/auth/controller/AuthController.kt | 16 +++++++++++++++ .../controller/request/UpdateUserRequest.kt | 8 ++++++++ .../raemian/api/auth/service/AuthService.kt | 15 ++++++++++++++ .../io/raemian/storage/db/core/BaseEntity.kt | 7 ------- .../raemian/storage/db/core/ExampleEntity.kt | 7 +++++++ .../io/raemian/storage/db/core/user/User.kt | 20 ++++++++++++++++++- 6 files changed, 65 insertions(+), 8 deletions(-) create mode 100644 application/api/src/main/kotlin/io/raemian/api/auth/controller/request/UpdateUserRequest.kt diff --git a/application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt b/application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt index 97e04368..db830131 100644 --- a/application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt +++ b/application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt @@ -1,12 +1,15 @@ package io.raemian.api.auth.controller import io.raemian.api.auth.controller.request.SignInRequest +import io.raemian.api.auth.controller.request.UpdateUserRequest import io.raemian.api.auth.domain.CurrentUser import io.raemian.api.auth.domain.TokenDTO import io.raemian.api.auth.service.AuthService +import org.springframework.http.ResponseEntity import org.springframework.security.core.annotation.AuthenticationPrincipal import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RestController @@ -24,4 +27,17 @@ class AuthController( fun my(@AuthenticationPrincipal currentUser: CurrentUser): CurrentUser { return currentUser } + + @PutMapping("/my") + fun update( + @AuthenticationPrincipal currentUser: CurrentUser, + @RequestBody updateUserRequest: UpdateUserRequest, + ): ResponseEntity { + authService.update( + id = currentUser.id, + nickname = updateUserRequest.nickname, + birth = updateUserRequest.birth, + ) + return ResponseEntity.ok().build() + } } diff --git a/application/api/src/main/kotlin/io/raemian/api/auth/controller/request/UpdateUserRequest.kt b/application/api/src/main/kotlin/io/raemian/api/auth/controller/request/UpdateUserRequest.kt new file mode 100644 index 00000000..ce1e76e8 --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/auth/controller/request/UpdateUserRequest.kt @@ -0,0 +1,8 @@ +package io.raemian.api.auth.controller.request + +import java.time.LocalDate + +data class UpdateUserRequest( + val nickname: String, + val birth: LocalDate, +) diff --git a/application/api/src/main/kotlin/io/raemian/api/auth/service/AuthService.kt b/application/api/src/main/kotlin/io/raemian/api/auth/service/AuthService.kt index ea4ab74b..6a9e6283 100644 --- a/application/api/src/main/kotlin/io/raemian/api/auth/service/AuthService.kt +++ b/application/api/src/main/kotlin/io/raemian/api/auth/service/AuthService.kt @@ -3,6 +3,7 @@ package io.raemian.api.auth.service import io.raemian.api.auth.domain.CurrentUser import io.raemian.api.auth.domain.TokenDTO import io.raemian.api.support.TokenProvider +import io.raemian.storage.db.core.user.User import io.raemian.storage.db.core.user.UserRepository import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder @@ -10,6 +11,8 @@ import org.springframework.security.core.userdetails.UserDetails import org.springframework.security.core.userdetails.UserDetailsService import org.springframework.security.core.userdetails.UsernameNotFoundException import org.springframework.stereotype.Service +import java.time.LocalDate +import kotlin.jvm.optionals.getOrNull @Service class AuthService( @@ -33,4 +36,16 @@ class AuthService( val authentication = authenticationManagerBuilder.`object`.authenticate(token) return tokenProvider.generateTokenDto(authentication) } + + fun update(id: Long, nickname: String, birth: LocalDate): User { + val user = userRepository.findById(id) + .getOrNull() ?: throw RuntimeException("") + + val copied = user.updateInfo( + nickname = nickname, + birth = birth, + ) + + return userRepository.save(copied) + } } diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/BaseEntity.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/BaseEntity.kt index b63d965d..a15e0f07 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/BaseEntity.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/BaseEntity.kt @@ -1,9 +1,6 @@ package io.raemian.storage.db.core import jakarta.persistence.Column -import jakarta.persistence.GeneratedValue -import jakarta.persistence.GenerationType -import jakarta.persistence.Id import jakarta.persistence.MappedSuperclass import org.hibernate.annotations.CreationTimestamp import org.hibernate.annotations.UpdateTimestamp @@ -11,10 +8,6 @@ import java.time.LocalDateTime @MappedSuperclass abstract class BaseEntity { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - val id: Long? = null - @CreationTimestamp @Column(updatable = false) val createdAt: LocalDateTime? = null diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/ExampleEntity.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/ExampleEntity.kt index ce6e15a9..ec7e8d50 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/ExampleEntity.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/ExampleEntity.kt @@ -2,9 +2,16 @@ package io.raemian.storage.db.core import jakarta.persistence.Column import jakarta.persistence.Entity +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id @Entity class ExampleEntity( + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long? = null, + @Column val exampleColumn: String, ) : BaseEntity() diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt index 15684d52..be98811f 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt @@ -6,6 +6,9 @@ import jakarta.persistence.Column import jakarta.persistence.Entity import jakarta.persistence.EnumType import jakarta.persistence.Enumerated +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id import java.time.LocalDate @Entity(name = "USERS") @@ -26,7 +29,22 @@ class User( @Column @Enumerated(EnumType.STRING) val authority: Authority, -) : BaseEntity() + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long? = null, +) : BaseEntity() { + fun updateInfo(nickname: String, birth: LocalDate): User { + return User( + email = email, + nickname = nickname, + birth = birth, + provider = provider, + authority = authority, + id = id, + ) + } +} enum class Authority { ROLE_USER, ROLE_ADMIN From da20a6fe0a369d91d2357884a636de75dc43a50c Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Sat, 2 Dec 2023 22:03:23 +0900 Subject: [PATCH 32/70] =?UTF-8?q?chore(#1):=20=EB=B3=80=EC=88=98=EB=AA=85?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/io/raemian/api/auth/service/AuthService.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/api/src/main/kotlin/io/raemian/api/auth/service/AuthService.kt b/application/api/src/main/kotlin/io/raemian/api/auth/service/AuthService.kt index 6a9e6283..4e58ebb8 100644 --- a/application/api/src/main/kotlin/io/raemian/api/auth/service/AuthService.kt +++ b/application/api/src/main/kotlin/io/raemian/api/auth/service/AuthService.kt @@ -41,11 +41,11 @@ class AuthService( val user = userRepository.findById(id) .getOrNull() ?: throw RuntimeException("") - val copied = user.updateInfo( + val updated = user.updateInfo( nickname = nickname, birth = birth, ) - return userRepository.save(copied) + return userRepository.save(updated) } } From 094894b50bd01588ceb1e5715cfec1a2adb46da7 Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Sat, 2 Dec 2023 22:07:46 +0900 Subject: [PATCH 33/70] chore(#1): lint --- .../main/kotlin/io/raemian/api/auth/service/OAuth2UserService.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/application/api/src/main/kotlin/io/raemian/api/auth/service/OAuth2UserService.kt b/application/api/src/main/kotlin/io/raemian/api/auth/service/OAuth2UserService.kt index d3282561..685a9917 100644 --- a/application/api/src/main/kotlin/io/raemian/api/auth/service/OAuth2UserService.kt +++ b/application/api/src/main/kotlin/io/raemian/api/auth/service/OAuth2UserService.kt @@ -54,6 +54,5 @@ class OAuth2UserService( authority = Authority.ROLE_USER, ), ) - } } From 1c17d5ce91ad1eaa57e2669747c71935400fbe4b Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Sat, 2 Dec 2023 22:13:08 +0900 Subject: [PATCH 34/70] chore(#1): edit test code --- .../kotlin/io/raemian/storage/db/core/ExampleRepositoryIT.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/db-core/src/test/kotlin/io/raemian/storage/db/core/ExampleRepositoryIT.kt b/storage/db-core/src/test/kotlin/io/raemian/storage/db/core/ExampleRepositoryIT.kt index cb1effbf..eaedad1e 100644 --- a/storage/db-core/src/test/kotlin/io/raemian/storage/db/core/ExampleRepositoryIT.kt +++ b/storage/db-core/src/test/kotlin/io/raemian/storage/db/core/ExampleRepositoryIT.kt @@ -9,7 +9,7 @@ class ExampleRepositoryIT( ) : CoreDbContextTest() { @Test fun testShouldBeSavedAndFound() { - val saved = exampleRepository.save(ExampleEntity("SPRING_BOOT")) + val saved = exampleRepository.save(ExampleEntity(1L, "SPRING_BOOT")) assertThat(saved.exampleColumn).isEqualTo("SPRING_BOOT") val found = exampleRepository.findById(saved.id!!).get() From 70d4e173b4ae3d619ca10c9b27c144ae117392fa Mon Sep 17 00:00:00 2001 From: hanmanhyuk Date: Sun, 3 Dec 2023 17:38:05 +0900 Subject: [PATCH 35/70] chore: add codeowners --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..ae45f763 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @ManHyuk @egg528 @binary-ho From c7c9a79f8f8ede9132be6c48ef8b7a714d55d26b Mon Sep 17 00:00:00 2001 From: hanmanhyuk Date: Sun, 3 Dec 2023 19:29:30 +0900 Subject: [PATCH 36/70] chore: add pre commit plugin --- build.gradle.kts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 36d91fef..7824576e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ plugins { id("org.springframework.boot") apply false id("io.spring.dependency-management") id("org.asciidoctor.jvm.convert") apply false - id("org.jlleitschuh.gradle.ktlint") apply false + id("org.jlleitschuh.gradle.ktlint") version "12.0.2" } java.sourceCompatibility = JavaVersion.valueOf("VERSION_${property("javaVersion")}") @@ -101,4 +101,8 @@ subprojects { tasks.getByName("asciidoctor") { dependsOn("restDocsTest") } + + configure { + debug.set(true) + } } From 6f94b71224aabaf6f68d24a1d9efdbe7bad0f844 Mon Sep 17 00:00:00 2001 From: wkwon Date: Mon, 11 Dec 2023 15:50:41 +0900 Subject: [PATCH 37/70] =?UTF-8?q?feat(#22):=20Actuator=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pull_request_template.md | 0 application/api/build.gradle.kts | 2 +- .../kotlin/io/raemian/CoreApiApplication.kt | 1 + .../raemian/api/config/WebSecurityConfig.kt | 1 + .../main/resources/application-security.yml | 95 +++++++++++++++++++ .../api/src/main/resources/application.yml | 67 ++++--------- .../main/resources/application-logging.yml | 13 +++ .../resources/logback/logback-local-dev.xml | 18 ---- .../resources/logback/logback-staging.xml | 27 ------ infra/logging/src/main/resources/logging.yml | 1 - .../{monitoring => metrics}/build.gradle.kts | 0 .../main/resources/application-metrics.yml | 63 ++++++++++++ .../src/main/resources/monitoring.yml | 5 - settings.gradle.kts | 2 +- .../{db-core.yml => application-db-core.yml} | 73 ++------------ 15 files changed, 202 insertions(+), 166 deletions(-) rename .github/{ => PULL_REQUEST_TEMPLATE}/pull_request_template.md (100%) create mode 100644 application/api/src/main/resources/application-security.yml create mode 100644 infra/logging/src/main/resources/application-logging.yml delete mode 100644 infra/logging/src/main/resources/logback/logback-local-dev.xml delete mode 100644 infra/logging/src/main/resources/logback/logback-staging.xml delete mode 100644 infra/logging/src/main/resources/logging.yml rename infra/{monitoring => metrics}/build.gradle.kts (100%) create mode 100644 infra/metrics/src/main/resources/application-metrics.yml delete mode 100644 infra/monitoring/src/main/resources/monitoring.yml rename storage/db-core/src/main/resources/{db-core.yml => application-db-core.yml} (55%) diff --git a/.github/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md similarity index 100% rename from .github/pull_request_template.md rename to .github/PULL_REQUEST_TEMPLATE/pull_request_template.md diff --git a/application/api/build.gradle.kts b/application/api/build.gradle.kts index dfd0b0b2..1d63ab09 100644 --- a/application/api/build.gradle.kts +++ b/application/api/build.gradle.kts @@ -7,7 +7,7 @@ tasks.getByName("jar") { } dependencies { - implementation(project(":infra:monitoring")) + implementation(project(":infra:metrics")) implementation(project(":infra:logging")) implementation(project(":storage:db-core")) diff --git a/application/api/src/main/kotlin/io/raemian/CoreApiApplication.kt b/application/api/src/main/kotlin/io/raemian/CoreApiApplication.kt index 7a6daa8f..28f36d78 100644 --- a/application/api/src/main/kotlin/io/raemian/CoreApiApplication.kt +++ b/application/api/src/main/kotlin/io/raemian/CoreApiApplication.kt @@ -1,3 +1,4 @@ + package io.raemian import org.springframework.boot.autoconfigure.SpringBootApplication diff --git a/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt b/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt index ee072c7a..f68ee226 100644 --- a/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt +++ b/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt @@ -86,6 +86,7 @@ class WebSecurityConfig( return WebSecurityCustomizer { it .ignoring() + .requestMatchers(AntPathRequestMatcher("/one-baily-actuator/**")) .requestMatchers(PathRequest.toH2Console()) .requestMatchers(AntPathRequestMatcher("/favicon.ico", "**/favicon.ico")) } diff --git a/application/api/src/main/resources/application-security.yml b/application/api/src/main/resources/application-security.yml new file mode 100644 index 00000000..a43ca102 --- /dev/null +++ b/application/api/src/main/resources/application-security.yml @@ -0,0 +1,95 @@ +# local +spring.config.activate.on-profile: local + +spring: + security: + oauth2: + client: + provider: + naver: + authorization_uri: https://nid.naver.com/oauth2.0/authorize + token_uri: https://nid.naver.com/oauth2.0/token + user-info-uri: https://openapi.naver.com/v1/nid/me + user_name_attribute: response + registration: + naver: + client-id: f0Y2iXBYxDsBPH699BkC + client-secret: xxOOW3Nr6X + redirect-uri: http://localhost:8080/login/oauth2/code/naver + authorization-grant-type: authorization_code + scope: + - email + - name + client-name: naver + google: + client-id: ${GOOGLE-CLIENT-ID} + client-secret: ${GOOGLE-CLIENT-SECRET} + scope: + - email + - profile + + +--- +# dev +spring.config.activate.on-profile: dev + +spring: + security: + oauth2: + client: + provider: + naver: + authorization_uri: https://nid.naver.com/oauth2.0/authorize + token_uri: https://nid.naver.com/oauth2.0/token + user-info-uri: https://openapi.naver.com/v1/nid/me + user_name_attribute: response + registration: + naver: + client-id: f0Y2iXBYxDsBPH699BkC + client-secret: xxOOW3Nr6X + redirect-uri: http://localhost:8080/login/oauth2/code/naver + authorization-grant-type: authorization_code + scope: + - email + - name + client-name: naver + google: + client-id: ${GOOGLE-CLIENT-ID} + client-secret: ${GOOGLE-CLIENT-SECRET} + scope: + - email + - profile + + + +--- +# live +spring.config.activate.on-profile: live + +spring: + security: + oauth2: + client: + provider: + naver: + authorization_uri: https://nid.naver.com/oauth2.0/authorize + token_uri: https://nid.naver.com/oauth2.0/token + user-info-uri: https://openapi.naver.com/v1/nid/me + user_name_attribute: response + registration: + naver: + client-id: f0Y2iXBYxDsBPH699BkC + client-secret: xxOOW3Nr6X + redirect-uri: http://localhost:8080/login/oauth2/code/naver + authorization-grant-type: authorization_code + scope: + - email + - name + client-name: naver + google: + client-id: ${GOOGLE-CLIENT-ID} + client-secret: ${GOOGLE-CLIENT-SECRET} + scope: + - email + - profile + diff --git a/application/api/src/main/resources/application.yml b/application/api/src/main/resources/application.yml index e26c71e9..22e698eb 100644 --- a/application/api/src/main/resources/application.yml +++ b/application/api/src/main/resources/application.yml @@ -1,56 +1,29 @@ -spring.application.name: core-api -spring.profiles.active: local - +# default spring: - config: - import: - - monitoring.yml - - logging.yml - - db-core.yml + profiles: + default: local + application: + name: api mvc.throw-exception-if-no-handler-found: true web.resources.add-mappings: false - security: - oauth2: - client: - provider: - naver: - authorization_uri: https://nid.naver.com/oauth2.0/authorize - token_uri: https://nid.naver.com/oauth2.0/token - user-info-uri: https://openapi.naver.com/v1/nid/me - user_name_attribute: response - registration: - naver: - client-id: f0Y2iXBYxDsBPH699BkC - client-secret: xxOOW3Nr6X - redirect-uri: http://localhost:8080/login/oauth2/code/naver - authorization-grant-type: authorization_code - scope: - - email - - name - client-name: naver - google: - client-id: ${GOOGLE-CLIENT-ID} - client-secret: ${GOOGLE-CLIENT-SECRET} - scope: - - email - - profile - ---- -spring.config.activate.on-profile: local - - ---- -spring.config.activate.on-profile: local-dev - --- -spring.config.activate.on-profile: dev - +# local +spring: + profiles: + group: + local: "security, db-core, logging, metrics" --- -spring.config.activate.on-profile: staging - +# dev +spring: + profiles: + group: + dev: "security, db-core, logging, metrics" --- -spring.config.activate.on-profile: live - +# live +spring: + profiles: + group: + live: "security, db-core, logging, metrics" \ No newline at end of file diff --git a/infra/logging/src/main/resources/application-logging.yml b/infra/logging/src/main/resources/application-logging.yml new file mode 100644 index 00000000..e98d258d --- /dev/null +++ b/infra/logging/src/main/resources/application-logging.yml @@ -0,0 +1,13 @@ +# local +spring.config.activate.on-profile: local +logging.config: classpath:logback/logback-local.xml + +--- +# dev +spring.config.activate.on-profile: dev +logging.config: classpath:logback/logback-dev.xml + +--- +# live +spring.config.activate.on-profile: live +logging.config: classpath:logback/logback-live.xml \ No newline at end of file diff --git a/infra/logging/src/main/resources/logback/logback-local-dev.xml b/infra/logging/src/main/resources/logback/logback-local-dev.xml deleted file mode 100644 index 378b1a33..00000000 --- a/infra/logging/src/main/resources/logback/logback-local-dev.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - %clr(%d{HH:mm:ss.SSS}){faint}|%clr(${level:-%5p})|%32X{traceId:-},%16X{spanId:-}|%clr(%-40.40logger{39}){cyan}%clr(|){faint}%m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx} - utf8 - - - - - - - - - - diff --git a/infra/logging/src/main/resources/logback/logback-staging.xml b/infra/logging/src/main/resources/logback/logback-staging.xml deleted file mode 100644 index 2f11d40e..00000000 --- a/infra/logging/src/main/resources/logback/logback-staging.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - %clr(%d{HH:mm:ss.SSS}){faint}|%clr(${level:-%5p})|%32X{traceId:-},%16X{spanId:-}|%clr(%-40.40logger{39}){cyan}%clr(|){faint}%m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx} - utf8 - - - - - - YOUR_DSN - - WARN - INFO - - - - - - - - - - diff --git a/infra/logging/src/main/resources/logging.yml b/infra/logging/src/main/resources/logging.yml deleted file mode 100644 index 8f932ad6..00000000 --- a/infra/logging/src/main/resources/logging.yml +++ /dev/null @@ -1 +0,0 @@ -logging.config: classpath:logback/logback-${spring.profiles.active}.xml \ No newline at end of file diff --git a/infra/monitoring/build.gradle.kts b/infra/metrics/build.gradle.kts similarity index 100% rename from infra/monitoring/build.gradle.kts rename to infra/metrics/build.gradle.kts diff --git a/infra/metrics/src/main/resources/application-metrics.yml b/infra/metrics/src/main/resources/application-metrics.yml new file mode 100644 index 00000000..7d18155c --- /dev/null +++ b/infra/metrics/src/main/resources/application-metrics.yml @@ -0,0 +1,63 @@ +# local +spring.config.activate.on-profile: local + +management: # Actuator + endpoints: + enabled-by-default: false # default 사용하지 않을 것 + jmx: # JMX 형태 사용 불가 처리 + exposure: + exclude: '*' + web: + base-path: /one-baily-actuator # Actuator 경로 변경 + exposure: + include: metrics, prometheus + endpoint: + metrics: + enabled: true + prometheus: + enabled: true + # actuator 포트 변경 + server: + port: ${MANAGEMENT_PORT:7463} +--- +# dev +spring.config.activate.on-profile: dev + +management: # Actuator + endpoints: + enabled-by-default: false + jmx: + exposure: + exclude: '*' + web: + base-path: /one-baily-actuator + exposure: + include: metrics, prometheus + endpoint: + metrics: + enabled: true + prometheus: + enabled: true + server: + port: ${MANAGEMENT_PORT:7463} +--- +# live +spring.config.activate.on-profile: live + +management: # Actuator + endpoints: + enabled-by-default: false + jmx: + exposure: + exclude: '*' + web: + base-path: /one-baily-actuator + exposure: + include: metrics, prometheus + endpoint: + metrics: + enabled: true + prometheus: + enabled: true + server: + port: ${MANAGEMENT_PORT:7463} diff --git a/infra/monitoring/src/main/resources/monitoring.yml b/infra/monitoring/src/main/resources/monitoring.yml deleted file mode 100644 index 4f84fa61..00000000 --- a/infra/monitoring/src/main/resources/monitoring.yml +++ /dev/null @@ -1,5 +0,0 @@ -management: - endpoints: - web: - exposure: - include: prometheus diff --git a/settings.gradle.kts b/settings.gradle.kts index e71e1ac0..a8894792 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -4,7 +4,7 @@ include( "application:api", "storage:db-core", "infra:logging", - "infra:monitoring", + "infra:metrics", ) pluginManagement { diff --git a/storage/db-core/src/main/resources/db-core.yml b/storage/db-core/src/main/resources/application-db-core.yml similarity index 55% rename from storage/db-core/src/main/resources/db-core.yml rename to storage/db-core/src/main/resources/application-db-core.yml index bad45f5c..cfbb624c 100644 --- a/storage/db-core/src/main/resources/db-core.yml +++ b/storage/db-core/src/main/resources/application-db-core.yml @@ -1,3 +1,4 @@ +# default spring: jpa: open-in-view: false @@ -7,9 +8,11 @@ spring: hibernate.default_batch_fetch_size: 100 --- -spring.config.activate.on-profile: local - +# local spring: + config: + active: + on-profile: local jpa: hibernate: ddl-auto: create @@ -32,43 +35,7 @@ storage: rewriteBatchedStatements: true --- -spring.config.activate.on-profile: local-dev - -spring: - jpa: - properties: - hibernate: - show_log: true - format_sql: true - show-sql: true - -storage: - datasource: - core: - driver-class-name: com.mysql.cj.jdbc.Driver - jdbc-url: jdbc:mysql://${storage.database.core-db.url} - username: ${storage.database.core-db.username} - password: ${storage.database.core-db.password} - maximum-pool-size: 5 - connection-timeout: 1100 - keepalive-time: 30000 - validation-timeout: 1000 - max-lifetime: 600000 - pool-name: core-db-pool - data-source-properties: - socketTimeout: 3000 - cachePrepStmts: true - prepStmtCacheSize: 250 - prepStmtCacheSqlLimit: 2048 - useServerPrepStmts: true - useLocalSessionState: true - rewriteBatchedStatements: true - cacheResultSetMetadata: true - cacheServerConfiguration: true - elideSetAutoCommits: true - maintainTimeStats: false - ---- +# dev spring.config.activate.on-profile: dev storage: @@ -97,36 +64,10 @@ storage: elideSetAutoCommits: true maintainTimeStats: false ---- -spring.config.activate.on-profile: staging -storage: - datasource: - core: - driver-class-name: com.mysql.cj.jdbc.Driver - jdbc-url: jdbc:mysql://${storage.database.core-db.url} - username: ${storage.database.core-db.username} - password: ${storage.database.core-db.password} - maximum-pool-size: 5 - connection-timeout: 1100 - keepalive-time: 30000 - validation-timeout: 1000 - max-lifetime: 600000 - pool-name: core-db-pool - data-source-properties: - socketTimeout: 3000 - cachePrepStmts: true - prepStmtCacheSize: 250 - prepStmtCacheSqlLimit: 2048 - useServerPrepStmts: true - useLocalSessionState: true - rewriteBatchedStatements: true - cacheResultSetMetadata: true - cacheServerConfiguration: true - elideSetAutoCommits: true - maintainTimeStats: false --- +# live spring.config.activate.on-profile: live storage: From 6a2b10bbca7a5e8c00f5a903c49687f0340aab93 Mon Sep 17 00:00:00 2001 From: wkwon Date: Tue, 12 Dec 2023 00:09:34 +0900 Subject: [PATCH 38/70] =?UTF-8?q?fix(#22):=20profiles=20group=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EB=B0=A9=EC=8B=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/src/main/resources/application.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/application/api/src/main/resources/application.yml b/application/api/src/main/resources/application.yml index 22e698eb..27e4a515 100644 --- a/application/api/src/main/resources/application.yml +++ b/application/api/src/main/resources/application.yml @@ -12,18 +12,30 @@ spring: spring: profiles: group: - local: "security, db-core, logging, metrics" + local: + - security + - db-core + - logging + - metrics --- # dev spring: profiles: group: - dev: "security, db-core, logging, metrics" + dev: + - security + - db-core + - logging + - metrics --- # live spring: profiles: group: - live: "security, db-core, logging, metrics" \ No newline at end of file + live: + - security + - db-core + - logging + - metrics \ No newline at end of file From a3b028fb4d94e915f18cb621abc55a374d465313 Mon Sep 17 00:00:00 2001 From: binary_ho Date: Thu, 14 Dec 2023 22:23:53 +0900 Subject: [PATCH 39/70] =?UTF-8?q?refactor=20:=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20db-core=20package=20example=20files=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0=20(#26)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../raemian/storage/db/core/ExampleEntity.kt | 17 -------------- .../storage/db/core/ExampleRepository.kt | 5 ----- .../db/core/config/CoreDataSourceConfig.kt | 22 ------------------- .../storage/db/core/config/CoreJpaConfig.kt | 12 ---------- .../raemian/storage/db/CoreDbContextTest.kt | 12 ---------- .../storage/db/CoreDbTestApplication.kt | 13 ----------- .../storage/db/core/ExampleRepositoryIT.kt | 18 --------------- .../src/test/resources/application.yml | 6 ----- 8 files changed, 105 deletions(-) delete mode 100644 storage/db-core/src/main/kotlin/io/raemian/storage/db/core/ExampleEntity.kt delete mode 100644 storage/db-core/src/main/kotlin/io/raemian/storage/db/core/ExampleRepository.kt delete mode 100644 storage/db-core/src/main/kotlin/io/raemian/storage/db/core/config/CoreDataSourceConfig.kt delete mode 100644 storage/db-core/src/main/kotlin/io/raemian/storage/db/core/config/CoreJpaConfig.kt delete mode 100644 storage/db-core/src/test/kotlin/io/raemian/storage/db/CoreDbContextTest.kt delete mode 100644 storage/db-core/src/test/kotlin/io/raemian/storage/db/CoreDbTestApplication.kt delete mode 100644 storage/db-core/src/test/kotlin/io/raemian/storage/db/core/ExampleRepositoryIT.kt diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/ExampleEntity.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/ExampleEntity.kt deleted file mode 100644 index ec7e8d50..00000000 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/ExampleEntity.kt +++ /dev/null @@ -1,17 +0,0 @@ -package io.raemian.storage.db.core - -import jakarta.persistence.Column -import jakarta.persistence.Entity -import jakarta.persistence.GeneratedValue -import jakarta.persistence.GenerationType -import jakarta.persistence.Id - -@Entity -class ExampleEntity( - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - val id: Long? = null, - - @Column - val exampleColumn: String, -) : BaseEntity() diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/ExampleRepository.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/ExampleRepository.kt deleted file mode 100644 index e0f2ab06..00000000 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/ExampleRepository.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.raemian.storage.db.core - -import org.springframework.data.jpa.repository.JpaRepository - -interface ExampleRepository : JpaRepository diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/config/CoreDataSourceConfig.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/config/CoreDataSourceConfig.kt deleted file mode 100644 index 580e9610..00000000 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/config/CoreDataSourceConfig.kt +++ /dev/null @@ -1,22 +0,0 @@ -package io.raemian.storage.db.core.config - -import com.zaxxer.hikari.HikariConfig -import com.zaxxer.hikari.HikariDataSource -import org.springframework.beans.factory.annotation.Qualifier -import org.springframework.boot.context.properties.ConfigurationProperties -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration - -@Configuration -internal class CoreDataSourceConfig { - @Bean - @ConfigurationProperties(prefix = "storage.datasource.core") - fun coreHikariConfig(): HikariConfig { - return HikariConfig() - } - - @Bean - fun coreDataSource(@Qualifier("coreHikariConfig") config: HikariConfig): HikariDataSource { - return HikariDataSource(config) - } -} diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/config/CoreJpaConfig.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/config/CoreJpaConfig.kt deleted file mode 100644 index 07b71fa5..00000000 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/config/CoreJpaConfig.kt +++ /dev/null @@ -1,12 +0,0 @@ -package io.raemian.storage.db.core.config - -import org.springframework.boot.autoconfigure.domain.EntityScan -import org.springframework.context.annotation.Configuration -import org.springframework.data.jpa.repository.config.EnableJpaRepositories -import org.springframework.transaction.annotation.EnableTransactionManagement - -@Configuration -@EnableTransactionManagement -@EntityScan(basePackages = ["io.raemian.storage.db.core"]) -@EnableJpaRepositories(basePackages = ["io.raemian.storage.db.core"]) -internal class CoreJpaConfig diff --git a/storage/db-core/src/test/kotlin/io/raemian/storage/db/CoreDbContextTest.kt b/storage/db-core/src/test/kotlin/io/raemian/storage/db/CoreDbContextTest.kt deleted file mode 100644 index 1fec50be..00000000 --- a/storage/db-core/src/test/kotlin/io/raemian/storage/db/CoreDbContextTest.kt +++ /dev/null @@ -1,12 +0,0 @@ -package io.raemian.storage.db - -import org.junit.jupiter.api.Tag -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.test.context.ActiveProfiles -import org.springframework.test.context.TestConstructor - -@ActiveProfiles("local") -@Tag("context") -@SpringBootTest -@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL) -abstract class CoreDbContextTest diff --git a/storage/db-core/src/test/kotlin/io/raemian/storage/db/CoreDbTestApplication.kt b/storage/db-core/src/test/kotlin/io/raemian/storage/db/CoreDbTestApplication.kt deleted file mode 100644 index cacc7013..00000000 --- a/storage/db-core/src/test/kotlin/io/raemian/storage/db/CoreDbTestApplication.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.raemian.storage.db - -import org.springframework.boot.autoconfigure.SpringBootApplication -import org.springframework.boot.context.properties.ConfigurationPropertiesScan -import org.springframework.boot.runApplication - -@ConfigurationPropertiesScan -@SpringBootApplication -class CoreDbTestApplication - -fun main(args: Array) { - runApplication(*args) -} diff --git a/storage/db-core/src/test/kotlin/io/raemian/storage/db/core/ExampleRepositoryIT.kt b/storage/db-core/src/test/kotlin/io/raemian/storage/db/core/ExampleRepositoryIT.kt deleted file mode 100644 index eaedad1e..00000000 --- a/storage/db-core/src/test/kotlin/io/raemian/storage/db/core/ExampleRepositoryIT.kt +++ /dev/null @@ -1,18 +0,0 @@ -package io.raemian.storage.db.core - -import io.raemian.storage.db.CoreDbContextTest -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -class ExampleRepositoryIT( - val exampleRepository: ExampleRepository, -) : CoreDbContextTest() { - @Test - fun testShouldBeSavedAndFound() { - val saved = exampleRepository.save(ExampleEntity(1L, "SPRING_BOOT")) - assertThat(saved.exampleColumn).isEqualTo("SPRING_BOOT") - - val found = exampleRepository.findById(saved.id!!).get() - assertThat(found.exampleColumn).isEqualTo("SPRING_BOOT") - } -} diff --git a/storage/db-core/src/test/resources/application.yml b/storage/db-core/src/test/resources/application.yml index db132cfe..e69de29b 100644 --- a/storage/db-core/src/test/resources/application.yml +++ b/storage/db-core/src/test/resources/application.yml @@ -1,6 +0,0 @@ -spring.application.name: db-core-test - -spring: - config: - import: - - db-core.yml From 95a5cd45a094d8d607278f018d669c601fc2a88b Mon Sep 17 00:00:00 2001 From: binary_ho Date: Thu, 14 Dec 2023 22:55:52 +0900 Subject: [PATCH 40/70] =?UTF-8?q?ERD=20=EA=B8=B0=EB=B0=98=20Entity=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20#21=20(#24)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat : 엔티티의 공통 컬럼 id를 갖는 BaseEntity 구현 (#21) * feat : Jpa Auditing을 Enable 하기 위한 JPA Config 작성 (#21) * refactor : BaseEntity에 JpaAduit을 활용한 생성 시간과 수정 시간 필드 추가 (#21) * refactor : 중복 구현한 BaseEntity와 불필요한 JpaConfig 삭제 (#21) * feat : 기본 엔티티 Goal, Sticker, Tag, Task 구현 (#21) * refactor : User 필드 email, userName에 Unique 제한 조건 추가 (#21) * refactor : User 필드 username, nickname을 nvarchar로 변경 (#21) * refactor : Sticker가 Image를 Wrapping 객체 StickerImage로 가지고 있도록 변경 (#21) * refactor : Emoji 패키지명을 Sticker로 변경 (#21) * refactor : Tag의 내용물을 name에서 content로 변경 (#21) * refactor : ManyToOne field에서 @Column 어노테이션 제거 (#21) --- .../io/raemian/storage/db/core/goal/Goal.kt | 54 +++++++++++++++++++ .../storage/db/core/sticker/Sticker.kt | 27 ++++++++++ .../storage/db/core/sticker/StickerImage.kt | 8 +++ .../io/raemian/storage/db/core/tag/Tag.kt | 22 ++++++++ .../io/raemian/storage/db/core/task/Task.kt | 32 +++++++++++ .../io/raemian/storage/db/core/user/User.kt | 8 ++- 6 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 storage/db-core/src/main/kotlin/io/raemian/storage/db/core/goal/Goal.kt create mode 100644 storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/Sticker.kt create mode 100644 storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerImage.kt create mode 100644 storage/db-core/src/main/kotlin/io/raemian/storage/db/core/tag/Tag.kt create mode 100644 storage/db-core/src/main/kotlin/io/raemian/storage/db/core/task/Task.kt diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/goal/Goal.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/goal/Goal.kt new file mode 100644 index 00000000..1ba6bd36 --- /dev/null +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/goal/Goal.kt @@ -0,0 +1,54 @@ +package io.raemian.storage.db.core.goal + +import io.raemian.storage.db.core.BaseEntity +import io.raemian.storage.db.core.sticker.Sticker +import io.raemian.storage.db.core.tag.Tag +import io.raemian.storage.db.core.task.Task +import io.raemian.storage.db.core.user.User +import jakarta.persistence.CascadeType +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.FetchType +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import jakarta.persistence.OneToMany +import jakarta.persistence.Table +import org.hibernate.annotations.Nationalized +import java.time.LocalDate + +@Entity +@Table(name = "GOALS") +class Goal( + @ManyToOne + @JoinColumn(name = "user_id", nullable = false) + val user: User, + + @Column(nullable = false) + @Nationalized + val title: String, + + @Column(nullable = false) + val deadline: LocalDate, + + @ManyToOne + @JoinColumn(name = "sticker_id", nullable = false) + val sticker: Sticker, + + @ManyToOne + @JoinColumn(name = "tag_id", nullable = false) + val tagId: Tag, + + @Column(nullable = false) + @Nationalized + val description: String, + + @OneToMany(mappedBy = "goal", cascade = [CascadeType.REMOVE], fetch = FetchType.LAZY) + val tasks: List, + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long? = null, +) : BaseEntity() diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/Sticker.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/Sticker.kt new file mode 100644 index 00000000..a4257a43 --- /dev/null +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/Sticker.kt @@ -0,0 +1,27 @@ +package io.raemian.storage.db.core.sticker + +import io.raemian.storage.db.core.BaseEntity +import jakarta.persistence.Column +import jakarta.persistence.Embedded +import jakarta.persistence.Entity +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import jakarta.persistence.Table +import org.hibernate.annotations.Nationalized + +@Entity +@Table(name = "STICKERS") +class Sticker( + @Column(nullable = false) + @Nationalized + val name: String, + + @Embedded + @Column(nullable = false) + val stickerImage: StickerImage, + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long? = null, +) : BaseEntity() diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerImage.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerImage.kt new file mode 100644 index 00000000..f7b1b14d --- /dev/null +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerImage.kt @@ -0,0 +1,8 @@ +package io.raemian.storage.db.core.sticker + +import jakarta.persistence.Embeddable + +@Embeddable +class StickerImage( + val stickerImage: String, +) diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/tag/Tag.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/tag/Tag.kt new file mode 100644 index 00000000..51f7539c --- /dev/null +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/tag/Tag.kt @@ -0,0 +1,22 @@ +package io.raemian.storage.db.core.tag + +import io.raemian.storage.db.core.BaseEntity +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import jakarta.persistence.Table +import org.hibernate.annotations.Nationalized + +@Entity +@Table(name = "TAGS") +class Tag( + @Column(nullable = false) + @Nationalized + val content: String, + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long? = null, +) : BaseEntity() diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/task/Task.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/task/Task.kt new file mode 100644 index 00000000..2fba5903 --- /dev/null +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/task/Task.kt @@ -0,0 +1,32 @@ +package io.raemian.storage.db.core.task + +import io.raemian.storage.db.core.BaseEntity +import io.raemian.storage.db.core.goal.Goal +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType +import jakarta.persistence.Id +import jakarta.persistence.JoinColumn +import jakarta.persistence.ManyToOne +import jakarta.persistence.Table +import org.hibernate.annotations.Nationalized + +@Entity +@Table(name = "TASKS") +class Task( + @ManyToOne + @JoinColumn(name = "goal_id") + val goal: Goal, + + @Column(nullable = false) + val isDone: Boolean, + + @Column(nullable = false) + @Nationalized + val description: String, + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long? = null, +) : BaseEntity() diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt index be98811f..db261d44 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt @@ -9,14 +9,20 @@ import jakarta.persistence.Enumerated import jakarta.persistence.GeneratedValue import jakarta.persistence.GenerationType import jakarta.persistence.Id +import org.hibernate.annotations.Nationalized import java.time.LocalDate @Entity(name = "USERS") class User( - @Column + @Column(unique = true, nullable = false) val email: String, + @Column(unique = true) + @Nationalized + val userName: String? = null, + @Column + @Nationalized val nickname: String? = null, @Column From e7e6e59573e394efcef64dd141c4605a5a8133a9 Mon Sep 17 00:00:00 2001 From: binary_ho Date: Fri, 15 Dec 2023 23:31:44 +0900 Subject: [PATCH 41/70] =?UTF-8?q?[Feature]=20Sticker,=20Tag=20API=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20(#29)=20(#30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat : Tag 전체 리스트를 조회하는 Service 메서드 구현 (#29) * feat : Tag 전체 리스트를 조회하는 API 구현 (#29) * feat : Sticker 전체 리스트를 조회하는 Service 메서드 구현 (#29) * feat : Sticker 전체 리스트를 조회하는 API 구현 (#29) * refactor : Sticker와 Tag API가 Wrapping 되지 않은 응답 List를 반환하도록 변경 (#29) * refactor : StickerImage를 data class로 변경 (#29) * test : Sticker, Tag Service Integration Test 작성 (#29) * chore : ktlint fomatting - StickerResponse에 콤마 추가 (#29) --- .../io/raemian/api/sticker/StickerService.kt | 18 ++++ .../sticker/controller/StickerController.kt | 20 ++++ .../controller/response/StickerResponse.kt | 17 ++++ .../kotlin/io/raemian/api/tag/TagService.kt | 18 ++++ .../api/tag/controller/TagController.kt | 20 ++++ .../tag/controller/response/TagResponse.kt | 14 +++ .../io/raemian/api/CoreApiApplicationTest.kt | 12 +++ .../integration/sticker/StickerServiceTest.kt | 48 ++++++++++ .../api/integration/tag/TagServiceTest.kt | 45 +++++++++ .../test/resources/application-security.yml | 94 +++++++++++++++++++ .../api/src/test/resources/application.yml | 49 ++++++++++ .../storage/db/core/sticker/StickerImage.kt | 2 +- .../db/core/sticker/StickerRepository.kt | 5 + .../storage/db/core/tag/TagRepository.kt | 5 + 14 files changed, 366 insertions(+), 1 deletion(-) create mode 100644 application/api/src/main/kotlin/io/raemian/api/sticker/StickerService.kt create mode 100644 application/api/src/main/kotlin/io/raemian/api/sticker/controller/StickerController.kt create mode 100644 application/api/src/main/kotlin/io/raemian/api/sticker/controller/response/StickerResponse.kt create mode 100644 application/api/src/main/kotlin/io/raemian/api/tag/TagService.kt create mode 100644 application/api/src/main/kotlin/io/raemian/api/tag/controller/TagController.kt create mode 100644 application/api/src/main/kotlin/io/raemian/api/tag/controller/response/TagResponse.kt create mode 100644 application/api/src/test/kotlin/io/raemian/api/CoreApiApplicationTest.kt create mode 100644 application/api/src/test/kotlin/io/raemian/api/integration/sticker/StickerServiceTest.kt create mode 100644 application/api/src/test/kotlin/io/raemian/api/integration/tag/TagServiceTest.kt create mode 100644 application/api/src/test/resources/application-security.yml create mode 100644 application/api/src/test/resources/application.yml create mode 100644 storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerRepository.kt create mode 100644 storage/db-core/src/main/kotlin/io/raemian/storage/db/core/tag/TagRepository.kt diff --git a/application/api/src/main/kotlin/io/raemian/api/sticker/StickerService.kt b/application/api/src/main/kotlin/io/raemian/api/sticker/StickerService.kt new file mode 100644 index 00000000..ca327c1c --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/sticker/StickerService.kt @@ -0,0 +1,18 @@ +package io.raemian.api.sticker + +import io.raemian.api.sticker.controller.response.StickerResponse +import io.raemian.storage.db.core.sticker.StickerRepository +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional + +@Service +class StickerService( + private val stickerRepository: StickerRepository, +) { + + @Transactional(readOnly = true) + fun findAll(): List { + return stickerRepository.findAll() + .map(::StickerResponse) + } +} diff --git a/application/api/src/main/kotlin/io/raemian/api/sticker/controller/StickerController.kt b/application/api/src/main/kotlin/io/raemian/api/sticker/controller/StickerController.kt new file mode 100644 index 00000000..4636a44c --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/sticker/controller/StickerController.kt @@ -0,0 +1,20 @@ +package io.raemian.api.sticker.controller + +import io.raemian.api.sticker.StickerService +import io.raemian.api.sticker.controller.response.StickerResponse +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.RestController + +@RestController +@RequestMapping("/sticker") +class StickerController( + private val stickerService: StickerService, +) { + + @GetMapping + fun findAll(): ResponseEntity> { + return ResponseEntity.ok(stickerService.findAll()) + } +} diff --git a/application/api/src/main/kotlin/io/raemian/api/sticker/controller/response/StickerResponse.kt b/application/api/src/main/kotlin/io/raemian/api/sticker/controller/response/StickerResponse.kt new file mode 100644 index 00000000..408ce2b1 --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/sticker/controller/response/StickerResponse.kt @@ -0,0 +1,17 @@ +package io.raemian.api.sticker.controller.response + +import io.raemian.storage.db.core.sticker.Sticker +import io.raemian.storage.db.core.sticker.StickerImage + +data class StickerResponse( + val id: Long?, + val name: String, + val stickerImage: StickerImage, +) { + + constructor(sticker: Sticker) : this( + sticker.id, + sticker.name, + sticker.stickerImage, + ) +} diff --git a/application/api/src/main/kotlin/io/raemian/api/tag/TagService.kt b/application/api/src/main/kotlin/io/raemian/api/tag/TagService.kt new file mode 100644 index 00000000..eaea0ed3 --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/tag/TagService.kt @@ -0,0 +1,18 @@ +package io.raemian.api.tag + +import io.raemian.api.tag.controller.response.TagResponse +import io.raemian.storage.db.core.tag.TagRepository +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional + +@Service +class TagService( + private val tagRepository: TagRepository, +) { + + @Transactional(readOnly = true) + fun findAll(): List { + return tagRepository.findAll() + .map(::TagResponse) + } +} diff --git a/application/api/src/main/kotlin/io/raemian/api/tag/controller/TagController.kt b/application/api/src/main/kotlin/io/raemian/api/tag/controller/TagController.kt new file mode 100644 index 00000000..ca8d4cfc --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/tag/controller/TagController.kt @@ -0,0 +1,20 @@ +package io.raemian.api.tag.controller + +import io.raemian.api.tag.TagService +import io.raemian.api.tag.controller.response.TagResponse +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.RestController + +@RestController +@RequestMapping("/tag") +class TagController( + private val tagService: TagService, +) { + + @GetMapping + fun findAll(): ResponseEntity> { + return ResponseEntity.ok(tagService.findAll()) + } +} diff --git a/application/api/src/main/kotlin/io/raemian/api/tag/controller/response/TagResponse.kt b/application/api/src/main/kotlin/io/raemian/api/tag/controller/response/TagResponse.kt new file mode 100644 index 00000000..e135bf6d --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/tag/controller/response/TagResponse.kt @@ -0,0 +1,14 @@ +package io.raemian.api.tag.controller.response + +import io.raemian.storage.db.core.tag.Tag + +data class TagResponse( + val id: Long?, + val content: String, +) { + + constructor(tag: Tag) : this( + tag.id, + tag.content, + ) +} diff --git a/application/api/src/test/kotlin/io/raemian/api/CoreApiApplicationTest.kt b/application/api/src/test/kotlin/io/raemian/api/CoreApiApplicationTest.kt new file mode 100644 index 00000000..175c0b4d --- /dev/null +++ b/application/api/src/test/kotlin/io/raemian/api/CoreApiApplicationTest.kt @@ -0,0 +1,12 @@ +package io.raemian.api + +import org.junit.jupiter.api.Test +import org.springframework.boot.test.context.SpringBootTest + +@SpringBootTest +class CoreApiApplicationTest { + + @Test + fun contextLoads() { + } +} diff --git a/application/api/src/test/kotlin/io/raemian/api/integration/sticker/StickerServiceTest.kt b/application/api/src/test/kotlin/io/raemian/api/integration/sticker/StickerServiceTest.kt new file mode 100644 index 00000000..1431df29 --- /dev/null +++ b/application/api/src/test/kotlin/io/raemian/api/integration/sticker/StickerServiceTest.kt @@ -0,0 +1,48 @@ +package io.raemian.api.integration.sticker + +import io.raemian.api.sticker.StickerService +import io.raemian.storage.db.core.sticker.Sticker +import io.raemian.storage.db.core.sticker.StickerImage +import io.raemian.storage.db.core.sticker.StickerRepository +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Assertions.assertAll +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.function.Executable +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest + +@SpringBootTest +class StickerServiceTest { + + @Autowired + private lateinit var stickerService: StickerService + + @Autowired + private lateinit var stickerRepository: StickerRepository + + @Test + @DisplayName("저장된 전체 Tag를 조회할 수 있다.") + fun findAllByUserIdTest() { + // given + val sticker1 = Sticker("sticker", StickerImage("image1")) + val sticker2 = Sticker("sticker2", StickerImage("image2")) + + stickerRepository.save(sticker1) + stickerRepository.save(sticker2) + + // when + val stickers = stickerService.findAll() + + // then + assertAll( + Executable { + assertThat(stickers.size).isEqualTo(2) + assertThat(stickers[0].name).isEqualTo(sticker1.name) + assertThat(stickers[0].stickerImage).isEqualTo(sticker1.stickerImage) + assertThat(stickers[1].name).isEqualTo(sticker2.name) + assertThat(stickers[1].stickerImage).isEqualTo(sticker2.stickerImage) + }, + ) + } +} diff --git a/application/api/src/test/kotlin/io/raemian/api/integration/tag/TagServiceTest.kt b/application/api/src/test/kotlin/io/raemian/api/integration/tag/TagServiceTest.kt new file mode 100644 index 00000000..b8536a80 --- /dev/null +++ b/application/api/src/test/kotlin/io/raemian/api/integration/tag/TagServiceTest.kt @@ -0,0 +1,45 @@ +package io.raemian.api.integration.tag + +import io.raemian.api.tag.TagService +import io.raemian.storage.db.core.tag.Tag +import io.raemian.storage.db.core.tag.TagRepository +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Assertions.assertAll +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.function.Executable +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest + +@SpringBootTest +class TagServiceTest { + + @Autowired + private lateinit var tagService: TagService + + @Autowired + private lateinit var tagRepository: TagRepository + + @Test + @DisplayName("저장된 전체 Sticker를 조회할 수 있다.") + fun findAllByUserIdTest() { + // given + val tag1 = Tag("tag1") + val tag2 = Tag("tag2") + + tagRepository.save(tag1) + tagRepository.save(tag2) + + // when + val tags = tagService.findAll() + + // then + assertAll( + Executable { + assertThat(tags.size).isEqualTo(2) + assertThat(tags[0].content).isEqualTo(tag1.content) + assertThat(tags[1].content).isEqualTo(tag2.content) + }, + ) + } +} diff --git a/application/api/src/test/resources/application-security.yml b/application/api/src/test/resources/application-security.yml new file mode 100644 index 00000000..967fa6e6 --- /dev/null +++ b/application/api/src/test/resources/application-security.yml @@ -0,0 +1,94 @@ +# local +spring.config.activate.on-profile: local + +spring: + security: + oauth2: + client: + provider: + naver: + authorization_uri: https://nid.naver.com/oauth2.0/authorize + token_uri: https://nid.naver.com/oauth2.0/token + user-info-uri: https://openapi.naver.com/v1/nid/me + user_name_attribute: response + registration: + naver: + client-id: f0Y2iXBYxDsBPH699BkC + client-secret: xxOOW3Nr6X + redirect-uri: http://localhost:8080/login/oauth2/code/naver + authorization-grant-type: authorization_code + scope: + - email + - name + client-name: naver + google: + client-id: ${GOOGLE-CLIENT-ID} + client-secret: ${GOOGLE-CLIENT-SECRET} + scope: + - email + - profile + + +--- +# dev +spring.config.activate.on-profile: dev + +spring: + security: + oauth2: + client: + provider: + naver: + authorization_uri: https://nid.naver.com/oauth2.0/authorize + token_uri: https://nid.naver.com/oauth2.0/token + user-info-uri: https://openapi.naver.com/v1/nid/me + user_name_attribute: response + registration: + naver: + client-id: f0Y2iXBYxDsBPH699BkC + client-secret: xxOOW3Nr6X + redirect-uri: http://localhost:8080/login/oauth2/code/naver + authorization-grant-type: authorization_code + scope: + - email + - name + client-name: naver + google: + client-id: ${GOOGLE-CLIENT-ID} + client-secret: ${GOOGLE-CLIENT-SECRET} + scope: + - email + - profile + + + +--- +# live +spring.config.activate.on-profile: live + +spring: + security: + oauth2: + client: + provider: + naver: + authorization_uri: https://nid.naver.com/oauth2.0/authorize + token_uri: https://nid.naver.com/oauth2.0/token + user-info-uri: https://openapi.naver.com/v1/nid/me + user_name_attribute: response + registration: + naver: + client-id: f0Y2iXBYxDsBPH699BkC + client-secret: xxOOW3Nr6X + redirect-uri: http://localhost:8080/login/oauth2/code/naver + authorization-grant-type: authorization_code + scope: + - email + - name + client-name: naver + google: + client-id: ${GOOGLE-CLIENT-ID} + client-secret: ${GOOGLE-CLIENT-SECRET} + scope: + - email + - profile diff --git a/application/api/src/test/resources/application.yml b/application/api/src/test/resources/application.yml new file mode 100644 index 00000000..59e338e1 --- /dev/null +++ b/application/api/src/test/resources/application.yml @@ -0,0 +1,49 @@ +# default +spring: + profiles: + default: local + application: + name: api + mvc.throw-exception-if-no-handler-found: true + web.resources.add-mappings: false + + jpa: + hibernate: + ddl-auto: create + database-platform: org.hibernate.dialect.H2Dialect + properties: + hibernate: + format_sql: true + +--- +# local +spring: + profiles: + group: + local: + - security + - db-core + - logging + - metrics + +--- +# dev +spring: + profiles: + group: + dev: + - security + - db-core + - logging + - metrics + +--- +# live +spring: + profiles: + group: + live: + - security + - db-core + - logging + - metrics diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerImage.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerImage.kt index f7b1b14d..387fc257 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerImage.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerImage.kt @@ -3,6 +3,6 @@ package io.raemian.storage.db.core.sticker import jakarta.persistence.Embeddable @Embeddable -class StickerImage( +data class StickerImage( val stickerImage: String, ) diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerRepository.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerRepository.kt new file mode 100644 index 00000000..b5cde0c6 --- /dev/null +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerRepository.kt @@ -0,0 +1,5 @@ +package io.raemian.storage.db.core.sticker + +import org.springframework.data.jpa.repository.JpaRepository + +interface StickerRepository : JpaRepository diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/tag/TagRepository.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/tag/TagRepository.kt new file mode 100644 index 00000000..72e923e4 --- /dev/null +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/tag/TagRepository.kt @@ -0,0 +1,5 @@ +package io.raemian.storage.db.core.tag + +import org.springframework.data.jpa.repository.JpaRepository + +interface TagRepository : JpaRepository From b16cffe014e14d8ee81adfa3ff39c907c34c218d Mon Sep 17 00:00:00 2001 From: binary_ho Date: Sat, 16 Dec 2023 02:58:49 +0900 Subject: [PATCH 42/70] =?UTF-8?q?[Feature]=20Goal=20API=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=20#27=20(#32)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor : Goal의 Tag 타입 프로퍼티 tagId의 이름을 tag로 변경 (#27) * refactor : SecrityUtil의 currentMemberId 메서드의 이름을 유저 객체 이름에 맞게 currentUserId로 변경 (#27) * feat : Goal 단건 조회, 전체 조회 API 구현 (#27) * chore : GoalRepository 메서드 체이닝 줄 바꿈 변경 (#27) * refactor : Goal의 description에 Nullable 속성 추가 (#27) * feat : year와 month를 표현하는 String을 통해 LocalDate를 생성하는 RaemianLocalDate 구현 (#27) * feat : Goal Create를 위한 User, Sticker, Tag getById 메서드 구현 (#27) * feat : Goal Create, Delete 메서드 구현 (#27) * test : Goal 조회 테스트 코드 작성 (#27) * feat : GoalController 구현 (#27) * chore : ktlint formatting (#27) * chore : GoalController PathVariable을 카멜 케이스로 변경 (#27) * test : GoalServiceTest 잘못된 부분 수정 (#27) * refactor : Delete 요청 성공시 204 No Content 응답을 내리도록 변경 (#27) * refactor : description이 null인 경우 ""가 채워지도록 변경 (#27) --- .../io/raemian/api/goal/CreateGoalResponse.kt | 5 + .../kotlin/io/raemian/api/goal/GoalService.kt | 62 +++++++++ .../api/goal/controller/GoalController.kt | 62 +++++++++ .../controller/request/CreateGoalRequest.kt | 10 ++ .../controller/request/DeleteGoalRequest.kt | 5 + .../goal/controller/response/GoalResponse.kt | 41 ++++++ .../goal/controller/response/GoalsResponse.kt | 39 ++++++ .../io/raemian/api/sticker/StickerService.kt | 6 + .../raemian/api/support/RaemianLocalDate.kt | 38 +++++ .../io/raemian/api/support/SecurityUtil.kt | 2 +- .../kotlin/io/raemian/api/tag/TagService.kt | 6 + .../kotlin/io/raemian/api/user/UserService.kt | 17 +++ .../api/integration/goal/GoalServiceTest.kt | 130 ++++++++++++++++++ .../io/raemian/storage/db/core/goal/Goal.kt | 5 +- .../storage/db/core/goal/GoalRepository.kt | 10 ++ .../db/core/sticker/StickerRepository.kt | 6 +- .../storage/db/core/tag/TagRepository.kt | 6 +- .../storage/db/core/user/UserRepository.kt | 4 + 18 files changed, 448 insertions(+), 6 deletions(-) create mode 100644 application/api/src/main/kotlin/io/raemian/api/goal/CreateGoalResponse.kt create mode 100644 application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt create mode 100644 application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt create mode 100644 application/api/src/main/kotlin/io/raemian/api/goal/controller/request/CreateGoalRequest.kt create mode 100644 application/api/src/main/kotlin/io/raemian/api/goal/controller/request/DeleteGoalRequest.kt create mode 100644 application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalResponse.kt create mode 100644 application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalsResponse.kt create mode 100644 application/api/src/main/kotlin/io/raemian/api/support/RaemianLocalDate.kt create mode 100644 application/api/src/main/kotlin/io/raemian/api/user/UserService.kt create mode 100644 application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt create mode 100644 storage/db-core/src/main/kotlin/io/raemian/storage/db/core/goal/GoalRepository.kt diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/CreateGoalResponse.kt b/application/api/src/main/kotlin/io/raemian/api/goal/CreateGoalResponse.kt new file mode 100644 index 00000000..6bd0ee20 --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/goal/CreateGoalResponse.kt @@ -0,0 +1,5 @@ +package io.raemian.api.goal + +data class CreateGoalResponse( + val id: Long, +) diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt b/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt new file mode 100644 index 00000000..269af89b --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt @@ -0,0 +1,62 @@ +package io.raemian.api.goal + +import io.raemian.api.goal.controller.request.CreateGoalRequest +import io.raemian.api.goal.controller.request.DeleteGoalRequest +import io.raemian.api.goal.controller.response.GoalResponse +import io.raemian.api.goal.controller.response.GoalsResponse +import io.raemian.api.sticker.StickerService +import io.raemian.api.support.RaemianLocalDate +import io.raemian.api.tag.TagService +import io.raemian.api.user.UserService +import io.raemian.storage.db.core.goal.Goal +import io.raemian.storage.db.core.goal.GoalRepository +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional + +@Service +class GoalService( + private val userService: UserService, + private val stickerService: StickerService, + private val tagService: TagService, + private val goalRepository: GoalRepository, +) { + + @Transactional(readOnly = true) + fun findAllByUserId(userId: Long): GoalsResponse { + val goals = goalRepository.findAllByUserId(userId) + return GoalsResponse(goals) + } + + @Transactional(readOnly = true) + fun getById(id: Long): GoalResponse { + val goal = goalRepository.getById(id) + return GoalResponse(goal) + } + + @Transactional + fun create(userId: Long, createGoalRequest: CreateGoalRequest): CreateGoalResponse { + val (title, yearOfDeadline, monthOfDeadLine, stickerId, tagId, description) = createGoalRequest + + val deadline = RaemianLocalDate.of(yearOfDeadline, monthOfDeadLine) + val sticker = stickerService.getById(stickerId) + val tag = tagService.getById(tagId) + val user = userService.getById(userId) + + val goal = Goal(user, title, deadline, sticker, tag, description!!, emptyList()) + val savedGoal = goalRepository.save(goal) + return CreateGoalResponse(savedGoal.id!!) + } + + @Transactional + fun delete(userId: Long, deleteGoalRequest: DeleteGoalRequest) { + val goal = goalRepository.getById(deleteGoalRequest.goalId) + validateGoalIsUsers(userId, goal) + goalRepository.delete(goal) + } + + private fun validateGoalIsUsers(userId: Long, goal: Goal) { + if (userId != goal.user.id) { + throw SecurityException() + } + } +} diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt b/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt new file mode 100644 index 00000000..09f2f748 --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt @@ -0,0 +1,62 @@ +package io.raemian.api.goal.controller + +import io.raemian.api.auth.domain.CurrentUser +import io.raemian.api.goal.CreateGoalResponse +import io.raemian.api.goal.GoalService +import io.raemian.api.goal.controller.request.CreateGoalRequest +import io.raemian.api.goal.controller.request.DeleteGoalRequest +import io.raemian.api.goal.controller.response.GoalResponse +import io.raemian.api.goal.controller.response.GoalsResponse +import org.springframework.http.ResponseEntity +import org.springframework.security.core.annotation.AuthenticationPrincipal +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 +import java.net.URI + +fun String.toUri(): URI = URI.create(this) + +@RestController +@RequestMapping("/goal") +class GoalController( + private val goalService: GoalService, +) { + + @GetMapping + fun findAllByUserId( + @AuthenticationPrincipal currentUser: CurrentUser, + ): ResponseEntity { + val response = goalService.findAllByUserId(currentUser.id) + return ResponseEntity.ok(response) + } + + @GetMapping("/{goalId}") + fun getByUserId( + @PathVariable("goalId") goalId: Long, + ): ResponseEntity = + ResponseEntity.ok(goalService.getById(goalId)) + + @PostMapping + fun create( + @AuthenticationPrincipal currentUser: CurrentUser, + @RequestBody createGoalRequest: CreateGoalRequest, + ): ResponseEntity { + val response = goalService.create(currentUser.id, createGoalRequest) + return ResponseEntity + .created("/goal/${response.id}".toUri()) + .body(response) + } + + @DeleteMapping + fun delete( + @AuthenticationPrincipal currentUser: CurrentUser, + @RequestBody deleteGoalRequest: DeleteGoalRequest, + ): ResponseEntity { + goalService.delete(currentUser.id, deleteGoalRequest) + return ResponseEntity.noContent().build() + } +} diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/controller/request/CreateGoalRequest.kt b/application/api/src/main/kotlin/io/raemian/api/goal/controller/request/CreateGoalRequest.kt new file mode 100644 index 00000000..d6358d68 --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/goal/controller/request/CreateGoalRequest.kt @@ -0,0 +1,10 @@ +package io.raemian.api.goal.controller.request + +data class CreateGoalRequest( + val title: String, + val yearOfDeadline: String, + val monthOfDeadLine: String, + val stickerId: Long, + val tagId: Long, + val description: String? = "", +) diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/controller/request/DeleteGoalRequest.kt b/application/api/src/main/kotlin/io/raemian/api/goal/controller/request/DeleteGoalRequest.kt new file mode 100644 index 00000000..09c79249 --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/goal/controller/request/DeleteGoalRequest.kt @@ -0,0 +1,5 @@ +package io.raemian.api.goal.controller.request + +class DeleteGoalRequest( + val goalId: Long, +) diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalResponse.kt b/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalResponse.kt new file mode 100644 index 00000000..7e1103cf --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalResponse.kt @@ -0,0 +1,41 @@ +package io.raemian.api.goal.controller.response + +import io.raemian.storage.db.core.goal.Goal +import io.raemian.storage.db.core.sticker.StickerImage +import io.raemian.storage.db.core.tag.Tag +import io.raemian.storage.db.core.task.Task +import java.time.LocalDate + +data class GoalResponse( + val title: String, + val deadline: LocalDate, + val sticker: StickerImage, + val tagInfo: TagInfo, + val tasks: List, +) { + + constructor(goal: Goal) : this( + goal.title, + goal.deadline, + goal.sticker.stickerImage, + TagInfo(goal.tag), + goal.tasks.map(::TaskInfo), + ) + + data class TagInfo( + val tagId: Long?, + val tagContent: String, + ) { + + constructor(tag: Tag) : this(tag.id, tag.content) + } + + data class TaskInfo( + val taskId: Long?, + val isTaskDone: Boolean, + val taskDescription: String, + ) { + + constructor(task: Task) : this(task.id, task.isDone, task.description) + } +} diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalsResponse.kt b/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalsResponse.kt new file mode 100644 index 00000000..752cae73 --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalsResponse.kt @@ -0,0 +1,39 @@ +package io.raemian.api.goal.controller.response + +import io.raemian.storage.db.core.goal.Goal +import io.raemian.storage.db.core.sticker.StickerImage +import java.time.LocalDate + +data class GoalsResponse( + val goals: Goals, +) { + + constructor(goals: List) : this( + Goals( + goals.map(::GoalInfo), + ), + ) + + data class GoalInfo( + val id: Long?, + val title: String, + val deadline: LocalDate, + val sticker: StickerImage, + val tagContent: String, + val description: String? = "", + ) { + + constructor(goal: Goal) : this( + id = goal.id, + title = goal.title, + deadline = goal.deadline, + sticker = goal.sticker.stickerImage, + tagContent = goal.tag.content, + description = goal.description, + ) + } + + data class Goals( + val goalInfos: List, + ) +} diff --git a/application/api/src/main/kotlin/io/raemian/api/sticker/StickerService.kt b/application/api/src/main/kotlin/io/raemian/api/sticker/StickerService.kt index ca327c1c..92885aca 100644 --- a/application/api/src/main/kotlin/io/raemian/api/sticker/StickerService.kt +++ b/application/api/src/main/kotlin/io/raemian/api/sticker/StickerService.kt @@ -1,6 +1,7 @@ package io.raemian.api.sticker import io.raemian.api.sticker.controller.response.StickerResponse +import io.raemian.storage.db.core.sticker.Sticker import io.raemian.storage.db.core.sticker.StickerRepository import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional @@ -15,4 +16,9 @@ class StickerService( return stickerRepository.findAll() .map(::StickerResponse) } + + @Transactional(readOnly = true) + fun getById(id: Long): Sticker { + return stickerRepository.getById(id) + } } diff --git a/application/api/src/main/kotlin/io/raemian/api/support/RaemianLocalDate.kt b/application/api/src/main/kotlin/io/raemian/api/support/RaemianLocalDate.kt new file mode 100644 index 00000000..c4ac36be --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/support/RaemianLocalDate.kt @@ -0,0 +1,38 @@ +package io.raemian.api.support + +import java.time.LocalDate +import java.time.Month +import java.time.Year + +object RaemianLocalDate { + + private const val DAY_OF_MONTH = 1 + + fun of(year: String, month: String): LocalDate { + val parsedYear = parseYear(year) + val parsedMonth = parseMonth(month) + return LocalDate.of(parsedYear, parsedMonth, DAY_OF_MONTH) + } + + private fun parseYear(year: String): Int { + validateYearFormat(year) + return year.toInt() + } + + private fun validateYearFormat(year: String) { + runCatching { + Year.parse(year) + }.onFailure { + throw IllegalArgumentException() + } + } + + private fun parseMonth(month: String): Month { + val result = runCatching { + Month.of(month.toInt()) + } + + return result.getOrNull() + ?: throw IllegalArgumentException() + } +} diff --git a/application/api/src/main/kotlin/io/raemian/api/support/SecurityUtil.kt b/application/api/src/main/kotlin/io/raemian/api/support/SecurityUtil.kt index 9258a157..b045f6f1 100644 --- a/application/api/src/main/kotlin/io/raemian/api/support/SecurityUtil.kt +++ b/application/api/src/main/kotlin/io/raemian/api/support/SecurityUtil.kt @@ -5,7 +5,7 @@ import org.springframework.security.core.context.SecurityContextHolder object SecurityUtil { // SecurityContext 에 유저 정보가 저장되는 시점 - fun currentMemberId(): Long { + fun currentUserId(): Long { val authentication: Authentication? = SecurityContextHolder.getContext().authentication if (authentication == null || authentication.name == null) { throw RuntimeException("Security Context 에 인증 정보가 없습니다.") diff --git a/application/api/src/main/kotlin/io/raemian/api/tag/TagService.kt b/application/api/src/main/kotlin/io/raemian/api/tag/TagService.kt index eaea0ed3..1d220c90 100644 --- a/application/api/src/main/kotlin/io/raemian/api/tag/TagService.kt +++ b/application/api/src/main/kotlin/io/raemian/api/tag/TagService.kt @@ -1,6 +1,7 @@ package io.raemian.api.tag import io.raemian.api.tag.controller.response.TagResponse +import io.raemian.storage.db.core.tag.Tag import io.raemian.storage.db.core.tag.TagRepository import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional @@ -15,4 +16,9 @@ class TagService( return tagRepository.findAll() .map(::TagResponse) } + + @Transactional(readOnly = true) + fun getById(id: Long): Tag { + return tagRepository.getById(id) + } } diff --git a/application/api/src/main/kotlin/io/raemian/api/user/UserService.kt b/application/api/src/main/kotlin/io/raemian/api/user/UserService.kt new file mode 100644 index 00000000..3930a02d --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/user/UserService.kt @@ -0,0 +1,17 @@ +package io.raemian.api.user + +import io.raemian.storage.db.core.user.User +import io.raemian.storage.db.core.user.UserRepository +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional + +@Service +class UserService( + private val userRepository: UserRepository, +) { + + @Transactional(readOnly = true) + fun getById(userId: Long): User { + return userRepository.getById(userId) + } +} diff --git a/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt b/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt new file mode 100644 index 00000000..6cbac153 --- /dev/null +++ b/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt @@ -0,0 +1,130 @@ +package io.raemian.api.integration.goal + +import io.raemian.api.goal.GoalService +import io.raemian.storage.db.core.goal.Goal +import io.raemian.storage.db.core.goal.GoalRepository +import io.raemian.storage.db.core.sticker.Sticker +import io.raemian.storage.db.core.sticker.StickerImage +import io.raemian.storage.db.core.sticker.StickerRepository +import io.raemian.storage.db.core.tag.Tag +import io.raemian.storage.db.core.tag.TagRepository +import io.raemian.storage.db.core.user.Authority +import io.raemian.storage.db.core.user.User +import io.raemian.storage.db.core.user.UserRepository +import io.raemian.storage.db.core.user.enums.OAuthProvider +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatCode +import org.junit.jupiter.api.Assertions.assertAll +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.function.Executable +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.transaction.annotation.Transactional +import java.time.LocalDate + +@SpringBootTest +class GoalServiceTest { + + companion object { + val USER_FIXTURE = User( + "dfghcvb111@naver.com", + "binaryHoHo", + "binaryHoHoHo", + LocalDate.MIN, + OAuthProvider.NAVER, + Authority.ROLE_USER, + ) + + val STICKER_FIXTURE = Sticker("sticker", StickerImage("image yeah")) + val TAG_FIXTURE = Tag("꿈") + } + + @Autowired + private lateinit var goalService: GoalService + + @Autowired + private lateinit var goalRepository: GoalRepository + + @Autowired + private lateinit var userRepository: UserRepository + + @Autowired + private lateinit var stickerRepository: StickerRepository + + @Autowired + private lateinit var tagRepository: TagRepository + + @BeforeEach + fun saveEntities() { + userRepository.save(USER_FIXTURE) + stickerRepository.save(STICKER_FIXTURE) + tagRepository.save(TAG_FIXTURE) + } + + @Test + @DisplayName("Goal ID를 통해 Goal을 조회 할 수 있다.") + @Transactional + fun getByIdTest() { + // given + val goal = Goal( + USER_FIXTURE, + "짱이 될거야", + LocalDate.MAX, + STICKER_FIXTURE, + TAG_FIXTURE, + "열심히, 잘, 최선을 다해 꼭 짱이 된다.", + emptyList(), + ) + + val savedGoal = goalRepository.save(goal) + + // when + // then + assertThatCode { + goalService.getById(savedGoal.id!!) + }.doesNotThrowAnyException() + } + + @Test + @DisplayName("User ID를 통해 유저가 가진 전체 Goal을 조회 할 수 있다.") + @Transactional + fun findAllByUserIdTest() { + // given + val goal1 = Goal( + USER_FIXTURE, + "제목1", + LocalDate.MAX, + STICKER_FIXTURE, + TAG_FIXTURE, + "", + emptyList(), + ) + + val goal2 = Goal( + USER_FIXTURE, + "제목2", + LocalDate.MAX, + STICKER_FIXTURE, + TAG_FIXTURE, + "", + emptyList(), + ) + + // when + // then + goalRepository.save(goal1) + goalRepository.save(goal2) + + val savedGoals = goalService.findAllByUserId(USER_FIXTURE.id!!) + + assertAll( + Executable { + assertThat(savedGoals.goals.goalInfos.size).isEqualTo(2) + assertThat(savedGoals.goals.goalInfos[0].title).isEqualTo(goal1.title) + assertThat(savedGoals.goals.goalInfos[1].title).isEqualTo(goal2.title) + }, + ) + } +} diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/goal/Goal.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/goal/Goal.kt index 1ba6bd36..edd25d35 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/goal/Goal.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/goal/Goal.kt @@ -39,11 +39,10 @@ class Goal( @ManyToOne @JoinColumn(name = "tag_id", nullable = false) - val tagId: Tag, + val tag: Tag, - @Column(nullable = false) @Nationalized - val description: String, + val description: String = "", @OneToMany(mappedBy = "goal", cascade = [CascadeType.REMOVE], fetch = FetchType.LAZY) val tasks: List, diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/goal/GoalRepository.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/goal/GoalRepository.kt new file mode 100644 index 00000000..3271b5bd --- /dev/null +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/goal/GoalRepository.kt @@ -0,0 +1,10 @@ +package io.raemian.storage.db.core.goal + +import org.springframework.data.jpa.repository.JpaRepository + +interface GoalRepository : JpaRepository { + fun findAllByUserId(userId: Long): List + + override fun getById(id: Long): Goal = + findById(id).orElseThrow() { NoSuchElementException("목표가 없습니다 $id") } +} diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerRepository.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerRepository.kt index b5cde0c6..87cb60a2 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerRepository.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerRepository.kt @@ -2,4 +2,8 @@ package io.raemian.storage.db.core.sticker import org.springframework.data.jpa.repository.JpaRepository -interface StickerRepository : JpaRepository +interface StickerRepository : JpaRepository { + + override fun getById(id: Long): Sticker = + findById(id).orElseThrow { NoSuchElementException("존재하지 않는 스티커입니다. $id") } +} diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/tag/TagRepository.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/tag/TagRepository.kt index 72e923e4..c19b7878 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/tag/TagRepository.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/tag/TagRepository.kt @@ -2,4 +2,8 @@ package io.raemian.storage.db.core.tag import org.springframework.data.jpa.repository.JpaRepository -interface TagRepository : JpaRepository +interface TagRepository : JpaRepository { + + override fun getById(id: Long): Tag = + findById(id).orElseThrow { NoSuchElementException("존재하지 않는 태그입니다. $id") } +} diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/UserRepository.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/UserRepository.kt index 5d95e378..cd44b629 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/UserRepository.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/UserRepository.kt @@ -4,5 +4,9 @@ import org.springframework.data.jpa.repository.JpaRepository interface UserRepository : JpaRepository { fun findByEmail(email: String): User? + fun existsByEmail(email: String): Boolean + + override fun getById(id: Long): User = + findById(id).orElseThrow { NoSuchElementException("존재하지 않는 유저입니다. $id") } } From ae727ebe0553b899fe5da504f7a8f134afa20bf0 Mon Sep 17 00:00:00 2001 From: binary_ho Date: Sat, 16 Dec 2023 10:47:41 +0900 Subject: [PATCH 43/70] =?UTF-8?q?[Feature]=20Task=20API=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=20(#33)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor : Task 생성시 isDone이 false일 수 있도록, 정적 팩터리 메서드를 사용해야만 생성 가능하도록 변경 (#33) * refactor : Task description을 바꾸는 rewrite 구현 (#33) * refactor : Task 수행 여부를 바꾸는 updateTaskCompletion 구현 (#33) * feat : Task 생성, description 수정, isDone 수정, 삭제 메서드 구현 (#33) * test : Task 생성, description 수정, isDone 수정, 삭제 테스트 작성 (#33) * refactor : GoalService에서 Repositort 반환 객체 사용 제거 (#33) * test : GoalServiceTest에서 persist 제거 (#33) * refactor : Request Body가 있는 메서드의 파라미터를 Wrapping (#33) * feat : Task 생성, description, isDone 변경, 삭제 API 구현 (#33) * test : Service Method 시그니처 변화에 따른 테스트 코드 수정 (#33) --- .../kotlin/io/raemian/api/goal/GoalService.kt | 4 +- .../controller/request/DeleteGoalRequest.kt | 2 +- .../kotlin/io/raemian/api/task/TaskService.kt | 65 +++++++ .../api/task/controller/TaskController.kt | 64 +++++++ .../controller/request/CreateTaskRequest.kt | 6 + .../controller/request/RewriteTaskRequest.kt | 5 + .../request/UpdateTaskCompletionRequest.kt | 5 + .../controller/response/CreateTaskResponse.kt | 5 + .../api/integration/goal/GoalServiceTest.kt | 18 +- .../api/integration/task/TaskServiceTest.kt | 160 ++++++++++++++++++ .../io/raemian/storage/db/core/task/Task.kt | 27 ++- .../storage/db/core/task/TaskRepository.kt | 9 + 12 files changed, 350 insertions(+), 20 deletions(-) create mode 100644 application/api/src/main/kotlin/io/raemian/api/task/TaskService.kt create mode 100644 application/api/src/main/kotlin/io/raemian/api/task/controller/TaskController.kt create mode 100644 application/api/src/main/kotlin/io/raemian/api/task/controller/request/CreateTaskRequest.kt create mode 100644 application/api/src/main/kotlin/io/raemian/api/task/controller/request/RewriteTaskRequest.kt create mode 100644 application/api/src/main/kotlin/io/raemian/api/task/controller/request/UpdateTaskCompletionRequest.kt create mode 100644 application/api/src/main/kotlin/io/raemian/api/task/controller/response/CreateTaskResponse.kt create mode 100644 application/api/src/test/kotlin/io/raemian/api/integration/task/TaskServiceTest.kt create mode 100644 storage/db-core/src/main/kotlin/io/raemian/storage/db/core/task/TaskRepository.kt diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt b/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt index 269af89b..114e440d 100644 --- a/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt +++ b/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt @@ -43,8 +43,8 @@ class GoalService( val user = userService.getById(userId) val goal = Goal(user, title, deadline, sticker, tag, description!!, emptyList()) - val savedGoal = goalRepository.save(goal) - return CreateGoalResponse(savedGoal.id!!) + goalRepository.save(goal) + return CreateGoalResponse(goal.id!!) } @Transactional diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/controller/request/DeleteGoalRequest.kt b/application/api/src/main/kotlin/io/raemian/api/goal/controller/request/DeleteGoalRequest.kt index 09c79249..2cb324f8 100644 --- a/application/api/src/main/kotlin/io/raemian/api/goal/controller/request/DeleteGoalRequest.kt +++ b/application/api/src/main/kotlin/io/raemian/api/goal/controller/request/DeleteGoalRequest.kt @@ -1,5 +1,5 @@ package io.raemian.api.goal.controller.request -class DeleteGoalRequest( +data class DeleteGoalRequest( val goalId: Long, ) diff --git a/application/api/src/main/kotlin/io/raemian/api/task/TaskService.kt b/application/api/src/main/kotlin/io/raemian/api/task/TaskService.kt new file mode 100644 index 00000000..007836a2 --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/task/TaskService.kt @@ -0,0 +1,65 @@ +package io.raemian.api.task + +import io.raemian.api.task.controller.request.CreateTaskRequest +import io.raemian.api.task.controller.request.RewriteTaskRequest +import io.raemian.api.task.controller.request.UpdateTaskCompletionRequest +import io.raemian.api.task.controller.response.CreateTaskResponse +import io.raemian.storage.db.core.goal.Goal +import io.raemian.storage.db.core.goal.GoalRepository +import io.raemian.storage.db.core.task.Task +import io.raemian.storage.db.core.task.TaskRepository +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional + +@Service +class TaskService( + val taskRepository: TaskRepository, + val goalRepository: GoalRepository, +) { + + @Transactional + fun create(currentUserId: Long, createTaskRequest: CreateTaskRequest): CreateTaskResponse { + val goal = goalRepository.getById(createTaskRequest.goalId) + validateCurrentUserIsGoalOwner(currentUserId, goal) + + val task = Task.createTask(goal, createTaskRequest.description) + taskRepository.save(task) + return CreateTaskResponse(task.id!!) + } + + @Transactional + fun rewrite(currentUserId: Long, taskId: Long, rewriteTaskRequest: RewriteTaskRequest) { + val task = taskRepository.getById(taskId) + validateCurrentUserIsGoalOwner(currentUserId, task.goal) + + task.rewrite(rewriteTaskRequest.newDescription) + taskRepository.save(task) + } + + @Transactional + fun updateTaskCompletion( + currentUserId: Long, + taskId: Long, + updateTaskCompletionRequest: UpdateTaskCompletionRequest, + ) { + val task = taskRepository.getById(taskId) + validateCurrentUserIsGoalOwner(currentUserId, task.goal) + + task.updateTaskCompletion(updateTaskCompletionRequest.isDone) + taskRepository.save(task) + } + + @Transactional + fun delete(currentUserId: Long, taskId: Long) { + val task = taskRepository.getById(taskId) + validateCurrentUserIsGoalOwner(currentUserId, task.goal) + + taskRepository.delete(task) + } + + private fun validateCurrentUserIsGoalOwner(currentUserId: Long, goal: Goal) { + if (currentUserId != goal.user.id) { + throw SecurityException() + } + } +} diff --git a/application/api/src/main/kotlin/io/raemian/api/task/controller/TaskController.kt b/application/api/src/main/kotlin/io/raemian/api/task/controller/TaskController.kt new file mode 100644 index 00000000..48a016af --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/task/controller/TaskController.kt @@ -0,0 +1,64 @@ +package io.raemian.api.task.controller + +import io.raemian.api.auth.domain.CurrentUser +import io.raemian.api.goal.controller.toUri +import io.raemian.api.task.TaskService +import io.raemian.api.task.controller.request.CreateTaskRequest +import io.raemian.api.task.controller.request.RewriteTaskRequest +import io.raemian.api.task.controller.request.UpdateTaskCompletionRequest +import io.raemian.api.task.controller.response.CreateTaskResponse +import org.springframework.http.ResponseEntity +import org.springframework.security.core.annotation.AuthenticationPrincipal +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.PatchMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping("/task") +class TaskController( + private val taskService: TaskService, +) { + + @PostMapping + fun create( + @AuthenticationPrincipal currentUser: CurrentUser, + @RequestBody createTaskRequest: CreateTaskRequest, + ): ResponseEntity { + val response = taskService.create(currentUser.id, createTaskRequest) + return ResponseEntity.created("/task/${response.id}".toUri()) + .body(response) + } + + @PatchMapping("/{taskId}/description") + fun rewrite( + @AuthenticationPrincipal currentUser: CurrentUser, + @PathVariable("taskId") taskId: Long, + @RequestBody rewriteTaskRequest: RewriteTaskRequest, + ): ResponseEntity { + taskService.rewrite(currentUser.id, taskId, rewriteTaskRequest) + return ResponseEntity.ok().build() + } + + @PatchMapping("/{taskId}/isDone") + fun updateTaskCompletion( + @AuthenticationPrincipal currentUser: CurrentUser, + @PathVariable("taskId") taskId: Long, + @RequestBody updateTaskCompletionRequest: UpdateTaskCompletionRequest, + ): ResponseEntity { + taskService.updateTaskCompletion(currentUser.id, taskId, updateTaskCompletionRequest) + return ResponseEntity.ok().build() + } + + @DeleteMapping("/{taskId}") + fun updateTaskCompletion( + @AuthenticationPrincipal currentUser: CurrentUser, + @PathVariable("taskId") taskId: Long, + ): ResponseEntity { + taskService.delete(currentUser.id, taskId) + return ResponseEntity.noContent().build() + } +} diff --git a/application/api/src/main/kotlin/io/raemian/api/task/controller/request/CreateTaskRequest.kt b/application/api/src/main/kotlin/io/raemian/api/task/controller/request/CreateTaskRequest.kt new file mode 100644 index 00000000..78a92682 --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/task/controller/request/CreateTaskRequest.kt @@ -0,0 +1,6 @@ +package io.raemian.api.task.controller.request + +data class CreateTaskRequest( + val goalId: Long, + val description: String, +) diff --git a/application/api/src/main/kotlin/io/raemian/api/task/controller/request/RewriteTaskRequest.kt b/application/api/src/main/kotlin/io/raemian/api/task/controller/request/RewriteTaskRequest.kt new file mode 100644 index 00000000..40d58457 --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/task/controller/request/RewriteTaskRequest.kt @@ -0,0 +1,5 @@ +package io.raemian.api.task.controller.request + +data class RewriteTaskRequest( + val newDescription: String, +) diff --git a/application/api/src/main/kotlin/io/raemian/api/task/controller/request/UpdateTaskCompletionRequest.kt b/application/api/src/main/kotlin/io/raemian/api/task/controller/request/UpdateTaskCompletionRequest.kt new file mode 100644 index 00000000..6bc42adc --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/task/controller/request/UpdateTaskCompletionRequest.kt @@ -0,0 +1,5 @@ +package io.raemian.api.task.controller.request + +data class UpdateTaskCompletionRequest( + val isDone: Boolean, +) diff --git a/application/api/src/main/kotlin/io/raemian/api/task/controller/response/CreateTaskResponse.kt b/application/api/src/main/kotlin/io/raemian/api/task/controller/response/CreateTaskResponse.kt new file mode 100644 index 00000000..8a8f4c96 --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/task/controller/response/CreateTaskResponse.kt @@ -0,0 +1,5 @@ +package io.raemian.api.task.controller.response + +class CreateTaskResponse( + val id: Long, +) diff --git a/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt b/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt index 6cbac153..6213a317 100644 --- a/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt +++ b/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt @@ -5,13 +5,11 @@ import io.raemian.storage.db.core.goal.Goal import io.raemian.storage.db.core.goal.GoalRepository import io.raemian.storage.db.core.sticker.Sticker import io.raemian.storage.db.core.sticker.StickerImage -import io.raemian.storage.db.core.sticker.StickerRepository import io.raemian.storage.db.core.tag.Tag -import io.raemian.storage.db.core.tag.TagRepository import io.raemian.storage.db.core.user.Authority import io.raemian.storage.db.core.user.User -import io.raemian.storage.db.core.user.UserRepository import io.raemian.storage.db.core.user.enums.OAuthProvider +import jakarta.persistence.EntityManager import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatCode import org.junit.jupiter.api.Assertions.assertAll @@ -48,19 +46,13 @@ class GoalServiceTest { private lateinit var goalRepository: GoalRepository @Autowired - private lateinit var userRepository: UserRepository - - @Autowired - private lateinit var stickerRepository: StickerRepository - - @Autowired - private lateinit var tagRepository: TagRepository + private lateinit var entityManager: EntityManager @BeforeEach fun saveEntities() { - userRepository.save(USER_FIXTURE) - stickerRepository.save(STICKER_FIXTURE) - tagRepository.save(TAG_FIXTURE) + entityManager.merge(USER_FIXTURE) + entityManager.merge(STICKER_FIXTURE) + entityManager.merge(TAG_FIXTURE) } @Test diff --git a/application/api/src/test/kotlin/io/raemian/api/integration/task/TaskServiceTest.kt b/application/api/src/test/kotlin/io/raemian/api/integration/task/TaskServiceTest.kt new file mode 100644 index 00000000..b34470b8 --- /dev/null +++ b/application/api/src/test/kotlin/io/raemian/api/integration/task/TaskServiceTest.kt @@ -0,0 +1,160 @@ +package io.raemian.api.integration.task + +import io.raemian.api.task.TaskService +import io.raemian.api.task.controller.request.CreateTaskRequest +import io.raemian.api.task.controller.request.RewriteTaskRequest +import io.raemian.api.task.controller.request.UpdateTaskCompletionRequest +import io.raemian.storage.db.core.goal.Goal +import io.raemian.storage.db.core.goal.GoalRepository +import io.raemian.storage.db.core.sticker.Sticker +import io.raemian.storage.db.core.sticker.StickerImage +import io.raemian.storage.db.core.tag.Tag +import io.raemian.storage.db.core.task.Task +import io.raemian.storage.db.core.task.TaskRepository +import io.raemian.storage.db.core.user.Authority +import io.raemian.storage.db.core.user.User +import io.raemian.storage.db.core.user.enums.OAuthProvider +import jakarta.persistence.EntityManager +import org.assertj.core.api.Assertions.assertThat +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.transaction.annotation.Transactional +import java.time.LocalDate + +@SpringBootTest +@Transactional +class TaskServiceTest { + + companion object { + val USER_FIXTURE = User( + email = "dfghcvb111@naver.com", + userName = "binaryHoHo", + nickname = "binaryHoHoHo", + LocalDate.MIN, + OAuthProvider.NAVER, + Authority.ROLE_USER, + ) + + val STICKER_FIXTURE = Sticker("sticker", StickerImage("image yeah")) + val TAG_FIXTURE = Tag("꿈") + val GOAL_FIXTURE = Goal( + user = USER_FIXTURE, + title = "title", + deadline = LocalDate.MAX, + sticker = STICKER_FIXTURE, + tag = TAG_FIXTURE, + description = "description", + tasks = emptyList(), + ) + } + + @Autowired + private lateinit var taskService: TaskService + + @Autowired + private lateinit var taskRepository: TaskRepository + + @Autowired + private lateinit var goalRepository: GoalRepository + + @Autowired + private lateinit var entityManager: EntityManager + + @BeforeEach + fun saveEntities() { + entityManager.merge(USER_FIXTURE) + entityManager.merge(STICKER_FIXTURE) + entityManager.merge(TAG_FIXTURE) + goalRepository.save(GOAL_FIXTURE) + } + + @Test + @DisplayName("Goal ID와 description으로 Task를 생성할 수 있다.") + fun createTest() { + // given + // when + val response = taskService.create( + currentUserId = USER_FIXTURE.id!!, + CreateTaskRequest(GOAL_FIXTURE.id!!, "description"), + ) + + // then + val task = taskRepository.getById(response.id) + assertThat(task.id).isEqualTo(response.id) + assertThat(task.description).isEqualTo("description") + assertThat(task.goal.description).isEqualTo(GOAL_FIXTURE.description) + } + + @Test + @DisplayName("Task 생성시 isDone 값은 false로 설정된다.") + fun createTaskIsDoneFalseTest() { + // given + // when + val response = taskService.create( + currentUserId = USER_FIXTURE.id!!, + CreateTaskRequest(GOAL_FIXTURE.id!!, "description"), + ) + + // then + val task = taskRepository.getById(response.id) + assertThat(task.isDone).isEqualTo(false) + } + + @Test + @DisplayName("Task의 Description을 수정할 수 있다.") + fun rewriteTest() { + // given + val description = "description" + val newTask = Task.createTask(GOAL_FIXTURE, description) + taskRepository.save(newTask) + + // when + val newDescription = "new description" + taskService.rewrite( + currentUserId = USER_FIXTURE.id!!, + taskId = newTask.id!!, + RewriteTaskRequest(newDescription), + ) + + // then + val task = taskRepository.getById(newTask.id!!) + assertThat(task.description).isEqualTo(newDescription) + } + + @Test + @DisplayName("Task의 수행 여부를 변경할 수 있다.") + fun updateTaskCompletionTest() { + // given + val newTask = Task.createTask(GOAL_FIXTURE, "description") + taskRepository.save(newTask) + + // when + taskService.updateTaskCompletion( + currentUserId = USER_FIXTURE.id!!, + taskId = newTask.id!!, + UpdateTaskCompletionRequest(true), + ) + + // then + val task = taskRepository.getById(newTask.id!!) + assertThat(task.isDone).isEqualTo(true) + } + + @Test + @DisplayName("Task를 삭제할 수 있다.") + fun deleteTest() { + // given + val newTask = Task.createTask(GOAL_FIXTURE, "description") + taskRepository.save(newTask) + + // when + taskService.delete(USER_FIXTURE.id!!, newTask.id!!) + + // then + val task = taskRepository.findById(newTask.id!!) + assertThat(task.isEmpty).isEqualTo(true) + } +} diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/task/Task.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/task/Task.kt index 2fba5903..cce75144 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/task/Task.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/task/Task.kt @@ -14,19 +14,38 @@ import org.hibernate.annotations.Nationalized @Entity @Table(name = "TASKS") -class Task( +class Task private constructor( @ManyToOne @JoinColumn(name = "goal_id") val goal: Goal, @Column(nullable = false) - val isDone: Boolean, + var isDone: Boolean, @Column(nullable = false) @Nationalized - val description: String, + var description: String, @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long? = null, -) : BaseEntity() +) : BaseEntity() { + + companion object { + fun createTask(goal: Goal, description: String): Task { + return Task( + goal = goal, + isDone = false, + description = description, + ) + } + } + + fun rewrite(newDescription: String) { + this.description = newDescription + } + + fun updateTaskCompletion(isDone: Boolean) { + this.isDone = isDone + } +} diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/task/TaskRepository.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/task/TaskRepository.kt new file mode 100644 index 00000000..6f603a22 --- /dev/null +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/task/TaskRepository.kt @@ -0,0 +1,9 @@ +package io.raemian.storage.db.core.task + +import org.springframework.data.jpa.repository.JpaRepository + +interface TaskRepository : JpaRepository { + + override fun getById(id: Long): Task = + findById(id).orElseThrow() { NoSuchElementException("Task가 없습니다 $id") } +} From 01135e2a76db7feadd72160877d3796e2e18ce27 Mon Sep 17 00:00:00 2001 From: binary_ho Date: Sat, 16 Dec 2023 10:48:59 +0900 Subject: [PATCH 44/70] =?UTF-8?q?[Feature]=20Swagger=20=EB=8F=84=EC=9E=85?= =?UTF-8?q?=20(#35)=20(#37)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat : springdoc 의존성 추가 (#35) * feat : Swagger 관련 경로 시큐리티 설정 추가 (#35) * feat : API Operation summary 추가 (#35) --- application/api/build.gradle.kts | 13 ++++++++----- .../raemian/api/auth/controller/AuthController.kt | 4 ++++ .../io/raemian/api/config/WebSecurityConfig.kt | 6 ++++++ .../raemian/api/goal/controller/GoalController.kt | 5 +++++ .../api/sticker/controller/StickerController.kt | 2 ++ .../io/raemian/api/tag/controller/TagController.kt | 2 ++ 6 files changed, 27 insertions(+), 5 deletions(-) diff --git a/application/api/build.gradle.kts b/application/api/build.gradle.kts index 1d63ab09..023b799a 100644 --- a/application/api/build.gradle.kts +++ b/application/api/build.gradle.kts @@ -13,23 +13,26 @@ dependencies { implementation("org.springframework.boot:spring-boot-starter-web") - // jwt + /* jwt */ implementation("io.jsonwebtoken:jjwt-api:0.11.5") runtimeOnly("io.jsonwebtoken:jjwt-impl:0.11.5") runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.11.5") - // security + /* security */ implementation("org.springframework.boot:spring-boot-starter-security") - // oauth-client + /* oauth-client */ implementation("org.springframework.boot:spring-boot-starter-oauth2-client") - // web-client + /* web-client */ implementation("org.springframework.boot:spring-boot-starter-webflux") - // test + /* test */ testImplementation("org.springframework.security:spring-security-test") testImplementation("org.springframework.restdocs:spring-restdocs-mockmvc") testImplementation("org.springframework.restdocs:spring-restdocs-restassured") testImplementation("io.rest-assured:spring-mock-mvc") + + /* swagger */ + implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2") } diff --git a/application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt b/application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt index db830131..d09cc858 100644 --- a/application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt +++ b/application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt @@ -5,6 +5,7 @@ import io.raemian.api.auth.controller.request.UpdateUserRequest import io.raemian.api.auth.domain.CurrentUser import io.raemian.api.auth.domain.TokenDTO import io.raemian.api.auth.service.AuthService +import io.swagger.v3.oas.annotations.Operation import org.springframework.http.ResponseEntity import org.springframework.security.core.annotation.AuthenticationPrincipal import org.springframework.web.bind.annotation.GetMapping @@ -18,16 +19,19 @@ class AuthController( private val authService: AuthService, ) { + @Operation(summary = "로그인 API") @PostMapping("/auth/sign-in") fun signIn(@RequestBody signInRequest: SignInRequest): TokenDTO { return authService.signIn(signInRequest.email) } + @Operation(summary = "토큰 유저 정보 조회 API") @GetMapping("/my") fun my(@AuthenticationPrincipal currentUser: CurrentUser): CurrentUser { return currentUser } + @Operation(summary = "유저 온보딩 이후 정보 업데이트 API") @PutMapping("/my") fun update( @AuthenticationPrincipal currentUser: CurrentUser, diff --git a/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt b/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt index f68ee226..e0808786 100644 --- a/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt +++ b/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt @@ -56,6 +56,12 @@ class WebSecurityConfig( it.requestMatchers(AntPathRequestMatcher("/auth/**")).permitAll() .requestMatchers(AntPathRequestMatcher("/oauth2/**")).permitAll() .requestMatchers(AntPathRequestMatcher("/login/**")).permitAll() + .requestMatchers( + AntPathRequestMatcher("/swagger*/**"), + AntPathRequestMatcher("/v3/api-docs/**"), + AntPathRequestMatcher("/swagger-resources/**"), + AntPathRequestMatcher("/webjars/**"), + ).permitAll() .anyRequest().authenticated() } .oauth2Login { diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt b/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt index 09f2f748..543ed422 100644 --- a/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt +++ b/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt @@ -7,6 +7,7 @@ import io.raemian.api.goal.controller.request.CreateGoalRequest import io.raemian.api.goal.controller.request.DeleteGoalRequest import io.raemian.api.goal.controller.response.GoalResponse import io.raemian.api.goal.controller.response.GoalsResponse +import io.swagger.v3.oas.annotations.Operation import org.springframework.http.ResponseEntity import org.springframework.security.core.annotation.AuthenticationPrincipal import org.springframework.web.bind.annotation.DeleteMapping @@ -26,6 +27,7 @@ class GoalController( private val goalService: GoalService, ) { + @Operation(summary = "유저 목표 전체 조회 API") @GetMapping fun findAllByUserId( @AuthenticationPrincipal currentUser: CurrentUser, @@ -34,12 +36,14 @@ class GoalController( return ResponseEntity.ok(response) } + @Operation(summary = "목표 단건 조회 API") @GetMapping("/{goalId}") fun getByUserId( @PathVariable("goalId") goalId: Long, ): ResponseEntity = ResponseEntity.ok(goalService.getById(goalId)) + @Operation(summary = "목표 생성 API") @PostMapping fun create( @AuthenticationPrincipal currentUser: CurrentUser, @@ -51,6 +55,7 @@ class GoalController( .body(response) } + @Operation(summary = "목표 삭제 API") @DeleteMapping fun delete( @AuthenticationPrincipal currentUser: CurrentUser, diff --git a/application/api/src/main/kotlin/io/raemian/api/sticker/controller/StickerController.kt b/application/api/src/main/kotlin/io/raemian/api/sticker/controller/StickerController.kt index 4636a44c..631cb860 100644 --- a/application/api/src/main/kotlin/io/raemian/api/sticker/controller/StickerController.kt +++ b/application/api/src/main/kotlin/io/raemian/api/sticker/controller/StickerController.kt @@ -2,6 +2,7 @@ package io.raemian.api.sticker.controller import io.raemian.api.sticker.StickerService import io.raemian.api.sticker.controller.response.StickerResponse +import io.swagger.v3.oas.annotations.Operation import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RequestMapping @@ -13,6 +14,7 @@ class StickerController( private val stickerService: StickerService, ) { + @Operation(summary = "스티커 전체 조회 API") @GetMapping fun findAll(): ResponseEntity> { return ResponseEntity.ok(stickerService.findAll()) diff --git a/application/api/src/main/kotlin/io/raemian/api/tag/controller/TagController.kt b/application/api/src/main/kotlin/io/raemian/api/tag/controller/TagController.kt index ca8d4cfc..a4f6c890 100644 --- a/application/api/src/main/kotlin/io/raemian/api/tag/controller/TagController.kt +++ b/application/api/src/main/kotlin/io/raemian/api/tag/controller/TagController.kt @@ -2,6 +2,7 @@ package io.raemian.api.tag.controller import io.raemian.api.tag.TagService import io.raemian.api.tag.controller.response.TagResponse +import io.swagger.v3.oas.annotations.Operation import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RequestMapping @@ -13,6 +14,7 @@ class TagController( private val tagService: TagService, ) { + @Operation(summary = "태그 전체 조회 API") @GetMapping fun findAll(): ResponseEntity> { return ResponseEntity.ok(tagService.findAll()) From 483acb9af024cf7b9af5ef2900bdee43221b5f61 Mon Sep 17 00:00:00 2001 From: binary_ho Date: Mon, 18 Dec 2023 19:41:09 +0900 Subject: [PATCH 45/70] =?UTF-8?q?[Refactor]=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=98=EA=B2=8C=20Wrapping=EB=90=9C=20Response=EB=93=A4=20Un?= =?UTF-8?q?wrapping=20(#43)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor : GoalsResponse를 정적 팩터리 메서드를 통해 생성하도록 변경 (#41) * refactor : GoalsInfo 일급 컬렉션 Goals 삭제 (#41) * refactor : StickerImage 필드에 @JsonValue 추가 (#41) * refactor : 정적 팩터리 메서드 이름을 컨벤션에 맞게 from으로 변경 (#41) --- .../kotlin/io/raemian/api/goal/GoalService.kt | 2 +- .../goal/controller/response/GoalsResponse.kt | 17 ++++++----------- .../api/integration/goal/GoalServiceTest.kt | 6 +++--- .../storage/db/core/sticker/StickerImage.kt | 2 ++ 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt b/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt index 114e440d..5f842327 100644 --- a/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt +++ b/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt @@ -24,7 +24,7 @@ class GoalService( @Transactional(readOnly = true) fun findAllByUserId(userId: Long): GoalsResponse { val goals = goalRepository.findAllByUserId(userId) - return GoalsResponse(goals) + return GoalsResponse.from(goals) } @Transactional(readOnly = true) diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalsResponse.kt b/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalsResponse.kt index 752cae73..57e898b9 100644 --- a/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalsResponse.kt +++ b/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalsResponse.kt @@ -4,15 +4,14 @@ import io.raemian.storage.db.core.goal.Goal import io.raemian.storage.db.core.sticker.StickerImage import java.time.LocalDate -data class GoalsResponse( - val goals: Goals, +class GoalsResponse private constructor( + val goals: List, ) { - constructor(goals: List) : this( - Goals( - goals.map(::GoalInfo), - ), - ) + companion object { + fun from(goals: List): GoalsResponse = + GoalsResponse(goals.map(::GoalInfo)) + } data class GoalInfo( val id: Long?, @@ -32,8 +31,4 @@ data class GoalsResponse( description = goal.description, ) } - - data class Goals( - val goalInfos: List, - ) } diff --git a/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt b/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt index 6213a317..9755ed1e 100644 --- a/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt +++ b/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt @@ -113,9 +113,9 @@ class GoalServiceTest { assertAll( Executable { - assertThat(savedGoals.goals.goalInfos.size).isEqualTo(2) - assertThat(savedGoals.goals.goalInfos[0].title).isEqualTo(goal1.title) - assertThat(savedGoals.goals.goalInfos[1].title).isEqualTo(goal2.title) + assertThat(savedGoals.goals.size).isEqualTo(2) + assertThat(savedGoals.goals[0].title).isEqualTo(goal1.title) + assertThat(savedGoals.goals[1].title).isEqualTo(goal2.title) }, ) } diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerImage.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerImage.kt index 387fc257..b7fddea8 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerImage.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerImage.kt @@ -1,8 +1,10 @@ package io.raemian.storage.db.core.sticker +import com.fasterxml.jackson.annotation.JsonValue import jakarta.persistence.Embeddable @Embeddable data class StickerImage( + @JsonValue val stickerImage: String, ) From d6b724e47fba3b0235e42e733462d3f56694d65b Mon Sep 17 00:00:00 2001 From: binary_ho Date: Tue, 19 Dec 2023 13:56:53 +0900 Subject: [PATCH 46/70] =?UTF-8?q?[Refactor]=20Goal=20=EC=A0=84=EC=B2=B4=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20API=20=EC=88=98=EC=A0=95=20-=20=EC=B4=9D?= =?UTF-8?q?=20=EB=AA=A9=ED=91=9C=20=EA=B0=AF=EC=88=98=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?,=20title,=20description=20=EC=82=AD=EC=A0=9C,=20deadline=20?= =?UTF-8?q?=ED=8F=AC=EB=A7=B7=20=EB=B3=80=EA=B2=BD=20(#44)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor : GoalsResponse에서 title과 description 삭제 (#39) * refactor : GoalsResponse의 deadline 응답 포멧 변경 (#39) * refactor : GoalResponse의 deadline 응답 포멧 변경 (#39) * refactor : LocalDate format 확장함수 선언 위치 변경 (#39) * refactor : LocalDate format 확장함수 선언 위치 변경 (#39) * refactor : LocalDate formating시 month값 +1 추가 (#39) * refactor : deadline formating 테스트 코드 작성 (#39) * refactor : deadline month value +1 제거 (#39) * feat : GoalsResponse에 총 목표 갯수 필드 추가 (#39) * chore : ktlint source set formatting * chore : ktlint main source set formatting --- .../goal/controller/response/GoalResponse.kt | 6 +- .../goal/controller/response/GoalsResponse.kt | 16 +++--- .../raemian/api/support/RaemianLocalDate.kt | 9 +++ .../api/integration/goal/GoalServiceTest.kt | 55 ++++++++++++++++++- 4 files changed, 72 insertions(+), 14 deletions(-) diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalResponse.kt b/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalResponse.kt index 7e1103cf..e9773afd 100644 --- a/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalResponse.kt +++ b/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalResponse.kt @@ -1,14 +1,14 @@ package io.raemian.api.goal.controller.response +import io.raemian.api.support.format import io.raemian.storage.db.core.goal.Goal import io.raemian.storage.db.core.sticker.StickerImage import io.raemian.storage.db.core.tag.Tag import io.raemian.storage.db.core.task.Task -import java.time.LocalDate data class GoalResponse( val title: String, - val deadline: LocalDate, + val deadline: String, val sticker: StickerImage, val tagInfo: TagInfo, val tasks: List, @@ -16,7 +16,7 @@ data class GoalResponse( constructor(goal: Goal) : this( goal.title, - goal.deadline, + goal.deadline.format(), goal.sticker.stickerImage, TagInfo(goal.tag), goal.tasks.map(::TaskInfo), diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalsResponse.kt b/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalsResponse.kt index 57e898b9..95f6634d 100644 --- a/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalsResponse.kt +++ b/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalsResponse.kt @@ -1,34 +1,34 @@ package io.raemian.api.goal.controller.response +import io.raemian.api.support.format import io.raemian.storage.db.core.goal.Goal import io.raemian.storage.db.core.sticker.StickerImage -import java.time.LocalDate class GoalsResponse private constructor( val goals: List, + val goalsCount: Int, ) { companion object { fun from(goals: List): GoalsResponse = - GoalsResponse(goals.map(::GoalInfo)) + GoalsResponse( + goals.map(::GoalInfo), + goals.size, + ) } data class GoalInfo( val id: Long?, - val title: String, - val deadline: LocalDate, + val deadline: String, val sticker: StickerImage, val tagContent: String, - val description: String? = "", ) { constructor(goal: Goal) : this( id = goal.id, - title = goal.title, - deadline = goal.deadline, + deadline = goal.deadline.format(), sticker = goal.sticker.stickerImage, tagContent = goal.tag.content, - description = goal.description, ) } } diff --git a/application/api/src/main/kotlin/io/raemian/api/support/RaemianLocalDate.kt b/application/api/src/main/kotlin/io/raemian/api/support/RaemianLocalDate.kt index c4ac36be..d20b0983 100644 --- a/application/api/src/main/kotlin/io/raemian/api/support/RaemianLocalDate.kt +++ b/application/api/src/main/kotlin/io/raemian/api/support/RaemianLocalDate.kt @@ -4,6 +4,15 @@ import java.time.LocalDate import java.time.Month import java.time.Year +fun LocalDate.format(): String { + var month = (this.monthValue).toString() + if (month.length == 1) { + month = "0$month" + } + + return "${this.year}.$month" +} + object RaemianLocalDate { private const val DAY_OF_MONTH = 1 diff --git a/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt b/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt index 9755ed1e..355dc4d7 100644 --- a/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt +++ b/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt @@ -104,18 +104,67 @@ class GoalServiceTest { emptyList(), ) + goalRepository.save(goal1) + goalRepository.save(goal2) + // when + val savedGoals = goalService.findAllByUserId(USER_FIXTURE.id!!) + // then + assertAll( + Executable { + assertThat(savedGoals.goalsCount).isEqualTo(2) + assertThat(savedGoals.goals[0].tagContent).isEqualTo(goal1.tag.content) + assertThat(savedGoals.goals[1].tagContent).isEqualTo(goal2.tag.content) + }, + ) + } + + @Test + @DisplayName("GoalsResponse와 GoalResponse의 deadline 포멧은 'YYYY.MM'이다.") + @Transactional + fun responseFormattingTest() { + // given + val now = LocalDate.now() + val goal1 = Goal( + USER_FIXTURE, + "제목1", + now, + STICKER_FIXTURE, + TAG_FIXTURE, + "", + emptyList(), + ) + + val goal2 = Goal( + USER_FIXTURE, + "제목2", + now, + STICKER_FIXTURE, + TAG_FIXTURE, + "", + emptyList(), + ) + goalRepository.save(goal1) goalRepository.save(goal2) + // when + val savedGoal = goalService.getById(goal1.id!!) val savedGoals = goalService.findAllByUserId(USER_FIXTURE.id!!) + // then + var month = (now.monthValue).toString() + if (month.length == 1) { + month = "0$month" + } + val deadline = "${now.year}.$month" + assertAll( Executable { - assertThat(savedGoals.goals.size).isEqualTo(2) - assertThat(savedGoals.goals[0].title).isEqualTo(goal1.title) - assertThat(savedGoals.goals[1].title).isEqualTo(goal2.title) + assertThat(savedGoal.deadline).isEqualTo(deadline) + assertThat(savedGoals.goals[0].deadline).isEqualTo(deadline) + assertThat(savedGoals.goals[1].deadline).isEqualTo(deadline) }, ) } From b04243b7b9db2ac9489a01964cd4420bcc2d8695 Mon Sep 17 00:00:00 2001 From: binary_ho Date: Tue, 19 Dec 2023 22:25:42 +0900 Subject: [PATCH 47/70] =?UTF-8?q?[Refactor]=20=EC=83=9D=EC=84=B1=20API?= =?UTF-8?q?=EC=97=90=20=EC=83=9D=EC=84=B1=20=EB=A6=AC=EC=86=8C=EC=8A=A4=20?= =?UTF-8?q?=EB=B0=98=ED=99=98=20=EC=B6=94=EA=B0=80=20(#40)=20(#45)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor : Create Task API 응답에 description 추가 (#40) * refactor : Create Goal API 응답에 자세한 goal 정보들 추가 (#40) * chore : Task API 부연 설명 추가 (#40) --- .../io/raemian/api/goal/CreateGoalResponse.kt | 5 ---- .../kotlin/io/raemian/api/goal/GoalService.kt | 3 ++- .../api/goal/controller/GoalController.kt | 2 +- .../controller/response/CreateGoalResponse.kt | 24 +++++++++++++++++++ .../kotlin/io/raemian/api/task/TaskService.kt | 2 +- .../api/task/controller/TaskController.kt | 5 ++++ .../controller/response/CreateTaskResponse.kt | 1 + 7 files changed, 34 insertions(+), 8 deletions(-) delete mode 100644 application/api/src/main/kotlin/io/raemian/api/goal/CreateGoalResponse.kt create mode 100644 application/api/src/main/kotlin/io/raemian/api/goal/controller/response/CreateGoalResponse.kt diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/CreateGoalResponse.kt b/application/api/src/main/kotlin/io/raemian/api/goal/CreateGoalResponse.kt deleted file mode 100644 index 6bd0ee20..00000000 --- a/application/api/src/main/kotlin/io/raemian/api/goal/CreateGoalResponse.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.raemian.api.goal - -data class CreateGoalResponse( - val id: Long, -) diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt b/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt index 5f842327..ec90cb2d 100644 --- a/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt +++ b/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt @@ -2,6 +2,7 @@ package io.raemian.api.goal import io.raemian.api.goal.controller.request.CreateGoalRequest import io.raemian.api.goal.controller.request.DeleteGoalRequest +import io.raemian.api.goal.controller.response.CreateGoalResponse import io.raemian.api.goal.controller.response.GoalResponse import io.raemian.api.goal.controller.response.GoalsResponse import io.raemian.api.sticker.StickerService @@ -44,7 +45,7 @@ class GoalService( val goal = Goal(user, title, deadline, sticker, tag, description!!, emptyList()) goalRepository.save(goal) - return CreateGoalResponse(goal.id!!) + return CreateGoalResponse(goal) } @Transactional diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt b/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt index 543ed422..c9efc0c6 100644 --- a/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt +++ b/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt @@ -1,10 +1,10 @@ package io.raemian.api.goal.controller import io.raemian.api.auth.domain.CurrentUser -import io.raemian.api.goal.CreateGoalResponse import io.raemian.api.goal.GoalService import io.raemian.api.goal.controller.request.CreateGoalRequest import io.raemian.api.goal.controller.request.DeleteGoalRequest +import io.raemian.api.goal.controller.response.CreateGoalResponse import io.raemian.api.goal.controller.response.GoalResponse import io.raemian.api.goal.controller.response.GoalsResponse import io.swagger.v3.oas.annotations.Operation diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/CreateGoalResponse.kt b/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/CreateGoalResponse.kt new file mode 100644 index 00000000..04e26ac1 --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/CreateGoalResponse.kt @@ -0,0 +1,24 @@ +package io.raemian.api.goal.controller.response + +import io.raemian.api.support.format +import io.raemian.storage.db.core.goal.Goal +import io.raemian.storage.db.core.sticker.StickerImage + +data class CreateGoalResponse( + val id: Long, + val title: String, + val description: String, + val deadline: String, + val sticker: StickerImage, + val tag: String, +) { + + constructor(goal: Goal) : this( + id = goal.id!!, + title = goal.title, + description = goal.description, + deadline = goal.deadline.format(), + sticker = goal.sticker.stickerImage, + tag = goal.tag.content, + ) +} diff --git a/application/api/src/main/kotlin/io/raemian/api/task/TaskService.kt b/application/api/src/main/kotlin/io/raemian/api/task/TaskService.kt index 007836a2..6cdeca42 100644 --- a/application/api/src/main/kotlin/io/raemian/api/task/TaskService.kt +++ b/application/api/src/main/kotlin/io/raemian/api/task/TaskService.kt @@ -24,7 +24,7 @@ class TaskService( val task = Task.createTask(goal, createTaskRequest.description) taskRepository.save(task) - return CreateTaskResponse(task.id!!) + return CreateTaskResponse(task.id!!, task.description) } @Transactional diff --git a/application/api/src/main/kotlin/io/raemian/api/task/controller/TaskController.kt b/application/api/src/main/kotlin/io/raemian/api/task/controller/TaskController.kt index 48a016af..150718f0 100644 --- a/application/api/src/main/kotlin/io/raemian/api/task/controller/TaskController.kt +++ b/application/api/src/main/kotlin/io/raemian/api/task/controller/TaskController.kt @@ -7,6 +7,7 @@ import io.raemian.api.task.controller.request.CreateTaskRequest import io.raemian.api.task.controller.request.RewriteTaskRequest import io.raemian.api.task.controller.request.UpdateTaskCompletionRequest import io.raemian.api.task.controller.response.CreateTaskResponse +import io.swagger.v3.oas.annotations.Operation import org.springframework.http.ResponseEntity import org.springframework.security.core.annotation.AuthenticationPrincipal import org.springframework.web.bind.annotation.DeleteMapping @@ -23,6 +24,7 @@ class TaskController( private val taskService: TaskService, ) { + @Operation(summary = "Task 생성 API입니다.") @PostMapping fun create( @AuthenticationPrincipal currentUser: CurrentUser, @@ -33,6 +35,7 @@ class TaskController( .body(response) } + @Operation(summary = "Task의 description을 수정하는 API입니다.") @PatchMapping("/{taskId}/description") fun rewrite( @AuthenticationPrincipal currentUser: CurrentUser, @@ -43,6 +46,7 @@ class TaskController( return ResponseEntity.ok().build() } + @Operation(summary = "Task의 완료 여부를 수정하는 API입니다.") @PatchMapping("/{taskId}/isDone") fun updateTaskCompletion( @AuthenticationPrincipal currentUser: CurrentUser, @@ -53,6 +57,7 @@ class TaskController( return ResponseEntity.ok().build() } + @Operation(summary = "Task를 삭제하는 API입니다.") @DeleteMapping("/{taskId}") fun updateTaskCompletion( @AuthenticationPrincipal currentUser: CurrentUser, diff --git a/application/api/src/main/kotlin/io/raemian/api/task/controller/response/CreateTaskResponse.kt b/application/api/src/main/kotlin/io/raemian/api/task/controller/response/CreateTaskResponse.kt index 8a8f4c96..8355d9a5 100644 --- a/application/api/src/main/kotlin/io/raemian/api/task/controller/response/CreateTaskResponse.kt +++ b/application/api/src/main/kotlin/io/raemian/api/task/controller/response/CreateTaskResponse.kt @@ -2,4 +2,5 @@ package io.raemian.api.task.controller.response class CreateTaskResponse( val id: Long, + val description: String, ) From 15f81b7659e20789d134fb8293e366398fa08971 Mon Sep 17 00:00:00 2001 From: binary_ho Date: Tue, 19 Dec 2023 23:42:13 +0900 Subject: [PATCH 48/70] =?UTF-8?q?[Feature]=20=EA=B8=B0=EC=A4=80=EC=97=90?= =?UTF-8?q?=20=EB=94=B0=EB=9D=BC=20Goal=20=EC=A1=B0=ED=9A=8C=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=20=EC=A0=95=EB=A0=AC=20(#38)=20(#47)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat : Goal 전체 조회시 Deadline 기준 오름차순으로, 값이 같은 경우 생성일 기준 내림차순으로 정렬하는 기능 구현 (#38) * test : Goal 전체 조회시 Deadline 기준 오름차순, 생성일 기준 내림차순으로 정렬 테스트 코드 작성 (#38) * refactor : GoalService의 사이즈가 너무 커져 Read Method를 GoalReadService로 분리 (#38) --- .../io/raemian/api/goal/GoalReadService.kt | 33 +++ .../kotlin/io/raemian/api/goal/GoalService.kt | 15 -- .../api/goal/controller/GoalController.kt | 6 +- .../integration/goal/GoalReadServiceTest.kt | 226 ++++++++++++++++++ .../api/integration/goal/GoalServiceTest.kt | 171 ------------- 5 files changed, 263 insertions(+), 188 deletions(-) create mode 100644 application/api/src/main/kotlin/io/raemian/api/goal/GoalReadService.kt create mode 100644 application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalReadServiceTest.kt delete mode 100644 application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/GoalReadService.kt b/application/api/src/main/kotlin/io/raemian/api/goal/GoalReadService.kt new file mode 100644 index 00000000..4cd7b75f --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/goal/GoalReadService.kt @@ -0,0 +1,33 @@ +package io.raemian.api.goal + +import io.raemian.api.goal.controller.response.GoalResponse +import io.raemian.api.goal.controller.response.GoalsResponse +import io.raemian.storage.db.core.goal.Goal +import io.raemian.storage.db.core.goal.GoalRepository +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional + +@Service +class GoalReadService( + private val goalRepository: GoalRepository, +) { + @Transactional(readOnly = true) + fun findAllByUserId(userId: Long): GoalsResponse { + val goals = goalRepository.findAllByUserId(userId) + val sortedGoals = sortByDeadlineAscendingAndCreatedAtDescending(goals) + return GoalsResponse.from(sortedGoals) + } + + @Transactional(readOnly = true) + fun getById(id: Long): GoalResponse { + val goal = goalRepository.getById(id) + return GoalResponse(goal) + } + + private fun sortByDeadlineAscendingAndCreatedAtDescending(goals: List): List { + return goals.sortedWith( + compareBy { it.deadline } + .thenByDescending { it.createdAt }, + ) + } +} diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt b/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt index ec90cb2d..133ce801 100644 --- a/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt +++ b/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt @@ -3,8 +3,6 @@ package io.raemian.api.goal import io.raemian.api.goal.controller.request.CreateGoalRequest import io.raemian.api.goal.controller.request.DeleteGoalRequest import io.raemian.api.goal.controller.response.CreateGoalResponse -import io.raemian.api.goal.controller.response.GoalResponse -import io.raemian.api.goal.controller.response.GoalsResponse import io.raemian.api.sticker.StickerService import io.raemian.api.support.RaemianLocalDate import io.raemian.api.tag.TagService @@ -21,19 +19,6 @@ class GoalService( private val tagService: TagService, private val goalRepository: GoalRepository, ) { - - @Transactional(readOnly = true) - fun findAllByUserId(userId: Long): GoalsResponse { - val goals = goalRepository.findAllByUserId(userId) - return GoalsResponse.from(goals) - } - - @Transactional(readOnly = true) - fun getById(id: Long): GoalResponse { - val goal = goalRepository.getById(id) - return GoalResponse(goal) - } - @Transactional fun create(userId: Long, createGoalRequest: CreateGoalRequest): CreateGoalResponse { val (title, yearOfDeadline, monthOfDeadLine, stickerId, tagId, description) = createGoalRequest diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt b/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt index c9efc0c6..fc5bdf6e 100644 --- a/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt +++ b/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt @@ -1,6 +1,7 @@ package io.raemian.api.goal.controller import io.raemian.api.auth.domain.CurrentUser +import io.raemian.api.goal.GoalReadService import io.raemian.api.goal.GoalService import io.raemian.api.goal.controller.request.CreateGoalRequest import io.raemian.api.goal.controller.request.DeleteGoalRequest @@ -25,6 +26,7 @@ fun String.toUri(): URI = URI.create(this) @RequestMapping("/goal") class GoalController( private val goalService: GoalService, + private val goalReadService: GoalReadService, ) { @Operation(summary = "유저 목표 전체 조회 API") @@ -32,7 +34,7 @@ class GoalController( fun findAllByUserId( @AuthenticationPrincipal currentUser: CurrentUser, ): ResponseEntity { - val response = goalService.findAllByUserId(currentUser.id) + val response = goalReadService.findAllByUserId(currentUser.id) return ResponseEntity.ok(response) } @@ -41,7 +43,7 @@ class GoalController( fun getByUserId( @PathVariable("goalId") goalId: Long, ): ResponseEntity = - ResponseEntity.ok(goalService.getById(goalId)) + ResponseEntity.ok(goalReadService.getById(goalId)) @Operation(summary = "목표 생성 API") @PostMapping diff --git a/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalReadServiceTest.kt b/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalReadServiceTest.kt new file mode 100644 index 00000000..8119f3df --- /dev/null +++ b/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalReadServiceTest.kt @@ -0,0 +1,226 @@ +package io.raemian.api.integration.goal + +import io.raemian.api.goal.GoalReadService +import io.raemian.storage.db.core.goal.Goal +import io.raemian.storage.db.core.goal.GoalRepository +import io.raemian.storage.db.core.sticker.Sticker +import io.raemian.storage.db.core.sticker.StickerImage +import io.raemian.storage.db.core.tag.Tag +import io.raemian.storage.db.core.user.Authority +import io.raemian.storage.db.core.user.User +import io.raemian.storage.db.core.user.enums.OAuthProvider +import jakarta.persistence.EntityManager +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatCode +import org.junit.jupiter.api.Assertions.assertAll +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.function.Executable +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.transaction.annotation.Transactional +import java.time.LocalDate + +@SpringBootTest +class GoalReadServiceTest { + + companion object { + val USER_FIXTURE = User( + "dfghcvb111@naver.com", + "binaryHoHo", + "binaryHoHoHo", + LocalDate.MIN, + OAuthProvider.NAVER, + Authority.ROLE_USER, + ) + + val STICKER_FIXTURE = Sticker("sticker", StickerImage("image yeah")) + val TAG_FIXTURE = Tag("꿈") + } + + @Autowired + private lateinit var goalReadService: GoalReadService + + @Autowired + private lateinit var goalRepository: GoalRepository + + @Autowired + private lateinit var entityManager: EntityManager + + @BeforeEach + fun saveEntities() { + entityManager.merge(USER_FIXTURE) + entityManager.merge(STICKER_FIXTURE) + entityManager.merge(TAG_FIXTURE) + } + + @Test + @DisplayName("Goal ID를 통해 Goal을 조회 할 수 있다.") + @Transactional + fun getByIdTest() { + // given + val goal = Goal( + user = USER_FIXTURE, + title = "짱이 될거야", + deadline = LocalDate.MAX, + sticker = STICKER_FIXTURE, + tag = TAG_FIXTURE, + description = "열심히, 잘, 최선을 다해 꼭 짱이 된다.", + tasks = emptyList(), + ) + + val savedGoal = goalRepository.save(goal) + + // when + // then + assertThatCode { + goalReadService.getById(savedGoal.id!!) + }.doesNotThrowAnyException() + } + + @Test + @DisplayName("User ID를 통해 유저가 가진 전체 Goal을 조회 할 수 있다.") + @Transactional + fun findAllByUserIdTest() { + // given + val goal1 = Goal( + user = USER_FIXTURE, + title = "제목1", + deadline = LocalDate.MAX, + sticker = STICKER_FIXTURE, + tag = TAG_FIXTURE, + description = "", + tasks = emptyList(), + ) + + val goal2 = Goal( + user = USER_FIXTURE, + title = "제목2", + deadline = LocalDate.MAX, + sticker = STICKER_FIXTURE, + tag = TAG_FIXTURE, + description = "", + tasks = emptyList(), + ) + + goalRepository.save(goal1) + goalRepository.save(goal2) + + // when + val savedGoals = goalReadService.findAllByUserId(USER_FIXTURE.id!!) + + // then + assertAll( + Executable { + assertThat(savedGoals.goalsCount).isEqualTo(2) + assertThat(savedGoals.goals[0].tagContent).isEqualTo(goal1.tag.content) + assertThat(savedGoals.goals[1].tagContent).isEqualTo(goal2.tag.content) + }, + ) + } + + @Test + @DisplayName("GoalsResponse와 GoalResponse의 deadline 포멧은 'YYYY.MM'이다.") + @Transactional + fun responseFormattingTest() { + // given + val now = LocalDate.now() + val goal1 = Goal( + user = USER_FIXTURE, + title = "제목1", + deadline = now, + sticker = STICKER_FIXTURE, + tag = TAG_FIXTURE, + description = "", + tasks = emptyList(), + ) + + val goal2 = Goal( + user = USER_FIXTURE, + title = "제목2", + deadline = now, + sticker = STICKER_FIXTURE, + tag = TAG_FIXTURE, + description = "", + tasks = emptyList(), + ) + goalRepository.save(goal1) + goalRepository.save(goal2) + + // when + val savedGoal = goalReadService.getById(goal1.id!!) + val savedGoals = goalReadService.findAllByUserId(USER_FIXTURE.id!!) + + // then + var month = (now.monthValue).toString() + if (month.length == 1) { + month = "0$month" + } + val deadline = "${now.year}.$month" + + assertAll( + Executable { + assertThat(savedGoal.deadline).isEqualTo(deadline) + assertThat(savedGoals.goals[0].deadline).isEqualTo(deadline) + assertThat(savedGoals.goals[1].deadline).isEqualTo(deadline) + }, + ) + } + + // 정렬 테스트 + @Test + @DisplayName("Goals 전체 조회시 Deadline 기준 오름차순, CreatedAt 기준 내림차순으로 정렬된다.") + @Transactional + fun sortGoalsTest() { + // given + val deadline이_내일이고_가장_처음_만들어진_객체 = Goal( + user = USER_FIXTURE, + title = "제목1", + deadline = LocalDate.now() + .plusDays(1), + sticker = STICKER_FIXTURE, + tag = TAG_FIXTURE, + description = "", + tasks = emptyList(), + ) + + val deadline이_내일이고_가장_나중에_만들어진_객체 = Goal( + user = USER_FIXTURE, + title = "제목2", + deadline = LocalDate.now() + .plusDays(1), + sticker = STICKER_FIXTURE, + tag = TAG_FIXTURE, + description = "", + tasks = emptyList(), + ) + + val deadline이_오늘인_객체 = Goal( + user = USER_FIXTURE, + title = "제목2", + deadline = LocalDate.now(), + sticker = STICKER_FIXTURE, + tag = TAG_FIXTURE, + description = "", + tasks = emptyList(), + ) + + // 역순으로 저장한다. + goalRepository.save(deadline이_내일이고_가장_처음_만들어진_객체) + goalRepository.save(deadline이_내일이고_가장_나중에_만들어진_객체) + goalRepository.save(deadline이_오늘인_객체) + + // when + val savedGoals = goalReadService.findAllByUserId(USER_FIXTURE.id!!) + + // then + assertAll( + Executable { + assertThat(savedGoals.goals[0].id).isEqualTo(deadline이_오늘인_객체.id) + assertThat(savedGoals.goals[1].id).isEqualTo(deadline이_내일이고_가장_나중에_만들어진_객체.id) + assertThat(savedGoals.goals[2].id).isEqualTo(deadline이_내일이고_가장_처음_만들어진_객체.id) + }, + ) + } +} diff --git a/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt b/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt deleted file mode 100644 index 355dc4d7..00000000 --- a/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt +++ /dev/null @@ -1,171 +0,0 @@ -package io.raemian.api.integration.goal - -import io.raemian.api.goal.GoalService -import io.raemian.storage.db.core.goal.Goal -import io.raemian.storage.db.core.goal.GoalRepository -import io.raemian.storage.db.core.sticker.Sticker -import io.raemian.storage.db.core.sticker.StickerImage -import io.raemian.storage.db.core.tag.Tag -import io.raemian.storage.db.core.user.Authority -import io.raemian.storage.db.core.user.User -import io.raemian.storage.db.core.user.enums.OAuthProvider -import jakarta.persistence.EntityManager -import org.assertj.core.api.Assertions.assertThat -import org.assertj.core.api.Assertions.assertThatCode -import org.junit.jupiter.api.Assertions.assertAll -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.DisplayName -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.function.Executable -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.transaction.annotation.Transactional -import java.time.LocalDate - -@SpringBootTest -class GoalServiceTest { - - companion object { - val USER_FIXTURE = User( - "dfghcvb111@naver.com", - "binaryHoHo", - "binaryHoHoHo", - LocalDate.MIN, - OAuthProvider.NAVER, - Authority.ROLE_USER, - ) - - val STICKER_FIXTURE = Sticker("sticker", StickerImage("image yeah")) - val TAG_FIXTURE = Tag("꿈") - } - - @Autowired - private lateinit var goalService: GoalService - - @Autowired - private lateinit var goalRepository: GoalRepository - - @Autowired - private lateinit var entityManager: EntityManager - - @BeforeEach - fun saveEntities() { - entityManager.merge(USER_FIXTURE) - entityManager.merge(STICKER_FIXTURE) - entityManager.merge(TAG_FIXTURE) - } - - @Test - @DisplayName("Goal ID를 통해 Goal을 조회 할 수 있다.") - @Transactional - fun getByIdTest() { - // given - val goal = Goal( - USER_FIXTURE, - "짱이 될거야", - LocalDate.MAX, - STICKER_FIXTURE, - TAG_FIXTURE, - "열심히, 잘, 최선을 다해 꼭 짱이 된다.", - emptyList(), - ) - - val savedGoal = goalRepository.save(goal) - - // when - // then - assertThatCode { - goalService.getById(savedGoal.id!!) - }.doesNotThrowAnyException() - } - - @Test - @DisplayName("User ID를 통해 유저가 가진 전체 Goal을 조회 할 수 있다.") - @Transactional - fun findAllByUserIdTest() { - // given - val goal1 = Goal( - USER_FIXTURE, - "제목1", - LocalDate.MAX, - STICKER_FIXTURE, - TAG_FIXTURE, - "", - emptyList(), - ) - - val goal2 = Goal( - USER_FIXTURE, - "제목2", - LocalDate.MAX, - STICKER_FIXTURE, - TAG_FIXTURE, - "", - emptyList(), - ) - - goalRepository.save(goal1) - goalRepository.save(goal2) - - // when - val savedGoals = goalService.findAllByUserId(USER_FIXTURE.id!!) - - // then - assertAll( - Executable { - assertThat(savedGoals.goalsCount).isEqualTo(2) - assertThat(savedGoals.goals[0].tagContent).isEqualTo(goal1.tag.content) - assertThat(savedGoals.goals[1].tagContent).isEqualTo(goal2.tag.content) - }, - ) - } - - @Test - @DisplayName("GoalsResponse와 GoalResponse의 deadline 포멧은 'YYYY.MM'이다.") - @Transactional - fun responseFormattingTest() { - // given - val now = LocalDate.now() - val goal1 = Goal( - USER_FIXTURE, - "제목1", - now, - STICKER_FIXTURE, - TAG_FIXTURE, - "", - emptyList(), - ) - - val goal2 = Goal( - USER_FIXTURE, - "제목2", - now, - STICKER_FIXTURE, - TAG_FIXTURE, - "", - emptyList(), - ) - - goalRepository.save(goal1) - goalRepository.save(goal2) - - // when - val savedGoal = goalService.getById(goal1.id!!) - val savedGoals = goalService.findAllByUserId(USER_FIXTURE.id!!) - - // then - var month = (now.monthValue).toString() - if (month.length == 1) { - month = "0$month" - } - val deadline = "${now.year}.$month" - - assertAll( - Executable { - assertThat(savedGoal.deadline).isEqualTo(deadline) - assertThat(savedGoals.goals[0].deadline).isEqualTo(deadline) - assertThat(savedGoals.goals[1].deadline).isEqualTo(deadline) - }, - ) - } -} From d3695cdd0f485c95e1d802767957f1abcfe7c298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=EC=9A=B0=EC=84=9D=20=28Woosuk=20Kwon=29?= Date: Wed, 20 Dec 2023 01:23:19 +0900 Subject: [PATCH 49/70] =?UTF-8?q?[Feature]=20Dockerfile=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20/=20DB=20=EC=84=A4=EC=A0=95=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?/=20springdoc=20=EC=84=A4=EB=AA=85=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B0=8F=20JWT=20=EC=B6=94=EA=B0=80=20=EA=B8=B0=EB=8A=A5=20(#4?= =?UTF-8?q?)=20(#46)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(#4): Dockerfile 생성 * chore(#4): DB 설정 정보 변경 * chore(#4): security permit 정보 수정 * chore(#4): springdoc version update * docs(#4): springdoc 설명 추가 및 JWT 추가 기능 * docs(#4): springdoc 설명 추가 및 JWT 추가 기능 * chore: pull request template 위치 변경 * chore(#4): context-path 수정 / -> /api * chore: google redirect uri 설정 정보 추가 * fix(#4): swagger 서버 수정 * fix: oauth2 redirect url 수정 --------- Co-authored-by: wkwon --- .../pull_request_template.md | 0 Dockerfile | 4 + application/api/build.gradle.kts | 2 +- .../io/raemian/api/config/SpringdocConfig.kt | 35 +++++++ .../raemian/api/config/WebSecurityConfig.kt | 4 +- .../main/resources/application-security.yml | 3 + .../api/src/main/resources/application.yml | 3 + .../main/resources/application-db-core.yml | 94 +++++-------------- 8 files changed, 74 insertions(+), 71 deletions(-) rename .github/{PULL_REQUEST_TEMPLATE => }/pull_request_template.md (100%) create mode 100644 Dockerfile create mode 100644 application/api/src/main/kotlin/io/raemian/api/config/SpringdocConfig.kt diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/pull_request_template.md similarity index 100% rename from .github/PULL_REQUEST_TEMPLATE/pull_request_template.md rename to .github/pull_request_template.md diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..6692c053 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,4 @@ +FROM --platform=linux/amd64 openjdk:17-jdk-slim +EXPOSE 8080 7463 +COPY application/api/build/libs/*.jar app.jar +ENTRYPOINT ["java","-jar","/app.jar"] \ No newline at end of file diff --git a/application/api/build.gradle.kts b/application/api/build.gradle.kts index 023b799a..0121db0e 100644 --- a/application/api/build.gradle.kts +++ b/application/api/build.gradle.kts @@ -34,5 +34,5 @@ dependencies { testImplementation("io.rest-assured:spring-mock-mvc") /* swagger */ - implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2") + implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0") } diff --git a/application/api/src/main/kotlin/io/raemian/api/config/SpringdocConfig.kt b/application/api/src/main/kotlin/io/raemian/api/config/SpringdocConfig.kt new file mode 100644 index 00000000..bd313051 --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/config/SpringdocConfig.kt @@ -0,0 +1,35 @@ +package io.raemian.api.config + +import io.swagger.v3.oas.annotations.OpenAPIDefinition +import io.swagger.v3.oas.annotations.info.Info +import io.swagger.v3.oas.annotations.servers.Server +import io.swagger.v3.oas.models.Components +import io.swagger.v3.oas.models.OpenAPI +import io.swagger.v3.oas.models.security.SecurityRequirement +import io.swagger.v3.oas.models.security.SecurityScheme +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +@OpenAPIDefinition( + servers = arrayOf(Server(url = "https://www.one-bailey.o-r.kr/api")), + info = Info( + title = "BANDIBOODI API 명세", + description = "BANDIBOODI 메인/어드밍 API 명세서", + version = "v1.0.0", + ), +) +@Configuration +class SpringdocConfig { + + @Bean + fun openAPI(): OpenAPI { + val securityScheme: SecurityScheme = SecurityScheme() + .type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT") + .`in`(SecurityScheme.In.HEADER).name("Authorization") + val securityRequirement: SecurityRequirement = SecurityRequirement().addList("bearerAuth") + + return OpenAPI() + .components(Components().addSecuritySchemes("bearerAuth", securityScheme)) + .security(listOf(securityRequirement)) + } +} diff --git a/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt b/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt index e0808786..23969c02 100644 --- a/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt +++ b/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt @@ -56,6 +56,7 @@ class WebSecurityConfig( it.requestMatchers(AntPathRequestMatcher("/auth/**")).permitAll() .requestMatchers(AntPathRequestMatcher("/oauth2/**")).permitAll() .requestMatchers(AntPathRequestMatcher("/login/**")).permitAll() + .requestMatchers(AntPathRequestMatcher("/one-baily-actuator/**")).permitAll() .requestMatchers( AntPathRequestMatcher("/swagger*/**"), AntPathRequestMatcher("/v3/api-docs/**"), @@ -74,7 +75,7 @@ class WebSecurityConfig( val tokenDTO = tokenProvider.generateTokenDto(user) response.setHeader("x-token", tokenDTO.accessToken) // TODO edit redirect url - response.sendRedirect("http://localhost:8080/login/oauth2/code/google?token=${tokenDTO.accessToken}&refresh=${tokenDTO.refreshToken}") + response.sendRedirect("http://localhost:3000/login/oauth2/code/google?token=${tokenDTO.accessToken}&refresh=${tokenDTO.refreshToken}") } it.failureHandler { request, response, exception -> response.addHeader("x-token", exception.message) @@ -92,7 +93,6 @@ class WebSecurityConfig( return WebSecurityCustomizer { it .ignoring() - .requestMatchers(AntPathRequestMatcher("/one-baily-actuator/**")) .requestMatchers(PathRequest.toH2Console()) .requestMatchers(AntPathRequestMatcher("/favicon.ico", "**/favicon.ico")) } diff --git a/application/api/src/main/resources/application-security.yml b/application/api/src/main/resources/application-security.yml index a43ca102..032cc2fa 100644 --- a/application/api/src/main/resources/application-security.yml +++ b/application/api/src/main/resources/application-security.yml @@ -22,6 +22,7 @@ spring: - name client-name: naver google: + redirect-uri: ${GOOGLE-REDIRECT-URI} client-id: ${GOOGLE-CLIENT-ID} client-secret: ${GOOGLE-CLIENT-SECRET} scope: @@ -54,6 +55,7 @@ spring: - name client-name: naver google: + redirect-uri: ${GOOGLE-REDIRECT-URI} client-id: ${GOOGLE-CLIENT-ID} client-secret: ${GOOGLE-CLIENT-SECRET} scope: @@ -87,6 +89,7 @@ spring: - name client-name: naver google: + redirect-uri: ${GOOGLE-REDIRECT-URI} client-id: ${GOOGLE-CLIENT-ID} client-secret: ${GOOGLE-CLIENT-SECRET} scope: diff --git a/application/api/src/main/resources/application.yml b/application/api/src/main/resources/application.yml index 27e4a515..fde49d19 100644 --- a/application/api/src/main/resources/application.yml +++ b/application/api/src/main/resources/application.yml @@ -7,6 +7,9 @@ spring: mvc.throw-exception-if-no-handler-found: true web.resources.add-mappings: false +server: + servlet: + context-path: /api --- # local spring: diff --git a/storage/db-core/src/main/resources/application-db-core.yml b/storage/db-core/src/main/resources/application-db-core.yml index cfbb624c..4d48b21c 100644 --- a/storage/db-core/src/main/resources/application-db-core.yml +++ b/storage/db-core/src/main/resources/application-db-core.yml @@ -4,15 +4,22 @@ spring: open-in-view: false hibernate: ddl-auto: none - properties: - hibernate.default_batch_fetch_size: 100 --- # local +spring.config.activate.on-profile: local + spring: - config: - active: - on-profile: local + datasource: + driver-class-name: org.h2.Driver + url: jdbc:h2:mem:core;MODE=MySQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE + username: sa + hikari: + pool-name: db-core-pool + h2: + console: + enabled: true + path: /h2-console jpa: hibernate: ddl-auto: create @@ -20,78 +27,29 @@ spring: hibernate: format_sql: true show_sql: true - h2: - console: - enabled: true - -storage: - datasource: - core: - driver-class-name: org.h2.Driver - jdbc-url: jdbc:h2:mem:core;MODE=MySQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE - username: sa - pool-name: core-db-pool - data-source-properties: - rewriteBatchedStatements: true - --- # dev spring.config.activate.on-profile: dev -storage: +spring: datasource: - core: - driver-class-name: com.mysql.cj.jdbc.Driver - jdbc-url: jdbc:mysql://${storage.database.core-db.url} - username: ${storage.database.core-db.username} - password: ${storage.database.core-db.password} - maximum-pool-size: 5 - connection-timeout: 1100 - keepalive-time: 30000 - validation-timeout: 1000 - max-lifetime: 600000 - pool-name: core-db-pool - data-source-properties: - socketTimeout: 3000 - cachePrepStmts: true - prepStmtCacheSize: 250 - prepStmtCacheSqlLimit: 2048 - useServerPrepStmts: true - useLocalSessionState: true - rewriteBatchedStatements: true - cacheResultSetMetadata: true - cacheServerConfiguration: true - elideSetAutoCommits: true - maintainTimeStats: false - + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://${DB-URL} + username: ${DB-USERNAME} + password: ${DB-PASSWORD} + hikari: + pool-name: db-core-pool --- # live spring.config.activate.on-profile: live -storage: +spring: datasource: - core: - driver-class-name: com.mysql.cj.jdbc.Driver - jdbc-url: jdbc:mysql://${storage.database.core-db.url} - username: ${storage.database.core-db.username} - password: ${storage.database.core-db.password} - maximum-pool-size: 25 - connection-timeout: 1100 - keepalive-time: 30000 - validation-timeout: 1000 - max-lifetime: 600000 - pool-name: core-db-pool - data-source-properties: - socketTimeout: 3000 - cachePrepStmts: true - prepStmtCacheSize: 250 - prepStmtCacheSqlLimit: 2048 - useServerPrepStmts: true - useLocalSessionState: true - rewriteBatchedStatements: true - cacheResultSetMetadata: true - cacheServerConfiguration: true - elideSetAutoCommits: true - maintainTimeStats: false \ No newline at end of file + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://${DB-URL} + username: ${DB-USERNAME} + password: ${DB-PASSWORD} + hikari: + pool-name: db-core-pool \ No newline at end of file From cf26e9b6d92aca6d8d8323a06b43586ea7702859 Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Wed, 20 Dec 2023 01:55:39 +0900 Subject: [PATCH 50/70] feat(#50): edit current user info api --- .../api/auth/controller/AuthController.kt | 16 +++------- .../auth/controller/response/UserResponse.kt | 24 ++++++++++++++ .../raemian/api/auth/service/AuthService.kt | 32 +++++++------------ .../io/raemian/api/support/TokenProvider.kt | 31 ------------------ 4 files changed, 41 insertions(+), 62 deletions(-) create mode 100644 application/api/src/main/kotlin/io/raemian/api/auth/controller/response/UserResponse.kt diff --git a/application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt b/application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt index d09cc858..70d03692 100644 --- a/application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt +++ b/application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt @@ -1,15 +1,13 @@ package io.raemian.api.auth.controller -import io.raemian.api.auth.controller.request.SignInRequest import io.raemian.api.auth.controller.request.UpdateUserRequest +import io.raemian.api.auth.controller.response.UserResponse import io.raemian.api.auth.domain.CurrentUser -import io.raemian.api.auth.domain.TokenDTO import io.raemian.api.auth.service.AuthService import io.swagger.v3.oas.annotations.Operation import org.springframework.http.ResponseEntity import org.springframework.security.core.annotation.AuthenticationPrincipal import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.PutMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RestController @@ -19,16 +17,12 @@ class AuthController( private val authService: AuthService, ) { - @Operation(summary = "로그인 API") - @PostMapping("/auth/sign-in") - fun signIn(@RequestBody signInRequest: SignInRequest): TokenDTO { - return authService.signIn(signInRequest.email) - } - @Operation(summary = "토큰 유저 정보 조회 API") @GetMapping("/my") - fun my(@AuthenticationPrincipal currentUser: CurrentUser): CurrentUser { - return currentUser + fun my(@AuthenticationPrincipal currentUser: CurrentUser): ResponseEntity { + val user = authService.getUserById(currentUser.id) + val response = UserResponse.of(user) + return ResponseEntity.ok().body(response) } @Operation(summary = "유저 온보딩 이후 정보 업데이트 API") diff --git a/application/api/src/main/kotlin/io/raemian/api/auth/controller/response/UserResponse.kt b/application/api/src/main/kotlin/io/raemian/api/auth/controller/response/UserResponse.kt new file mode 100644 index 00000000..eb7b05ca --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/auth/controller/response/UserResponse.kt @@ -0,0 +1,24 @@ +package io.raemian.api.auth.controller.response + +import io.raemian.storage.db.core.user.User +import java.time.LocalDate + +data class UserResponse( + val id: Long, + val email: String, + val username: String?, + val nickname: String?, + val birth: LocalDate?, +) { + companion object { + fun of(user: User): UserResponse { + return UserResponse( + id = user.id!!, + email = user.email, + username = user.userName, + nickname = user.nickname, + birth = user.birth, + ) + } + } +} diff --git a/application/api/src/main/kotlin/io/raemian/api/auth/service/AuthService.kt b/application/api/src/main/kotlin/io/raemian/api/auth/service/AuthService.kt index 4e58ebb8..328c6d53 100644 --- a/application/api/src/main/kotlin/io/raemian/api/auth/service/AuthService.kt +++ b/application/api/src/main/kotlin/io/raemian/api/auth/service/AuthService.kt @@ -1,12 +1,8 @@ package io.raemian.api.auth.service import io.raemian.api.auth.domain.CurrentUser -import io.raemian.api.auth.domain.TokenDTO -import io.raemian.api.support.TokenProvider import io.raemian.storage.db.core.user.User import io.raemian.storage.db.core.user.UserRepository -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder import org.springframework.security.core.userdetails.UserDetails import org.springframework.security.core.userdetails.UserDetailsService import org.springframework.security.core.userdetails.UsernameNotFoundException @@ -17,24 +13,11 @@ import kotlin.jvm.optionals.getOrNull @Service class AuthService( private val userRepository: UserRepository, - private val authenticationManagerBuilder: AuthenticationManagerBuilder, - private val tokenProvider: TokenProvider, ) : UserDetailsService { - override fun loadUserByUsername(username: String): UserDetails { - val user = userRepository.findByEmail(username) ?: throw UsernameNotFoundException("not found $username") - return CurrentUser( - id = user.id!!, - email = user.email, - authorities = listOf(), - ) - } - - fun signIn(email: String): TokenDTO { - val user = userRepository.findByEmail(email) ?: throw RuntimeException("아이디 또는 비밀번호 불일치 ") - val token = UsernamePasswordAuthenticationToken(user.email, "", arrayListOf()) - val authentication = authenticationManagerBuilder.`object`.authenticate(token) - return tokenProvider.generateTokenDto(authentication) + fun getUserById(id: Long): User { + val user = userRepository.findById(id).getOrNull() ?: throw RuntimeException("") + return user } fun update(id: Long, nickname: String, birth: LocalDate): User { @@ -48,4 +31,13 @@ class AuthService( return userRepository.save(updated) } + + override fun loadUserByUsername(username: String): UserDetails { + val user = userRepository.findByEmail(username) ?: throw UsernameNotFoundException("not found $username") + return CurrentUser( + id = user.id!!, + email = user.email, + authorities = listOf(), + ) + } } diff --git a/application/api/src/main/kotlin/io/raemian/api/support/TokenProvider.kt b/application/api/src/main/kotlin/io/raemian/api/support/TokenProvider.kt index 1927ec98..c63a1605 100644 --- a/application/api/src/main/kotlin/io/raemian/api/support/TokenProvider.kt +++ b/application/api/src/main/kotlin/io/raemian/api/support/TokenProvider.kt @@ -67,37 +67,6 @@ class TokenProvider { ) } - fun generateTokenDto(authentication: Authentication): TokenDTO { - val currentUser = authentication.principal as CurrentUser - // 권한들 가져오기 - val authorities: String = authentication.authorities - .map { obj: GrantedAuthority -> obj.authority } - .joinToString(",") - val now: Long = Date().time - - // Access Token 생성 - val accessTokenExpiresIn = Date(now + ACCESS_TOKEN_EXPIRE_TIME) - val accessToken: String = Jwts.builder() - .setSubject(authentication.name) // payload "sub": "name" - .claim(AUTHORITIES_KEY, authorities) // payload "auth": "ROLE_USER" - .claim(EMAIL_KEY, authentication.name) - .claim(ID_KEY, currentUser.id) - .setExpiration(accessTokenExpiresIn) // payload "exp": 151621022 (ex) - .signWith(key, SignatureAlgorithm.HS512) // header "alg": "HS512" - .compact() - - // Refresh Token 생성 - val refreshToken: String = Jwts.builder() - .setExpiration(Date(now + REFRESH_TOKEN_EXPIRE_TIME)) - .signWith(key, SignatureAlgorithm.HS512) - .compact() - return TokenDTO( - grantType = BEARER_TYPE, - accessToken = accessToken, - refreshToken = refreshToken, - accessTokenExpiresIn = accessTokenExpiresIn.time, - ) - } fun getAuthentication(accessToken: String): Authentication { // 토큰 복호화 From 91ba43a0bc6cc034e60e06846bc5f4ede18f4008 Mon Sep 17 00:00:00 2001 From: binary_ho Date: Wed, 20 Dec 2023 01:57:06 +0900 Subject: [PATCH 51/70] =?UTF-8?q?[feature]=20=EC=95=94=ED=98=B8=ED=99=94?= =?UTF-8?q?=EB=A5=BC=20=EC=9C=84=ED=95=9C=20Jasypt=20=EB=8F=84=EC=9E=85?= =?UTF-8?q?=EA=B3=BC=20=EC=82=AC=EC=9A=A9=20=EC=84=A4=EB=AA=85=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1=20(#48)=20(#49)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor : Jasypt 의존성 추가 (#48) * feat : jasypt을 위한 EncryptorConfig 작성 (#48) * feat : application yml에 jasypt 설정 추가 (#48) * docs : 암호화 가이드 작성 (#48) * docs : 암호화 추가 가이드 작성 (#48) * feat : 빌드 테스트시 Github Actions 시크릿값 대입 추가 (#48) * refactor : DB, OAuth 관련 프로퍼티 암호화 도입 (#48) --- .../pull-request-gradle-build-test.yml | 8 ++-- application/api/build.gradle.kts | 3 ++ .../io/raemian/api/config/EncryptorConfig.kt | 26 +++++++++++ .../main/resources/application-security.yml | 19 ++++---- .../api/src/main/resources/application.yml | 9 +++- .../io/raemian/api/support/Encryptor.kt | 45 +++++++++++++++++++ .../test/resources/application-security.yml | 15 ++++--- .../api/src/test/resources/application.yml | 5 +++ .../main/resources/application-db-core.yml | 8 ++-- 9 files changed, 114 insertions(+), 24 deletions(-) create mode 100644 application/api/src/main/kotlin/io/raemian/api/config/EncryptorConfig.kt create mode 100644 application/api/src/test/kotlin/io/raemian/api/support/Encryptor.kt diff --git a/.github/workflows/pull-request-gradle-build-test.yml b/.github/workflows/pull-request-gradle-build-test.yml index e6082998..90db4150 100644 --- a/.github/workflows/pull-request-gradle-build-test.yml +++ b/.github/workflows/pull-request-gradle-build-test.yml @@ -1,8 +1,8 @@ -name : Pull Request Gradle Build Test +name: Pull Request Gradle Build Test on: pull_request: - types: [opened, synchronize, closed] + types: [ opened, synchronize, closed ] permissions: read-all @@ -34,8 +34,10 @@ jobs: - name: gradlew 권한 부여 run: chmod +x ./gradlew - + - name: Gradle Build if: steps.changes.outputs.application == 'true' + env: + JASYPT_ENCRYPTION_PASSWORD: ${{ secrets.PROPERTY_ENCRYPTION_PASSWORD }} run: | ./gradlew build --no-build-cache diff --git a/application/api/build.gradle.kts b/application/api/build.gradle.kts index 0121db0e..d1f5d3ba 100644 --- a/application/api/build.gradle.kts +++ b/application/api/build.gradle.kts @@ -35,4 +35,7 @@ dependencies { /* swagger */ implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0") + + /* jasypt */ + implementation("com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.4") } diff --git a/application/api/src/main/kotlin/io/raemian/api/config/EncryptorConfig.kt b/application/api/src/main/kotlin/io/raemian/api/config/EncryptorConfig.kt new file mode 100644 index 00000000..41b9ba6b --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/config/EncryptorConfig.kt @@ -0,0 +1,26 @@ +package io.raemian.api.config + +import org.jasypt.encryption.StringEncryptor +import org.jasypt.encryption.pbe.PooledPBEStringEncryptor +import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig +import org.springframework.beans.factory.annotation.Value +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +@Configuration +class EncryptorConfig { + + @Bean("stringEncryptor") + fun stringEncryptor( + @Value(value = "\${jasypt.secret-key}") encryptorPassword: String?, + ): StringEncryptor { + val pooledPBEStringEncryptor = PooledPBEStringEncryptor() + + val simpleStringPBEConfig = SimpleStringPBEConfig() + simpleStringPBEConfig.setPassword(encryptorPassword) + simpleStringPBEConfig.poolSize = 1 + + pooledPBEStringEncryptor.setConfig(simpleStringPBEConfig) + return pooledPBEStringEncryptor + } +} diff --git a/application/api/src/main/resources/application-security.yml b/application/api/src/main/resources/application-security.yml index 032cc2fa..a2fd43df 100644 --- a/application/api/src/main/resources/application-security.yml +++ b/application/api/src/main/resources/application-security.yml @@ -22,9 +22,9 @@ spring: - name client-name: naver google: - redirect-uri: ${GOOGLE-REDIRECT-URI} - client-id: ${GOOGLE-CLIENT-ID} - client-secret: ${GOOGLE-CLIENT-SECRET} + redirect-uri: ENC(1nLPI1HHtBur53TcEE1vt/aFsQVvfwwUHoIe0bxrztiAPLuHfrIlVQdXfPOQPKjR/5BAH1WTNwyy3bVtHwL9UuNQP583Nxyu) + client-id: ENC(DcoBp86FnyGsZ3QGf++3vLiyeJwWtZcCHHcQR1o5bSHqrsGWGvemGgjSnMgRJy1BZXTNQEGEbg36gPSh+LuMqV5U2PO5vohM+5LH0UWm/gVhlNl/vM85cw==) + client-secret: ENC(SCv0TGTTXDdlyn76WzcaErJgPRfAhSeBDa1SkHN1UyeMNNWMTU40qGhFFmvirudA) scope: - email - profile @@ -55,9 +55,9 @@ spring: - name client-name: naver google: - redirect-uri: ${GOOGLE-REDIRECT-URI} - client-id: ${GOOGLE-CLIENT-ID} - client-secret: ${GOOGLE-CLIENT-SECRET} + redirect-uri: ENC(1nLPI1HHtBur53TcEE1vt/aFsQVvfwwUHoIe0bxrztiAPLuHfrIlVQdXfPOQPKjR/5BAH1WTNwyy3bVtHwL9UuNQP583Nxyu) + client-id: ENC(DcoBp86FnyGsZ3QGf++3vLiyeJwWtZcCHHcQR1o5bSHqrsGWGvemGgjSnMgRJy1BZXTNQEGEbg36gPSh+LuMqV5U2PO5vohM+5LH0UWm/gVhlNl/vM85cw==) + client-secret: ENC(SCv0TGTTXDdlyn76WzcaErJgPRfAhSeBDa1SkHN1UyeMNNWMTU40qGhFFmvirudA) scope: - email - profile @@ -89,10 +89,9 @@ spring: - name client-name: naver google: - redirect-uri: ${GOOGLE-REDIRECT-URI} - client-id: ${GOOGLE-CLIENT-ID} - client-secret: ${GOOGLE-CLIENT-SECRET} + redirect-uri: ENC(1nLPI1HHtBur53TcEE1vt/aFsQVvfwwUHoIe0bxrztiAPLuHfrIlVQdXfPOQPKjR/5BAH1WTNwyy3bVtHwL9UuNQP583Nxyu) + client-id: ENC(DcoBp86FnyGsZ3QGf++3vLiyeJwWtZcCHHcQR1o5bSHqrsGWGvemGgjSnMgRJy1BZXTNQEGEbg36gPSh+LuMqV5U2PO5vohM+5LH0UWm/gVhlNl/vM85cw==) + client-secret: ENC(SCv0TGTTXDdlyn76WzcaErJgPRfAhSeBDa1SkHN1UyeMNNWMTU40qGhFFmvirudA) scope: - email - profile - diff --git a/application/api/src/main/resources/application.yml b/application/api/src/main/resources/application.yml index fde49d19..74b28d7c 100644 --- a/application/api/src/main/resources/application.yml +++ b/application/api/src/main/resources/application.yml @@ -7,9 +7,16 @@ spring: mvc.throw-exception-if-no-handler-found: true web.resources.add-mappings: false +jasypt: + encryptor: + bean: stringEncryptor + secret-key: ${JASYPT_ENCRYPTION_PASSWORD} + + server: servlet: context-path: /api + --- # local spring: @@ -41,4 +48,4 @@ spring: - security - db-core - logging - - metrics \ No newline at end of file + - metrics diff --git a/application/api/src/test/kotlin/io/raemian/api/support/Encryptor.kt b/application/api/src/test/kotlin/io/raemian/api/support/Encryptor.kt new file mode 100644 index 00000000..dcd3690b --- /dev/null +++ b/application/api/src/test/kotlin/io/raemian/api/support/Encryptor.kt @@ -0,0 +1,45 @@ +package io.raemian.api.support + +import io.raemian.api.config.EncryptorConfig +import org.jasypt.encryption.StringEncryptor +import org.junit.jupiter.api.Test + +class Encryptor { + + /** + * @Author 이진호 + * @see 암호화를_하는_방법은_아래와_같습니다 (https://github.com/depromeet/amazing3-be/pull/49) + * 1. 사용할 yaml의 최상위 파일에 아래 코드를 추가합니다. + * ``` + * jasypt: + * encryptor: + * bean: stringEncryptor + * secret-key: ${JASYPT_ENCRYPTION_PASSWORD} + * ``` + * + * 2. 환경 변수 JASYPT_ENCRYPTION_PASSWORD에 비밀번호를 대입합니다. + * 3. password 변수 값에 비밀번호를 대입합니다. (빈으로 관리하고 싶지 않아 자동 주입 넣지 않았습니다.) + * 4. encrypt 메서드에 ","로 구분해 암호화할 String 값을 넣으세요. + * 5. ENC() 가 포함된 전체 결과를 기존 값 대신에 대입하세요. + * + * + * @see 주의 : 순수 숫자는 안 됩니다. + * */ + + val password = "enter password" + + @Test + fun encrypt() { + // 암호화 할 값을 대입해세요 + encrypt("enter", "password") + } + + fun encrypt(vararg string: String) { + val encryptor: StringEncryptor = EncryptorConfig() + .stringEncryptor(password) + + string.forEach { + println("$it 암호화 -> ENC(${encryptor.encrypt(it)})") + } + } +} diff --git a/application/api/src/test/resources/application-security.yml b/application/api/src/test/resources/application-security.yml index 967fa6e6..a2fd43df 100644 --- a/application/api/src/test/resources/application-security.yml +++ b/application/api/src/test/resources/application-security.yml @@ -22,8 +22,9 @@ spring: - name client-name: naver google: - client-id: ${GOOGLE-CLIENT-ID} - client-secret: ${GOOGLE-CLIENT-SECRET} + redirect-uri: ENC(1nLPI1HHtBur53TcEE1vt/aFsQVvfwwUHoIe0bxrztiAPLuHfrIlVQdXfPOQPKjR/5BAH1WTNwyy3bVtHwL9UuNQP583Nxyu) + client-id: ENC(DcoBp86FnyGsZ3QGf++3vLiyeJwWtZcCHHcQR1o5bSHqrsGWGvemGgjSnMgRJy1BZXTNQEGEbg36gPSh+LuMqV5U2PO5vohM+5LH0UWm/gVhlNl/vM85cw==) + client-secret: ENC(SCv0TGTTXDdlyn76WzcaErJgPRfAhSeBDa1SkHN1UyeMNNWMTU40qGhFFmvirudA) scope: - email - profile @@ -54,8 +55,9 @@ spring: - name client-name: naver google: - client-id: ${GOOGLE-CLIENT-ID} - client-secret: ${GOOGLE-CLIENT-SECRET} + redirect-uri: ENC(1nLPI1HHtBur53TcEE1vt/aFsQVvfwwUHoIe0bxrztiAPLuHfrIlVQdXfPOQPKjR/5BAH1WTNwyy3bVtHwL9UuNQP583Nxyu) + client-id: ENC(DcoBp86FnyGsZ3QGf++3vLiyeJwWtZcCHHcQR1o5bSHqrsGWGvemGgjSnMgRJy1BZXTNQEGEbg36gPSh+LuMqV5U2PO5vohM+5LH0UWm/gVhlNl/vM85cw==) + client-secret: ENC(SCv0TGTTXDdlyn76WzcaErJgPRfAhSeBDa1SkHN1UyeMNNWMTU40qGhFFmvirudA) scope: - email - profile @@ -87,8 +89,9 @@ spring: - name client-name: naver google: - client-id: ${GOOGLE-CLIENT-ID} - client-secret: ${GOOGLE-CLIENT-SECRET} + redirect-uri: ENC(1nLPI1HHtBur53TcEE1vt/aFsQVvfwwUHoIe0bxrztiAPLuHfrIlVQdXfPOQPKjR/5BAH1WTNwyy3bVtHwL9UuNQP583Nxyu) + client-id: ENC(DcoBp86FnyGsZ3QGf++3vLiyeJwWtZcCHHcQR1o5bSHqrsGWGvemGgjSnMgRJy1BZXTNQEGEbg36gPSh+LuMqV5U2PO5vohM+5LH0UWm/gVhlNl/vM85cw==) + client-secret: ENC(SCv0TGTTXDdlyn76WzcaErJgPRfAhSeBDa1SkHN1UyeMNNWMTU40qGhFFmvirudA) scope: - email - profile diff --git a/application/api/src/test/resources/application.yml b/application/api/src/test/resources/application.yml index 59e338e1..254dd972 100644 --- a/application/api/src/test/resources/application.yml +++ b/application/api/src/test/resources/application.yml @@ -15,6 +15,11 @@ spring: hibernate: format_sql: true +jasypt: + encryptor: + bean: stringEncryptor + secret-key: ${JASYPT_ENCRYPTION_PASSWORD} + --- # local spring: diff --git a/storage/db-core/src/main/resources/application-db-core.yml b/storage/db-core/src/main/resources/application-db-core.yml index 4d48b21c..c208ca70 100644 --- a/storage/db-core/src/main/resources/application-db-core.yml +++ b/storage/db-core/src/main/resources/application-db-core.yml @@ -34,9 +34,9 @@ spring.config.activate.on-profile: dev spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://${DB-URL} - username: ${DB-USERNAME} - password: ${DB-PASSWORD} + url: ENC(beSp896XvPBkns0kzH3tlNQEz21NwXRDod/p0bVV0DjBfa4GcSyitf/1D9v5iwGmLNXzRwekPS8=) + username: ENC(WcnAxhO0qmAO5+qduh85dQ==) + password: ENC(cKgWKoQ1xPm3stuyPT0sCg==) hikari: pool-name: db-core-pool @@ -52,4 +52,4 @@ spring: username: ${DB-USERNAME} password: ${DB-PASSWORD} hikari: - pool-name: db-core-pool \ No newline at end of file + pool-name: db-core-pool From a0dd0318d77684914fdfa3817b963e628a04aa0c Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Wed, 20 Dec 2023 01:59:56 +0900 Subject: [PATCH 52/70] chore(#50): edit lint --- .../api/src/main/kotlin/io/raemian/api/support/TokenProvider.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/application/api/src/main/kotlin/io/raemian/api/support/TokenProvider.kt b/application/api/src/main/kotlin/io/raemian/api/support/TokenProvider.kt index c63a1605..b35b3a8e 100644 --- a/application/api/src/main/kotlin/io/raemian/api/support/TokenProvider.kt +++ b/application/api/src/main/kotlin/io/raemian/api/support/TokenProvider.kt @@ -67,7 +67,6 @@ class TokenProvider { ) } - fun getAuthentication(accessToken: String): Authentication { // 토큰 복호화 val claims = parseClaims(accessToken) From 49d32cf4169db9defec86e0f26ce4edb89649890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=EC=9A=B0=EC=84=9D=20=28Woosuk=20Kwon=29?= Date: Wed, 20 Dec 2023 02:10:26 +0900 Subject: [PATCH 53/70] =?UTF-8?q?fix:=20Sticker=20=ED=95=84=EB=93=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#52)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/goal/controller/response/CreateGoalResponse.kt | 5 ++--- .../api/goal/controller/response/GoalResponse.kt | 5 ++--- .../api/goal/controller/response/GoalsResponse.kt | 5 ++--- .../api/sticker/controller/response/StickerResponse.kt | 5 ++--- .../api/integration/goal/GoalReadServiceTest.kt | 3 +-- .../api/integration/sticker/StickerServiceTest.kt | 9 ++++----- .../io/raemian/api/integration/task/TaskServiceTest.kt | 3 +-- .../io/raemian/storage/db/core/sticker/Sticker.kt | 4 +--- .../io/raemian/storage/db/core/sticker/StickerImage.kt | 10 ---------- 9 files changed, 15 insertions(+), 34 deletions(-) delete mode 100644 storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerImage.kt diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/CreateGoalResponse.kt b/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/CreateGoalResponse.kt index 04e26ac1..73476cfe 100644 --- a/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/CreateGoalResponse.kt +++ b/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/CreateGoalResponse.kt @@ -2,14 +2,13 @@ package io.raemian.api.goal.controller.response import io.raemian.api.support.format import io.raemian.storage.db.core.goal.Goal -import io.raemian.storage.db.core.sticker.StickerImage data class CreateGoalResponse( val id: Long, val title: String, val description: String, val deadline: String, - val sticker: StickerImage, + val stickerUrl: String, val tag: String, ) { @@ -18,7 +17,7 @@ data class CreateGoalResponse( title = goal.title, description = goal.description, deadline = goal.deadline.format(), - sticker = goal.sticker.stickerImage, + stickerUrl = goal.sticker.url, tag = goal.tag.content, ) } diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalResponse.kt b/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalResponse.kt index e9773afd..e57853c0 100644 --- a/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalResponse.kt +++ b/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalResponse.kt @@ -2,14 +2,13 @@ package io.raemian.api.goal.controller.response import io.raemian.api.support.format import io.raemian.storage.db.core.goal.Goal -import io.raemian.storage.db.core.sticker.StickerImage import io.raemian.storage.db.core.tag.Tag import io.raemian.storage.db.core.task.Task data class GoalResponse( val title: String, val deadline: String, - val sticker: StickerImage, + val stickerUrl: String, val tagInfo: TagInfo, val tasks: List, ) { @@ -17,7 +16,7 @@ data class GoalResponse( constructor(goal: Goal) : this( goal.title, goal.deadline.format(), - goal.sticker.stickerImage, + goal.sticker.url, TagInfo(goal.tag), goal.tasks.map(::TaskInfo), ) diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalsResponse.kt b/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalsResponse.kt index 95f6634d..c0850e92 100644 --- a/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalsResponse.kt +++ b/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalsResponse.kt @@ -2,7 +2,6 @@ package io.raemian.api.goal.controller.response import io.raemian.api.support.format import io.raemian.storage.db.core.goal.Goal -import io.raemian.storage.db.core.sticker.StickerImage class GoalsResponse private constructor( val goals: List, @@ -20,14 +19,14 @@ class GoalsResponse private constructor( data class GoalInfo( val id: Long?, val deadline: String, - val sticker: StickerImage, + val stickerUrl: String, val tagContent: String, ) { constructor(goal: Goal) : this( id = goal.id, deadline = goal.deadline.format(), - sticker = goal.sticker.stickerImage, + stickerUrl = goal.sticker.url, tagContent = goal.tag.content, ) } diff --git a/application/api/src/main/kotlin/io/raemian/api/sticker/controller/response/StickerResponse.kt b/application/api/src/main/kotlin/io/raemian/api/sticker/controller/response/StickerResponse.kt index 408ce2b1..36505c9d 100644 --- a/application/api/src/main/kotlin/io/raemian/api/sticker/controller/response/StickerResponse.kt +++ b/application/api/src/main/kotlin/io/raemian/api/sticker/controller/response/StickerResponse.kt @@ -1,17 +1,16 @@ package io.raemian.api.sticker.controller.response import io.raemian.storage.db.core.sticker.Sticker -import io.raemian.storage.db.core.sticker.StickerImage data class StickerResponse( val id: Long?, val name: String, - val stickerImage: StickerImage, + val url: String, ) { constructor(sticker: Sticker) : this( sticker.id, sticker.name, - sticker.stickerImage, + sticker.url, ) } diff --git a/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalReadServiceTest.kt b/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalReadServiceTest.kt index 8119f3df..bf9bae7d 100644 --- a/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalReadServiceTest.kt +++ b/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalReadServiceTest.kt @@ -4,7 +4,6 @@ import io.raemian.api.goal.GoalReadService import io.raemian.storage.db.core.goal.Goal import io.raemian.storage.db.core.goal.GoalRepository import io.raemian.storage.db.core.sticker.Sticker -import io.raemian.storage.db.core.sticker.StickerImage import io.raemian.storage.db.core.tag.Tag import io.raemian.storage.db.core.user.Authority import io.raemian.storage.db.core.user.User @@ -35,7 +34,7 @@ class GoalReadServiceTest { Authority.ROLE_USER, ) - val STICKER_FIXTURE = Sticker("sticker", StickerImage("image yeah")) + val STICKER_FIXTURE = Sticker("sticker", "image yeah") val TAG_FIXTURE = Tag("꿈") } diff --git a/application/api/src/test/kotlin/io/raemian/api/integration/sticker/StickerServiceTest.kt b/application/api/src/test/kotlin/io/raemian/api/integration/sticker/StickerServiceTest.kt index 1431df29..8d6fd869 100644 --- a/application/api/src/test/kotlin/io/raemian/api/integration/sticker/StickerServiceTest.kt +++ b/application/api/src/test/kotlin/io/raemian/api/integration/sticker/StickerServiceTest.kt @@ -2,7 +2,6 @@ package io.raemian.api.integration.sticker import io.raemian.api.sticker.StickerService import io.raemian.storage.db.core.sticker.Sticker -import io.raemian.storage.db.core.sticker.StickerImage import io.raemian.storage.db.core.sticker.StickerRepository import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Assertions.assertAll @@ -25,8 +24,8 @@ class StickerServiceTest { @DisplayName("저장된 전체 Tag를 조회할 수 있다.") fun findAllByUserIdTest() { // given - val sticker1 = Sticker("sticker", StickerImage("image1")) - val sticker2 = Sticker("sticker2", StickerImage("image2")) + val sticker1 = Sticker("sticker", "image1") + val sticker2 = Sticker("sticker2", "image2") stickerRepository.save(sticker1) stickerRepository.save(sticker2) @@ -39,9 +38,9 @@ class StickerServiceTest { Executable { assertThat(stickers.size).isEqualTo(2) assertThat(stickers[0].name).isEqualTo(sticker1.name) - assertThat(stickers[0].stickerImage).isEqualTo(sticker1.stickerImage) + assertThat(stickers[0].url).isEqualTo(sticker1.url) assertThat(stickers[1].name).isEqualTo(sticker2.name) - assertThat(stickers[1].stickerImage).isEqualTo(sticker2.stickerImage) + assertThat(stickers[1].url).isEqualTo(sticker2.url) }, ) } diff --git a/application/api/src/test/kotlin/io/raemian/api/integration/task/TaskServiceTest.kt b/application/api/src/test/kotlin/io/raemian/api/integration/task/TaskServiceTest.kt index b34470b8..2d158da8 100644 --- a/application/api/src/test/kotlin/io/raemian/api/integration/task/TaskServiceTest.kt +++ b/application/api/src/test/kotlin/io/raemian/api/integration/task/TaskServiceTest.kt @@ -7,7 +7,6 @@ import io.raemian.api.task.controller.request.UpdateTaskCompletionRequest import io.raemian.storage.db.core.goal.Goal import io.raemian.storage.db.core.goal.GoalRepository import io.raemian.storage.db.core.sticker.Sticker -import io.raemian.storage.db.core.sticker.StickerImage import io.raemian.storage.db.core.tag.Tag import io.raemian.storage.db.core.task.Task import io.raemian.storage.db.core.task.TaskRepository @@ -38,7 +37,7 @@ class TaskServiceTest { Authority.ROLE_USER, ) - val STICKER_FIXTURE = Sticker("sticker", StickerImage("image yeah")) + val STICKER_FIXTURE = Sticker("sticker", "image yeah") val TAG_FIXTURE = Tag("꿈") val GOAL_FIXTURE = Goal( user = USER_FIXTURE, diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/Sticker.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/Sticker.kt index a4257a43..1c31b298 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/Sticker.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/Sticker.kt @@ -2,7 +2,6 @@ package io.raemian.storage.db.core.sticker import io.raemian.storage.db.core.BaseEntity import jakarta.persistence.Column -import jakarta.persistence.Embedded import jakarta.persistence.Entity import jakarta.persistence.GeneratedValue import jakarta.persistence.GenerationType @@ -17,9 +16,8 @@ class Sticker( @Nationalized val name: String, - @Embedded @Column(nullable = false) - val stickerImage: StickerImage, + val url: String, @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerImage.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerImage.kt deleted file mode 100644 index b7fddea8..00000000 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/StickerImage.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.raemian.storage.db.core.sticker - -import com.fasterxml.jackson.annotation.JsonValue -import jakarta.persistence.Embeddable - -@Embeddable -data class StickerImage( - @JsonValue - val stickerImage: String, -) From 351c1d7019f9037defe0a6171b4458420eef9a56 Mon Sep 17 00:00:00 2001 From: wkwon Date: Wed, 20 Dec 2023 02:32:38 +0900 Subject: [PATCH 54/70] =?UTF-8?q?fix:=20db-core=20live=20=ED=99=98?= =?UTF-8?q?=EA=B2=BD=20=EB=B3=80=EC=88=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- storage/db-core/src/main/resources/application-db-core.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/storage/db-core/src/main/resources/application-db-core.yml b/storage/db-core/src/main/resources/application-db-core.yml index c208ca70..85152e30 100644 --- a/storage/db-core/src/main/resources/application-db-core.yml +++ b/storage/db-core/src/main/resources/application-db-core.yml @@ -48,8 +48,8 @@ spring.config.activate.on-profile: live spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://${DB-URL} - username: ${DB-USERNAME} - password: ${DB-PASSWORD} + url: ENC(beSp896XvPBkns0kzH3tlNQEz21NwXRDod/p0bVV0DjBfa4GcSyitf/1D9v5iwGmLNXzRwekPS8=) + username: ENC(WcnAxhO0qmAO5+qduh85dQ==) + password: ENC(cKgWKoQ1xPm3stuyPT0sCg==) hikari: pool-name: db-core-pool From dfa0ebb911eda2fdaa4fdb7e595743588c321283 Mon Sep 17 00:00:00 2001 From: binary_ho Date: Wed, 20 Dec 2023 16:43:21 +0900 Subject: [PATCH 55/70] =?UTF-8?q?[Feature]=20=EA=B3=B5=ED=86=B5=20Response?= =?UTF-8?q?=20Wrapping=20(#53)=20(#54)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor : 공통 Response 예시 코드 수정 (#53) * refactor : Unit 외의 Response에 공통 Response Wrapping (#53) --- .../api/auth/controller/AuthController.kt | 6 ++++-- .../api/goal/controller/GoalController.kt | 16 ++++++++++------ .../api/sticker/controller/StickerController.kt | 8 +++++--- .../raemian/api/support/response/ApiResponse.kt | 8 ++------ .../raemian/api/tag/controller/TagController.kt | 8 +++++--- .../api/task/controller/TaskController.kt | 5 +++-- 6 files changed, 29 insertions(+), 22 deletions(-) diff --git a/application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt b/application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt index 70d03692..3dd22f8e 100644 --- a/application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt +++ b/application/api/src/main/kotlin/io/raemian/api/auth/controller/AuthController.kt @@ -4,6 +4,7 @@ import io.raemian.api.auth.controller.request.UpdateUserRequest import io.raemian.api.auth.controller.response.UserResponse import io.raemian.api.auth.domain.CurrentUser import io.raemian.api.auth.service.AuthService +import io.raemian.api.support.response.ApiResponse import io.swagger.v3.oas.annotations.Operation import org.springframework.http.ResponseEntity import org.springframework.security.core.annotation.AuthenticationPrincipal @@ -19,10 +20,11 @@ class AuthController( @Operation(summary = "토큰 유저 정보 조회 API") @GetMapping("/my") - fun my(@AuthenticationPrincipal currentUser: CurrentUser): ResponseEntity { + fun my(@AuthenticationPrincipal currentUser: CurrentUser): ResponseEntity> { val user = authService.getUserById(currentUser.id) val response = UserResponse.of(user) - return ResponseEntity.ok().body(response) + + return ResponseEntity.ok(ApiResponse.success(response)) } @Operation(summary = "유저 온보딩 이후 정보 업데이트 API") diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt b/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt index fc5bdf6e..dbafaa64 100644 --- a/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt +++ b/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt @@ -8,6 +8,7 @@ import io.raemian.api.goal.controller.request.DeleteGoalRequest import io.raemian.api.goal.controller.response.CreateGoalResponse import io.raemian.api.goal.controller.response.GoalResponse import io.raemian.api.goal.controller.response.GoalsResponse +import io.raemian.api.support.response.ApiResponse import io.swagger.v3.oas.annotations.Operation import org.springframework.http.ResponseEntity import org.springframework.security.core.annotation.AuthenticationPrincipal @@ -33,28 +34,31 @@ class GoalController( @GetMapping fun findAllByUserId( @AuthenticationPrincipal currentUser: CurrentUser, - ): ResponseEntity { + ): ResponseEntity> { val response = goalReadService.findAllByUserId(currentUser.id) - return ResponseEntity.ok(response) + return ResponseEntity + .ok(ApiResponse.success(response)) } @Operation(summary = "목표 단건 조회 API") @GetMapping("/{goalId}") fun getByUserId( @PathVariable("goalId") goalId: Long, - ): ResponseEntity = - ResponseEntity.ok(goalReadService.getById(goalId)) + ): ResponseEntity> = + ResponseEntity.ok( + ApiResponse.success(goalReadService.getById(goalId)), + ) @Operation(summary = "목표 생성 API") @PostMapping fun create( @AuthenticationPrincipal currentUser: CurrentUser, @RequestBody createGoalRequest: CreateGoalRequest, - ): ResponseEntity { + ): ResponseEntity> { val response = goalService.create(currentUser.id, createGoalRequest) return ResponseEntity .created("/goal/${response.id}".toUri()) - .body(response) + .body(ApiResponse.success(response)) } @Operation(summary = "목표 삭제 API") diff --git a/application/api/src/main/kotlin/io/raemian/api/sticker/controller/StickerController.kt b/application/api/src/main/kotlin/io/raemian/api/sticker/controller/StickerController.kt index 631cb860..e6915a3f 100644 --- a/application/api/src/main/kotlin/io/raemian/api/sticker/controller/StickerController.kt +++ b/application/api/src/main/kotlin/io/raemian/api/sticker/controller/StickerController.kt @@ -2,6 +2,7 @@ package io.raemian.api.sticker.controller import io.raemian.api.sticker.StickerService import io.raemian.api.sticker.controller.response.StickerResponse +import io.raemian.api.support.response.ApiResponse import io.swagger.v3.oas.annotations.Operation import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping @@ -16,7 +17,8 @@ class StickerController( @Operation(summary = "스티커 전체 조회 API") @GetMapping - fun findAll(): ResponseEntity> { - return ResponseEntity.ok(stickerService.findAll()) - } + fun findAll(): ResponseEntity>> = + ResponseEntity.ok( + ApiResponse.success(stickerService.findAll()), + ) } diff --git a/application/api/src/main/kotlin/io/raemian/api/support/response/ApiResponse.kt b/application/api/src/main/kotlin/io/raemian/api/support/response/ApiResponse.kt index 96672385..41eccbb8 100644 --- a/application/api/src/main/kotlin/io/raemian/api/support/response/ApiResponse.kt +++ b/application/api/src/main/kotlin/io/raemian/api/support/response/ApiResponse.kt @@ -3,16 +3,12 @@ package io.raemian.api.support.response import io.raemian.api.support.error.ErrorMessage import io.raemian.api.support.error.ErrorType -data class ApiResponse private constructor( +class ApiResponse private constructor( val result: ResultType, - val data: T? = null, + val body: T? = null, val error: ErrorMessage? = null, ) { companion object { - fun success(): ApiResponse { - return ApiResponse(ResultType.SUCCESS, null, null) - } - fun success(data: S): ApiResponse { return ApiResponse(ResultType.SUCCESS, data, null) } diff --git a/application/api/src/main/kotlin/io/raemian/api/tag/controller/TagController.kt b/application/api/src/main/kotlin/io/raemian/api/tag/controller/TagController.kt index a4f6c890..f278478e 100644 --- a/application/api/src/main/kotlin/io/raemian/api/tag/controller/TagController.kt +++ b/application/api/src/main/kotlin/io/raemian/api/tag/controller/TagController.kt @@ -1,5 +1,6 @@ package io.raemian.api.tag.controller +import io.raemian.api.support.response.ApiResponse import io.raemian.api.tag.TagService import io.raemian.api.tag.controller.response.TagResponse import io.swagger.v3.oas.annotations.Operation @@ -16,7 +17,8 @@ class TagController( @Operation(summary = "태그 전체 조회 API") @GetMapping - fun findAll(): ResponseEntity> { - return ResponseEntity.ok(tagService.findAll()) - } + fun findAll(): ResponseEntity>> = + ResponseEntity.ok( + ApiResponse.success(tagService.findAll()), + ) } diff --git a/application/api/src/main/kotlin/io/raemian/api/task/controller/TaskController.kt b/application/api/src/main/kotlin/io/raemian/api/task/controller/TaskController.kt index 150718f0..e59d6460 100644 --- a/application/api/src/main/kotlin/io/raemian/api/task/controller/TaskController.kt +++ b/application/api/src/main/kotlin/io/raemian/api/task/controller/TaskController.kt @@ -2,6 +2,7 @@ package io.raemian.api.task.controller import io.raemian.api.auth.domain.CurrentUser import io.raemian.api.goal.controller.toUri +import io.raemian.api.support.response.ApiResponse import io.raemian.api.task.TaskService import io.raemian.api.task.controller.request.CreateTaskRequest import io.raemian.api.task.controller.request.RewriteTaskRequest @@ -29,10 +30,10 @@ class TaskController( fun create( @AuthenticationPrincipal currentUser: CurrentUser, @RequestBody createTaskRequest: CreateTaskRequest, - ): ResponseEntity { + ): ResponseEntity> { val response = taskService.create(currentUser.id, createTaskRequest) return ResponseEntity.created("/task/${response.id}".toUri()) - .body(response) + .body(ApiResponse.success(response)) } @Operation(summary = "Task의 description을 수정하는 API입니다.") From f1aa666d1602265dddabde38ac593fce732b51a6 Mon Sep 17 00:00:00 2001 From: wkwon Date: Thu, 21 Dec 2023 09:32:51 +0900 Subject: [PATCH 56/70] =?UTF-8?q?fix:=20create=20goal=20requestBody=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EC=98=A4=ED=83=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/raemian/api/goal/controller/request/CreateGoalRequest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/controller/request/CreateGoalRequest.kt b/application/api/src/main/kotlin/io/raemian/api/goal/controller/request/CreateGoalRequest.kt index d6358d68..20b28183 100644 --- a/application/api/src/main/kotlin/io/raemian/api/goal/controller/request/CreateGoalRequest.kt +++ b/application/api/src/main/kotlin/io/raemian/api/goal/controller/request/CreateGoalRequest.kt @@ -3,7 +3,7 @@ package io.raemian.api.goal.controller.request data class CreateGoalRequest( val title: String, val yearOfDeadline: String, - val monthOfDeadLine: String, + val monthOfDeadline: String, val stickerId: Long, val tagId: Long, val description: String? = "", From 26bb959c4ab72b2b047689ae8e311afa261b1aa7 Mon Sep 17 00:00:00 2001 From: wkwon Date: Thu, 21 Dec 2023 12:40:31 +0900 Subject: [PATCH 57/70] =?UTF-8?q?fix:=20GoalResponse=20description=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/raemian/api/goal/controller/response/GoalResponse.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalResponse.kt b/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalResponse.kt index e57853c0..80372a96 100644 --- a/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalResponse.kt +++ b/application/api/src/main/kotlin/io/raemian/api/goal/controller/response/GoalResponse.kt @@ -7,6 +7,7 @@ import io.raemian.storage.db.core.task.Task data class GoalResponse( val title: String, + val description: String, val deadline: String, val stickerUrl: String, val tagInfo: TagInfo, @@ -15,6 +16,7 @@ data class GoalResponse( constructor(goal: Goal) : this( goal.title, + goal.description, goal.deadline.format(), goal.sticker.url, TagInfo(goal.tag), From 31ffa941b7e0818cd4b231cacfc5de7c45214c69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=EC=9A=B0=EC=84=9D=20=28Woosuk=20Kwon=29?= Date: Thu, 21 Dec 2023 19:06:06 +0900 Subject: [PATCH 58/70] =?UTF-8?q?[Revert]=20"=EC=95=94=ED=98=B8=ED=99=94?= =?UTF-8?q?=EB=A5=BC=20=EC=9C=84=ED=95=9C=20Jasypt=20=EB=8F=84=EC=9E=85?= =?UTF-8?q?=EA=B3=BC=20=EC=82=AC=EC=9A=A9=20=EC=84=A4=EB=AA=85=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1=20(#48)=20(#49)"=20(#56?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Revert "[feature] 암호화를 위한 Jasypt 도입과 사용 설명 테스트 작성 (#48) (#49)" This reverts commit 91ba43a0bc6cc034e60e06846bc5f4ede18f4008. * revert: revert jasypt --- .../pull-request-gradle-build-test.yml | 8 ++-- application/api/build.gradle.kts | 3 -- .../io/raemian/api/config/EncryptorConfig.kt | 26 ----------- .../main/resources/application-security.yml | 19 ++++---- .../api/src/main/resources/application.yml | 9 +--- .../io/raemian/api/support/Encryptor.kt | 45 ------------------- .../test/resources/application-security.yml | 15 +++---- .../api/src/test/resources/application.yml | 5 --- .../main/resources/application-db-core.yml | 14 +++--- 9 files changed, 27 insertions(+), 117 deletions(-) delete mode 100644 application/api/src/main/kotlin/io/raemian/api/config/EncryptorConfig.kt delete mode 100644 application/api/src/test/kotlin/io/raemian/api/support/Encryptor.kt diff --git a/.github/workflows/pull-request-gradle-build-test.yml b/.github/workflows/pull-request-gradle-build-test.yml index 90db4150..e6082998 100644 --- a/.github/workflows/pull-request-gradle-build-test.yml +++ b/.github/workflows/pull-request-gradle-build-test.yml @@ -1,8 +1,8 @@ -name: Pull Request Gradle Build Test +name : Pull Request Gradle Build Test on: pull_request: - types: [ opened, synchronize, closed ] + types: [opened, synchronize, closed] permissions: read-all @@ -34,10 +34,8 @@ jobs: - name: gradlew 권한 부여 run: chmod +x ./gradlew - + - name: Gradle Build if: steps.changes.outputs.application == 'true' - env: - JASYPT_ENCRYPTION_PASSWORD: ${{ secrets.PROPERTY_ENCRYPTION_PASSWORD }} run: | ./gradlew build --no-build-cache diff --git a/application/api/build.gradle.kts b/application/api/build.gradle.kts index d1f5d3ba..0121db0e 100644 --- a/application/api/build.gradle.kts +++ b/application/api/build.gradle.kts @@ -35,7 +35,4 @@ dependencies { /* swagger */ implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0") - - /* jasypt */ - implementation("com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.4") } diff --git a/application/api/src/main/kotlin/io/raemian/api/config/EncryptorConfig.kt b/application/api/src/main/kotlin/io/raemian/api/config/EncryptorConfig.kt deleted file mode 100644 index 41b9ba6b..00000000 --- a/application/api/src/main/kotlin/io/raemian/api/config/EncryptorConfig.kt +++ /dev/null @@ -1,26 +0,0 @@ -package io.raemian.api.config - -import org.jasypt.encryption.StringEncryptor -import org.jasypt.encryption.pbe.PooledPBEStringEncryptor -import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig -import org.springframework.beans.factory.annotation.Value -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration - -@Configuration -class EncryptorConfig { - - @Bean("stringEncryptor") - fun stringEncryptor( - @Value(value = "\${jasypt.secret-key}") encryptorPassword: String?, - ): StringEncryptor { - val pooledPBEStringEncryptor = PooledPBEStringEncryptor() - - val simpleStringPBEConfig = SimpleStringPBEConfig() - simpleStringPBEConfig.setPassword(encryptorPassword) - simpleStringPBEConfig.poolSize = 1 - - pooledPBEStringEncryptor.setConfig(simpleStringPBEConfig) - return pooledPBEStringEncryptor - } -} diff --git a/application/api/src/main/resources/application-security.yml b/application/api/src/main/resources/application-security.yml index a2fd43df..032cc2fa 100644 --- a/application/api/src/main/resources/application-security.yml +++ b/application/api/src/main/resources/application-security.yml @@ -22,9 +22,9 @@ spring: - name client-name: naver google: - redirect-uri: ENC(1nLPI1HHtBur53TcEE1vt/aFsQVvfwwUHoIe0bxrztiAPLuHfrIlVQdXfPOQPKjR/5BAH1WTNwyy3bVtHwL9UuNQP583Nxyu) - client-id: ENC(DcoBp86FnyGsZ3QGf++3vLiyeJwWtZcCHHcQR1o5bSHqrsGWGvemGgjSnMgRJy1BZXTNQEGEbg36gPSh+LuMqV5U2PO5vohM+5LH0UWm/gVhlNl/vM85cw==) - client-secret: ENC(SCv0TGTTXDdlyn76WzcaErJgPRfAhSeBDa1SkHN1UyeMNNWMTU40qGhFFmvirudA) + redirect-uri: ${GOOGLE-REDIRECT-URI} + client-id: ${GOOGLE-CLIENT-ID} + client-secret: ${GOOGLE-CLIENT-SECRET} scope: - email - profile @@ -55,9 +55,9 @@ spring: - name client-name: naver google: - redirect-uri: ENC(1nLPI1HHtBur53TcEE1vt/aFsQVvfwwUHoIe0bxrztiAPLuHfrIlVQdXfPOQPKjR/5BAH1WTNwyy3bVtHwL9UuNQP583Nxyu) - client-id: ENC(DcoBp86FnyGsZ3QGf++3vLiyeJwWtZcCHHcQR1o5bSHqrsGWGvemGgjSnMgRJy1BZXTNQEGEbg36gPSh+LuMqV5U2PO5vohM+5LH0UWm/gVhlNl/vM85cw==) - client-secret: ENC(SCv0TGTTXDdlyn76WzcaErJgPRfAhSeBDa1SkHN1UyeMNNWMTU40qGhFFmvirudA) + redirect-uri: ${GOOGLE-REDIRECT-URI} + client-id: ${GOOGLE-CLIENT-ID} + client-secret: ${GOOGLE-CLIENT-SECRET} scope: - email - profile @@ -89,9 +89,10 @@ spring: - name client-name: naver google: - redirect-uri: ENC(1nLPI1HHtBur53TcEE1vt/aFsQVvfwwUHoIe0bxrztiAPLuHfrIlVQdXfPOQPKjR/5BAH1WTNwyy3bVtHwL9UuNQP583Nxyu) - client-id: ENC(DcoBp86FnyGsZ3QGf++3vLiyeJwWtZcCHHcQR1o5bSHqrsGWGvemGgjSnMgRJy1BZXTNQEGEbg36gPSh+LuMqV5U2PO5vohM+5LH0UWm/gVhlNl/vM85cw==) - client-secret: ENC(SCv0TGTTXDdlyn76WzcaErJgPRfAhSeBDa1SkHN1UyeMNNWMTU40qGhFFmvirudA) + redirect-uri: ${GOOGLE-REDIRECT-URI} + client-id: ${GOOGLE-CLIENT-ID} + client-secret: ${GOOGLE-CLIENT-SECRET} scope: - email - profile + diff --git a/application/api/src/main/resources/application.yml b/application/api/src/main/resources/application.yml index 74b28d7c..fde49d19 100644 --- a/application/api/src/main/resources/application.yml +++ b/application/api/src/main/resources/application.yml @@ -7,16 +7,9 @@ spring: mvc.throw-exception-if-no-handler-found: true web.resources.add-mappings: false -jasypt: - encryptor: - bean: stringEncryptor - secret-key: ${JASYPT_ENCRYPTION_PASSWORD} - - server: servlet: context-path: /api - --- # local spring: @@ -48,4 +41,4 @@ spring: - security - db-core - logging - - metrics + - metrics \ No newline at end of file diff --git a/application/api/src/test/kotlin/io/raemian/api/support/Encryptor.kt b/application/api/src/test/kotlin/io/raemian/api/support/Encryptor.kt deleted file mode 100644 index dcd3690b..00000000 --- a/application/api/src/test/kotlin/io/raemian/api/support/Encryptor.kt +++ /dev/null @@ -1,45 +0,0 @@ -package io.raemian.api.support - -import io.raemian.api.config.EncryptorConfig -import org.jasypt.encryption.StringEncryptor -import org.junit.jupiter.api.Test - -class Encryptor { - - /** - * @Author 이진호 - * @see 암호화를_하는_방법은_아래와_같습니다 (https://github.com/depromeet/amazing3-be/pull/49) - * 1. 사용할 yaml의 최상위 파일에 아래 코드를 추가합니다. - * ``` - * jasypt: - * encryptor: - * bean: stringEncryptor - * secret-key: ${JASYPT_ENCRYPTION_PASSWORD} - * ``` - * - * 2. 환경 변수 JASYPT_ENCRYPTION_PASSWORD에 비밀번호를 대입합니다. - * 3. password 변수 값에 비밀번호를 대입합니다. (빈으로 관리하고 싶지 않아 자동 주입 넣지 않았습니다.) - * 4. encrypt 메서드에 ","로 구분해 암호화할 String 값을 넣으세요. - * 5. ENC() 가 포함된 전체 결과를 기존 값 대신에 대입하세요. - * - * - * @see 주의 : 순수 숫자는 안 됩니다. - * */ - - val password = "enter password" - - @Test - fun encrypt() { - // 암호화 할 값을 대입해세요 - encrypt("enter", "password") - } - - fun encrypt(vararg string: String) { - val encryptor: StringEncryptor = EncryptorConfig() - .stringEncryptor(password) - - string.forEach { - println("$it 암호화 -> ENC(${encryptor.encrypt(it)})") - } - } -} diff --git a/application/api/src/test/resources/application-security.yml b/application/api/src/test/resources/application-security.yml index a2fd43df..967fa6e6 100644 --- a/application/api/src/test/resources/application-security.yml +++ b/application/api/src/test/resources/application-security.yml @@ -22,9 +22,8 @@ spring: - name client-name: naver google: - redirect-uri: ENC(1nLPI1HHtBur53TcEE1vt/aFsQVvfwwUHoIe0bxrztiAPLuHfrIlVQdXfPOQPKjR/5BAH1WTNwyy3bVtHwL9UuNQP583Nxyu) - client-id: ENC(DcoBp86FnyGsZ3QGf++3vLiyeJwWtZcCHHcQR1o5bSHqrsGWGvemGgjSnMgRJy1BZXTNQEGEbg36gPSh+LuMqV5U2PO5vohM+5LH0UWm/gVhlNl/vM85cw==) - client-secret: ENC(SCv0TGTTXDdlyn76WzcaErJgPRfAhSeBDa1SkHN1UyeMNNWMTU40qGhFFmvirudA) + client-id: ${GOOGLE-CLIENT-ID} + client-secret: ${GOOGLE-CLIENT-SECRET} scope: - email - profile @@ -55,9 +54,8 @@ spring: - name client-name: naver google: - redirect-uri: ENC(1nLPI1HHtBur53TcEE1vt/aFsQVvfwwUHoIe0bxrztiAPLuHfrIlVQdXfPOQPKjR/5BAH1WTNwyy3bVtHwL9UuNQP583Nxyu) - client-id: ENC(DcoBp86FnyGsZ3QGf++3vLiyeJwWtZcCHHcQR1o5bSHqrsGWGvemGgjSnMgRJy1BZXTNQEGEbg36gPSh+LuMqV5U2PO5vohM+5LH0UWm/gVhlNl/vM85cw==) - client-secret: ENC(SCv0TGTTXDdlyn76WzcaErJgPRfAhSeBDa1SkHN1UyeMNNWMTU40qGhFFmvirudA) + client-id: ${GOOGLE-CLIENT-ID} + client-secret: ${GOOGLE-CLIENT-SECRET} scope: - email - profile @@ -89,9 +87,8 @@ spring: - name client-name: naver google: - redirect-uri: ENC(1nLPI1HHtBur53TcEE1vt/aFsQVvfwwUHoIe0bxrztiAPLuHfrIlVQdXfPOQPKjR/5BAH1WTNwyy3bVtHwL9UuNQP583Nxyu) - client-id: ENC(DcoBp86FnyGsZ3QGf++3vLiyeJwWtZcCHHcQR1o5bSHqrsGWGvemGgjSnMgRJy1BZXTNQEGEbg36gPSh+LuMqV5U2PO5vohM+5LH0UWm/gVhlNl/vM85cw==) - client-secret: ENC(SCv0TGTTXDdlyn76WzcaErJgPRfAhSeBDa1SkHN1UyeMNNWMTU40qGhFFmvirudA) + client-id: ${GOOGLE-CLIENT-ID} + client-secret: ${GOOGLE-CLIENT-SECRET} scope: - email - profile diff --git a/application/api/src/test/resources/application.yml b/application/api/src/test/resources/application.yml index 254dd972..59e338e1 100644 --- a/application/api/src/test/resources/application.yml +++ b/application/api/src/test/resources/application.yml @@ -15,11 +15,6 @@ spring: hibernate: format_sql: true -jasypt: - encryptor: - bean: stringEncryptor - secret-key: ${JASYPT_ENCRYPTION_PASSWORD} - --- # local spring: diff --git a/storage/db-core/src/main/resources/application-db-core.yml b/storage/db-core/src/main/resources/application-db-core.yml index 85152e30..4d48b21c 100644 --- a/storage/db-core/src/main/resources/application-db-core.yml +++ b/storage/db-core/src/main/resources/application-db-core.yml @@ -34,9 +34,9 @@ spring.config.activate.on-profile: dev spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver - url: ENC(beSp896XvPBkns0kzH3tlNQEz21NwXRDod/p0bVV0DjBfa4GcSyitf/1D9v5iwGmLNXzRwekPS8=) - username: ENC(WcnAxhO0qmAO5+qduh85dQ==) - password: ENC(cKgWKoQ1xPm3stuyPT0sCg==) + url: jdbc:mysql://${DB-URL} + username: ${DB-USERNAME} + password: ${DB-PASSWORD} hikari: pool-name: db-core-pool @@ -48,8 +48,8 @@ spring.config.activate.on-profile: live spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver - url: ENC(beSp896XvPBkns0kzH3tlNQEz21NwXRDod/p0bVV0DjBfa4GcSyitf/1D9v5iwGmLNXzRwekPS8=) - username: ENC(WcnAxhO0qmAO5+qduh85dQ==) - password: ENC(cKgWKoQ1xPm3stuyPT0sCg==) + url: jdbc:mysql://${DB-URL} + username: ${DB-USERNAME} + password: ${DB-PASSWORD} hikari: - pool-name: db-core-pool + pool-name: db-core-pool \ No newline at end of file From 767566291c51acf175711d99830a7515336d1ffc Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Fri, 22 Dec 2023 00:27:15 +0900 Subject: [PATCH 59/70] feat(#16): add user profile image --- .../raemian/api/auth/controller/response/UserResponse.kt | 2 ++ .../io/raemian/api/auth/service/OAuth2UserService.kt | 9 ++++++--- .../main/kotlin/io/raemian/storage/db/core/user/User.kt | 4 ++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/application/api/src/main/kotlin/io/raemian/api/auth/controller/response/UserResponse.kt b/application/api/src/main/kotlin/io/raemian/api/auth/controller/response/UserResponse.kt index eb7b05ca..6b6cac15 100644 --- a/application/api/src/main/kotlin/io/raemian/api/auth/controller/response/UserResponse.kt +++ b/application/api/src/main/kotlin/io/raemian/api/auth/controller/response/UserResponse.kt @@ -9,6 +9,7 @@ data class UserResponse( val username: String?, val nickname: String?, val birth: LocalDate?, + val image: String, ) { companion object { fun of(user: User): UserResponse { @@ -18,6 +19,7 @@ data class UserResponse( username = user.userName, nickname = user.nickname, birth = user.birth, + image = user.image, ) } } diff --git a/application/api/src/main/kotlin/io/raemian/api/auth/service/OAuth2UserService.kt b/application/api/src/main/kotlin/io/raemian/api/auth/service/OAuth2UserService.kt index 685a9917..d94d974e 100644 --- a/application/api/src/main/kotlin/io/raemian/api/auth/service/OAuth2UserService.kt +++ b/application/api/src/main/kotlin/io/raemian/api/auth/service/OAuth2UserService.kt @@ -24,7 +24,8 @@ class OAuth2UserService( OAuthProvider.GOOGLE -> { val email = oAuth2User.attributes["email"]?.toString() ?: throw RuntimeException("이메일이없음") val name = oAuth2User.attributes["name"] - val user = upsert(email, OAuthProvider.GOOGLE) + val image = oAuth2User.attributes["picture"]?.toString() ?: "" + val user = upsert(email, image, OAuthProvider.GOOGLE) CurrentUser( id = user.id!!, email = email, @@ -35,7 +36,8 @@ class OAuth2UserService( OAuthProvider.NAVER -> { val userInfo = oAuth2User.attributes[usernameAttributeName] as Map val email = userInfo["email"] ?: throw RuntimeException("이메일없음") - val user = upsert(email, OAuthProvider.NAVER) + val image = "" + val user = upsert(email, image, OAuthProvider.NAVER) CurrentUser( id = user.id!!, email = email, @@ -45,11 +47,12 @@ class OAuth2UserService( } } - private fun upsert(email: String, oAuthProvider: OAuthProvider): User { + private fun upsert(email: String, image: String, oAuthProvider: OAuthProvider): User { return userRepository.findByEmail(email) ?: return userRepository.save( User( email = email, + image = image, provider = oAuthProvider, authority = Authority.ROLE_USER, ), diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt index db261d44..22baed61 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/user/User.kt @@ -28,6 +28,9 @@ class User( @Column val birth: LocalDate? = null, + @Column + val image: String, + @Column @Enumerated(EnumType.STRING) val provider: OAuthProvider, @@ -45,6 +48,7 @@ class User( email = email, nickname = nickname, birth = birth, + image = image, provider = provider, authority = authority, id = id, From 7c6f550dc9197207cedfdfb2b47c094e4adbc9d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=EC=9A=B0=EC=84=9D=20=28Woosuk=20Kwon=29?= Date: Fri, 22 Dec 2023 00:30:08 +0900 Subject: [PATCH 60/70] =?UTF-8?q?feature(#4):=20github=20action=20CI/CD=20?= =?UTF-8?q?pipeline=20=EA=B5=AC=EC=B6=95=20(#57)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-cd.yml | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/ci-cd.yml diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml new file mode 100644 index 00000000..79dcc5dc --- /dev/null +++ b/.github/workflows/ci-cd.yml @@ -0,0 +1,39 @@ +name: Java CI with Gradle + +on: + push: + branches: [ "develop" ] + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: setup jdk 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + + - name: build with gradle + run: ./gradlew bootJar + + - name: push to dockerhub + run: | + docker login -u ${{ secrets.DOCKER_ID }} -p ${{ secrets.DOCKER_PASSWORD }} + docker build --no-cache -t ${{ secrets.DOCKER_ID }}/${{ secrets.DOCKER_REPO }} . + docker push ${{ secrets.DOCKER_ID }}/${{ secrets.DOCKER_REPO }} + - name: deploy + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.SSH_HOST }} + port: ${{ secrets.SSH_PORT }} + username: ${{ secrets.SSH_USERNAME }} + password: ${{ secrets.SSH_PASSWORD }} + script: | + ${{ secrets.SSH_SCRIPT }} \ No newline at end of file From e625731ce1aa3745b72700849c56e63a2012dd4c Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Fri, 22 Dec 2023 00:32:16 +0900 Subject: [PATCH 61/70] feat(#59): edit DELETE /goal params --- .../api/src/main/kotlin/io/raemian/api/goal/GoalService.kt | 5 ++--- .../io/raemian/api/goal/controller/GoalController.kt | 7 +++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt b/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt index 133ce801..42259efb 100644 --- a/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt +++ b/application/api/src/main/kotlin/io/raemian/api/goal/GoalService.kt @@ -1,7 +1,6 @@ package io.raemian.api.goal import io.raemian.api.goal.controller.request.CreateGoalRequest -import io.raemian.api.goal.controller.request.DeleteGoalRequest import io.raemian.api.goal.controller.response.CreateGoalResponse import io.raemian.api.sticker.StickerService import io.raemian.api.support.RaemianLocalDate @@ -34,8 +33,8 @@ class GoalService( } @Transactional - fun delete(userId: Long, deleteGoalRequest: DeleteGoalRequest) { - val goal = goalRepository.getById(deleteGoalRequest.goalId) + fun delete(userId: Long, goalId: Long) { + val goal = goalRepository.getById(goalId) validateGoalIsUsers(userId, goal) goalRepository.delete(goal) } diff --git a/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt b/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt index dbafaa64..b5688fad 100644 --- a/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt +++ b/application/api/src/main/kotlin/io/raemian/api/goal/controller/GoalController.kt @@ -4,7 +4,6 @@ import io.raemian.api.auth.domain.CurrentUser import io.raemian.api.goal.GoalReadService import io.raemian.api.goal.GoalService import io.raemian.api.goal.controller.request.CreateGoalRequest -import io.raemian.api.goal.controller.request.DeleteGoalRequest import io.raemian.api.goal.controller.response.CreateGoalResponse import io.raemian.api.goal.controller.response.GoalResponse import io.raemian.api.goal.controller.response.GoalsResponse @@ -62,12 +61,12 @@ class GoalController( } @Operation(summary = "목표 삭제 API") - @DeleteMapping + @DeleteMapping("/{goalId}") fun delete( @AuthenticationPrincipal currentUser: CurrentUser, - @RequestBody deleteGoalRequest: DeleteGoalRequest, + @PathVariable goalId: Long, ): ResponseEntity { - goalService.delete(currentUser.id, deleteGoalRequest) + goalService.delete(currentUser.id, goalId) return ResponseEntity.noContent().build() } } From fb239b96255df770bce4fa6abf23b3ee034ed99e Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Fri, 22 Dec 2023 00:35:42 +0900 Subject: [PATCH 62/70] chore(#16): edit test user field --- .../api/integration/goal/GoalReadServiceTest.kt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalReadServiceTest.kt b/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalReadServiceTest.kt index bf9bae7d..5615d3cc 100644 --- a/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalReadServiceTest.kt +++ b/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalReadServiceTest.kt @@ -26,12 +26,13 @@ class GoalReadServiceTest { companion object { val USER_FIXTURE = User( - "dfghcvb111@naver.com", - "binaryHoHo", - "binaryHoHoHo", - LocalDate.MIN, - OAuthProvider.NAVER, - Authority.ROLE_USER, + email = "dfghcvb111@naver.com", + userName = "binaryHoHo", + nickname = "binaryHoHoHo", + birth = LocalDate.MIN, + image = "", + provider = OAuthProvider.NAVER, + authority = Authority.ROLE_USER, ) val STICKER_FIXTURE = Sticker("sticker", "image yeah") From 3502feefdb3d40120918e1b19c9b14c1eb216c7d Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Fri, 22 Dec 2023 00:41:31 +0900 Subject: [PATCH 63/70] chore(#16): edit test user field --- .../io/raemian/api/integration/task/TaskServiceTest.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/application/api/src/test/kotlin/io/raemian/api/integration/task/TaskServiceTest.kt b/application/api/src/test/kotlin/io/raemian/api/integration/task/TaskServiceTest.kt index 2d158da8..a9c7f870 100644 --- a/application/api/src/test/kotlin/io/raemian/api/integration/task/TaskServiceTest.kt +++ b/application/api/src/test/kotlin/io/raemian/api/integration/task/TaskServiceTest.kt @@ -32,9 +32,10 @@ class TaskServiceTest { email = "dfghcvb111@naver.com", userName = "binaryHoHo", nickname = "binaryHoHoHo", - LocalDate.MIN, - OAuthProvider.NAVER, - Authority.ROLE_USER, + image = "", + birth = LocalDate.MIN, + provider = OAuthProvider.NAVER, + authority = Authority.ROLE_USER, ) val STICKER_FIXTURE = Sticker("sticker", "image yeah") From a840324c43de1dd03118a3d55208b21a5890815c Mon Sep 17 00:00:00 2001 From: ManHyuk Date: Fri, 22 Dec 2023 14:21:57 +0900 Subject: [PATCH 64/70] Update WebSecurityConfig.kt --- .../src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt b/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt index 23969c02..fc76ff99 100644 --- a/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt +++ b/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt @@ -75,7 +75,7 @@ class WebSecurityConfig( val tokenDTO = tokenProvider.generateTokenDto(user) response.setHeader("x-token", tokenDTO.accessToken) // TODO edit redirect url - response.sendRedirect("http://localhost:3000/login/oauth2/code/google?token=${tokenDTO.accessToken}&refresh=${tokenDTO.refreshToken}") + response.sendRedirect("https://www.bandiboodi.com/login/oauth2/code/google?token=${tokenDTO.accessToken}&refresh=${tokenDTO.refreshToken}") } it.failureHandler { request, response, exception -> response.addHeader("x-token", exception.message) From a462d6294d3cc06cf34ccecea7deb1b9a43a54f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=EC=9A=B0=EC=84=9D=20=28Woosuk=20Kwon=29?= Date: Sun, 24 Dec 2023 22:09:25 +0900 Subject: [PATCH 65/70] =?UTF-8?q?[Feature]=20Slack=20Webhook=EC=9D=84=20?= =?UTF-8?q?=ED=99=9C=EC=9A=A9=ED=95=9C=20Logger=20=EC=B6=94=EA=B0=80=20(#6?= =?UTF-8?q?3)=20(#64)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feature(#63): slack logger 추가 * fix: 객체 및 파일 명 변경 (logging -> log) * fix: CreateSlackErrorLogRequest 파일 명 변경 * fix: slack webhook url 환경 변수 default값 추가 * delete: rest docs 폴더 삭제 * fix: createSlackErrorLog referer, userAgent set nullable / 테스트용 코드 삭제 * fix: log API swagger 명세 추가 --- application/api/build.gradle.kts | 3 - application/api/src/docs/asciidoc/index.adoc | 38 ----- .../io/raemian/api/config/AsyncConfig.kt | 31 ++++ .../api/config/GlobalExceptionHandler.kt | 18 +- .../raemian/api/config/WebSecurityConfig.kt | 1 + .../kotlin/io/raemian/api/log/LogService.kt | 32 ++++ .../api/log/controller/LogController.kt | 24 +++ .../request/CreateSlackErrorLogRequest.kt | 11 ++ build.gradle.kts | 24 +-- infra/logging/build.gradle.kts | 4 + .../infra/logging/enums/ErrorLocationEnum.kt | 18 ++ .../infra/logging/enums/LogTemplate.kt | 14 ++ .../infra/logging/logger/SlackLogger.kt | 155 ++++++++++++++++++ .../main/resources/application-logging.yml | 12 +- 14 files changed, 311 insertions(+), 74 deletions(-) delete mode 100644 application/api/src/docs/asciidoc/index.adoc create mode 100644 application/api/src/main/kotlin/io/raemian/api/config/AsyncConfig.kt create mode 100644 application/api/src/main/kotlin/io/raemian/api/log/LogService.kt create mode 100644 application/api/src/main/kotlin/io/raemian/api/log/controller/LogController.kt create mode 100644 application/api/src/main/kotlin/io/raemian/api/log/controller/request/CreateSlackErrorLogRequest.kt create mode 100644 infra/logging/src/main/kotlin/io/raemian/infra/logging/enums/ErrorLocationEnum.kt create mode 100644 infra/logging/src/main/kotlin/io/raemian/infra/logging/enums/LogTemplate.kt create mode 100644 infra/logging/src/main/kotlin/io/raemian/infra/logging/logger/SlackLogger.kt diff --git a/application/api/build.gradle.kts b/application/api/build.gradle.kts index 0121db0e..0fa0263b 100644 --- a/application/api/build.gradle.kts +++ b/application/api/build.gradle.kts @@ -24,9 +24,6 @@ dependencies { /* oauth-client */ implementation("org.springframework.boot:spring-boot-starter-oauth2-client") - /* web-client */ - implementation("org.springframework.boot:spring-boot-starter-webflux") - /* test */ testImplementation("org.springframework.security:spring-security-test") testImplementation("org.springframework.restdocs:spring-restdocs-mockmvc") diff --git a/application/api/src/docs/asciidoc/index.adoc b/application/api/src/docs/asciidoc/index.adoc deleted file mode 100644 index fd2c461d..00000000 --- a/application/api/src/docs/asciidoc/index.adoc +++ /dev/null @@ -1,38 +0,0 @@ -= API Docs -:doctype: book -:icons: font -:source-highlighter: highlightjs -:toc: left -:toclevels: 3 -:sectlinks: -:snippets: build/generated-snippets - -== Introduce - -This is the Core API documentation. - -== Example API - -=== Example GET API -==== Curl Request -include::{snippets}/exampleGet/curl-request.adoc[] -==== Path Parameters -include::{snippets}/exampleGet/path-parameters.adoc[] -==== Query Parameters -include::{snippets}/exampleGet/query-parameters.adoc[] -==== Http Response -include::{snippets}/exampleGet/http-response.adoc[] -==== Response Fields -include::{snippets}/exampleGet/response-fields.adoc[] - -''' - -=== Example POST API -==== Curl Request -include::{snippets}/examplePost/curl-request.adoc[] -==== Request Fields -include::{snippets}/examplePost/request-fields.adoc[] -==== Http Response -include::{snippets}/examplePost/http-response.adoc[] -==== Response Fields -include::{snippets}/examplePost/response-fields.adoc[] diff --git a/application/api/src/main/kotlin/io/raemian/api/config/AsyncConfig.kt b/application/api/src/main/kotlin/io/raemian/api/config/AsyncConfig.kt new file mode 100644 index 00000000..0a68ffe2 --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/config/AsyncConfig.kt @@ -0,0 +1,31 @@ +package io.raemian.api.config + +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler +import org.springframework.context.annotation.Configuration +import org.springframework.scheduling.annotation.AsyncConfigurer +import org.springframework.scheduling.annotation.EnableAsync +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor +import java.util.concurrent.Executor + +@EnableAsync +@Configuration +class AsyncConfig : AsyncConfigurer { + private val log: Logger = LoggerFactory.getLogger(javaClass) + + override fun getAsyncExecutor(): Executor { + val executor = ThreadPoolTaskExecutor() + executor.corePoolSize = 8 + executor.maxPoolSize = 8 + executor.queueCapacity = 200 + executor.setWaitForTasksToCompleteOnShutdown(true) + executor.setAwaitTerminationSeconds(10) + executor.initialize() + return executor + } + + override fun getAsyncUncaughtExceptionHandler(): AsyncUncaughtExceptionHandler { + return AsyncUncaughtExceptionHandler { e, method, param -> log.error("Exception : {}", e.message, e) } + } +} diff --git a/application/api/src/main/kotlin/io/raemian/api/config/GlobalExceptionHandler.kt b/application/api/src/main/kotlin/io/raemian/api/config/GlobalExceptionHandler.kt index cc0d8090..8df2f48a 100644 --- a/application/api/src/main/kotlin/io/raemian/api/config/GlobalExceptionHandler.kt +++ b/application/api/src/main/kotlin/io/raemian/api/config/GlobalExceptionHandler.kt @@ -1,32 +1,24 @@ package io.raemian.api.config -import io.raemian.api.support.error.CoreApiException +import io.raemian.api.log.LogService import io.raemian.api.support.error.ErrorType import io.raemian.api.support.response.ApiResponse import org.slf4j.Logger import org.slf4j.LoggerFactory -import org.springframework.boot.logging.LogLevel import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.web.bind.annotation.RestControllerAdvice @RestControllerAdvice -class GlobalExceptionHandler { +class GlobalExceptionHandler( + val logService: LogService, +) { private val log: Logger = LoggerFactory.getLogger(javaClass) - @ExceptionHandler(CoreApiException::class) - fun handleCoreApiException(e: CoreApiException): ResponseEntity> { - when (e.errorType.logLevel) { - LogLevel.ERROR -> log.error("CoreApiException : {}", e.message, e) - LogLevel.WARN -> log.warn("CoreApiException : {}", e.message, e) - else -> log.info("CoreApiException : {}", e.message, e) - } - return ResponseEntity(ApiResponse.error(e.errorType, e.data), e.errorType.status) - } - @ExceptionHandler(Exception::class) fun handleException(e: Exception): ResponseEntity> { log.error("Exception : {}", e.message, e) + logService.createSlackErrorLog(e) return ResponseEntity(ApiResponse.error(ErrorType.DEFAULT_ERROR), ErrorType.DEFAULT_ERROR.status) } } diff --git a/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt b/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt index fc76ff99..e0ab4279 100644 --- a/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt +++ b/application/api/src/main/kotlin/io/raemian/api/config/WebSecurityConfig.kt @@ -57,6 +57,7 @@ class WebSecurityConfig( .requestMatchers(AntPathRequestMatcher("/oauth2/**")).permitAll() .requestMatchers(AntPathRequestMatcher("/login/**")).permitAll() .requestMatchers(AntPathRequestMatcher("/one-baily-actuator/**")).permitAll() + .requestMatchers(AntPathRequestMatcher("/log/**")).permitAll() .requestMatchers( AntPathRequestMatcher("/swagger*/**"), AntPathRequestMatcher("/v3/api-docs/**"), diff --git a/application/api/src/main/kotlin/io/raemian/api/log/LogService.kt b/application/api/src/main/kotlin/io/raemian/api/log/LogService.kt new file mode 100644 index 00000000..8640e9d0 --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/log/LogService.kt @@ -0,0 +1,32 @@ +package io.raemian.api.log + +import io.raemian.api.log.controller.request.CreateSlackErrorLogRequest +import io.raemian.infra.logging.enums.ErrorLocationEnum +import io.raemian.infra.logging.logger.SlackLogger +import org.springframework.stereotype.Service + +@Service +class LogService( + val slackLogger: SlackLogger, +) { + + private final val EMPTY_VALUE: String = "EMPTY VALUE" + + fun createSlackErrorLog(createSlackErrorLogRequest: CreateSlackErrorLogRequest) { + slackLogger.error( + createSlackErrorLogRequest.errorLocation, + createSlackErrorLogRequest.appName, + createSlackErrorLogRequest.errormessage, + createSlackErrorLogRequest.userAgent, + createSlackErrorLogRequest.referer, + ) + } + + fun createSlackErrorLog(exception: Exception) { + slackLogger.error( + ErrorLocationEnum.BACKEND_SERVER, + "one-bailey api", + exception.message ?: EMPTY_VALUE, + ) + } +} diff --git a/application/api/src/main/kotlin/io/raemian/api/log/controller/LogController.kt b/application/api/src/main/kotlin/io/raemian/api/log/controller/LogController.kt new file mode 100644 index 00000000..af5dc130 --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/log/controller/LogController.kt @@ -0,0 +1,24 @@ +package io.raemian.api.log.controller + +import io.raemian.api.log.LogService +import io.raemian.api.log.controller.request.CreateSlackErrorLogRequest +import io.swagger.v3.oas.annotations.Operation +import org.springframework.http.ResponseEntity +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("/log") +class LogController( + val logService: LogService, +) { + + @Operation(summary = "Slack Log 생성 API") + @PostMapping("/slack/error") + fun createSlackErrorLog(@RequestBody createSlackErrorLogRequest: CreateSlackErrorLogRequest): ResponseEntity { + logService.createSlackErrorLog(createSlackErrorLogRequest) + return ResponseEntity.noContent().build() + } +} diff --git a/application/api/src/main/kotlin/io/raemian/api/log/controller/request/CreateSlackErrorLogRequest.kt b/application/api/src/main/kotlin/io/raemian/api/log/controller/request/CreateSlackErrorLogRequest.kt new file mode 100644 index 00000000..13118721 --- /dev/null +++ b/application/api/src/main/kotlin/io/raemian/api/log/controller/request/CreateSlackErrorLogRequest.kt @@ -0,0 +1,11 @@ +package io.raemian.api.log.controller.request + +import io.raemian.infra.logging.enums.ErrorLocationEnum + +data class CreateSlackErrorLogRequest( + val errorLocation: ErrorLocationEnum, + val appName: String, + val errormessage: String, + val referer: String?, + val userAgent: String?, +) diff --git a/build.gradle.kts b/build.gradle.kts index 7824576e..27f5f759 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -32,19 +32,16 @@ subprojects { apply(plugin = "org.asciidoctor.jvm.convert") apply(plugin = "org.jlleitschuh.gradle.ktlint") - dependencyManagement { - imports { - mavenBom("org.springframework.cloud:spring-cloud-dependencies:${property("springCloudDependenciesVersion")}") - } - } - dependencies { implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.springframework.boot:spring-boot-gradle-plugin:3.1.5") testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation("com.ninja-squad:springmockk:${property("springMockkVersion")}") annotationProcessor("org.springframework.boot:spring-boot-configuration-processor") + implementation("org.springframework:spring-context") + kapt("org.springframework.boot:spring-boot-configuration-processor") } @@ -66,14 +63,14 @@ subprojects { tasks.test { useJUnitPlatform { - excludeTags("develop", "restdocs") + excludeTags("develop") } } tasks.register("unitTest") { group = "verification" useJUnitPlatform { - excludeTags("develop", "context", "restdocs") + excludeTags("develop", "context") } } @@ -84,13 +81,6 @@ subprojects { } } - tasks.register("restDocsTest") { - group = "verification" - useJUnitPlatform { - includeTags("restdocs") - } - } - tasks.register("developTest") { group = "verification" useJUnitPlatform { @@ -98,10 +88,6 @@ subprojects { } } - tasks.getByName("asciidoctor") { - dependsOn("restDocsTest") - } - configure { debug.set(true) } diff --git a/infra/logging/build.gradle.kts b/infra/logging/build.gradle.kts index 9118a20c..ba819303 100644 --- a/infra/logging/build.gradle.kts +++ b/infra/logging/build.gradle.kts @@ -1,4 +1,8 @@ dependencies { implementation("io.micrometer:micrometer-tracing-bridge-brave") implementation("io.sentry:sentry-logback:${property("sentryVersion")}") + + implementation("com.slack.api:slack-api-model-kotlin-extension:1.36.1") + implementation("com.slack.api:slack-api-client-kotlin-extension:1.36.1") + implementation("com.slack.api:slack-api-client:1.36.1") } diff --git a/infra/logging/src/main/kotlin/io/raemian/infra/logging/enums/ErrorLocationEnum.kt b/infra/logging/src/main/kotlin/io/raemian/infra/logging/enums/ErrorLocationEnum.kt new file mode 100644 index 00000000..d5adde50 --- /dev/null +++ b/infra/logging/src/main/kotlin/io/raemian/infra/logging/enums/ErrorLocationEnum.kt @@ -0,0 +1,18 @@ +package io.raemian.infra.logging.enums + +import com.fasterxml.jackson.annotation.JsonProperty + +enum class ErrorLocationEnum(val value: String) { + @JsonProperty("CL") + CLIENT("CLIENT"), + + @JsonProperty("FS") + FRONTEND_SERVER("FRONTEND SERVER"), + + @JsonProperty("FM") + FRONTEND_MIDDLEWARE("FRONTEND MIDDLEWARE"), + + @JsonProperty("BS") + BACKEND_SERVER("BACKEND SERVER"), + ; +} diff --git a/infra/logging/src/main/kotlin/io/raemian/infra/logging/enums/LogTemplate.kt b/infra/logging/src/main/kotlin/io/raemian/infra/logging/enums/LogTemplate.kt new file mode 100644 index 00000000..378656a9 --- /dev/null +++ b/infra/logging/src/main/kotlin/io/raemian/infra/logging/enums/LogTemplate.kt @@ -0,0 +1,14 @@ +package io.raemian.infra.logging.enums + +enum class LogTemplate(val message: String) { + ERROR_HEADER(":red_circle: [%s] 오류 발생"), + ERROR_MESSAGE("Error Message"), + APP_NAME("*App Name*: %s"), + USERAGENT("*User Agent*: %s"), + REFERER("*Referer*: %s"), + ; + + fun of(vararg value: String?): String { + return this.message.format(*value) + } +} diff --git a/infra/logging/src/main/kotlin/io/raemian/infra/logging/logger/SlackLogger.kt b/infra/logging/src/main/kotlin/io/raemian/infra/logging/logger/SlackLogger.kt new file mode 100644 index 00000000..bcc9605f --- /dev/null +++ b/infra/logging/src/main/kotlin/io/raemian/infra/logging/logger/SlackLogger.kt @@ -0,0 +1,155 @@ +package io.raemian.infra.logging.logger + +import com.slack.api.Slack +import com.slack.api.model.block.Blocks.asBlocks +import com.slack.api.model.block.Blocks.divider +import com.slack.api.model.block.Blocks.header +import com.slack.api.model.block.Blocks.richText +import com.slack.api.model.block.Blocks.section +import com.slack.api.model.block.HeaderBlock +import com.slack.api.model.block.RichTextBlock +import com.slack.api.model.block.SectionBlock +import com.slack.api.model.block.composition.BlockCompositions.markdownText +import com.slack.api.model.block.composition.BlockCompositions.plainText +import com.slack.api.model.block.element.BlockElements.asElements +import com.slack.api.model.block.element.BlockElements.asRichTextElements +import com.slack.api.model.block.element.BlockElements.richTextPreformatted +import com.slack.api.model.block.element.BlockElements.richTextSection +import com.slack.api.model.block.element.RichTextSectionElement.Text +import com.slack.api.model.block.element.RichTextSectionElement.TextStyle +import com.slack.api.webhook.Payload.PayloadBuilder +import com.slack.api.webhook.WebhookPayloads.payload +import io.raemian.infra.logging.enums.ErrorLocationEnum +import io.raemian.infra.logging.enums.LogTemplate +import io.raemian.infra.logging.enums.LogTemplate.APP_NAME +import io.raemian.infra.logging.enums.LogTemplate.ERROR_HEADER +import io.raemian.infra.logging.enums.LogTemplate.ERROR_MESSAGE +import io.raemian.infra.logging.enums.LogTemplate.REFERER +import io.raemian.infra.logging.enums.LogTemplate.USERAGENT +import org.springframework.beans.factory.annotation.Value +import org.springframework.scheduling.annotation.Async +import org.springframework.stereotype.Component + +@Component +class SlackLogger( + private val slack: Slack = Slack.getInstance(), +) { + @Value("\${slack.webhook.url}") + private lateinit var url: String + + @Async + fun error( + errorLocation: ErrorLocationEnum, + appName: String, + errorMessage: String = "EMPTY VALUE", + userAgent: String? = "", + referer: String? = "", + ) { + when (errorLocation) { + ErrorLocationEnum.CLIENT -> clientError(errorLocation, appName, errorMessage, userAgent, referer) + else -> defaultError(errorLocation, appName, errorMessage) + } + } + + private fun clientError( + errorLocation: ErrorLocationEnum, + appName: String, + errorMessage: String, + userAgent: String?, + referer: String?, + ) { + slack.send( + url, + payload { p: PayloadBuilder -> + p.text(LogTemplate.ERROR_HEADER.of(errorLocation.value)) + .blocks( + asBlocks( + createHeaderBlock(errorLocation), + divider(), + createAppNameBlock(appName), + createUserAgentBlock(userAgent), + createRefererBlock(referer), + createErrorMessageBlock(errorMessage), + divider(), + + ), + ) + }, + ) + } + + private fun defaultError( + errorLocation: ErrorLocationEnum, + errorMessage: String, + appName: String, + ) { + slack.send( + url, + payload { p: PayloadBuilder -> + p.text(ERROR_HEADER.of(errorLocation.value)) + .blocks( + asBlocks( + createHeaderBlock(errorLocation), + divider(), + createAppNameBlock(appName), + createErrorMessageBlock(errorMessage), + divider(), + ), + ) + }, + ) + } + + private fun createHeaderBlock(errorLocation: ErrorLocationEnum): HeaderBlock { + return header { header -> + header.text(plainText(ERROR_HEADER.of(errorLocation.value))) + } + } + + private fun createAppNameBlock(appName: String): SectionBlock { + return section { section: SectionBlock.SectionBlockBuilder -> + section.text( + markdownText(APP_NAME.of(appName)), + ) + } + } + + private fun createUserAgentBlock(userAgent: String?): SectionBlock { + return section { section: SectionBlock.SectionBlockBuilder -> + section.text( + markdownText(USERAGENT.of(userAgent)), + ) + } + } + + private fun createRefererBlock(referer: String?): SectionBlock { + return section { section: SectionBlock.SectionBlockBuilder -> + section.text( + markdownText(REFERER.of(referer)), + ) + } + } + + private fun createErrorMessageBlock(errorMessage: String): RichTextBlock { + return richText { richText -> + richText.elements( + asElements( + richTextSection { section -> + section.elements( + asRichTextElements( + Text.builder().text(ERROR_MESSAGE.message).style(TextStyle.builder().bold(true).build()).build(), + ), + ) + }, + richTextPreformatted { section -> + section.elements( + asRichTextElements( + Text.builder().text(errorMessage).build(), + ), + ) + }, + ), + ) + } + } +} diff --git a/infra/logging/src/main/resources/application-logging.yml b/infra/logging/src/main/resources/application-logging.yml index e98d258d..b46c9836 100644 --- a/infra/logging/src/main/resources/application-logging.yml +++ b/infra/logging/src/main/resources/application-logging.yml @@ -2,12 +2,22 @@ spring.config.activate.on-profile: local logging.config: classpath:logback/logback-local.xml +slack: + webhook: + url: ${SLACK-WEBHOOK-URL:EMPTY} --- # dev spring.config.activate.on-profile: dev logging.config: classpath:logback/logback-dev.xml +slack: + webhook: + url: ${SLACK-WEBHOOK-URL:EMPTY} --- # live spring.config.activate.on-profile: live -logging.config: classpath:logback/logback-live.xml \ No newline at end of file +logging.config: classpath:logback/logback-live.xml + +slack: + webhook: + url: ${SLACK-WEBHOOK-URL:EMPTY} \ No newline at end of file From 5e6ab44cf857f0131e6d39907ac567cdeee14dc5 Mon Sep 17 00:00:00 2001 From: wkwon Date: Sun, 24 Dec 2023 23:32:45 +0900 Subject: [PATCH 66/70] =?UTF-8?q?fix:=20Slack=20Logger=20defaultError()=20?= =?UTF-8?q?=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EC=88=9C=EC=84=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/io/raemian/infra/logging/logger/SlackLogger.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/logging/src/main/kotlin/io/raemian/infra/logging/logger/SlackLogger.kt b/infra/logging/src/main/kotlin/io/raemian/infra/logging/logger/SlackLogger.kt index bcc9605f..8a793594 100644 --- a/infra/logging/src/main/kotlin/io/raemian/infra/logging/logger/SlackLogger.kt +++ b/infra/logging/src/main/kotlin/io/raemian/infra/logging/logger/SlackLogger.kt @@ -80,8 +80,8 @@ class SlackLogger( private fun defaultError( errorLocation: ErrorLocationEnum, - errorMessage: String, appName: String, + errorMessage: String, ) { slack.send( url, From 0651fd5756c114785faaa1ea68cd56b225967ba4 Mon Sep 17 00:00:00 2001 From: binary_ho Date: Tue, 26 Dec 2023 17:33:13 +0900 Subject: [PATCH 67/70] =?UTF-8?q?Goal=20Serivce,=20CustomLocalDate=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=B3=B4=EC=B6=A9=20(#42)=20(#55?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test : Goal 생성, 삭제 테스트 코드 작성 (#42) * test : RaemianLocalDate Test 코드 작성 (#42) * chore : ktlint Test Source Set Formatting (#42) * resolve conflict with develop (#42) --- .../api/integration/goal/GoalServiceTest.kt | 115 ++++++++++++++++++ .../api/integration/task/TaskServiceTest.kt | 2 +- .../api/support/RaemianLocalDateTest.kt | 78 ++++++++++++ 3 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt create mode 100644 application/api/src/test/kotlin/io/raemian/api/support/RaemianLocalDateTest.kt diff --git a/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt b/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt new file mode 100644 index 00000000..100d146a --- /dev/null +++ b/application/api/src/test/kotlin/io/raemian/api/integration/goal/GoalServiceTest.kt @@ -0,0 +1,115 @@ +package io.raemian.api.integration.goal + +import io.raemian.api.goal.GoalService +import io.raemian.api.goal.controller.request.CreateGoalRequest +import io.raemian.storage.db.core.goal.Goal +import io.raemian.storage.db.core.goal.GoalRepository +import io.raemian.storage.db.core.sticker.Sticker +import io.raemian.storage.db.core.tag.Tag +import io.raemian.storage.db.core.user.Authority +import io.raemian.storage.db.core.user.User +import io.raemian.storage.db.core.user.enums.OAuthProvider +import jakarta.persistence.EntityManager +import org.assertj.core.api.Assertions +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Assertions.assertAll +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.function.Executable +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.transaction.annotation.Transactional +import java.time.LocalDate + +@SpringBootTest +@Transactional +class GoalServiceTest { + + companion object { + val USER_FIXTURE = User( + email = "dfghcvb111@naver.com", + userName = "binaryHoHo", + nickname = "binaryHoHoHo", + birth = LocalDate.MIN, + image = "", + provider = OAuthProvider.NAVER, + authority = Authority.ROLE_USER, + ) + + val STICKER_FIXTURE = Sticker("sticker", "image yeah") + val TAG_FIXTURE = Tag("꿈") + } + + @Autowired + private lateinit var goalService: GoalService + + @Autowired + private lateinit var goalRepository: GoalRepository + + @Autowired + private lateinit var entityManager: EntityManager + + @BeforeEach + fun saveEntities() { + entityManager.merge(USER_FIXTURE) + entityManager.merge(STICKER_FIXTURE) + entityManager.merge(TAG_FIXTURE) + } + + @Test + @DisplayName("Goal을 생성할 수 있다.") + fun createGoalTest() { + val createGoalRequest = CreateGoalRequest( + title = "title", + description = "description", + stickerId = STICKER_FIXTURE.id!!, + tagId = TAG_FIXTURE.id!!, + yearOfDeadline = "2023", + monthOfDeadline = "12", + ) + + val createResponse = goalService.create( + USER_FIXTURE.id!!, + createGoalRequest, + ) + + val goal = goalRepository.getById(createResponse.id) + assertAll( + Executable { + Assertions.assertThat(goal.title).isEqualTo(createGoalRequest.title) + Assertions.assertThat(goal.description).isEqualTo(createGoalRequest.description) + Assertions.assertThat(goal.sticker.id).isEqualTo(createGoalRequest.stickerId) + Assertions.assertThat(goal.tag.id).isEqualTo(createGoalRequest.tagId) + Assertions.assertThat(goal.deadline.year.toString()) + .isEqualTo(createGoalRequest.yearOfDeadline) + Assertions.assertThat(goal.deadline.monthValue.toString()) + .isEqualTo(createGoalRequest.monthOfDeadline) + }, + ) + } + + @Test + @DisplayName("Goal을 삭제할 수 있다.") + @Transactional + fun deleteGoalTest() { + // given + val goal = Goal( + user = USER_FIXTURE, + title = "title", + description = "", + deadline = LocalDate.now(), + sticker = STICKER_FIXTURE, + tag = TAG_FIXTURE, + tasks = emptyList(), + ) + + goalRepository.save(goal) + + // when + goalService.delete(USER_FIXTURE.id!!, goal.id!!) + + // then + assertThat(goalRepository.findById(goal.id!!).isEmpty).isTrue() + } +} diff --git a/application/api/src/test/kotlin/io/raemian/api/integration/task/TaskServiceTest.kt b/application/api/src/test/kotlin/io/raemian/api/integration/task/TaskServiceTest.kt index a9c7f870..26f7c4d1 100644 --- a/application/api/src/test/kotlin/io/raemian/api/integration/task/TaskServiceTest.kt +++ b/application/api/src/test/kotlin/io/raemian/api/integration/task/TaskServiceTest.kt @@ -155,6 +155,6 @@ class TaskServiceTest { // then val task = taskRepository.findById(newTask.id!!) - assertThat(task.isEmpty).isEqualTo(true) + assertThat(task.isEmpty).isTrue() } } diff --git a/application/api/src/test/kotlin/io/raemian/api/support/RaemianLocalDateTest.kt b/application/api/src/test/kotlin/io/raemian/api/support/RaemianLocalDateTest.kt new file mode 100644 index 00000000..1dbcbf8d --- /dev/null +++ b/application/api/src/test/kotlin/io/raemian/api/support/RaemianLocalDateTest.kt @@ -0,0 +1,78 @@ +package io.raemian.api.support + +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatThrownBy +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource +import java.time.LocalDate + +class RaemianLocalDateTest { + + @Test + @DisplayName("RaemianLocalDate를 통해 연도와 날짜 string으로 LocalDate를 만들 수 있다.") + fun createRaemianLocalDateTest() { + // given + val year = "2023" + val month = "11" + + // when + val localDate = RaemianLocalDate.of(year, month) + + // then + assertThat(localDate.year.toString()).isEqualTo(year) + assertThat(localDate.monthValue.toString()).isEqualTo(month) + } + + @Test + @DisplayName("RaemianLocalDate를 통해 생성된 LocalDate의 날짜가 모두 같다.") + fun createRaemianLocalDateFixedDayTest() { + // given + val year1 = (1..2024).random().toString() + val month1 = (1..12).random().toString() + + val year2 = (1..2024).random().toString() + val month2 = (1..12).random().toString() + + // when + val localDate1 = RaemianLocalDate.of(year1, month1) + val localDate2 = RaemianLocalDate.of(year2, month2) + + // then + assertThat(localDate1.dayOfMonth).isEqualTo(localDate2.dayOfMonth) + } + + @DisplayName("RaemianLocalDate를 통해 생성된 LocalDate생성시 연도나 월의 형식이 잘못 되면 예외가 발생한다.") + @ParameterizedTest + @ValueSource(strings = ["13", "-1", "abcdabcd", "331er"]) + fun createRaemianLocalDateOutOfBoundTest(yearAndMonth: String) { + // given + // when + // then + assertThatThrownBy { + RaemianLocalDate.of(yearAndMonth, yearAndMonth) + }.isInstanceOf(RuntimeException::class.java) + } + + @Test + @DisplayName("LocalDate Format을 'YYYY.MM'로 변환할 수 있다.") + fun localDateFormattingTest() { + // given + val localDate = LocalDate.now() + + // when + val formattedLocalDate = localDate.format() + + // then + val year = localDate.year.toString() + var month = localDate.monthValue.toString() + if (month.length == 1) { + month = "0$month" + } + + val expectedLocalDate = "$year.$month" + + assertThat(formattedLocalDate).isEqualTo(expectedLocalDate) + } +} From 65c2d1febf9b129499b9c27b14ddcd2c2ef884da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=EC=9A=B0=EC=84=9D=20=28Woosuk=20Kwon=29?= Date: Wed, 27 Dec 2023 14:59:21 +0900 Subject: [PATCH 68/70] =?UTF-8?q?fix(#65):=20swagger=20=EC=84=9C=EB=B2=84?= =?UTF-8?q?=20url=20=EA=B0=92=20=ED=99=98=EA=B2=BD=20=EB=B3=80=EC=88=98?= =?UTF-8?q?=EB=A1=9C=20=EB=B9=BC=EA=B8=B0=20(#66)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/raemian/api/config/SpringdocConfig.kt | 41 +++++++++++-------- .../api/src/main/resources/application.yml | 6 +++ .../api/src/test/resources/application.yml | 17 ++++---- 3 files changed, 38 insertions(+), 26 deletions(-) diff --git a/application/api/src/main/kotlin/io/raemian/api/config/SpringdocConfig.kt b/application/api/src/main/kotlin/io/raemian/api/config/SpringdocConfig.kt index bd313051..fc0aad83 100644 --- a/application/api/src/main/kotlin/io/raemian/api/config/SpringdocConfig.kt +++ b/application/api/src/main/kotlin/io/raemian/api/config/SpringdocConfig.kt @@ -1,35 +1,40 @@ package io.raemian.api.config -import io.swagger.v3.oas.annotations.OpenAPIDefinition -import io.swagger.v3.oas.annotations.info.Info -import io.swagger.v3.oas.annotations.servers.Server import io.swagger.v3.oas.models.Components import io.swagger.v3.oas.models.OpenAPI +import io.swagger.v3.oas.models.info.Info import io.swagger.v3.oas.models.security.SecurityRequirement import io.swagger.v3.oas.models.security.SecurityScheme +import io.swagger.v3.oas.models.servers.Server +import org.springframework.beans.factory.annotation.Value import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration -@OpenAPIDefinition( - servers = arrayOf(Server(url = "https://www.one-bailey.o-r.kr/api")), - info = Info( - title = "BANDIBOODI API 명세", - description = "BANDIBOODI 메인/어드밍 API 명세서", - version = "v1.0.0", - ), -) @Configuration class SpringdocConfig { + @Value("\${springdoc.server.url}") + private lateinit var url: String + @Bean fun openAPI(): OpenAPI { - val securityScheme: SecurityScheme = SecurityScheme() - .type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT") - .`in`(SecurityScheme.In.HEADER).name("Authorization") - val securityRequirement: SecurityRequirement = SecurityRequirement().addList("bearerAuth") - return OpenAPI() - .components(Components().addSecuritySchemes("bearerAuth", securityScheme)) - .security(listOf(securityRequirement)) + .components(Components().addSecuritySchemes("bearerAuth", apiSecurityScheme())) + .security(apiSecurityRequirementList()) + .info(apiInfo()) + .servers(listOf(apiServer())) } + + private fun apiInfo() = Info() + .title("BANDIBOODI API 명세") + .description("BANDIBOODI 메인/어드밍 API 명세서") + .version("v1.0.0") + + private fun apiServer() = Server().url(url) + + private fun apiSecurityScheme() = SecurityScheme() + .type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT") + .`in`(SecurityScheme.In.HEADER).name("Authorization") + + private fun apiSecurityRequirementList() = listOf(SecurityRequirement().addList("bearerAuth")) } diff --git a/application/api/src/main/resources/application.yml b/application/api/src/main/resources/application.yml index fde49d19..22326240 100644 --- a/application/api/src/main/resources/application.yml +++ b/application/api/src/main/resources/application.yml @@ -10,6 +10,12 @@ spring: server: servlet: context-path: /api + + +springdoc: + server: + url: ${SPRINGDOC-SERVER-URL:http://localhost:8080/api} + --- # local spring: diff --git a/application/api/src/test/resources/application.yml b/application/api/src/test/resources/application.yml index 59e338e1..22326240 100644 --- a/application/api/src/test/resources/application.yml +++ b/application/api/src/test/resources/application.yml @@ -7,13 +7,14 @@ spring: mvc.throw-exception-if-no-handler-found: true web.resources.add-mappings: false - jpa: - hibernate: - ddl-auto: create - database-platform: org.hibernate.dialect.H2Dialect - properties: - hibernate: - format_sql: true +server: + servlet: + context-path: /api + + +springdoc: + server: + url: ${SPRINGDOC-SERVER-URL:http://localhost:8080/api} --- # local @@ -46,4 +47,4 @@ spring: - security - db-core - logging - - metrics + - metrics \ No newline at end of file From dd9d68e5e166c28d219ef8eca028db67dbde9653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=EC=9A=B0=EC=84=9D=20=28Woosuk=20Kwon=29?= Date: Thu, 4 Jan 2024 23:25:35 +0900 Subject: [PATCH 69/70] =?UTF-8?q?[Feature]=20Admin=20Api=20=EA=B0=9C?= =?UTF-8?q?=EB=B0=9C=20(#68)=20(#74)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feature(#68): admin api 초기 세팅 * feature(#68): tag crud api * feature(#68): sticker crud 개발 * fix(#68): admin-api / api Dockerfile 분리 및 Github Action docker build 파트 Dockerfile path 설정 * feature(#68): admin api용 github action 추가 * fix(#68): docker build -f 옵션 추가 * fix(#68): module 명 변경 (admin-api -> admin) * fix(#68): tag findall method 블록 제거 * fix: apply lint --- .github/workflows/admin-api-ci-cd.yml | 41 +++++++++ .../workflows/{ci-cd.yml => api-ci-cd.yml} | 6 +- application/admin/Dockerfile | 4 + application/admin/build.gradle.kts | 17 ++++ .../kotlin/io/raemian/AdminApplication.kt | 13 +++ .../admin/config/GlobalExceptionHandler.kt | 27 ++++++ .../raemian/admin/config/SpringdocConfig.kt | 29 +++++++ .../raemian/admin/sticker/StickerService.kt | 84 +++++++++++++++++++ .../sticker/controller/StickerController.kt | 64 ++++++++++++++ .../request/CreateStickerRequest.kt | 9 ++ .../request/UpdateStickerRequest.kt | 8 ++ .../controller/response/StickerResponse.kt | 22 +++++ .../admin/support/error/CoreApiException.kt | 9 ++ .../raemian/admin/support/error/ErrorCode.kt | 5 ++ .../admin/support/error/ErrorMessage.kt | 23 +++++ .../raemian/admin/support/error/ErrorType.kt | 11 +++ .../admin/support/response/ApiResponse.kt | 24 ++++++ .../admin/support/response/ResultType.kt | 5 ++ .../kotlin/io/raemian/admin/tag/TagService.kt | 42 ++++++++++ .../admin/tag/controller/TagController.kt | 57 +++++++++++++ .../controller/request/CreateTagRequest.kt | 9 ++ .../controller/request/UpdateTagRequest.kt | 5 ++ .../tag/controller/response/TagResponse.kt | 22 +++++ .../admin/src/main/resources/application.yml | 44 ++++++++++ .../io/raemian/AdminApiApplicationTests.kt | 12 +++ Dockerfile => application/api/Dockerfile | 0 .../io/raemian/api/config/SpringdocConfig.kt | 2 +- settings.gradle.kts | 2 + .../storage/db/core/sticker/Sticker.kt | 14 +++- .../io/raemian/storage/db/core/tag/Tag.kt | 8 +- .../storage/db/core/tag/TagRepository.kt | 2 + storage/image/build.gradle.kts | 2 + .../raemian/image/enums/FileExtensionType.kt | 7 ++ .../image/repository/ImageRepository.kt | 76 +++++++++++++++++ .../src/main/resources/application-image.yml | 16 ++++ 35 files changed, 713 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/admin-api-ci-cd.yml rename .github/workflows/{ci-cd.yml => api-ci-cd.yml} (84%) create mode 100644 application/admin/Dockerfile create mode 100644 application/admin/build.gradle.kts create mode 100644 application/admin/src/main/kotlin/io/raemian/AdminApplication.kt create mode 100644 application/admin/src/main/kotlin/io/raemian/admin/config/GlobalExceptionHandler.kt create mode 100644 application/admin/src/main/kotlin/io/raemian/admin/config/SpringdocConfig.kt create mode 100644 application/admin/src/main/kotlin/io/raemian/admin/sticker/StickerService.kt create mode 100644 application/admin/src/main/kotlin/io/raemian/admin/sticker/controller/StickerController.kt create mode 100644 application/admin/src/main/kotlin/io/raemian/admin/sticker/controller/request/CreateStickerRequest.kt create mode 100644 application/admin/src/main/kotlin/io/raemian/admin/sticker/controller/request/UpdateStickerRequest.kt create mode 100644 application/admin/src/main/kotlin/io/raemian/admin/sticker/controller/response/StickerResponse.kt create mode 100644 application/admin/src/main/kotlin/io/raemian/admin/support/error/CoreApiException.kt create mode 100644 application/admin/src/main/kotlin/io/raemian/admin/support/error/ErrorCode.kt create mode 100644 application/admin/src/main/kotlin/io/raemian/admin/support/error/ErrorMessage.kt create mode 100644 application/admin/src/main/kotlin/io/raemian/admin/support/error/ErrorType.kt create mode 100644 application/admin/src/main/kotlin/io/raemian/admin/support/response/ApiResponse.kt create mode 100644 application/admin/src/main/kotlin/io/raemian/admin/support/response/ResultType.kt create mode 100644 application/admin/src/main/kotlin/io/raemian/admin/tag/TagService.kt create mode 100644 application/admin/src/main/kotlin/io/raemian/admin/tag/controller/TagController.kt create mode 100644 application/admin/src/main/kotlin/io/raemian/admin/tag/controller/request/CreateTagRequest.kt create mode 100644 application/admin/src/main/kotlin/io/raemian/admin/tag/controller/request/UpdateTagRequest.kt create mode 100644 application/admin/src/main/kotlin/io/raemian/admin/tag/controller/response/TagResponse.kt create mode 100644 application/admin/src/main/resources/application.yml create mode 100644 application/admin/src/test/kotlin/io/raemian/AdminApiApplicationTests.kt rename Dockerfile => application/api/Dockerfile (100%) create mode 100644 storage/image/build.gradle.kts create mode 100644 storage/image/src/main/kotlin/io/raemian/image/enums/FileExtensionType.kt create mode 100644 storage/image/src/main/kotlin/io/raemian/image/repository/ImageRepository.kt create mode 100644 storage/image/src/main/resources/application-image.yml diff --git a/.github/workflows/admin-api-ci-cd.yml b/.github/workflows/admin-api-ci-cd.yml new file mode 100644 index 00000000..1ec9a974 --- /dev/null +++ b/.github/workflows/admin-api-ci-cd.yml @@ -0,0 +1,41 @@ +name: Admin CI/CD + +on: + push: + branches: [ "develop" ] + paths-ignore: + - 'application/api/**' # application/api 폴더 내의 변화 무시 + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: setup jdk 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + + - name: build with gradle + run: ./gradlew bootJar + + - name: push to dockerhub + run: | + docker login -u ${{ secrets.DOCKER_ID }} -p ${{ secrets.DOCKER_PASSWORD }} + docker build --no-cache -t ${{ secrets.DOCKER_ID }}/${{ secrets.DOCKER_REPO }} -f ./application/admin/Dockerfile . + docker push ${{ secrets.DOCKER_ID }}/${{ secrets.DOCKER_ADMIN_REPO }} + - name: deploy + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.SSH_HOST }} + port: ${{ secrets.SSH_PORT }} + username: ${{ secrets.SSH_USERNAME }} + password: ${{ secrets.SSH_PASSWORD }} + script: | + ${{ secrets.SSH_SCRIPT_FOR_ADMIN }} \ No newline at end of file diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/api-ci-cd.yml similarity index 84% rename from .github/workflows/ci-cd.yml rename to .github/workflows/api-ci-cd.yml index 79dcc5dc..5b89e99c 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/api-ci-cd.yml @@ -1,8 +1,10 @@ -name: Java CI with Gradle +name: Api CI/CD on: push: branches: [ "develop" ] + paths-ignore: + - 'application/admin/**' # application/admin 폴더 내의 변화 무시 permissions: contents: read @@ -26,7 +28,7 @@ jobs: - name: push to dockerhub run: | docker login -u ${{ secrets.DOCKER_ID }} -p ${{ secrets.DOCKER_PASSWORD }} - docker build --no-cache -t ${{ secrets.DOCKER_ID }}/${{ secrets.DOCKER_REPO }} . + docker build --no-cache -t ${{ secrets.DOCKER_ID }}/${{ secrets.DOCKER_REPO }} -f ./application/api/Dockerfile . docker push ${{ secrets.DOCKER_ID }}/${{ secrets.DOCKER_REPO }} - name: deploy uses: appleboy/ssh-action@master diff --git a/application/admin/Dockerfile b/application/admin/Dockerfile new file mode 100644 index 00000000..2fea9f54 --- /dev/null +++ b/application/admin/Dockerfile @@ -0,0 +1,4 @@ +FROM --platform=linux/amd64 openjdk:17-jdk-slim +EXPOSE 7000 +COPY application/admin/build/libs/*.jar app.jar +ENTRYPOINT ["java","-jar","/app.jar"] \ No newline at end of file diff --git a/application/admin/build.gradle.kts b/application/admin/build.gradle.kts new file mode 100644 index 00000000..8636108e --- /dev/null +++ b/application/admin/build.gradle.kts @@ -0,0 +1,17 @@ +tasks.getByName("bootJar") { + enabled = true +} + +tasks.getByName("jar") { + enabled = false +} + +dependencies { + implementation(project(":storage:db-core")) + implementation(project(":storage:image")) + + implementation("org.springframework.boot:spring-boot-starter-web") + + /* swagger */ + implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0") +} diff --git a/application/admin/src/main/kotlin/io/raemian/AdminApplication.kt b/application/admin/src/main/kotlin/io/raemian/AdminApplication.kt new file mode 100644 index 00000000..cee85eb5 --- /dev/null +++ b/application/admin/src/main/kotlin/io/raemian/AdminApplication.kt @@ -0,0 +1,13 @@ +package io.raemian + +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.context.properties.ConfigurationPropertiesScan +import org.springframework.boot.runApplication + +@ConfigurationPropertiesScan +@SpringBootApplication +class AdminApplication + +fun main(args: Array) { + runApplication(*args) +} diff --git a/application/admin/src/main/kotlin/io/raemian/admin/config/GlobalExceptionHandler.kt b/application/admin/src/main/kotlin/io/raemian/admin/config/GlobalExceptionHandler.kt new file mode 100644 index 00000000..268e532c --- /dev/null +++ b/application/admin/src/main/kotlin/io/raemian/admin/config/GlobalExceptionHandler.kt @@ -0,0 +1,27 @@ +package io.raemian.admin.config + +import io.raemian.admin.support.error.CoreApiException +import io.raemian.admin.support.error.ErrorType +import io.raemian.admin.support.response.ApiResponse +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.ExceptionHandler +import org.springframework.web.bind.annotation.RestControllerAdvice + +@RestControllerAdvice +class GlobalExceptionHandler { + private val log: Logger = LoggerFactory.getLogger(javaClass) + + @ExceptionHandler(CoreApiException::class) + fun handleCoreApiException(e: CoreApiException): ResponseEntity> { + log.error("Exception : {}", e.message, e) + return ResponseEntity(ApiResponse.error(e.errorType), e.errorType.status) + } + + @ExceptionHandler(Exception::class) + fun handleException(e: Exception): ResponseEntity> { + log.error("Exception : {}", e.message, e) + return ResponseEntity(ApiResponse.error(ErrorType.DEFAULT_ERROR, e), ErrorType.DEFAULT_ERROR.status) + } +} diff --git a/application/admin/src/main/kotlin/io/raemian/admin/config/SpringdocConfig.kt b/application/admin/src/main/kotlin/io/raemian/admin/config/SpringdocConfig.kt new file mode 100644 index 00000000..ea6685e8 --- /dev/null +++ b/application/admin/src/main/kotlin/io/raemian/admin/config/SpringdocConfig.kt @@ -0,0 +1,29 @@ +package io.raemian.admin.config + +import io.swagger.v3.oas.models.OpenAPI +import io.swagger.v3.oas.models.info.Info +import io.swagger.v3.oas.models.servers.Server +import org.springframework.beans.factory.annotation.Value +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +@Configuration +class SpringdocConfig { + + @Value("\${springdoc.server.url}") + private lateinit var url: String + + @Bean + fun openAPI(): OpenAPI { + return OpenAPI() + .info(apiInfo()) + .servers(listOf(apiServer())) + } + + private fun apiInfo() = Info() + .title("BANDIBOODI Admin API 명세") + .description("BANDIBOODI Admin API 명세서") + .version("v1.0.0") + + private fun apiServer() = Server().url(url) +} diff --git a/application/admin/src/main/kotlin/io/raemian/admin/sticker/StickerService.kt b/application/admin/src/main/kotlin/io/raemian/admin/sticker/StickerService.kt new file mode 100644 index 00000000..d1b1024f --- /dev/null +++ b/application/admin/src/main/kotlin/io/raemian/admin/sticker/StickerService.kt @@ -0,0 +1,84 @@ +package io.raemian.admin.sticker + +import io.raemian.admin.sticker.controller.request.CreateStickerRequest +import io.raemian.admin.sticker.controller.request.UpdateStickerRequest +import io.raemian.admin.sticker.controller.response.StickerResponse +import io.raemian.admin.support.error.CoreApiException +import io.raemian.admin.support.error.ErrorType +import io.raemian.image.enums.FileExtensionType +import io.raemian.image.repository.ImageRepository +import io.raemian.storage.db.core.sticker.Sticker +import io.raemian.storage.db.core.sticker.StickerRepository +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional + +@Service +class StickerService( + private val stickerRepository: StickerRepository, + private val imageRepository: ImageRepository, +) { + + @Transactional + fun create( + createStickerRequest: CreateStickerRequest, + ): StickerResponse { + val fileName = validateFileName(createStickerRequest.image.originalFilename) + + val url = imageRepository.upload(fileName, createStickerRequest.image.inputStream) + + val stickers = stickerRepository.save(Sticker(createStickerRequest.name, url)) + + return StickerResponse.from(stickers) + } + + @Transactional(readOnly = true) + fun findAll(): List = + stickerRepository.findAll().map(::StickerResponse) + + @Transactional + fun update( + stickerId: Long, + updateStickerRequest: UpdateStickerRequest, + ): StickerResponse { + val newFileName = validateFileName(updateStickerRequest.image.originalFilename) + + val stickers = stickerRepository.getById(stickerId) + + val url = imageRepository.update( + newFileName, + splitFileNameFromUrl(stickers.url), + updateStickerRequest.image.inputStream, + ) + + val updatedStickers = stickerRepository.save(Sticker(updateStickerRequest.name, url)) + + return StickerResponse.from(stickers) + } + + @Transactional + fun delete( + stickerId: Long, + ) { + val stickers = stickerRepository.getById(stickerId) + + imageRepository.delete(splitFileNameFromUrl(stickers.url)) + + stickerRepository.delete(stickers) + } + + private fun splitFileNameFromUrl(url: String): String { + return url.split("/").last() + } + + private fun validateFileName(fileName: String?): String { + if (fileName.isNullOrBlank()) { + throw CoreApiException(ErrorType.NO_IMAGE_NAME_ERROR) + } + + if (!fileName.endsWith(FileExtensionType.PNG.value)) { + throw CoreApiException(ErrorType.NO_PNG_FILE_ERROR) + } + + return fileName + } +} diff --git a/application/admin/src/main/kotlin/io/raemian/admin/sticker/controller/StickerController.kt b/application/admin/src/main/kotlin/io/raemian/admin/sticker/controller/StickerController.kt new file mode 100644 index 00000000..2979b260 --- /dev/null +++ b/application/admin/src/main/kotlin/io/raemian/admin/sticker/controller/StickerController.kt @@ -0,0 +1,64 @@ +package io.raemian.admin.sticker.controller + +import io.raemian.admin.sticker.StickerService +import io.raemian.admin.sticker.controller.request.CreateStickerRequest +import io.raemian.admin.sticker.controller.request.UpdateStickerRequest +import io.raemian.admin.sticker.controller.response.StickerResponse +import io.raemian.admin.support.response.ApiResponse +import io.swagger.v3.oas.annotations.Operation +import org.springframework.http.MediaType +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.ModelAttribute +import org.springframework.web.bind.annotation.PatchMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import java.net.URI + +fun String.toUri(): URI = URI.create(this) + +@RestController +@RequestMapping("/sticker") +class StickerController( + private val stickerService: StickerService, +) { + + @Operation(summary = "스티커 생성 API") + @PostMapping(consumes = arrayOf(MediaType.MULTIPART_FORM_DATA_VALUE), produces = arrayOf(MediaType.APPLICATION_JSON_VALUE)) + fun create( + @ModelAttribute createStickerRequest: CreateStickerRequest, + ): ResponseEntity> { + val response = stickerService.create(createStickerRequest) + + return ResponseEntity + .created("/sticker/${response.id}".toUri()) + .body(ApiResponse.success(response)) + } + + @Operation(summary = "스티커 전체 조회 API") + @GetMapping + fun findAll(): ResponseEntity>> = + ResponseEntity.ok(ApiResponse.success(stickerService.findAll())) + + @Operation(summary = "스티커 수정 API") + @PatchMapping("/{stickerId}", consumes = arrayOf(MediaType.MULTIPART_FORM_DATA_VALUE), produces = arrayOf(MediaType.APPLICATION_JSON_VALUE)) + fun update( + @PathVariable stickerId: Long, + @ModelAttribute updateStickerRequest: UpdateStickerRequest, + ): ResponseEntity { + stickerService.update(stickerId, updateStickerRequest) + return ResponseEntity.ok().build() + } + + @Operation(summary = "스티커 삭제 API") + @DeleteMapping("/{stickerId}") + fun delete( + @PathVariable stickerId: Long, + ): ResponseEntity { + stickerService.delete(stickerId) + return ResponseEntity.noContent().build() + } +} diff --git a/application/admin/src/main/kotlin/io/raemian/admin/sticker/controller/request/CreateStickerRequest.kt b/application/admin/src/main/kotlin/io/raemian/admin/sticker/controller/request/CreateStickerRequest.kt new file mode 100644 index 00000000..7be3109d --- /dev/null +++ b/application/admin/src/main/kotlin/io/raemian/admin/sticker/controller/request/CreateStickerRequest.kt @@ -0,0 +1,9 @@ +package io.raemian.admin.sticker.controller.request + +import org.springframework.web.multipart.MultipartFile +import java.io.Serializable + +data class CreateStickerRequest( + val name: String, + val image: MultipartFile, +) : Serializable diff --git a/application/admin/src/main/kotlin/io/raemian/admin/sticker/controller/request/UpdateStickerRequest.kt b/application/admin/src/main/kotlin/io/raemian/admin/sticker/controller/request/UpdateStickerRequest.kt new file mode 100644 index 00000000..91a499a0 --- /dev/null +++ b/application/admin/src/main/kotlin/io/raemian/admin/sticker/controller/request/UpdateStickerRequest.kt @@ -0,0 +1,8 @@ +package io.raemian.admin.sticker.controller.request + +import org.springframework.web.multipart.MultipartFile + +data class UpdateStickerRequest( + val name: String, + val image: MultipartFile, +) diff --git a/application/admin/src/main/kotlin/io/raemian/admin/sticker/controller/response/StickerResponse.kt b/application/admin/src/main/kotlin/io/raemian/admin/sticker/controller/response/StickerResponse.kt new file mode 100644 index 00000000..d1730f96 --- /dev/null +++ b/application/admin/src/main/kotlin/io/raemian/admin/sticker/controller/response/StickerResponse.kt @@ -0,0 +1,22 @@ +package io.raemian.admin.sticker.controller.response + +import io.raemian.storage.db.core.sticker.Sticker + +data class StickerResponse( + val id: Long?, + val name: String, + val url: String, +) { + + constructor(sticker: Sticker) : this( + sticker.id, + sticker.name, + sticker.url, + ) + + companion object { + fun from(entity: Sticker): StickerResponse { + return StickerResponse(entity.id, entity.name, entity.url) + } + } +} diff --git a/application/admin/src/main/kotlin/io/raemian/admin/support/error/CoreApiException.kt b/application/admin/src/main/kotlin/io/raemian/admin/support/error/CoreApiException.kt new file mode 100644 index 00000000..2d833ee3 --- /dev/null +++ b/application/admin/src/main/kotlin/io/raemian/admin/support/error/CoreApiException.kt @@ -0,0 +1,9 @@ +package io.raemian.admin.support.error + +class CoreApiException( + val errorType: ErrorType, + val data: Any? = null, +) : RuntimeException(errorType.message) { + + override fun fillInStackTrace(): Throwable = this +} diff --git a/application/admin/src/main/kotlin/io/raemian/admin/support/error/ErrorCode.kt b/application/admin/src/main/kotlin/io/raemian/admin/support/error/ErrorCode.kt new file mode 100644 index 00000000..be5832a2 --- /dev/null +++ b/application/admin/src/main/kotlin/io/raemian/admin/support/error/ErrorCode.kt @@ -0,0 +1,5 @@ +package io.raemian.admin.support.error + +enum class ErrorCode { + E500, +} diff --git a/application/admin/src/main/kotlin/io/raemian/admin/support/error/ErrorMessage.kt b/application/admin/src/main/kotlin/io/raemian/admin/support/error/ErrorMessage.kt new file mode 100644 index 00000000..0eeab117 --- /dev/null +++ b/application/admin/src/main/kotlin/io/raemian/admin/support/error/ErrorMessage.kt @@ -0,0 +1,23 @@ +package io.raemian.admin.support.error + +data class ErrorMessage private constructor( + val code: String, + val message: String, + val data: Any? = null, +) { + companion object { + private val EMPTY_MESSAGE: String = "Empty Message" + } + + constructor(errorType: ErrorType, data: Any? = null) : this( + code = errorType.code.name, + message = errorType.message, + data = data, + ) + + constructor(errorType: ErrorType, e: Exception) : this( + code = errorType.code.name, + message = e.message ?: EMPTY_MESSAGE, + data = null, + ) +} diff --git a/application/admin/src/main/kotlin/io/raemian/admin/support/error/ErrorType.kt b/application/admin/src/main/kotlin/io/raemian/admin/support/error/ErrorType.kt new file mode 100644 index 00000000..7a85e080 --- /dev/null +++ b/application/admin/src/main/kotlin/io/raemian/admin/support/error/ErrorType.kt @@ -0,0 +1,11 @@ +package io.raemian.admin.support.error + +import org.springframework.boot.logging.LogLevel +import org.springframework.http.HttpStatus + +enum class ErrorType(val status: HttpStatus, val code: ErrorCode, val message: String, val logLevel: LogLevel) { + DEFAULT_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, ErrorCode.E500, "An unexpected error has occurred.", LogLevel.ERROR), + DUPLICATE_TAG_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, ErrorCode.E500, "해당 태그는 이미 존재합니다.", LogLevel.ERROR), + NO_IMAGE_NAME_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, ErrorCode.E500, "이미지 이름이 존재하지 않습니다.", LogLevel.ERROR), + NO_PNG_FILE_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, ErrorCode.E500, "이미지 파일의 확장자가 png가 아닙니다.", LogLevel.ERROR), +} diff --git a/application/admin/src/main/kotlin/io/raemian/admin/support/response/ApiResponse.kt b/application/admin/src/main/kotlin/io/raemian/admin/support/response/ApiResponse.kt new file mode 100644 index 00000000..87da4dca --- /dev/null +++ b/application/admin/src/main/kotlin/io/raemian/admin/support/response/ApiResponse.kt @@ -0,0 +1,24 @@ +package io.raemian.admin.support.response + +import io.raemian.admin.support.error.ErrorMessage +import io.raemian.admin.support.error.ErrorType + +class ApiResponse private constructor( + val result: ResultType, + val body: T? = null, + val error: ErrorMessage? = null, +) { + companion object { + fun success(data: S): ApiResponse { + return ApiResponse(ResultType.SUCCESS, data, null) + } + + fun error(error: ErrorType, errorData: Any? = null): ApiResponse { + return ApiResponse(ResultType.ERROR, null, ErrorMessage(error, errorData)) + } + + fun error(error: ErrorType, e: Exception): ApiResponse { + return ApiResponse(ResultType.ERROR, null, ErrorMessage(error, e)) + } + } +} diff --git a/application/admin/src/main/kotlin/io/raemian/admin/support/response/ResultType.kt b/application/admin/src/main/kotlin/io/raemian/admin/support/response/ResultType.kt new file mode 100644 index 00000000..e965bb09 --- /dev/null +++ b/application/admin/src/main/kotlin/io/raemian/admin/support/response/ResultType.kt @@ -0,0 +1,5 @@ +package io.raemian.admin.support.response + +enum class ResultType { + SUCCESS, ERROR +} diff --git a/application/admin/src/main/kotlin/io/raemian/admin/tag/TagService.kt b/application/admin/src/main/kotlin/io/raemian/admin/tag/TagService.kt new file mode 100644 index 00000000..8a223fc9 --- /dev/null +++ b/application/admin/src/main/kotlin/io/raemian/admin/tag/TagService.kt @@ -0,0 +1,42 @@ +package io.raemian.admin.tag + +import io.raemian.admin.support.error.CoreApiException +import io.raemian.admin.support.error.ErrorType +import io.raemian.admin.tag.controller.request.CreateTagRequest +import io.raemian.admin.tag.controller.request.UpdateTagRequest +import io.raemian.admin.tag.controller.response.TagResponse +import io.raemian.storage.db.core.tag.TagRepository +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional + +@Service +class TagService( + private val tagRepository: TagRepository, +) { + + @Transactional + fun create(createTagRequest: CreateTagRequest): TagResponse { + if (tagRepository.existsTagsByContent(createTagRequest.content)) { + throw CoreApiException(ErrorType.DUPLICATE_TAG_ERROR) + } + + return TagResponse.from(tagRepository.save(createTagRequest.toEntity())) + } + + @Transactional(readOnly = true) + fun findAll(): List = + tagRepository.findAll().map(::TagResponse) + + @Transactional + fun update(tagId: Long, updateTagRequest: UpdateTagRequest): TagResponse { + val tags = tagRepository.getById(tagId) + tags.updateContent(updateTagRequest.content) + return TagResponse.from(tagRepository.save(tags)) + } + + @Transactional + fun delete(tagId: Long) { + val tags = tagRepository.getById(tagId) + tagRepository.delete(tags) + } +} diff --git a/application/admin/src/main/kotlin/io/raemian/admin/tag/controller/TagController.kt b/application/admin/src/main/kotlin/io/raemian/admin/tag/controller/TagController.kt new file mode 100644 index 00000000..28399401 --- /dev/null +++ b/application/admin/src/main/kotlin/io/raemian/admin/tag/controller/TagController.kt @@ -0,0 +1,57 @@ +package io.raemian.admin.tag.controller + +import io.raemian.admin.support.response.ApiResponse +import io.raemian.admin.tag.TagService +import io.raemian.admin.tag.controller.request.CreateTagRequest +import io.raemian.admin.tag.controller.request.UpdateTagRequest +import io.raemian.admin.tag.controller.response.TagResponse +import io.swagger.v3.oas.annotations.Operation +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.PatchMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import java.net.URI + +fun String.toUri(): URI = URI.create(this) + +@RestController +@RequestMapping("/tag") +class TagController( + private val tagService: TagService, +) { + + @PostMapping + @Operation(summary = "태그 생성 API") + fun create( + @RequestBody createTagRequest: CreateTagRequest, + ): ResponseEntity> { + val response = tagService.create(createTagRequest) + return ResponseEntity.created("/tag/${response.id}".toUri()) + .body(ApiResponse.success(response)) + } + + @GetMapping + @Operation(summary = "태그 전체 조회 API") + fun findAll(): ResponseEntity>> = + ResponseEntity.ok(ApiResponse.success(tagService.findAll())) + + @PatchMapping("/{tagId}") + @Operation(summary = "태그 수정 API") + fun update( + @PathVariable tagId: Long, + @RequestBody updateTagRequest: UpdateTagRequest, + ): ResponseEntity> = + ResponseEntity.ok().body(ApiResponse.success(tagService.update(tagId, updateTagRequest))) + + @DeleteMapping("/{tagId}") + @Operation(summary = "태그 삭제 API") + fun delete(@PathVariable tagId: Long): ResponseEntity { + tagService.delete(tagId) + return ResponseEntity.ok().build() + } +} diff --git a/application/admin/src/main/kotlin/io/raemian/admin/tag/controller/request/CreateTagRequest.kt b/application/admin/src/main/kotlin/io/raemian/admin/tag/controller/request/CreateTagRequest.kt new file mode 100644 index 00000000..d1cd583d --- /dev/null +++ b/application/admin/src/main/kotlin/io/raemian/admin/tag/controller/request/CreateTagRequest.kt @@ -0,0 +1,9 @@ +package io.raemian.admin.tag.controller.request + +import io.raemian.storage.db.core.tag.Tag + +data class CreateTagRequest( + val content: String, +) { + fun toEntity() = Tag(content) +} diff --git a/application/admin/src/main/kotlin/io/raemian/admin/tag/controller/request/UpdateTagRequest.kt b/application/admin/src/main/kotlin/io/raemian/admin/tag/controller/request/UpdateTagRequest.kt new file mode 100644 index 00000000..b44c5738 --- /dev/null +++ b/application/admin/src/main/kotlin/io/raemian/admin/tag/controller/request/UpdateTagRequest.kt @@ -0,0 +1,5 @@ +package io.raemian.admin.tag.controller.request + +data class UpdateTagRequest( + val content: String, +) diff --git a/application/admin/src/main/kotlin/io/raemian/admin/tag/controller/response/TagResponse.kt b/application/admin/src/main/kotlin/io/raemian/admin/tag/controller/response/TagResponse.kt new file mode 100644 index 00000000..778d9c33 --- /dev/null +++ b/application/admin/src/main/kotlin/io/raemian/admin/tag/controller/response/TagResponse.kt @@ -0,0 +1,22 @@ +package io.raemian.admin.tag.controller.response + +import io.raemian.storage.db.core.tag.Tag + +fun from(entity: Tag): TagResponse = + TagResponse(entity.id, entity.content) + +data class TagResponse( + val id: Long?, + val content: String, +) { + + constructor(tag: Tag) : this( + tag.id, + tag.content, + ) + + companion object { + fun from(entity: Tag): TagResponse = + TagResponse(entity.id, entity.content) + } +} diff --git a/application/admin/src/main/resources/application.yml b/application/admin/src/main/resources/application.yml new file mode 100644 index 00000000..841a3b77 --- /dev/null +++ b/application/admin/src/main/resources/application.yml @@ -0,0 +1,44 @@ +# default +spring: + profiles: + default: local + application: + name: admin + mvc.throw-exception-if-no-handler-found: true + web.resources.add-mappings: false + +server: + servlet: + context-path: /admin + port: 7000 + +springdoc: + server: + url: ${SPRINGDOC-SERVER-URL:http://localhost:8080/admin} + +--- +# local +spring: + profiles: + group: + local: + - db-core + - image + +--- +# dev +spring: + profiles: + group: + dev: + - db-core + - image + +--- +# live +spring: + profiles: + group: + live: + - db-core + - image \ No newline at end of file diff --git a/application/admin/src/test/kotlin/io/raemian/AdminApiApplicationTests.kt b/application/admin/src/test/kotlin/io/raemian/AdminApiApplicationTests.kt new file mode 100644 index 00000000..41a40116 --- /dev/null +++ b/application/admin/src/test/kotlin/io/raemian/AdminApiApplicationTests.kt @@ -0,0 +1,12 @@ +package io.raemian + +import org.junit.jupiter.api.Test +import org.springframework.boot.test.context.SpringBootTest + +@SpringBootTest +class AdminApiApplicationTests { + + @Test + fun contextLoads() { + } +} diff --git a/Dockerfile b/application/api/Dockerfile similarity index 100% rename from Dockerfile rename to application/api/Dockerfile diff --git a/application/api/src/main/kotlin/io/raemian/api/config/SpringdocConfig.kt b/application/api/src/main/kotlin/io/raemian/api/config/SpringdocConfig.kt index fc0aad83..7b8ecb94 100644 --- a/application/api/src/main/kotlin/io/raemian/api/config/SpringdocConfig.kt +++ b/application/api/src/main/kotlin/io/raemian/api/config/SpringdocConfig.kt @@ -27,7 +27,7 @@ class SpringdocConfig { private fun apiInfo() = Info() .title("BANDIBOODI API 명세") - .description("BANDIBOODI 메인/어드밍 API 명세서") + .description("BANDIBOODI API 명세서") .version("v1.0.0") private fun apiServer() = Server().url(url) diff --git a/settings.gradle.kts b/settings.gradle.kts index a8894792..40a6227d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,7 +2,9 @@ rootProject.name = "one-bailey" include( "application:api", + "application:admin", "storage:db-core", + "storage:image", "infra:logging", "infra:metrics", ) diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/Sticker.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/Sticker.kt index 1c31b298..eb4352cc 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/Sticker.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/sticker/Sticker.kt @@ -14,12 +14,20 @@ import org.hibernate.annotations.Nationalized class Sticker( @Column(nullable = false) @Nationalized - val name: String, + var name: String, @Column(nullable = false) - val url: String, + var url: String, @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long? = null, -) : BaseEntity() +) : BaseEntity() { + fun updateNameAndUrl( + name: String, + url: String, + ) { + this.name = name + this.url = url + } +} diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/tag/Tag.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/tag/Tag.kt index 51f7539c..c6cc33fb 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/tag/Tag.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/tag/Tag.kt @@ -14,9 +14,13 @@ import org.hibernate.annotations.Nationalized class Tag( @Column(nullable = false) @Nationalized - val content: String, + var content: String, @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long? = null, -) : BaseEntity() +) : BaseEntity() { + fun updateContent(content: String) { + this.content = content + } +} diff --git a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/tag/TagRepository.kt b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/tag/TagRepository.kt index c19b7878..83add923 100644 --- a/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/tag/TagRepository.kt +++ b/storage/db-core/src/main/kotlin/io/raemian/storage/db/core/tag/TagRepository.kt @@ -6,4 +6,6 @@ interface TagRepository : JpaRepository { override fun getById(id: Long): Tag = findById(id).orElseThrow { NoSuchElementException("존재하지 않는 태그입니다. $id") } + + fun existsTagsByContent(content: String): Boolean } diff --git a/storage/image/build.gradle.kts b/storage/image/build.gradle.kts new file mode 100644 index 00000000..7d82dc72 --- /dev/null +++ b/storage/image/build.gradle.kts @@ -0,0 +1,2 @@ +dependencies { +} diff --git a/storage/image/src/main/kotlin/io/raemian/image/enums/FileExtensionType.kt b/storage/image/src/main/kotlin/io/raemian/image/enums/FileExtensionType.kt new file mode 100644 index 00000000..72975622 --- /dev/null +++ b/storage/image/src/main/kotlin/io/raemian/image/enums/FileExtensionType.kt @@ -0,0 +1,7 @@ +package io.raemian.image.enums + +enum class FileExtensionType( + val value: String, +) { + PNG(".png"), +} diff --git a/storage/image/src/main/kotlin/io/raemian/image/repository/ImageRepository.kt b/storage/image/src/main/kotlin/io/raemian/image/repository/ImageRepository.kt new file mode 100644 index 00000000..9b5a0514 --- /dev/null +++ b/storage/image/src/main/kotlin/io/raemian/image/repository/ImageRepository.kt @@ -0,0 +1,76 @@ +package io.raemian.image.repository + +import org.springframework.beans.factory.annotation.Value +import org.springframework.stereotype.Repository +import java.io.File +import java.io.InputStream +import java.nio.file.Files + +@Repository +class ImageRepository { + + @Value("\${server.image.url}") + private lateinit var url: String + + @Value("\${server.image.file-path}") + private lateinit var path: String + + fun upload( + fileName: String, + inputStream: InputStream, + ): String { + if (isExist(fileName)) { + throw IllegalStateException("이미 동일한 이름의 이미지가 존재합니다.") + } + + Files.copy(inputStream, File(createPath(fileName)).toPath()) + + return createUrl(fileName) + } + + fun update( + newFileName: String, + oldFileName: String, + inputStream: InputStream, + ): String { + // 파일이 존재하면 삭제 + if (isExist(oldFileName)) { + File(createPath(oldFileName)).delete() + } + + Files.copy(inputStream, File(createPath(newFileName)).toPath()) + + return createUrl(newFileName) + } + + fun delete( + fileName: String, + ) { + // 파일이 존재하지 않는다면 생략 + if (!isExist(fileName)) { + return + } + + val file: File = File(createPath(fileName)) + + file.delete() + } + + fun isExist( + fileName: String, + ): Boolean { + val file: File = File(createPath(fileName)) + + if (file.exists()) { + return true + } + + return false + } + + private fun createPath(fileName: String): String = + "%s/$fileName".format(path) + + private fun createUrl(fileName: String): String = + "%s/$fileName".format(url) +} diff --git a/storage/image/src/main/resources/application-image.yml b/storage/image/src/main/resources/application-image.yml new file mode 100644 index 00000000..28371e30 --- /dev/null +++ b/storage/image/src/main/resources/application-image.yml @@ -0,0 +1,16 @@ +server: + image: + url: ${IMAGE-SERVER-URL:http://localhost:8080} + file-path: ${IMAGE-FILE-PATH:/Users/{usename}/Desktop} + +--- +# local +spring.config.activate.on-profile: local + +--- +# dev +spring.config.activate.on-profile: dev + +--- +# live +spring.config.activate.on-profile: live From 5b7c93b9d96e4873c3bbcab5410d676d40d88f08 Mon Sep 17 00:00:00 2001 From: wkwon Date: Thu, 4 Jan 2024 23:38:43 +0900 Subject: [PATCH 70/70] =?UTF-8?q?fix:=20ci/cd=20github=20secrets=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/{admin-api-ci-cd.yml => admin-ci-cd.yml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{admin-api-ci-cd.yml => admin-ci-cd.yml} (94%) diff --git a/.github/workflows/admin-api-ci-cd.yml b/.github/workflows/admin-ci-cd.yml similarity index 94% rename from .github/workflows/admin-api-ci-cd.yml rename to .github/workflows/admin-ci-cd.yml index 1ec9a974..2bb6398f 100644 --- a/.github/workflows/admin-api-ci-cd.yml +++ b/.github/workflows/admin-ci-cd.yml @@ -28,7 +28,7 @@ jobs: - name: push to dockerhub run: | docker login -u ${{ secrets.DOCKER_ID }} -p ${{ secrets.DOCKER_PASSWORD }} - docker build --no-cache -t ${{ secrets.DOCKER_ID }}/${{ secrets.DOCKER_REPO }} -f ./application/admin/Dockerfile . + docker build --no-cache -t ${{ secrets.DOCKER_ID }}/${{ secrets.DOCKER_ADMIN_REPO }} -f ./application/admin/Dockerfile . docker push ${{ secrets.DOCKER_ID }}/${{ secrets.DOCKER_ADMIN_REPO }} - name: deploy uses: appleboy/ssh-action@master