From d812b1cc5f6bf2992c09abd564dea3c3e3368a5d Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Sat, 9 May 2026 16:17:00 +0330 Subject: [PATCH 1/2] Add interceptors dependency to all related modules --- accountant/accountant-app/pom.xml | 4 ++++ accountant/pom.xml | 5 +++++ auth-gateway/auth-gateway-app/pom.xml | 4 ++++ bc-gateway/bc-gateway-app/pom.xml | 8 ++++++++ device-management/device-management-app/pom.xml | 4 ++++ device-management/pom.xml | 5 +++++ docker-compose.yml | 4 ++-- matching-gateway/matching-gateway-app/pom.xml | 4 ++++ otp/otp-app/pom.xml | 4 ++++ profile/pom.xml | 5 +++++ profile/profile-app/pom.xml | 4 ++++ user-management/pom.xml | 5 +++++ 12 files changed, 54 insertions(+), 2 deletions(-) diff --git a/accountant/accountant-app/pom.xml b/accountant/accountant-app/pom.xml index 67649ff75..f56aee06a 100644 --- a/accountant/accountant-app/pom.xml +++ b/accountant/accountant-app/pom.xml @@ -51,6 +51,10 @@ co.nilin.opex.utility error-handler + + co.nilin.opex.utility + interceptors + org.springframework.cloud spring-cloud-starter-vault-config diff --git a/accountant/pom.xml b/accountant/pom.xml index 6eded39f6..edce57a88 100644 --- a/accountant/pom.xml +++ b/accountant/pom.xml @@ -82,6 +82,11 @@ error-handler ${error-hanlder.version} + + co.nilin.opex.utility + interceptors + ${interceptor.version} + org.springframework.cloud spring-cloud-dependencies diff --git a/auth-gateway/auth-gateway-app/pom.xml b/auth-gateway/auth-gateway-app/pom.xml index 0d31ffddd..0ff3a5ade 100644 --- a/auth-gateway/auth-gateway-app/pom.xml +++ b/auth-gateway/auth-gateway-app/pom.xml @@ -80,6 +80,10 @@ co.nilin.opex.utility error-handler + + co.nilin.opex.utility + interceptors + com.auth0 java-jwt diff --git a/bc-gateway/bc-gateway-app/pom.xml b/bc-gateway/bc-gateway-app/pom.xml index 2bdccb667..0046a178b 100644 --- a/bc-gateway/bc-gateway-app/pom.xml +++ b/bc-gateway/bc-gateway-app/pom.xml @@ -138,6 +138,14 @@ micrometer-registry-prometheus runtime + + co.nilin.opex.utility + interceptors + + + co.nilin.opex.utility + error-handler + diff --git a/device-management/device-management-app/pom.xml b/device-management/device-management-app/pom.xml index 82e41ff4e..ff9b70048 100644 --- a/device-management/device-management-app/pom.xml +++ b/device-management/device-management-app/pom.xml @@ -78,6 +78,10 @@ co.nilin.opex.utility error-handler + + co.nilin.opex.utility + interceptors + com.zaxxer HikariCP diff --git a/device-management/pom.xml b/device-management/pom.xml index d24596637..4800bfa7c 100644 --- a/device-management/pom.xml +++ b/device-management/pom.xml @@ -56,6 +56,11 @@ error-handler ${error-hanlder.version} + + co.nilin.opex.utility + interceptors + ${interceptor.version} + co.nilin.opex.device-management device-management-core diff --git a/docker-compose.yml b/docker-compose.yml index 63535e6e2..b9078536e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -546,8 +546,8 @@ services: - SMTP_USER=${SMTP_USER} - SMTP_PASS=${SMTP_PASS} - SMTP_FROM=${SMTP_FROM} - - SMTP_SOCKS_HOST=${SMTP_SOCKS_HOST} - - SMTP_SOCKS_PORT=${SMTP_SOCKS_PORT} + - SMTP_PROXY_HOST=${SMTP_PROXY_HOST} + - SMTP_PROXY_PORT=${SMTP_PROXY_PORT} - SMTP_PROXY_ENABLED=${SMTP_PROXY_ENABLED} - TOKEN_ISSUER_URL=${KC_ISSUER_URL} - OTP_CODE_RESPONSE_ENABLED=${OTP_CODE_RESPONSE_ENABLED} diff --git a/matching-gateway/matching-gateway-app/pom.xml b/matching-gateway/matching-gateway-app/pom.xml index 24e94ab58..86d029320 100644 --- a/matching-gateway/matching-gateway-app/pom.xml +++ b/matching-gateway/matching-gateway-app/pom.xml @@ -77,6 +77,10 @@ co.nilin.opex.utility error-handler + + co.nilin.opex.utility + interceptors + io.mockk mockk diff --git a/otp/otp-app/pom.xml b/otp/otp-app/pom.xml index 1d3d72124..49cb4f0c0 100644 --- a/otp/otp-app/pom.xml +++ b/otp/otp-app/pom.xml @@ -87,6 +87,10 @@ co.nilin.opex.utility error-handler + + co.nilin.opex.utility + interceptors + io.mockk mockk diff --git a/profile/pom.xml b/profile/pom.xml index 7ac615097..ffd3ab564 100644 --- a/profile/pom.xml +++ b/profile/pom.xml @@ -66,6 +66,11 @@ logging-handler ${logging-handler.version} + + co.nilin.opex.utility + error-handler + ${error-hanlder.version} + co.nilin.opex.utility interceptors diff --git a/profile/profile-app/pom.xml b/profile/profile-app/pom.xml index 685459a22..2b2412044 100644 --- a/profile/profile-app/pom.xml +++ b/profile/profile-app/pom.xml @@ -98,6 +98,10 @@ org.springframework.cloud spring-cloud-starter-vault-config + + co.nilin.opex.utility + error-handler + co.nilin.opex.utility interceptors diff --git a/user-management/pom.xml b/user-management/pom.xml index 0c0b0c5a4..fbb1146c0 100644 --- a/user-management/pom.xml +++ b/user-management/pom.xml @@ -49,6 +49,11 @@ error-handler ${error-hanlder.version} + + co.nilin.opex.utility + interceptors + ${interceptor.version} + co.nilin.opex.auth user-management-core From 5fe5e4bf705c7199644889ce3892d32c9e4992e1 Mon Sep 17 00:00:00 2001 From: Amir Rajabi Date: Mon, 11 May 2026 13:10:11 +0330 Subject: [PATCH 2/2] update language services --- .../opex/api/app/config/WebClientConfig.kt | 3 +- .../app/service/OpexFilterExceptionHandler.kt | 2 +- .../src/main/resources/application.yml | 2 + .../api/core/inout/UpdateWebConfigRequest.kt | 18 +++++++ .../co/nilin/opex/api/core/spi/ConfigProxy.kt | 11 ++++ .../ports/binance/config/SecurityConfig.kt | 1 + .../ports/opex/controller/ConfigController.kt | 29 +++++++++++ .../opex/controller/GatewayAdminController.kt | 2 +- .../api/ports/proxy/impl/ConfigProxyImpl.kt | 51 +++++++++++++++++++ .../dao/CurrencyImplementationRepository.kt | 4 +- .../nilin/opex/common/config/ErrorConfig.kt | 8 +-- .../co/nilin/opex/common/data/CalenderType.kt | 5 ++ .../opex/common/data/LanguageDirection.kt | 5 ++ .../nilin/opex/common/data/LanguageOption.kt | 8 +++ .../kotlin/co/nilin/opex/common/data/Theme.kt | 5 ++ .../co/nilin/opex/common/data/UserLanguage.kt | 16 +++--- .../co/nilin/opex/common/data/WebConfig.kt | 13 +++++ .../nilin/opex/common/proxy/ConfigClient.kt | 26 ++++++++++ .../CustomMessageClient.kt} | 5 +- .../CustomErrorTranslator.kt | 2 +- .../service/CustomUserLanguageConfig.kt | 15 ++++++ .../TranslationCacheService.kt | 11 ++-- .../common/service/WebConfigCacheService.kt | 30 +++++++++++ .../nilin/opex/common/utils/LanguageUtils.kt | 11 +++- pom.xml | 2 +- .../opex/auth/gateway/utils/ErrorHandler.kt | 2 +- .../opex/wallet/app/config/WebClientConfig.kt | 3 +- .../postgres/dao/CurrencyRepositoryV2.kt | 6 +-- .../postgres/dao/GatewayTerminalRepository.kt | 4 +- .../postgres/dao/OffChainGatewayRepository.kt | 4 +- .../ports/postgres/dao/TerminalRepository.kt | 4 +- 31 files changed, 265 insertions(+), 43 deletions(-) create mode 100644 api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/UpdateWebConfigRequest.kt create mode 100644 api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/ConfigProxy.kt create mode 100644 api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ConfigController.kt create mode 100644 api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/ConfigProxyImpl.kt create mode 100644 common/src/main/kotlin/co/nilin/opex/common/data/CalenderType.kt create mode 100644 common/src/main/kotlin/co/nilin/opex/common/data/LanguageDirection.kt create mode 100644 common/src/main/kotlin/co/nilin/opex/common/data/LanguageOption.kt create mode 100644 common/src/main/kotlin/co/nilin/opex/common/data/Theme.kt create mode 100644 common/src/main/kotlin/co/nilin/opex/common/data/WebConfig.kt create mode 100644 common/src/main/kotlin/co/nilin/opex/common/proxy/ConfigClient.kt rename common/src/main/kotlin/co/nilin/opex/common/{translation/ConfigClient.kt => proxy/CustomMessageClient.kt} (87%) rename common/src/main/kotlin/co/nilin/opex/common/{translation => service}/CustomErrorTranslator.kt (96%) create mode 100644 common/src/main/kotlin/co/nilin/opex/common/service/CustomUserLanguageConfig.kt rename common/src/main/kotlin/co/nilin/opex/common/{translation => service}/TranslationCacheService.kt (83%) create mode 100644 common/src/main/kotlin/co/nilin/opex/common/service/WebConfigCacheService.kt diff --git a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/WebClientConfig.kt b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/WebClientConfig.kt index a2fb64d13..6c905a414 100644 --- a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/WebClientConfig.kt +++ b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/WebClientConfig.kt @@ -1,6 +1,7 @@ package co.nilin.opex.api.app.config import co.nilin.opex.common.data.UserLanguage +import co.nilin.opex.common.utils.LanguageUtils.getDefaultUserLanguage import io.netty.channel.ChannelOption import io.netty.handler.logging.LogLevel import org.springframework.cloud.client.ServiceInstance @@ -76,7 +77,7 @@ class WebClientConfig(private val logbook: Logbook) { private fun languageFilter() = ExchangeFilterFunction { request, next -> Mono.deferContextual { ctx -> - val lang = ctx.getOrDefault("lang", UserLanguage.EN.toString()) + val lang = ctx.getOrDefault("lang", getDefaultUserLanguage()) val mutatedRequest = ClientRequest.from(request) .header("Accept-Language", lang) .build() diff --git a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/service/OpexFilterExceptionHandler.kt b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/service/OpexFilterExceptionHandler.kt index 131fb0522..afc37bcf0 100644 --- a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/service/OpexFilterExceptionHandler.kt +++ b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/service/OpexFilterExceptionHandler.kt @@ -22,7 +22,7 @@ class OpexFilterExceptionHandler( if (ex is OpexException) { return translator.translate(ex).flatMap { error -> - exchange.response.statusCode = HttpStatusCode.valueOf(error.status.value()) + exchange.response.statusCode = HttpStatusCode.valueOf(error.status?.value() ?: 500) exchange.response.headers.contentType = MediaType.APPLICATION_JSON val bytes = objectMapper.writeValueAsBytes(error) diff --git a/api/api-app/src/main/resources/application.yml b/api/api-app/src/main/resources/application.yml index 75e48f9e2..1e6b9190e 100644 --- a/api/api-app/src/main/resources/application.yml +++ b/api/api-app/src/main/resources/application.yml @@ -129,6 +129,8 @@ app: url: http://opex-bc-gateway storage: url: http://storage + config: + url: http://opex-config auth: cert-url: http://keycloak:8080/realms/opex/protocol/openid-connect/certs iss-url: ${TOKEN_ISSUER_URL:http://keycloak:8080/realms/opex} diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/UpdateWebConfigRequest.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/UpdateWebConfigRequest.kt new file mode 100644 index 000000000..c855a89b2 --- /dev/null +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/UpdateWebConfigRequest.kt @@ -0,0 +1,18 @@ +package co.nilin.opex.api.core.inout + +import co.nilin.opex.common.data.CalenderType +import co.nilin.opex.common.data.LanguageOption +import co.nilin.opex.common.data.Theme +import co.nilin.opex.common.data.UserLanguage + +data class UpdateWebConfigRequest( + val logoUrl: String?, + val title: String?, + val description: String?, + var defaultLanguage: UserLanguage?, + var supportedLanguages: Map?, + var supportedCalenders: List?, + val defaultTheme: Theme?, + val supportedThemes: List?, + val supportEmail: String?, +) \ No newline at end of file diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/ConfigProxy.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/ConfigProxy.kt new file mode 100644 index 000000000..a5518654a --- /dev/null +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/ConfigProxy.kt @@ -0,0 +1,11 @@ +package co.nilin.opex.api.core.spi + +import co.nilin.opex.api.core.inout.UpdateWebConfigRequest +import co.nilin.opex.common.data.WebConfig + +interface ConfigProxy { + + suspend fun getWebConfig(): WebConfig + suspend fun updateWebConfig(token: String, request: UpdateWebConfigRequest) : WebConfig + +} diff --git a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt index 8528dfabf..4e60277b4 100644 --- a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt +++ b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt @@ -51,6 +51,7 @@ class SecurityConfig( // Opex endpoints .pathMatchers("/opex/v1/admin/transactions/**").hasAnyAuthority("ROLE_monitoring", "ROLE_admin") .pathMatchers("/opex/v1/storage/**").permitAll() + .pathMatchers("/opex/v1/web/config/**").permitAll() .pathMatchers("/opex/v1/admin/**").hasAuthority("ROLE_admin") .pathMatchers("/opex/v1/deposit/**").hasAuthority("PERM_deposit:write") .pathMatchers(HttpMethod.POST, "/opex/v1/order").hasAuthority("PERM_order:write") diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ConfigController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ConfigController.kt new file mode 100644 index 000000000..dd8576efd --- /dev/null +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ConfigController.kt @@ -0,0 +1,29 @@ +package co.nilin.opex.api.ports.opex.controller + +import co.nilin.opex.api.core.inout.UpdateWebConfigRequest +import co.nilin.opex.api.core.spi.ConfigProxy +import co.nilin.opex.api.ports.opex.util.jwtAuthentication +import co.nilin.opex.api.ports.opex.util.tokenValue +import co.nilin.opex.common.data.WebConfig +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.* + +@RestController +@RequestMapping("/opex/v1") +class ConfigController(private val configProxy: ConfigProxy) { + + @GetMapping("/web/config") + suspend fun getWebConfig(): WebConfig { + return configProxy.getWebConfig() + } + + @PutMapping("/admin/web/config") + suspend fun updateWebConfig( + @CurrentSecurityContext securityContext: SecurityContext, + @RequestBody request: UpdateWebConfigRequest + ): WebConfig { + return configProxy.updateWebConfig(securityContext.jwtAuthentication().tokenValue(), request) + } + +} \ No newline at end of file diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt index 8b82f11c0..85889788f 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt @@ -14,7 +14,7 @@ class GatewayAdminController( private val walletProxy: WalletProxy, ) { @PostMapping("/{currencySymbol}/gateway") - suspend fun addCurrencyToGateway( + suspend fun addGatewayToCurrency( @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("currencySymbol") currencySymbol: String, @RequestBody body: CurrencyGatewayCommand, diff --git a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/ConfigProxyImpl.kt b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/ConfigProxyImpl.kt new file mode 100644 index 000000000..8f6d6d265 --- /dev/null +++ b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/ConfigProxyImpl.kt @@ -0,0 +1,51 @@ +package co.nilin.opex.api.ports.proxy.impl + +import co.nilin.opex.api.core.inout.UpdateWebConfigRequest +import co.nilin.opex.api.core.spi.ConfigProxy +import co.nilin.opex.common.OpexError +import co.nilin.opex.common.data.WebConfig +import co.nilin.opex.common.utils.LoggerDelegate +import kotlinx.coroutines.reactive.awaitFirstOrElse +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.beans.factory.annotation.Value +import org.springframework.http.HttpHeaders +import org.springframework.http.MediaType +import org.springframework.stereotype.Component +import org.springframework.web.reactive.function.client.WebClient +import org.springframework.web.reactive.function.client.body +import org.springframework.web.reactive.function.client.bodyToMono +import reactor.core.publisher.Mono + +@Component +class ConfigProxyImpl(@Qualifier("generalWebClient") private val webClient: WebClient) : ConfigProxy { + + private val logger by LoggerDelegate() + + @Value("\${app.config.url}") + private lateinit var baseUrl: String + + override suspend fun getWebConfig(): WebConfig { + return webClient.get() + .uri("$baseUrl/web/v1") + .accept(MediaType.APPLICATION_JSON) + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono() + .awaitFirstOrElse { throw OpexError.BadRequest.exception("Failed to get web config") } + } + + override suspend fun updateWebConfig( + token: String, + request: UpdateWebConfigRequest + ): WebConfig { + return webClient.put() + .uri("$baseUrl/web/v1") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .body(Mono.just(request)) + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono() + .awaitFirstOrElse { throw OpexError.BadRequest.exception() } + } +} diff --git a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/dao/CurrencyImplementationRepository.kt b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/dao/CurrencyImplementationRepository.kt index b1b62570c..00ad40987 100644 --- a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/dao/CurrencyImplementationRepository.kt +++ b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/dao/CurrencyImplementationRepository.kt @@ -53,7 +53,7 @@ interface CurrencyImplementationRepository : ReactiveCrudRepository? fun deleteByGatewayUuid(uuid: String): Mono @@ -101,7 +101,7 @@ interface CurrencyImplementationRepository : ReactiveCrudRepository? @Query("select * from currency_on_chain_gateway where chain = :chain and is_token is false") diff --git a/common/src/main/kotlin/co/nilin/opex/common/config/ErrorConfig.kt b/common/src/main/kotlin/co/nilin/opex/common/config/ErrorConfig.kt index c8f93a946..c501cbd4b 100644 --- a/common/src/main/kotlin/co/nilin/opex/common/config/ErrorConfig.kt +++ b/common/src/main/kotlin/co/nilin/opex/common/config/ErrorConfig.kt @@ -1,16 +1,10 @@ package co.nilin.opex.common.config -import co.nilin.opex.common.translation.CustomErrorTranslator +import co.nilin.opex.common.service.CustomErrorTranslator import co.nilin.opex.utility.error.spi.ErrorTranslator -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean -import org.springframework.context.MessageSource import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Primary -import org.springframework.context.annotation.Scope -import org.springframework.context.support.ReloadableResourceBundleMessageSource -import org.springframework.scheduling.annotation.EnableScheduling -import org.springframework.web.server.ServerWebExchange @Configuration class ErrorConfig { diff --git a/common/src/main/kotlin/co/nilin/opex/common/data/CalenderType.kt b/common/src/main/kotlin/co/nilin/opex/common/data/CalenderType.kt new file mode 100644 index 000000000..e36d83c29 --- /dev/null +++ b/common/src/main/kotlin/co/nilin/opex/common/data/CalenderType.kt @@ -0,0 +1,5 @@ +package co.nilin.opex.common.data + +enum class CalenderType { + JALALI, HIJRI, GREGORIAN +} \ No newline at end of file diff --git a/common/src/main/kotlin/co/nilin/opex/common/data/LanguageDirection.kt b/common/src/main/kotlin/co/nilin/opex/common/data/LanguageDirection.kt new file mode 100644 index 000000000..2263833c8 --- /dev/null +++ b/common/src/main/kotlin/co/nilin/opex/common/data/LanguageDirection.kt @@ -0,0 +1,5 @@ +package co.nilin.opex.common.data + +enum class LanguageDirection { + RTL, LTR +} \ No newline at end of file diff --git a/common/src/main/kotlin/co/nilin/opex/common/data/LanguageOption.kt b/common/src/main/kotlin/co/nilin/opex/common/data/LanguageOption.kt new file mode 100644 index 000000000..9ba072ca0 --- /dev/null +++ b/common/src/main/kotlin/co/nilin/opex/common/data/LanguageOption.kt @@ -0,0 +1,8 @@ +package co.nilin.opex.common.data + +data class LanguageOption( + val label: String, + val nativeLabel: String, + val direction: LanguageDirection, + val defaultCalender: CalenderType, +) \ No newline at end of file diff --git a/common/src/main/kotlin/co/nilin/opex/common/data/Theme.kt b/common/src/main/kotlin/co/nilin/opex/common/data/Theme.kt new file mode 100644 index 000000000..a3b814cf3 --- /dev/null +++ b/common/src/main/kotlin/co/nilin/opex/common/data/Theme.kt @@ -0,0 +1,5 @@ +package co.nilin.opex.common.data + +enum class Theme { + DARK, LIGHT, SYSTEM +} \ No newline at end of file diff --git a/common/src/main/kotlin/co/nilin/opex/common/data/UserLanguage.kt b/common/src/main/kotlin/co/nilin/opex/common/data/UserLanguage.kt index 9cb07c446..8abf88463 100644 --- a/common/src/main/kotlin/co/nilin/opex/common/data/UserLanguage.kt +++ b/common/src/main/kotlin/co/nilin/opex/common/data/UserLanguage.kt @@ -1,22 +1,22 @@ package co.nilin.opex.common.data -//After adjusting versions in various modules it should be moved to common project +import co.nilin.opex.common.service.GlobalWebConfigCache enum class UserLanguage { - EN, FA; + EN, FA, AR, UZ; companion object { + + fun getDefaultLanguage(): String = + GlobalWebConfigCache.webConfig?.defaultLanguage?.name ?: EN.name + fun safeValueOf(lang: String?): UserLanguage { return try { - if (lang.isNullOrBlank()) EN + if (lang.isNullOrBlank()) valueOf(getDefaultLanguage()) else valueOf(lang.uppercase()) } catch (e: IllegalArgumentException) { - EN + valueOf(getDefaultLanguage()) } } - - fun getDefault(): UserLanguage { - return EN - } } } \ No newline at end of file diff --git a/common/src/main/kotlin/co/nilin/opex/common/data/WebConfig.kt b/common/src/main/kotlin/co/nilin/opex/common/data/WebConfig.kt new file mode 100644 index 000000000..7a129f612 --- /dev/null +++ b/common/src/main/kotlin/co/nilin/opex/common/data/WebConfig.kt @@ -0,0 +1,13 @@ +package co.nilin.opex.common.data + +data class WebConfig( + val logoUrl: String?, + val title: String?, + val description: String?, + var defaultLanguage: UserLanguage?, + var supportedLanguages: Map?, + var supportedCalenders: List?, + val defaultTheme: Theme?, + var supportedThemes: List?, + val supportEmail: String?, +) \ No newline at end of file diff --git a/common/src/main/kotlin/co/nilin/opex/common/proxy/ConfigClient.kt b/common/src/main/kotlin/co/nilin/opex/common/proxy/ConfigClient.kt new file mode 100644 index 000000000..6a28796e5 --- /dev/null +++ b/common/src/main/kotlin/co/nilin/opex/common/proxy/ConfigClient.kt @@ -0,0 +1,26 @@ +package co.nilin.opex.common.proxy + +import co.nilin.opex.common.config.CommonWebClient +import co.nilin.opex.common.data.WebConfig +import kotlinx.coroutines.reactive.awaitFirst +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.core.ParameterizedTypeReference +import org.springframework.stereotype.Component + +inline fun typeRef(): ParameterizedTypeReference = object : ParameterizedTypeReference() {} + +@Component +class ConfigClient( + @Qualifier("CommonWebClient") private val webClient: CommonWebClient +) { + + suspend fun getWebConfig(): WebConfig { + return webClient.delegate.get().uri("http://config:8080/web/v1") { + it.build() + }.retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono(typeRef()) + .log() + .awaitFirst() + } +} diff --git a/common/src/main/kotlin/co/nilin/opex/common/translation/ConfigClient.kt b/common/src/main/kotlin/co/nilin/opex/common/proxy/CustomMessageClient.kt similarity index 87% rename from common/src/main/kotlin/co/nilin/opex/common/translation/ConfigClient.kt rename to common/src/main/kotlin/co/nilin/opex/common/proxy/CustomMessageClient.kt index 71be97e6b..089d6291d 100644 --- a/common/src/main/kotlin/co/nilin/opex/common/translation/ConfigClient.kt +++ b/common/src/main/kotlin/co/nilin/opex/common/proxy/CustomMessageClient.kt @@ -1,4 +1,4 @@ -package co.nilin.opex.common.translation +package co.nilin.opex.common.proxy import co.nilin.opex.common.config.CommonWebClient import co.nilin.opex.common.data.MessageTranslation @@ -9,11 +9,10 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.core.ParameterizedTypeReference import org.springframework.stereotype.Component -inline fun typeRef(): ParameterizedTypeReference = object : ParameterizedTypeReference() {} @Component @ConditionalOnProperty(name = ["app.custom-message.enabled"], havingValue = "true", matchIfMissing = false) -class ConfigClient( +class CustomMessageClient( @Qualifier("CommonWebClient") private val webClient: CommonWebClient ) { @Value("\${app.custom-message.base-url}") diff --git a/common/src/main/kotlin/co/nilin/opex/common/translation/CustomErrorTranslator.kt b/common/src/main/kotlin/co/nilin/opex/common/service/CustomErrorTranslator.kt similarity index 96% rename from common/src/main/kotlin/co/nilin/opex/common/translation/CustomErrorTranslator.kt rename to common/src/main/kotlin/co/nilin/opex/common/service/CustomErrorTranslator.kt index 1fcffc9d6..9e18f268d 100644 --- a/common/src/main/kotlin/co/nilin/opex/common/translation/CustomErrorTranslator.kt +++ b/common/src/main/kotlin/co/nilin/opex/common/service/CustomErrorTranslator.kt @@ -1,4 +1,4 @@ -package co.nilin.opex.common.translation +package co.nilin.opex.common.service import co.nilin.opex.common.utils.LanguageUtils.getUserLanguage import co.nilin.opex.utility.error.data.DefaultExceptionResponse diff --git a/common/src/main/kotlin/co/nilin/opex/common/service/CustomUserLanguageConfig.kt b/common/src/main/kotlin/co/nilin/opex/common/service/CustomUserLanguageConfig.kt new file mode 100644 index 000000000..ffb148a60 --- /dev/null +++ b/common/src/main/kotlin/co/nilin/opex/common/service/CustomUserLanguageConfig.kt @@ -0,0 +1,15 @@ +package co.nilin.opex.common.service + +import co.nilin.opex.common.data.UserLanguage.EN +import co.nilin.opex.utility.interceptors.spi.UserLanguageConfig +import org.springframework.context.annotation.Primary +import org.springframework.stereotype.Service + +@Service +@Primary +class CustomUserLanguageConfig : UserLanguageConfig { + override fun getDefaultLanguage(): String = + runCatching { + GlobalWebConfigCache.webConfig?.defaultLanguage?.name + }.getOrNull() ?: EN.name +} \ No newline at end of file diff --git a/common/src/main/kotlin/co/nilin/opex/common/translation/TranslationCacheService.kt b/common/src/main/kotlin/co/nilin/opex/common/service/TranslationCacheService.kt similarity index 83% rename from common/src/main/kotlin/co/nilin/opex/common/translation/TranslationCacheService.kt rename to common/src/main/kotlin/co/nilin/opex/common/service/TranslationCacheService.kt index a75ced806..9193f38ef 100644 --- a/common/src/main/kotlin/co/nilin/opex/common/translation/TranslationCacheService.kt +++ b/common/src/main/kotlin/co/nilin/opex/common/service/TranslationCacheService.kt @@ -1,7 +1,8 @@ -package co.nilin.opex.common.translation +package co.nilin.opex.common.service import co.nilin.opex.common.data.MessageTranslation import co.nilin.opex.common.data.UserLanguage +import co.nilin.opex.common.proxy.CustomMessageClient import kotlinx.coroutines.* import org.slf4j.LoggerFactory import org.springframework.context.MessageSource @@ -13,8 +14,8 @@ import javax.annotation.PreDestroy @Service class TranslationCacheService( - private val configClient: ConfigClient?, - private val messageSource: MessageSource? + private val customMessageClient: CustomMessageClient?, + private val messageSource: MessageSource? ) { private val cache: MutableMap, MessageTranslation> = ConcurrentHashMap() @@ -28,8 +29,8 @@ class TranslationCacheService( job = CoroutineScope(Dispatchers.IO).launch { logger.info("Going to get messages which are updated after {}", lastUpdate) while (isActive) { - if (configClient != null) { - val newMessages = configClient.getMessagesUpdatedAfter(cache?.let { lastUpdate }) + if (customMessageClient != null) { + val newMessages = customMessageClient.getMessagesUpdatedAfter(cache?.let { lastUpdate }) newMessages?.forEach { msg -> cache[Pair(msg.key, msg.language)] = MessageTranslation(msg.key, msg.message, msg.language) diff --git a/common/src/main/kotlin/co/nilin/opex/common/service/WebConfigCacheService.kt b/common/src/main/kotlin/co/nilin/opex/common/service/WebConfigCacheService.kt new file mode 100644 index 000000000..89a7e8ee8 --- /dev/null +++ b/common/src/main/kotlin/co/nilin/opex/common/service/WebConfigCacheService.kt @@ -0,0 +1,30 @@ +package co.nilin.opex.common.service + +import co.nilin.opex.common.data.WebConfig +import co.nilin.opex.common.proxy.ConfigClient +import kotlinx.coroutines.runBlocking +import org.springframework.scheduling.annotation.Scheduled +import org.springframework.stereotype.Service + +object GlobalWebConfigCache { + @Volatile + var webConfig: WebConfig? = null +} + +@Service +class WebConfigService( + private val configClient: ConfigClient, +) { + + @Scheduled(fixedDelay = 5 * 60 * 1000) + fun refreshWebConfig() = runBlocking { + try { + val webConfig: WebConfig = configClient.getWebConfig() + + GlobalWebConfigCache.webConfig = webConfig + + } catch (e: Exception) { + println("WebConfig refresh failed: ${e.message}") + } + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/co/nilin/opex/common/utils/LanguageUtils.kt b/common/src/main/kotlin/co/nilin/opex/common/utils/LanguageUtils.kt index 3d03941f8..9c04ab8db 100644 --- a/common/src/main/kotlin/co/nilin/opex/common/utils/LanguageUtils.kt +++ b/common/src/main/kotlin/co/nilin/opex/common/utils/LanguageUtils.kt @@ -1,12 +1,19 @@ package co.nilin.opex.common.utils import co.nilin.opex.common.data.UserLanguage +import co.nilin.opex.common.service.GlobalWebConfigCache import reactor.core.publisher.Mono object LanguageUtils { fun getUserLanguage(): Mono = - Mono.deferContextual { ctx -> Mono.just(ctx.getOrDefault("lang", UserLanguage.EN.toString())!!) } + Mono.deferContextual { ctx -> Mono.just(ctx.getOrDefault("lang", getDefaultUserLanguage())!!) } - fun getDefaultUserLanguage(): String = UserLanguage.EN.toString() + fun getDefaultUserLanguage(): String { + return try { + GlobalWebConfigCache.webConfig?.defaultLanguage?.toString() ?: UserLanguage.EN.toString() + } catch (e: Exception) { + UserLanguage.EN.toString() + } + } } \ No newline at end of file diff --git a/pom.xml b/pom.xml index 6065ab1e4..e7514e336 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ 2.7.6 2021.0.5 1.2.23 - 1.0.7 + 1.0.8 true 1.0.1-beta.36 diff --git a/user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/utils/ErrorHandler.kt b/user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/utils/ErrorHandler.kt index c4400233d..b0281ca45 100644 --- a/user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/utils/ErrorHandler.kt +++ b/user-management/keycloak-gateway/src/main/kotlin/co/nilin/opex/auth/gateway/utils/ErrorHandler.kt @@ -1,7 +1,7 @@ package co.nilin.opex.auth.gateway.utils import co.nilin.opex.common.OpexError -import co.nilin.opex.common.translation.CustomErrorTranslator +import co.nilin.opex.common.service.CustomErrorTranslator import co.nilin.opex.utility.error.data.OpexException import javax.ws.rs.core.MediaType import javax.ws.rs.core.Response diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/WebClientConfig.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/WebClientConfig.kt index 4b6bdd82e..9405d2146 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/WebClientConfig.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/WebClientConfig.kt @@ -1,6 +1,7 @@ package co.nilin.opex.wallet.app.config import co.nilin.opex.common.data.UserLanguage +import co.nilin.opex.common.utils.LanguageUtils.getDefaultUserLanguage import io.netty.channel.ChannelOption import org.springframework.beans.factory.annotation.Qualifier import org.springframework.cloud.client.ServiceInstance @@ -64,7 +65,7 @@ class WebClientConfig(logbook: Logbook) { private fun languageFilter() = ExchangeFilterFunction { request, next -> Mono.deferContextual { ctx -> - val lang = ctx.getOrDefault("lang", UserLanguage.EN.toString()) + val lang = ctx.getOrDefault("lang", getDefaultUserLanguage()) val mutatedRequest = ClientRequest.from(request) .header("Accept-Language", lang) .build() diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/CurrencyRepositoryV2.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/CurrencyRepositoryV2.kt index 7ddf89102..9e5ad0959 100644 --- a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/CurrencyRepositoryV2.kt +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/CurrencyRepositoryV2.kt @@ -45,7 +45,7 @@ interface CurrencyRepositoryV2 : ReactiveCrudRepository { fun fetchCurrency( uuid: String? = null, symbol: String? = null, - lang: String? = UserLanguage.getDefault().toString() + lang: String? = UserLanguage.getDefaultLanguage() ): Mono? @@ -78,7 +78,7 @@ interface CurrencyRepositoryV2 : ReactiveCrudRepository { fun fetchSemiCurrencies( symbol: String? = null, name: String? = null, - lang: String? = UserLanguage.getDefault().toString() + lang: String? = UserLanguage.getDefaultLanguage() ): Flux? @@ -120,7 +120,7 @@ interface CurrencyRepositoryV2 : ReactiveCrudRepository { ORDER BY c.display_order """ ) - fun fetchAll(lang: String? = UserLanguage.getDefault().toString()): Flux + fun fetchAll(lang: String? = UserLanguage.getDefaultLanguage()): Flux @Query("select symbol,precision from currency") fun fetchAllCurrenciesPrecision(): Flux diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/GatewayTerminalRepository.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/GatewayTerminalRepository.kt index be1bc1949..65e594ffc 100644 --- a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/GatewayTerminalRepository.kt +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/GatewayTerminalRepository.kt @@ -33,7 +33,7 @@ interface GatewayTerminalRepository : ReactiveCrudRepository? + fun findByGatewayId(gatewayId: Long, lang: String? = UserLanguage.getDefaultLanguage()): Flux? @Query(""" @@ -57,5 +57,5 @@ interface GatewayTerminalRepository : ReactiveCrudRepository? + fun findByTerminalId(terminalId: Long, lang: String? = UserLanguage.getDefaultLanguage()): Flux? } diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/OffChainGatewayRepository.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/OffChainGatewayRepository.kt index fa4f33312..b28413a4e 100644 --- a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/OffChainGatewayRepository.kt +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/OffChainGatewayRepository.kt @@ -37,7 +37,7 @@ interface OffChainGatewayRepository : ReactiveCrudRepository? fun deleteByGatewayUuid(uuid: String): Mono @@ -67,7 +67,7 @@ interface OffChainGatewayRepository : ReactiveCrudRepository? fun findByCurrencySymbolAndAndTransferMethod( diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/TerminalRepository.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/TerminalRepository.kt index 30c230dab..219863116 100644 --- a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/TerminalRepository.kt +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/TerminalRepository.kt @@ -31,7 +31,7 @@ interface TerminalRepository : ReactiveCrudRepository { WHERE t.uuid = :uuid; """ ) - fun findByUuid(uuid: String, lang: String? = UserLanguage.getDefault().toString()): Mono? + fun findByUuid(uuid: String, lang: String? = UserLanguage.getDefaultLanguage()): Mono? @Query( """ @@ -51,7 +51,7 @@ interface TerminalRepository : ReactiveCrudRepository { order by t.display_order """ ) - fun findAllByOrderByDisplayOrder(lang: String?= UserLanguage.getDefault().toString()): Flux + fun findAllByOrderByDisplayOrder(lang: String?= UserLanguage.getDefaultLanguage()): Flux } \ No newline at end of file