Skip to content

Commit

Permalink
Merge pull request #135 from grida-diary/main
Browse files Browse the repository at this point in the history
docs
  • Loading branch information
wwan13 authored Aug 28, 2024
2 parents ba7ab1a + 6becdaf commit bca5bd0
Show file tree
Hide file tree
Showing 71 changed files with 430 additions and 186 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@ import org.springframework.boot.context.properties.ConstructorBinding
@ConfigurationProperties("kakao")
data class KakaoProperties(
val appKey: String,
val redirectUri: String
)
val baseUri: String,
val apiPath: String
) {
val redirectUri: String = baseUri + apiPath
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
spring:
config:
activate:
on-profile: dev
kakao:
appKey: ${KAKAO_APP_KEY}
base-uri: http://localhost:8080
api-path: ${KAKAO_REDIRECT_URL}

---
spring:
config:
activate:
on-profile: prod
kakao:
appKey: ${KAKAO_APP_KEY}
base-uri: https://grida.today
api-path: ${KAKAO_REDIRECT_URL}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
openai:
secret-key: ${OPEN_AI_SECRET_KEY}

---
spring:
config:
activate:
on-profile: dev

---
spring:
config:
activate:
on-profile: prod

This file was deleted.

File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ package org.grida

import com.amazonaws.AmazonClientException
import com.amazonaws.services.s3.AmazonS3
import org.grida.config.StorageClientProperties
import org.grida.config.S3ClientProperties
import org.grida.error.FileUploadFail
import org.grida.error.GridaException
import org.springframework.stereotype.Component
import java.io.File

@Component
class StorageClient(
private val properties: StorageClientProperties,
class S3Client(
private val properties: S3ClientProperties,
private val amazonS3: AmazonS3,
) {
fun uploadFile(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import org.springframework.context.annotation.Configuration

@Configuration
@ConfigurationPropertiesScan
class StorageClientConfig(
private val properties: StorageClientProperties,
class S3ClientConfig(
private val properties: S3ClientProperties,
) {
@Bean
fun amazonS3Client(properties: StorageClientProperties): AmazonS3 {
fun amazonS3Client(properties: S3ClientProperties): AmazonS3 {
val credential = BasicAWSCredentials(properties.accessKey, properties.secretKey)

return AmazonS3ClientBuilder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import org.springframework.boot.context.properties.ConstructorBinding

@ConstructorBinding
@ConfigurationProperties("storage.aws")
data class StorageClientProperties(
data class S3ClientProperties(
val accessKey: String,
val secretKey: String,
val region: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
storage:
aws:
access-key: ${S3_ACCESS_KEY}
secret-key: ${S3_SECRET_KEY}
region: ${S3_REGION}
bucket: ${S3_BUCKET}
host: ${CDN_HOST}
---
spring:
config:
activate:
on-profile: dev

---
spring:
config:
activate:
on-profile: prod

This file was deleted.

19 changes: 19 additions & 0 deletions grida-common/src/main/kotlin/org/grida/api/dto/ListResponse.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.grida.api.dto

data class ListResponse<T>(
val count: Int,
val list: List<T>
) {

companion object {
fun <T> from(
list: List<T>,
mapAction: () -> T
): ListResponse<T> {
return ListResponse(
list.size,
list.map { mapAction.invoke() }
)
}
}
}
Empty file.
10 changes: 4 additions & 6 deletions grida-core/core-api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ plugins {
dependencies {
// module dependencies
implementation(project(":grida-core:core-domain"))
implementation(project(":grida-database:database-rds"))
implementation(project(":grida-storage:rds-storage"))
implementation(project(":grida-clients:kakao-client"))
implementation(project(":grida-support:logging"))
implementation(project(":grida-support:monitoring"))

// web
implementation("org.springframework.boot:spring-boot-starter-web")
Expand All @@ -18,15 +20,11 @@ dependencies {
implementation("com.github.wwan13:winter-security:0.0.10")

// logging-request
implementation("com.github.wwan13:spring-request-logger:0.0.3")
implementation("com.github.wwan13:spring-request-logger:0.0.7")

// api docs
testImplementation("org.springframework.restdocs:spring-restdocs-mockmvc")
testImplementation("com.github.wwan13.kotlin-dsl-rest-docs:impl-mockmvc:1.2.9")

// monitoring
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("io.micrometer:micrometer-registry-prometheus")
}

tasks {
Expand Down
2 changes: 2 additions & 0 deletions grida-core/core-api/http/core-api.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
### Health Checking Api
GET {{core-api}}/api/health
8 changes: 8 additions & 0 deletions grida-core/core-api/http/http-client.env.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"local": {
"core-api": "http://localhost:8080"
},
"prod": {
"core-api": "https://grida.today"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.grida.auth

interface AuthProcessor {
fun process(code: String): AuthToken
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.grida.auth

import org.grida.error.GridaException
import org.grida.error.NotSupportedLoginPlatform
import org.springframework.stereotype.Component

@Component
class AuthProcessorSelector(
private val authProcessors: Map<String, AuthProcessor>
) {

fun select(platform: String): AuthProcessor {
return authProcessors["${platform}AuthProcessor"]
?: throw GridaException(NotSupportedLoginPlatform)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.grida.auth

data class AuthToken(
val accessToken: String,
val refreshToken: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.grida.auth

import io.wwan13.wintersecurity.jwt.TokenGenerator
import org.grida.config.TokenPayload
import org.grida.domain.user.User
import org.springframework.stereotype.Component

@Component
class AuthTokenProvider(
private val tokenGenerator: TokenGenerator
) {

fun provide(
user: User
): AuthToken {
val tokenPayload = TokenPayload(user.id, user.role)
return AuthToken(
accessToken = tokenGenerator.accessToken(tokenPayload),
refreshToken = tokenGenerator.refreshToken(tokenPayload)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.grida.auth

import org.grida.domain.user.LoginOption
import org.grida.domain.user.LoginPlatform
import org.grida.domain.user.UserService
import org.grida.error.GridaException
import org.grida.error.NotSupportedLoginPlatform
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component

@Component
class InternalAuthProcessor(
@Value("\${spring.profiles.active}")
private val activeProfile: String,
private val userService: UserService,
private val authTokenProvider: AuthTokenProvider
) : AuthProcessor {

override fun process(code: String): AuthToken {
validateActiveProfile()
val loginOption = LoginOption(LoginPlatform.ADMIN, code)
val user = userService.read(loginOption.identifier.toLong())

return authTokenProvider.provide(user)
}

private fun validateActiveProfile() {
if (!enableProfiles.contains(activeProfile)) {
throw throw GridaException(NotSupportedLoginPlatform)
}
}

companion object {
val enableProfiles = listOf("dev", "stag")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.grida.auth

import org.grida.domain.user.LoginOption
import org.grida.domain.user.LoginPlatform
import org.grida.domain.user.UserService
import org.grida.user.KakaoUserClient
import org.springframework.stereotype.Component

@Component
class KakaoAuthProcessor(
private val kakaoAuthClient: KakaoAuthClient,
private val kakaoUserClient: KakaoUserClient,
private val userService: UserService,
private val authTokenProvider: AuthTokenProvider
) : AuthProcessor {

override fun process(code: String): AuthToken {
val kakaoToken = kakaoAuthClient.provideAuthToken(code)
val kakaoProfile = kakaoUserClient.readUserProfile(kakaoToken.accessToken)
val loginOption = LoginOption(LoginPlatform.KAKAO, kakaoProfile.id)

val user = userService.readUserByLoginOption(loginOption)
?: userService.appendAndReturnNormalUser(kakaoProfile.name, loginOption)
return authTokenProvider.provide(user)
}
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,8 @@
package org.grida.config

import io.wwan13.springrequestlogger.configure.EnableLoggingRequest
import io.wwan13.springrequestlogger.configure.LogMessageConfigurer
import io.wwan13.springrequestlogger.context.RequestContext
import org.springframework.boot.context.properties.ConfigurationPropertiesScan
import org.springframework.context.annotation.Configuration
import java.util.function.Function

@Configuration
@ConfigurationPropertiesScan
@EnableLoggingRequest
class CoreApiConfig : LogMessageConfigurer {

override fun format(): Function<RequestContext, String> {
return Function { context ->
"""
|
| ${context.method} '${context.uri}' - ${context.status} (${context.elapsed} s)
| >> Request Headers : ${context.requestHeaders}
| >> Request Params : ${context.requestParams}
| >> Request Body : ${context.requestBody}
| >> Response Body : ${context.responseBody}
""".trimMargin()
}
}
}
class CoreApiConfig
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ class CoreApiSecurityConfig(

override fun registerAuthPatterns(registry: AuthPatternsRegistry) {
registry.apply {
uriPatterns("/api/health")
.httpMethodGet()
.permitAll()

uriPatterns("/api/v1/auth/**")
.allHttpMethods()
.permitAll()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.grida.config

import io.wwan13.springrequestlogger.configure.EnableLoggingRequest
import io.wwan13.springrequestlogger.configure.LogMessageConfigurer
import org.springframework.context.annotation.Configuration

@Configuration
@EnableLoggingRequest
class RequestLoggingConfig : LogMessageConfigurer {

override fun excludePathPatterns(): List<String> {
return listOf("/api/actuator/**")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import org.grida.http.BAD_REQUEST

sealed interface CoreApiErrorType : ErrorType

data object LoginFailed : CoreApiErrorType {
data object NotSupportedLoginPlatform : CoreApiErrorType {
override val httpStatusCode: Int = BAD_REQUEST
override val errorCode: String = "AUTH_400_1"
override val message: String = "아이디 혹은 비밀번호를 확인하세요."
override val errorCode: String = "AUTH_PLATFORM_400_1"
override val message: String = "지원하지 않는 로그인 플랫폼 입니다."
override val logLevel: LogLevel = INFO
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.http.converter.HttpMessageNotReadableException
import org.springframework.web.HttpRequestMethodNotSupportedException
import org.springframework.web.bind.MissingServletRequestParameterException
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.RestControllerAdvice
import org.springframework.web.servlet.NoHandlerFoundException
Expand Down Expand Up @@ -98,6 +99,15 @@ class ApiControllerAdvice {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response)
}

@ExceptionHandler(MissingServletRequestParameterException::class)
fun handleMissingServletRequestParameterException(
e: MissingServletRequestParameterException
): ResponseEntity<ApiResponse<ErrorResponse>> {
log.info(e.message)
val response = ApiResponse.error("HTTP_400", "요청에 필요한 쿼리 파라미터 ${e.parameterName}가 없습니다.")
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response)
}

@ExceptionHandler(HttpMessageNotReadableException::class)
fun handleHttpMessageNotReadableException(
e: HttpMessageNotReadableException
Expand Down
Loading

0 comments on commit bca5bd0

Please sign in to comment.