-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
dfda718
commit 916752e
Showing
16 changed files
with
942 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
17 changes: 17 additions & 0 deletions
17
...ackend-service/src/main/kotlin/com/aamdigital/aambackendservice/auth/core/AuthProvider.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package com.aamdigital.aambackendservice.auth.core | ||
|
||
import reactor.core.publisher.Mono | ||
|
||
data class TokenResponse(val token: String) | ||
|
||
data class AuthConfig( | ||
val clientId: String, | ||
val clientSecret: String, | ||
val tokenEndpoint: String, | ||
val grantType: String, | ||
val scope: String, | ||
) | ||
|
||
interface AuthProvider { | ||
fun fetchToken(authClientConfig: AuthConfig): Mono<TokenResponse> | ||
} |
63 changes: 63 additions & 0 deletions
63
...ervice/src/main/kotlin/com/aamdigital/aambackendservice/auth/core/KeycloakAuthProvider.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package com.aamdigital.aambackendservice.auth.core | ||
|
||
import com.aamdigital.aambackendservice.error.ExternalSystemException | ||
import com.fasterxml.jackson.annotation.JsonProperty | ||
import com.fasterxml.jackson.databind.ObjectMapper | ||
import org.slf4j.LoggerFactory | ||
import org.springframework.http.MediaType | ||
import org.springframework.util.LinkedMultiValueMap | ||
import org.springframework.web.reactive.function.BodyInserters | ||
import org.springframework.web.reactive.function.client.WebClient | ||
import reactor.core.publisher.Mono | ||
|
||
data class KeycloakTokenResponse( | ||
@JsonProperty("access_token") val accessToken: String, | ||
) | ||
|
||
class KeycloakAuthProvider( | ||
val webClient: WebClient, | ||
val objectMapper: ObjectMapper, | ||
) : AuthProvider { | ||
|
||
private val logger = LoggerFactory.getLogger(javaClass) | ||
|
||
override fun fetchToken(authClientConfig: AuthConfig): Mono<TokenResponse> { | ||
val formData = LinkedMultiValueMap( | ||
mutableMapOf( | ||
"client_id" to listOf(authClientConfig.clientId), | ||
"client_secret" to listOf(authClientConfig.clientSecret), | ||
"grant_type" to listOf(authClientConfig.grantType), | ||
).also { | ||
if (authClientConfig.scope.isNotBlank()) { | ||
"scope" to listOf(authClientConfig.scope) | ||
} | ||
} | ||
) | ||
|
||
return webClient.post() | ||
.uri(authClientConfig.tokenEndpoint) | ||
.headers { | ||
it.contentType = MediaType.APPLICATION_FORM_URLENCODED | ||
} | ||
.body( | ||
BodyInserters.fromFormData( | ||
formData | ||
) | ||
).exchangeToMono { | ||
it.bodyToMono(String::class.java) | ||
}.map { | ||
parseResponse(it) | ||
}.doOnError { logger.error(it.message, it) } | ||
} | ||
|
||
private fun parseResponse(raw: String): TokenResponse { | ||
try { | ||
val keycloakTokenResponse = objectMapper.readValue(raw, KeycloakTokenResponse::class.java) | ||
return TokenResponse( | ||
token = keycloakTokenResponse.accessToken | ||
) | ||
} catch (e: Exception) { | ||
throw ExternalSystemException("Could not parse access token from KeycloakAuthProvider", e) | ||
} | ||
} | ||
} |
47 changes: 47 additions & 0 deletions
47
...end-service/src/main/kotlin/com/aamdigital/aambackendservice/auth/di/AuthConfiguration.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package com.aamdigital.aambackendservice.auth.di | ||
|
||
import com.aamdigital.aambackendservice.auth.core.AuthProvider | ||
import com.aamdigital.aambackendservice.auth.core.KeycloakAuthProvider | ||
import com.fasterxml.jackson.databind.ObjectMapper | ||
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 | ||
import org.springframework.http.client.reactive.ReactorClientHttpConnector | ||
import org.springframework.web.reactive.function.client.WebClient | ||
import reactor.netty.http.client.HttpClient | ||
|
||
|
||
@ConfigurationProperties("aam-keycloak-client-configuration") | ||
data class KeycloakConfiguration( | ||
val maxInMemorySizeInMegaBytes: Int = 16, | ||
) | ||
|
||
@Configuration | ||
class AuthConfiguration { | ||
companion object { | ||
const val MEGA_BYTES_MULTIPLIER = 1024 * 1024 | ||
} | ||
|
||
@Bean(name = ["aam-keycloak-client"]) | ||
fun aamKeycloakWebClient( | ||
configuration: KeycloakConfiguration, | ||
): WebClient { | ||
val clientBuilder = | ||
WebClient.builder() | ||
.codecs { | ||
it.defaultCodecs() | ||
.maxInMemorySize(configuration.maxInMemorySizeInMegaBytes * MEGA_BYTES_MULTIPLIER) | ||
} | ||
|
||
return clientBuilder.clientConnector(ReactorClientHttpConnector(HttpClient.create())).build() | ||
} | ||
|
||
@Bean(name = ["aam-keycloak"]) | ||
fun aamKeycloakAuthProvider( | ||
@Qualifier("aam-keycloak-client") webClient: WebClient, | ||
objectMapper: ObjectMapper, | ||
): AuthProvider = | ||
KeycloakAuthProvider(webClient = webClient, objectMapper = objectMapper) | ||
|
||
} |
73 changes: 73 additions & 0 deletions
73
...ain/kotlin/com/aamdigital/aambackendservice/export/controller/TemplateExportController.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package com.aamdigital.aambackendservice.export.controller | ||
|
||
import com.aamdigital.aambackendservice.domain.DomainReference | ||
import com.aamdigital.aambackendservice.export.core.CreateTemplateRequest | ||
import com.aamdigital.aambackendservice.export.core.CreateTemplateUseCase | ||
import com.aamdigital.aambackendservice.export.core.RenderTemplateUseCase | ||
import com.fasterxml.jackson.databind.JsonNode | ||
import org.springframework.beans.factory.annotation.Qualifier | ||
import org.springframework.core.io.buffer.DataBuffer | ||
import org.springframework.http.MediaType | ||
import org.springframework.http.codec.multipart.FilePart | ||
import org.springframework.validation.annotation.Validated | ||
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.RequestPart | ||
import org.springframework.web.bind.annotation.RestController | ||
import org.springframework.web.reactive.function.client.WebClient | ||
import org.springframework.web.reactive.function.client.bodyToMono | ||
import reactor.core.publisher.Mono | ||
|
||
|
||
/** | ||
* @param templateId The external identifier of the implementing TemplateEngine | ||
*/ | ||
data class CreateTemplateResponseDto( | ||
val templateId: String, | ||
) | ||
|
||
@RestController | ||
@RequestMapping("/v1/export") | ||
@Validated | ||
class TemplateExportController( | ||
@Qualifier("aam-render-api-client") val webClient: WebClient, | ||
val createTemplateUseCase: CreateTemplateUseCase, | ||
val renderTemplateUseCase: RenderTemplateUseCase, | ||
) { | ||
|
||
@GetMapping("/status") | ||
fun getStatus(): Mono<String> { | ||
return webClient.get().uri("/status").exchangeToMono { | ||
it.bodyToMono() | ||
} | ||
} | ||
|
||
@PostMapping("/template") | ||
fun postTemplate( | ||
@RequestPart("template") file: FilePart | ||
): Mono<CreateTemplateResponseDto> { | ||
return createTemplateUseCase.createTemplate( | ||
CreateTemplateRequest( | ||
file = file | ||
) | ||
).map { createTemplateResponse -> | ||
CreateTemplateResponseDto( | ||
templateId = createTemplateResponse.template.id | ||
) | ||
} | ||
} | ||
|
||
@PostMapping("/render/{templateId}", produces = [MediaType.APPLICATION_PDF_VALUE]) | ||
fun getTemplate( | ||
@PathVariable templateId: String, | ||
@RequestBody templateData: JsonNode, | ||
): Mono<DataBuffer> { | ||
return renderTemplateUseCase.renderTemplate( | ||
templateRef = DomainReference(templateId), | ||
bodyData = templateData | ||
) | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
...ice/src/main/kotlin/com/aamdigital/aambackendservice/export/core/CreateTemplateUseCase.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package com.aamdigital.aambackendservice.export.core | ||
|
||
import com.aamdigital.aambackendservice.domain.DomainReference | ||
import org.springframework.http.codec.multipart.FilePart | ||
import reactor.core.publisher.Mono | ||
|
||
data class CreateTemplateResponse( | ||
val template: DomainReference, | ||
) | ||
|
||
data class CreateTemplateRequest( | ||
val file: FilePart, | ||
) | ||
|
||
interface CreateTemplateUseCase { | ||
fun createTemplate(createTemplateRequest: CreateTemplateRequest): Mono<CreateTemplateResponse> | ||
} |
9 changes: 9 additions & 0 deletions
9
...nd-service/src/main/kotlin/com/aamdigital/aambackendservice/export/core/ExportTemplate.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.aamdigital.aambackendservice.export.core | ||
|
||
data class ExportTemplate( | ||
val id: String, | ||
val templateId: String, | ||
val title: String, | ||
val description: String, | ||
val applicableForEntityTypes: List<String>, | ||
) |
10 changes: 10 additions & 0 deletions
10
...ice/src/main/kotlin/com/aamdigital/aambackendservice/export/core/RenderTemplateUseCase.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.aamdigital.aambackendservice.export.core | ||
|
||
import com.aamdigital.aambackendservice.domain.DomainReference | ||
import com.fasterxml.jackson.databind.JsonNode | ||
import org.springframework.core.io.buffer.DataBuffer | ||
import reactor.core.publisher.Mono | ||
|
||
interface RenderTemplateUseCase { | ||
fun renderTemplate(templateRef: DomainReference, bodyData: JsonNode): Mono<DataBuffer> | ||
} |
8 changes: 8 additions & 0 deletions
8
...d-service/src/main/kotlin/com/aamdigital/aambackendservice/export/core/TemplateStorage.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.aamdigital.aambackendservice.export.core | ||
|
||
import com.aamdigital.aambackendservice.domain.DomainReference | ||
import reactor.core.publisher.Mono | ||
|
||
interface TemplateStorage { | ||
fun fetchTemplate(template: DomainReference): Mono<ExportTemplate> | ||
} |
51 changes: 51 additions & 0 deletions
51
...e/src/main/kotlin/com/aamdigital/aambackendservice/export/di/AamRenderApiConfiguration.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package com.aamdigital.aambackendservice.export.di | ||
|
||
import com.aamdigital.aambackendservice.auth.core.AuthConfig | ||
import com.aamdigital.aambackendservice.auth.core.AuthProvider | ||
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 | ||
import org.springframework.http.HttpHeaders | ||
import org.springframework.http.client.reactive.ReactorClientHttpConnector | ||
import org.springframework.web.reactive.function.client.ClientRequest | ||
import org.springframework.web.reactive.function.client.WebClient | ||
import reactor.netty.http.client.HttpClient | ||
|
||
|
||
@ConfigurationProperties("aam-render-api-client-configuration") | ||
class AamRenderApiClientConfiguration( | ||
val basePath: String, | ||
val authConfig: AuthConfig, | ||
val maxInMemorySizeInMegaBytes: Int = 16, | ||
) | ||
|
||
@Configuration | ||
class AamRenderApiConfiguration { | ||
companion object { | ||
const val MEGA_BYTES_MULTIPLIER = 1024 * 1024 | ||
} | ||
|
||
@Bean(name = ["aam-render-api-client"]) | ||
fun aamRenderApiClient( | ||
@Qualifier("aam-keycloak") authProvider: AuthProvider, | ||
configuration: AamRenderApiClientConfiguration | ||
): WebClient { | ||
val clientBuilder = | ||
WebClient.builder() | ||
.codecs { | ||
it.defaultCodecs() | ||
.maxInMemorySize(configuration.maxInMemorySizeInMegaBytes * MEGA_BYTES_MULTIPLIER) | ||
} | ||
.baseUrl(configuration.basePath) | ||
.filter { request, next -> | ||
authProvider.fetchToken(configuration.authConfig).map { | ||
ClientRequest.from(request).header(HttpHeaders.AUTHORIZATION, "Bearer ${it.token}").build() | ||
}.flatMap { | ||
next.exchange(it) | ||
} | ||
} | ||
|
||
return clientBuilder.clientConnector(ReactorClientHttpConnector(HttpClient.create())).build() | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
...ervice/src/main/kotlin/com/aamdigital/aambackendservice/export/di/UseCaseConfiguration.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package com.aamdigital.aambackendservice.export.di | ||
|
||
import com.aamdigital.aambackendservice.couchdb.core.CouchDbClient | ||
import com.aamdigital.aambackendservice.export.core.CreateTemplateUseCase | ||
import com.aamdigital.aambackendservice.export.core.RenderTemplateUseCase | ||
import com.aamdigital.aambackendservice.export.core.TemplateStorage | ||
import com.aamdigital.aambackendservice.export.storage.DefaultTemplateStorage | ||
import com.aamdigital.aambackendservice.export.usecase.DefaultCreateTemplateUseCase | ||
import com.aamdigital.aambackendservice.export.usecase.DefaultRenderTemplateUseCase | ||
import com.fasterxml.jackson.databind.ObjectMapper | ||
import org.springframework.beans.factory.annotation.Qualifier | ||
import org.springframework.context.annotation.Bean | ||
import org.springframework.context.annotation.Configuration | ||
import org.springframework.web.reactive.function.client.WebClient | ||
|
||
@Configuration | ||
class UseCaseConfiguration { | ||
@Bean(name = ["default-template-storage"]) | ||
fun defaultTemplateStorage( | ||
couchDbClient: CouchDbClient, | ||
): TemplateStorage = DefaultTemplateStorage(couchDbClient) | ||
|
||
@Bean(name = ["default-create-template-use-case"]) | ||
fun defaultCreateTemplateUseCase( | ||
@Qualifier("aam-render-api-client") webClient: WebClient, | ||
objectMapper: ObjectMapper | ||
): CreateTemplateUseCase = DefaultCreateTemplateUseCase(webClient, objectMapper) | ||
|
||
@Bean(name = ["default-render-template-use-case"]) | ||
fun defaultRenderTemplateUseCase( | ||
@Qualifier("aam-render-api-client") webClient: WebClient, | ||
objectMapper: ObjectMapper, | ||
templateStorage: TemplateStorage | ||
): RenderTemplateUseCase = DefaultRenderTemplateUseCase(webClient, objectMapper, templateStorage) | ||
} |
Oops, something went wrong.