From be883adb48530d74ab03a26cee17ca589d1b75b0 Mon Sep 17 00:00:00 2001 From: Amir Rajabi Date: Mon, 27 Apr 2026 15:46:34 +0330 Subject: [PATCH 1/5] Add gateway localization support (step1) --- .../core/model/CurrencyOnChainGatewayView.kt | 29 +++++++++ .../dao/CurrencyImplementationRepository.kt | 64 ++++++++++++++++++- ...ncyOnChainGatewayLocalizationRepository.kt | 10 +++ .../postgres/impl/CurrencyHandlerImplV2.kt | 64 ++++++++++++++++--- ...CurrencyOnChainGatewayLocalizationModel.kt | 19 ++++++ .../model/CurrencyOnChainGatewayModel.kt | 5 +- .../ports/postgres/util/Convertor.kt | 33 ++++++++-- .../V4__drop_address_regex_from_chain.sql | 1 - .../V5__add_gateway_localization_table.sql | 20 ++++++ .../dao/CurrencyLocalizationsRepository.kt | 1 + 10 files changed, 226 insertions(+), 20 deletions(-) create mode 100644 bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/CurrencyOnChainGatewayView.kt create mode 100644 bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/dao/CurrencyOnChainGatewayLocalizationRepository.kt create mode 100644 bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/model/CurrencyOnChainGatewayLocalizationModel.kt delete mode 100644 bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/resources/db/migration/V4__drop_address_regex_from_chain.sql create mode 100644 bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/resources/db/migration/V5__add_gateway_localization_table.sql diff --git a/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/CurrencyOnChainGatewayView.kt b/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/CurrencyOnChainGatewayView.kt new file mode 100644 index 000000000..7e0100e49 --- /dev/null +++ b/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/CurrencyOnChainGatewayView.kt @@ -0,0 +1,29 @@ +package co.nilin.opex.bcgateway.core.model + +import java.math.BigDecimal + +data class CurrencyOnChainGatewayView( + var id: Long? = null, + val gatewayUuid: String, + val currencySymbol: String, + var implementationSymbol: String? = currencySymbol, + var chain: String, + var isToken: Boolean? = false, + var tokenAddress: String? = null, + var tokenName: String? = null, + var withdrawAllowed: Boolean, + var depositAllowed: Boolean, + var withdrawFee: BigDecimal, + var withdrawMin: BigDecimal? = BigDecimal.ZERO, + var withdrawMax: BigDecimal? = BigDecimal.ZERO, + var depositMin: BigDecimal? = BigDecimal.ZERO, + var depositMax: BigDecimal? = BigDecimal.ZERO, + var decimal: Int, + var isDepositActive: Boolean? = true, + var isWithdrawActive: Boolean? = true, + val depositDescription: String? = null, + val withdrawDescription: String? = null, + val displayOrder: Int? = null +) + + 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 51731495d..87cbd8ccc 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 @@ -1,5 +1,6 @@ package co.nilin.opex.bcgateway.ports.postgres.dao +import co.nilin.opex.bcgateway.core.model.CurrencyOnChainGatewayView import co.nilin.opex.bcgateway.core.model.WithdrawData import co.nilin.opex.bcgateway.ports.postgres.model.CurrencyOnChainGatewayModel import org.springframework.data.r2dbc.repository.Query @@ -13,13 +14,43 @@ interface CurrencyImplementationRepository : ReactiveCrudRepository? - @Query("select * from currency_on_chain_gateway where (:gatewayUuid is null or gateway_uuid=:gatewayUuid) and (:currencySymbol is null or currency_symbol=:currencySymbol ) and (:implementationSymbol is null or implementation_symbol=:implementationSymbol ) and (:chain is null or chain=:chain ) order by display_order") + @Query(""" + SELECT c.id, + c.gateway_uuid, + c.currency_symbol, + c.implementation_symbol, + c.chain, + c.is_token, + c.token_address, + c.token_name, + c.withdraw_allowed, + c.deposit_allowed, + c.withdraw_fee, + c.withdraw_min, + c.withdraw_max, + c.deposit_min, + c.deposit_max, + c.decimal, + c.is_deposit_active, + c.is_withdraw_active, + cl.deposit_description, + cl.withdraw_description, + c.display_order + FROM currency_on_chain_gateway c + LEFT JOIN public.currency_on_chain_gateway_localization cl ON c.id = cl.gateway_id AND cl.language = :lang + where (:gatewayUuid is null or gateway_uuid=:gatewayUuid) + and (:currencySymbol is null or currency_symbol=:currencySymbol ) + and (:implementationSymbol is null or implementation_symbol=:implementationSymbol ) + and (:chain is null or chain=:chain ) + order by display_order + """) + fun findGateways( currencySymbol: String? = null, gatewayUuid: String? = null, chain: String? = null, implementationSymbol: String? = null - ): Flux? + ): Flux? fun deleteByGatewayUuid(uuid: String): Mono @@ -34,7 +65,34 @@ interface CurrencyImplementationRepository : ReactiveCrudRepository - fun findByGatewayUuidAndCurrencySymbol(gatewayUuid: String?, symbol: String?): Mono? + @Query(""" + SELECT c.id, + c.gateway_uuid, + c.currency_symbol, + c.implementation_symbol, + c.chain, + c.is_token, + c.token_address, + c.token_name, + c.withdraw_allowed, + c.deposit_allowed, + c.withdraw_fee, + c.withdraw_min, + c.withdraw_max, + c.deposit_min, + c.deposit_max, + c.decimal, + c.is_deposit_active, + c.is_withdraw_active, + cl.deposit_description, + cl.withdraw_description, + c.display_order + FROM currency_on_chain_gateway c + LEFT JOIN public.currency_on_chain_gateway_localization cl ON c.id = cl.gateway_id AND cl.language = :lang + where c.gateway_uuid = :gatewayUuid + and c.currency_symbol = :symbol; + """) + fun findByGatewayUuidAndCurrencySymbol(gatewayUuid: String, symbol: String , lang : String): Mono? @Query("select * from currency_on_chain_gateway where chain = :chain and is_token is false") fun findMainAssetGateway(chain: String): Mono diff --git a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/dao/CurrencyOnChainGatewayLocalizationRepository.kt b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/dao/CurrencyOnChainGatewayLocalizationRepository.kt new file mode 100644 index 000000000..4cc007cc4 --- /dev/null +++ b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/dao/CurrencyOnChainGatewayLocalizationRepository.kt @@ -0,0 +1,10 @@ +package co.nilin.opex.bcgateway.ports.postgres.dao + +import co.nilin.opex.bcgateway.ports.postgres.model.CurrencyOnChainGatewayLocalizationModel +import org.springframework.data.repository.reactive.ReactiveCrudRepository +import org.springframework.stereotype.Repository + +@Repository +interface CurrencyOnChainGatewayLocalizationRepository : + ReactiveCrudRepository { +} \ No newline at end of file diff --git a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/impl/CurrencyHandlerImplV2.kt b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/impl/CurrencyHandlerImplV2.kt index 2d9645644..043503171 100644 --- a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/impl/CurrencyHandlerImplV2.kt +++ b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/impl/CurrencyHandlerImplV2.kt @@ -1,20 +1,28 @@ package co.nilin.opex.bcgateway.ports.postgres.impl import co.nilin.opex.bcgateway.core.model.CryptoCurrencyCommand +import co.nilin.opex.bcgateway.core.model.CurrencyOnChainGatewayView import co.nilin.opex.bcgateway.core.model.FetchGateways import co.nilin.opex.bcgateway.core.model.WithdrawData import co.nilin.opex.bcgateway.core.spi.CryptoCurrencyHandlerV2 import co.nilin.opex.bcgateway.ports.postgres.dao.ChainRepository import co.nilin.opex.bcgateway.ports.postgres.dao.CurrencyImplementationRepository +import co.nilin.opex.bcgateway.ports.postgres.dao.CurrencyOnChainGatewayLocalizationRepository +import co.nilin.opex.bcgateway.ports.postgres.model.CurrencyOnChainGatewayLocalizationModel import co.nilin.opex.bcgateway.ports.postgres.model.CurrencyOnChainGatewayModel import co.nilin.opex.bcgateway.ports.postgres.util.toDto import co.nilin.opex.bcgateway.ports.postgres.util.toModel import co.nilin.opex.common.OpexError +import co.nilin.opex.common.data.UserLanguage +import co.nilin.opex.common.utils.LanguageUtils.getDefaultUserLanguage +import co.nilin.opex.common.utils.LanguageUtils.getUserLanguage import kotlinx.coroutines.reactive.awaitFirstOrElse import kotlinx.coroutines.reactive.awaitFirstOrNull import kotlinx.coroutines.reactor.awaitSingleOrNull import org.slf4j.LoggerFactory import org.springframework.stereotype.Component +import org.springframework.transaction.reactive.TransactionalOperator +import org.springframework.transaction.reactive.executeAndAwait import reactor.core.publisher.Flux import reactor.core.publisher.Mono import java.util.stream.Collectors @@ -22,7 +30,9 @@ import java.util.stream.Collectors @Component class CurrencyHandlerImplV2( private val chainRepository: ChainRepository, - private val currencyImplementationRepository: CurrencyImplementationRepository + private val currencyImplementationRepository: CurrencyImplementationRepository, + private val currencyOnChainGatewayLocalizationRepository: CurrencyOnChainGatewayLocalizationRepository, + private val transactionalOperator: TransactionalOperator ) : CryptoCurrencyHandlerV2 { private val logger = LoggerFactory.getLogger(CurrencyHandlerImplV2::class.java) @@ -36,13 +46,13 @@ class CurrencyHandlerImplV2( implementationSymbol = request.implementationSymbol ) ?.awaitFirstOrNull()?.let { throw OpexError.GatewayIsExist.exception() } - return doSave(request.toModel())?.toDto(); + return doSave(request)?.toDto(); } override suspend fun updateOnChainGateway(request: CryptoCurrencyCommand): CryptoCurrencyCommand? { return loadImpls(FetchGateways(gatewayUuid = request.gatewayUuid, currencySymbol = request.currencySymbol)) ?.awaitFirstOrElse { throw OpexError.GatewayNotFount.exception() }?.let { oldGateway -> - doSave(oldGateway.toDto().updateTo(request).toModel().apply { id = oldGateway.id })?.toDto() + doUpdate(oldGateway.toDto().updateTo(request).toModel().apply { id = oldGateway.id })?.toDto() } } @@ -67,10 +77,14 @@ class CurrencyHandlerImplV2( } override suspend fun fetchOnChainGateway(gatewayUuid: String, symbol: String): CryptoCurrencyCommand? { - return loadImpl(gatewayUuid, symbol)?.awaitFirstOrNull()?.toDto() + return loadImpl( + gatewayUuid, + symbol, + UserLanguage.safeValueOf(getUserLanguage().awaitSingleOrNull()).toString() + )?.awaitFirstOrNull()?.toDto() } - private suspend fun loadImpls(request: FetchGateways?): Flux? { + private suspend fun loadImpls(request: FetchGateways?): Flux? { var resp = currencyImplementationRepository.findGateways( request?.currencySymbol, request?.gatewayUuid, @@ -81,13 +95,45 @@ class CurrencyHandlerImplV2( ?: throw OpexError.ImplNotFound.exception() } - private suspend fun loadImpl(gateway: String, symbol: String): Mono? { - return currencyImplementationRepository.findByGatewayUuidAndCurrencySymbol(gateway, symbol) + private suspend fun loadImpl( + gateway: String, + symbol: String, + language: String + ): Mono? { + return currencyImplementationRepository.findByGatewayUuidAndCurrencySymbol( + gateway, + symbol, + language + ) ?: throw OpexError.ImplNotFound.exception() } - private suspend fun doSave(request: CurrencyOnChainGatewayModel): CurrencyOnChainGatewayModel? { - return currencyImplementationRepository.save(request).awaitSingleOrNull() + private suspend fun doSave(request: CryptoCurrencyCommand): CurrencyOnChainGatewayView? { + return transactionalOperator.executeAndAwait { + + val gateway = currencyImplementationRepository.save(request.toModel()).awaitSingleOrNull() + if (gateway == null) { + return@executeAndAwait null + } + + if (!request.depositDescription.isNullOrEmpty() && !request.withdrawDescription.isNullOrEmpty()) { + currencyOnChainGatewayLocalizationRepository.save( + CurrencyOnChainGatewayLocalizationModel( + gatewayId = gateway.id!!, + depositDescription = request.depositDescription, + withdrawDescription = request.withdrawDescription, + language = getDefaultUserLanguage() + ) + ).awaitSingleOrNull() + } + loadImpl(gateway.gatewayUuid, gateway.currencySymbol, getDefaultUserLanguage())?.awaitFirstOrNull() + + } + } + + private suspend fun doUpdate(request: CurrencyOnChainGatewayModel): CurrencyOnChainGatewayView? { + val gateway = currencyImplementationRepository.save(request).awaitSingleOrNull() ?: return null + return loadImpl(gateway.gatewayUuid, gateway.currencySymbol, getDefaultUserLanguage())?.awaitFirstOrNull() } override suspend fun changeWithdrawStatus(symbol: String, chain: String, status: Boolean) { diff --git a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/model/CurrencyOnChainGatewayLocalizationModel.kt b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/model/CurrencyOnChainGatewayLocalizationModel.kt new file mode 100644 index 000000000..66f61a0a2 --- /dev/null +++ b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/model/CurrencyOnChainGatewayLocalizationModel.kt @@ -0,0 +1,19 @@ +package co.nilin.opex.bcgateway.ports.postgres.model + + +import org.springframework.data.annotation.Id +import org.springframework.data.relational.core.mapping.Table + +@Table("currency_on_chain_gateway_localization") +data class CurrencyOnChainGatewayLocalizationModel( + @Id var id: Long? = null, + var gatewayId: Long, + var depositDescription: String? = null, + var withdrawDescription: String? = null, + var language: String + +) + + + + diff --git a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/model/CurrencyOnChainGatewayModel.kt b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/model/CurrencyOnChainGatewayModel.kt index c11f68548..537c5c86c 100644 --- a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/model/CurrencyOnChainGatewayModel.kt +++ b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/model/CurrencyOnChainGatewayModel.kt @@ -22,11 +22,10 @@ class CurrencyOnChainGatewayModel( @Column("withdraw_min") var withdrawMin: BigDecimal? = BigDecimal.ZERO, @Column("withdraw_max") var withdrawMax: BigDecimal? = BigDecimal.ZERO, @Column("deposit_min") var depositMin: BigDecimal? = BigDecimal.ZERO, - @Column("deposit_max") var depositMax: BigDecimal? = BigDecimal.ZERO, @Column("decimal") var decimal: Int, + @Column("deposit_max") var depositMax: BigDecimal? = BigDecimal.ZERO, + @Column("decimal") var decimal: Int, @Column("is_deposit_active") var isDepositActive: Boolean? = true, @Column("is_withdraw_active") var isWithdrawActive: Boolean? = true, - @Column("deposit_description") val depositDescription: String?, - @Column("withdraw_description") val withdrawDescription: String?, @Column("display_order") val displayOrder: Int? = null, ) diff --git a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/util/Convertor.kt b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/util/Convertor.kt index b975de602..2cdc74969 100644 --- a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/util/Convertor.kt +++ b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/util/Convertor.kt @@ -1,6 +1,7 @@ package co.nilin.opex.bcgateway.ports.postgres.util import co.nilin.opex.bcgateway.core.model.CryptoCurrencyCommand +import co.nilin.opex.bcgateway.core.model.CurrencyOnChainGatewayView import co.nilin.opex.bcgateway.ports.postgres.model.CurrencyOnChainGatewayModel @@ -23,8 +24,6 @@ fun CryptoCurrencyCommand.toModel(): CurrencyOnChainGatewayModel { decimal, isDepositActive, isWithdrawActive, - depositDescription, - withdrawDescription, displayOrder, ) } @@ -49,10 +48,36 @@ fun CurrencyOnChainGatewayModel.toDto(): CryptoCurrencyCommand { depositMax, decimal, chain, - depositDescription, - withdrawDescription, + null,//todo + null,//todo displayOrder, ) } +fun CurrencyOnChainGatewayView.toDto(): CryptoCurrencyCommand { + + return CryptoCurrencyCommand( + currencySymbol, + gatewayUuid, + implementationSymbol, + isDepositActive, + isWithdrawActive, + isToken, + tokenName, + tokenAddress, + withdrawFee, + withdrawAllowed, + depositAllowed, + withdrawMin, + withdrawMax, + depositMin, + depositMax, + decimal, + chain, + depositDescription, + withdrawDescription, + displayOrder, + ) + +} \ No newline at end of file diff --git a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/resources/db/migration/V4__drop_address_regex_from_chain.sql b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/resources/db/migration/V4__drop_address_regex_from_chain.sql deleted file mode 100644 index 8f8185f28..000000000 --- a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/resources/db/migration/V4__drop_address_regex_from_chain.sql +++ /dev/null @@ -1 +0,0 @@ -Alter table chains drop column address_regex; diff --git a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/resources/db/migration/V5__add_gateway_localization_table.sql b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/resources/db/migration/V5__add_gateway_localization_table.sql new file mode 100644 index 000000000..0bdce6c8f --- /dev/null +++ b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/resources/db/migration/V5__add_gateway_localization_table.sql @@ -0,0 +1,20 @@ +CREATE TABLE IF NOT EXISTS currency_on_chain_gateway_localization +( + id SERIAL PRIMARY KEY, + gateway_id BIGINT NOT NULL REFERENCES currency_on_chain_gateway (id) ON DELETE CASCADE, + deposit_description TEXT, + withdraw_description TEXT, + language VARCHAR(10) NOT NULL, + UNIQUE (gateway_id, language) +); + +INSERT INTO currency_on_chain_gateway_localization (gateway_id, + deposit_description, + withdraw_description, + language) +SELECT id, deposit_description, withdraw_description, 'EN' +FROM currency_on_chain_gateway; + +ALTER TABLE currency_on_chain_gateway + DROP COLUMN deposit_description, + DROP COLUMN withdraw_description; \ No newline at end of file diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/CurrencyLocalizationsRepository.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/CurrencyLocalizationsRepository.kt index 034b1ef5b..30e0ffe03 100644 --- a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/CurrencyLocalizationsRepository.kt +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/CurrencyLocalizationsRepository.kt @@ -8,4 +8,5 @@ import reactor.core.publisher.Flux @Repository interface CurrencyLocalizationsRepository : ReactiveCrudRepository { suspend fun findByCurrency(currency: String): Flux + } \ No newline at end of file From 1b7bef0ec808aff6289564a3eb6294b1aece43ff Mon Sep 17 00:00:00 2001 From: Amir Rajabi Date: Sat, 2 May 2026 15:33:41 +0330 Subject: [PATCH 2/5] add gateway localization service --- .../core/inout/GatewayLocalizationCommand.kt | 13 +++ .../core/inout/GatewayLocalizationResponse.kt | 6 ++ .../opex/api/core/inout/TerminalCommand.kt | 4 +- .../api/core/spi/BlockchainGatewayProxy.kt | 10 +++ .../co/nilin/opex/api/core/spi/WalletProxy.kt | 9 ++ .../controller/LocalizationAdminController.kt | 65 +++++++++++++- .../proxy/impl/BlockchainGatewayProxyImpl.kt | 53 +++++++++-- .../api/ports/proxy/impl/WalletProxyImpl.kt | 42 +++++++++ .../controller/CryptoCurrencyController.kt | 26 ++++++ .../dto/OnChainGatewayLocalizationResponse.kt | 8 ++ ...rrencyOnChainGatewayLocalizationCommand.kt | 13 +++ .../core/spi/CryptoCurrencyHandlerV2.kt | 9 ++ .../dao/CurrencyImplementationRepository.kt | 22 +++-- ...ncyOnChainGatewayLocalizationRepository.kt | 23 +++++ .../postgres/impl/CurrencyHandlerImplV2.kt | 61 +++++++++++-- .../ports/postgres/util/Convertor.kt | 13 ++- .../co/nilin/opex/common/data/UserLanguage.kt | 4 + .../opex/wallet/app/config/SecurityConfig.kt | 1 + .../app/controller/CurrencyController.kt | 5 +- .../OffChainGatewayLocalizationController.kt | 33 +++++++ .../OffChainGatewayLocalizationResponse.kt | 8 ++ .../wallet/app/dto/UpdateCurrencyRequest.kt | 4 +- .../OffChainGatewayLocalizationCommand.kt | 13 +++ .../OffChainGatewayLocalizationPersister.kt | 20 +++++ .../postgres/dao/CurrencyRepositoryV2.kt | 7 +- .../OffChainGatewayLocalizationRepository.kt | 33 +++++++ .../postgres/dao/OffChainGatewayRepository.kt | 57 +++++++++++- .../ports/postgres/dao/TerminalRepository.kt | 5 +- .../ports/postgres/dto/OffChainGatewayView.kt | 23 +++++ ...ffChainGatewayLocalizationPersisterImpl.kt | 63 +++++++++++++ .../impl/OffChainGatewayManagerImpl.kt | 89 ++++++++++++++----- .../model/OffChainGatewayLocalizationModel.kt | 13 +++ .../postgres/model/OffChainGatewayModel.kt | 2 - .../wallet/ports/postgres/util/Convertor.kt | 15 +++- .../V11__add_gateway_localizations_table.sql | 20 +++++ 35 files changed, 728 insertions(+), 64 deletions(-) create mode 100644 api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/GatewayLocalizationCommand.kt create mode 100644 api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/GatewayLocalizationResponse.kt create mode 100644 bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/dto/OnChainGatewayLocalizationResponse.kt create mode 100644 bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/CurrencyOnChainGatewayLocalizationCommand.kt create mode 100644 wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/OffChainGatewayLocalizationController.kt create mode 100644 wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/OffChainGatewayLocalizationResponse.kt create mode 100644 wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/OffChainGatewayLocalizationCommand.kt create mode 100644 wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/OffChainGatewayLocalizationPersister.kt create mode 100644 wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/OffChainGatewayLocalizationRepository.kt create mode 100644 wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dto/OffChainGatewayView.kt create mode 100644 wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/OffChainGatewayLocalizationPersisterImpl.kt create mode 100644 wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/model/OffChainGatewayLocalizationModel.kt create mode 100644 wallet/wallet-ports/wallet-persister-postgres/src/main/resources/db/migration/V11__add_gateway_localizations_table.sql diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/GatewayLocalizationCommand.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/GatewayLocalizationCommand.kt new file mode 100644 index 000000000..9c147858b --- /dev/null +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/GatewayLocalizationCommand.kt @@ -0,0 +1,13 @@ +package co.nilin.opex.api.core.inout + + +data class GatewayLocalizationCommand( + var id: Long? = null, + var depositDescription: String? = null, + var withdrawDescription: String? = null, + var language: String +) + + + + diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/GatewayLocalizationResponse.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/GatewayLocalizationResponse.kt new file mode 100644 index 000000000..79e149333 --- /dev/null +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/GatewayLocalizationResponse.kt @@ -0,0 +1,6 @@ +package co.nilin.opex.api.core.inout + +data class GatewayLocalizationResponse( + val gatewayUuid: String, + val localizations: List +) diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/TerminalCommand.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/TerminalCommand.kt index bb0d1f943..cf8074378 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/TerminalCommand.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/TerminalCommand.kt @@ -2,12 +2,12 @@ package co.nilin.opex.api.core.inout data class TerminalCommand( var uuid: String?, - var owner: String, + var owner: String?=null, var identifier: String, var active: Boolean? = true, var type: TransferMethod, var metaData: String, - var description : String?, + var description : String?=null, var displayOrder: Int? = null, ) diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/BlockchainGatewayProxy.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/BlockchainGatewayProxy.kt index e6ede917d..2929c5f96 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/BlockchainGatewayProxy.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/BlockchainGatewayProxy.kt @@ -4,6 +4,8 @@ import co.nilin.opex.api.core.inout.AssignAddressRequest import co.nilin.opex.api.core.inout.AssignResponse import co.nilin.opex.api.core.inout.ChainInfo import co.nilin.opex.api.core.inout.DepositDetails +import co.nilin.opex.api.core.inout.GatewayLocalizationCommand +import co.nilin.opex.api.core.inout.GatewayLocalizationResponse interface BlockchainGatewayProxy { @@ -11,4 +13,12 @@ interface BlockchainGatewayProxy { suspend fun getDepositDetails(refs: List): List suspend fun getChainInfo(): List + suspend fun getOnChainGatewayLocalizations(token: String, gatewayUuid: String): GatewayLocalizationResponse + suspend fun saveOnChainGatewayLocalizations( + token: String, + gatewayUuid: String, + gatewayLocalizations: List + ): GatewayLocalizationResponse + + suspend fun deleteOnChainGatewayLocalization(token: String, id: Long) } \ No newline at end of file diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt index 9bbc50efa..dcf8d6c47 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt @@ -227,4 +227,13 @@ interface WalletProxy { ): TerminalLocalizationResponse suspend fun deleteTerminalLocalization(token: String, id: Long) + + suspend fun getOffChainGatewayLocalizations(token: String, gatewayUuid: String): GatewayLocalizationResponse + suspend fun saveOffChainGatewayLocalizations( + token: String, + gatewayUuid: String, + gatewayLocalizations: List + ): GatewayLocalizationResponse + + suspend fun deleteOffChainGatewayLocalization(token: String, id: Long) } \ 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/LocalizationAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/LocalizationAdminController.kt index c582cb7fb..dcb038f74 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/LocalizationAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/LocalizationAdminController.kt @@ -1,12 +1,11 @@ package co.nilin.opex.api.ports.opex.controller -import co.nilin.opex.api.core.inout.CurrencyLocalizationCommand -import co.nilin.opex.api.core.inout.CurrencyLocalizationResponse -import co.nilin.opex.api.core.inout.TerminalLocalizationCommand -import co.nilin.opex.api.core.inout.TerminalLocalizationResponse +import co.nilin.opex.api.core.inout.* +import co.nilin.opex.api.core.spi.BlockchainGatewayProxy import co.nilin.opex.api.core.spi.WalletProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue +import co.nilin.opex.common.OpexError import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.* @@ -15,6 +14,7 @@ import org.springframework.web.bind.annotation.* @RequestMapping("/opex/v1/admin") class LocalizationAdminController( private val walletProxy: WalletProxy, + private val blockchainGatewayProxy: BlockchainGatewayProxy ) { @GetMapping("/currency/{currency}/localization") suspend fun getCurrencyLocalizations( @@ -73,4 +73,61 @@ class LocalizationAdminController( ) { walletProxy.deleteTerminalLocalization(securityContext.jwtAuthentication().tokenValue(), id) } + + @GetMapping("/gateway/{gatewayUuid}/localization") + suspend fun getGatewayLocalization( + @CurrentSecurityContext securityContext: SecurityContext, + @PathVariable("gatewayUuid") gatewayUuid: String + ): GatewayLocalizationResponse { + return if (gatewayUuid.startsWith("ofg")) { + walletProxy.getOffChainGatewayLocalizations( + securityContext.jwtAuthentication().tokenValue(), + gatewayUuid + ) + } else if (gatewayUuid.startsWith("ong")) { + blockchainGatewayProxy.getOnChainGatewayLocalizations( + securityContext.jwtAuthentication().tokenValue(), gatewayUuid + ) + } else throw OpexError.GatewayNotFount.exception() + } + + @PostMapping("/gateway/{gatewayUuid}/localization") + suspend fun saveGatewayLocalizations( + @CurrentSecurityContext securityContext: SecurityContext, + @PathVariable("gatewayUuid") gatewayUuid: String, + @RequestBody gatewayLocalizations: List + ): GatewayLocalizationResponse { + return if (gatewayUuid.startsWith("ofg")) { + walletProxy.saveOffChainGatewayLocalizations( + securityContext.jwtAuthentication().tokenValue(), + gatewayUuid, + gatewayLocalizations + ) + } else if (gatewayUuid.startsWith("ong")) { + blockchainGatewayProxy.saveOnChainGatewayLocalizations( + securityContext.jwtAuthentication().tokenValue(), + gatewayUuid, + gatewayLocalizations + ) + } else throw OpexError.GatewayNotFount.exception() + } + + @DeleteMapping("/gateway/{gatewayUuid}/localization/{id}") + suspend fun deleteGatewayLocalization( + @CurrentSecurityContext securityContext: SecurityContext, + @PathVariable("id") id: Long, + @PathVariable("gatewayUuid") gatewayUuid: String + ) { + return if (gatewayUuid.startsWith("ofg")) { + walletProxy.deleteOffChainGatewayLocalization( + securityContext.jwtAuthentication().tokenValue(), + id + ) + } else if (gatewayUuid.startsWith("ong")) { + blockchainGatewayProxy.deleteOnChainGatewayLocalization( + securityContext.jwtAuthentication().tokenValue(), + id + ) + } else throw OpexError.GatewayNotFount.exception() + } } \ No newline at end of file diff --git a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/BlockchainGatewayProxyImpl.kt b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/BlockchainGatewayProxyImpl.kt index 38f9462ef..5cecfadaa 100644 --- a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/BlockchainGatewayProxyImpl.kt +++ b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/BlockchainGatewayProxyImpl.kt @@ -1,23 +1,20 @@ package co.nilin.opex.api.ports.proxy.impl -import co.nilin.opex.api.core.inout.AssignAddressRequest -import co.nilin.opex.api.core.inout.AssignResponse -import co.nilin.opex.api.core.inout.ChainInfo -import co.nilin.opex.api.core.inout.DepositDetails +import co.nilin.opex.api.core.inout.* import co.nilin.opex.api.core.spi.BlockchainGatewayProxy import co.nilin.opex.api.ports.proxy.config.ProxyDispatchers import co.nilin.opex.api.ports.proxy.data.DepositDetailsRequest +import co.nilin.opex.common.OpexError import co.nilin.opex.common.utils.LoggerDelegate import kotlinx.coroutines.reactive.awaitFirstOrElse import kotlinx.coroutines.reactor.awaitSingleOrNull import kotlinx.coroutines.withContext 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.bodyToFlux +import org.springframework.web.reactive.function.client.* import reactor.core.publisher.Mono import java.net.URI @@ -75,6 +72,48 @@ class BlockchainGatewayProxyImpl(@Qualifier("generalWebClient") private val clie } } + override suspend fun getOnChainGatewayLocalizations( + token: String, + gatewayUuid: String + ): GatewayLocalizationResponse { + return client.get() + .uri("$baseUrl/crypto-currency/gateway/${gatewayUuid}/localization") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono() + .awaitFirstOrElse { throw OpexError.BadRequest.exception() } + } + + override suspend fun saveOnChainGatewayLocalizations( + token: String, + gatewayUuid: String, + gatewayLocalizations: List + ): GatewayLocalizationResponse { + return client.post() + .uri("$baseUrl/crypto-currency/gateway/${gatewayUuid}/localization") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .body(Mono.just(gatewayLocalizations)) + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono() + .awaitFirstOrElse { throw OpexError.BadRequest.exception() } + } + + override suspend fun deleteOnChainGatewayLocalization(token: String, id: Long) { + client.delete() + .uri("$baseUrl/crypto-currency/gateway/localization/${id}") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .retrieve() + .onStatus({ it.isError }) { response -> + response.createException() + } + .awaitBodilessEntity() + } + // override suspend fun getCurrencyImplementations(currency: String?): List { // logger.info("calling bc-gateway chain details") // return client.get() diff --git a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt index dc68dabd2..5e8b87ecc 100644 --- a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt +++ b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt @@ -885,5 +885,47 @@ class WalletProxyImpl(@Qualifier("generalWebClient") private val webClient: WebC } .awaitBodilessEntity() } + + override suspend fun getOffChainGatewayLocalizations( + token: String, + gatewayUuid: String + ): GatewayLocalizationResponse { + return webClient.get() + .uri("$baseUrl/offchain-gateway/${gatewayUuid}/localization") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono() + .awaitFirstOrElse { throw OpexError.BadRequest.exception() } + } + + override suspend fun saveOffChainGatewayLocalizations( + token: String, + gatewayUuid: String, + gatewayLocalizations: List + ): GatewayLocalizationResponse { + return webClient.post() + .uri("$baseUrl/offchain-gateway/${gatewayUuid}/localization") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .body(Mono.just(gatewayLocalizations)) + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono() + .awaitFirstOrElse { throw OpexError.BadRequest.exception() } + } + + override suspend fun deleteOffChainGatewayLocalization(token: String, id: Long) { + webClient.delete() + .uri("$baseUrl/offchain-gateway/localization/${id}") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .retrieve() + .onStatus({ it.isError }) { response -> + response.createException() + } + .awaitBodilessEntity() + } } diff --git a/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/controller/CryptoCurrencyController.kt b/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/controller/CryptoCurrencyController.kt index 47f365e4b..bff642370 100644 --- a/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/controller/CryptoCurrencyController.kt +++ b/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/controller/CryptoCurrencyController.kt @@ -1,7 +1,9 @@ package co.nilin.opex.bcgateway.app.controller import co.nilin.opex.bcgateway.app.dto.ChainResponse +import co.nilin.opex.bcgateway.app.dto.OnChainGatewayLocalizationResponse import co.nilin.opex.bcgateway.core.model.CryptoCurrencyCommand +import co.nilin.opex.bcgateway.core.model.CurrencyOnChainGatewayLocalizationCommand import co.nilin.opex.bcgateway.core.model.FetchGateways import co.nilin.opex.bcgateway.core.model.WithdrawData import co.nilin.opex.bcgateway.core.spi.ChainLoader @@ -86,4 +88,28 @@ class CryptoCurrencyController( return cryptoCurrencyHandler.getWithdrawData(currency, network) } + @PostMapping("/gateway/{uuid}/localization") + suspend fun saveGatewayLocalization( + @PathVariable("uuid") gatewayUuid: String, + @RequestBody localizations: List + ): OnChainGatewayLocalizationResponse { + val gatewayLocalizations = cryptoCurrencyHandler.saveOnChainGatewayLocalization(gatewayUuid, localizations) + return OnChainGatewayLocalizationResponse(gatewayUuid, gatewayLocalizations) + } + + @GetMapping("/gateway/{uuid}/localization") + suspend fun getGatewayLocalization( + @PathVariable("uuid") gatewayUuid: String + ): OnChainGatewayLocalizationResponse { + val gatewayLocalizations = cryptoCurrencyHandler.fetchOnChainGatewayLocalizations(gatewayUuid) + return OnChainGatewayLocalizationResponse(gatewayUuid, gatewayLocalizations) + } + + @DeleteMapping("/gateway/localization/{id}") + suspend fun deleteGatewayLocalization( + @PathVariable("id") id: Long, + ) { + cryptoCurrencyHandler.deleteOnChainGatewayLocalizations(id) + } + } diff --git a/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/dto/OnChainGatewayLocalizationResponse.kt b/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/dto/OnChainGatewayLocalizationResponse.kt new file mode 100644 index 000000000..e4f63db18 --- /dev/null +++ b/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/dto/OnChainGatewayLocalizationResponse.kt @@ -0,0 +1,8 @@ +package co.nilin.opex.bcgateway.app.dto + +import co.nilin.opex.bcgateway.core.model.CurrencyOnChainGatewayLocalizationCommand + +data class OnChainGatewayLocalizationResponse( + val gatewayUuid: String, + val localizations: List +) diff --git a/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/CurrencyOnChainGatewayLocalizationCommand.kt b/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/CurrencyOnChainGatewayLocalizationCommand.kt new file mode 100644 index 000000000..e755663b9 --- /dev/null +++ b/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/model/CurrencyOnChainGatewayLocalizationCommand.kt @@ -0,0 +1,13 @@ +package co.nilin.opex.bcgateway.core.model + + +data class CurrencyOnChainGatewayLocalizationCommand( + var id: Long? = null, + var depositDescription: String? = null, + var withdrawDescription: String? = null, + var language: String +) + + + + diff --git a/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/spi/CryptoCurrencyHandlerV2.kt b/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/spi/CryptoCurrencyHandlerV2.kt index 11b4eb755..bb0f4d582 100644 --- a/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/spi/CryptoCurrencyHandlerV2.kt +++ b/bc-gateway/bc-gateway-core/src/main/kotlin/co/nilin/opex/bcgateway/core/spi/CryptoCurrencyHandlerV2.kt @@ -1,6 +1,7 @@ package co.nilin.opex.bcgateway.core.spi import co.nilin.opex.bcgateway.core.model.CryptoCurrencyCommand +import co.nilin.opex.bcgateway.core.model.CurrencyOnChainGatewayLocalizationCommand import co.nilin.opex.bcgateway.core.model.FetchGateways import co.nilin.opex.bcgateway.core.model.WithdrawData @@ -26,4 +27,12 @@ interface CryptoCurrencyHandlerV2 { tokenAddress: String? ): CryptoCurrencyCommand? + suspend fun saveOnChainGatewayLocalization( + gatewayUuid: String, + localizations: List + ): List + + suspend fun fetchOnChainGatewayLocalizations(gatewayUuid: String): List + suspend fun deleteOnChainGatewayLocalizations(id: Long) + } 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 87cbd8ccc..b1b62570c 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 @@ -3,6 +3,7 @@ package co.nilin.opex.bcgateway.ports.postgres.dao import co.nilin.opex.bcgateway.core.model.CurrencyOnChainGatewayView import co.nilin.opex.bcgateway.core.model.WithdrawData import co.nilin.opex.bcgateway.ports.postgres.model.CurrencyOnChainGatewayModel +import co.nilin.opex.common.data.UserLanguage import org.springframework.data.r2dbc.repository.Query import org.springframework.data.repository.reactive.ReactiveCrudRepository import org.springframework.stereotype.Repository @@ -14,7 +15,8 @@ interface CurrencyImplementationRepository : ReactiveCrudRepository? - @Query(""" + @Query( + """ SELECT c.id, c.gateway_uuid, c.currency_symbol, @@ -43,13 +45,15 @@ interface CurrencyImplementationRepository : ReactiveCrudRepository? fun deleteByGatewayUuid(uuid: String): Mono @@ -65,7 +69,8 @@ interface CurrencyImplementationRepository : ReactiveCrudRepository - @Query(""" + @Query( + """ SELECT c.id, c.gateway_uuid, c.currency_symbol, @@ -91,8 +96,13 @@ interface CurrencyImplementationRepository : ReactiveCrudRepository? + """ + ) + fun findByGatewayUuidAndCurrencySymbol( + gatewayUuid: String, + symbol: String, + lang: String? = UserLanguage.getDefault().toString() + ): Mono? @Query("select * from currency_on_chain_gateway where chain = :chain and is_token is false") fun findMainAssetGateway(chain: String): Mono diff --git a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/dao/CurrencyOnChainGatewayLocalizationRepository.kt b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/dao/CurrencyOnChainGatewayLocalizationRepository.kt index 4cc007cc4..68a1197e9 100644 --- a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/dao/CurrencyOnChainGatewayLocalizationRepository.kt +++ b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/dao/CurrencyOnChainGatewayLocalizationRepository.kt @@ -1,10 +1,33 @@ package co.nilin.opex.bcgateway.ports.postgres.dao import co.nilin.opex.bcgateway.ports.postgres.model.CurrencyOnChainGatewayLocalizationModel +import org.springframework.data.r2dbc.repository.Modifying +import org.springframework.data.r2dbc.repository.Query import org.springframework.data.repository.reactive.ReactiveCrudRepository import org.springframework.stereotype.Repository +import reactor.core.publisher.Flux +import reactor.core.publisher.Mono @Repository interface CurrencyOnChainGatewayLocalizationRepository : ReactiveCrudRepository { + @Modifying + @Query( + """ + INSERT INTO currency_on_chain_gateway_localization (gateway_id, deposit_description, withdraw_description, language) + VALUES (:gatewayId, :depositDescription, :withdrawDescription, :language) + ON CONFLICT (gateway_id, language) + DO UPDATE SET + deposit_description = :depositDescription, + withdraw_description = :withdrawDescription +""" + ) + fun upsert( + gatewayId: Long, + depositDescription: String?, + withdrawDescription: String?, + language: String + ): Mono + + suspend fun findByGatewayId(gatewayId: Long): Flux } \ No newline at end of file diff --git a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/impl/CurrencyHandlerImplV2.kt b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/impl/CurrencyHandlerImplV2.kt index 043503171..1b3e68220 100644 --- a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/impl/CurrencyHandlerImplV2.kt +++ b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/impl/CurrencyHandlerImplV2.kt @@ -1,15 +1,13 @@ package co.nilin.opex.bcgateway.ports.postgres.impl -import co.nilin.opex.bcgateway.core.model.CryptoCurrencyCommand -import co.nilin.opex.bcgateway.core.model.CurrencyOnChainGatewayView -import co.nilin.opex.bcgateway.core.model.FetchGateways -import co.nilin.opex.bcgateway.core.model.WithdrawData +import co.nilin.opex.bcgateway.core.model.* import co.nilin.opex.bcgateway.core.spi.CryptoCurrencyHandlerV2 import co.nilin.opex.bcgateway.ports.postgres.dao.ChainRepository import co.nilin.opex.bcgateway.ports.postgres.dao.CurrencyImplementationRepository import co.nilin.opex.bcgateway.ports.postgres.dao.CurrencyOnChainGatewayLocalizationRepository import co.nilin.opex.bcgateway.ports.postgres.model.CurrencyOnChainGatewayLocalizationModel import co.nilin.opex.bcgateway.ports.postgres.model.CurrencyOnChainGatewayModel +import co.nilin.opex.bcgateway.ports.postgres.util.toCommand import co.nilin.opex.bcgateway.ports.postgres.util.toDto import co.nilin.opex.bcgateway.ports.postgres.util.toModel import co.nilin.opex.common.OpexError @@ -72,7 +70,10 @@ class CurrencyHandlerImplV2( override suspend fun fetchCurrencyOnChainGateways(data: FetchGateways?): List? { logger.info("going to fetch impls of ${data?.currencySymbol ?: "all currencies"}") - return loadImpls(data)?.map { it.toDto() } + return loadImpls( + data, + UserLanguage.safeValueOf(getUserLanguage().awaitSingleOrNull()).toString() + )?.map { it.toDto() } ?.collect(Collectors.toList())?.awaitFirstOrNull() } @@ -84,12 +85,16 @@ class CurrencyHandlerImplV2( )?.awaitFirstOrNull()?.toDto() } - private suspend fun loadImpls(request: FetchGateways?): Flux? { + private suspend fun loadImpls( + request: FetchGateways?, + language: String? = null + ): Flux? { var resp = currencyImplementationRepository.findGateways( request?.currencySymbol, request?.gatewayUuid, request?.chain, - request?.currencyImplementationName + request?.currencyImplementationName, + language ?: getDefaultUserLanguage() ) return resp ?: throw OpexError.ImplNotFound.exception() @@ -164,4 +169,46 @@ class CurrencyHandlerImplV2( else currencyImplementationRepository.findMainAssetGateway(chain).awaitSingleOrNull()?.toDto() } + + override suspend fun saveOnChainGatewayLocalization( + gatewayUuid: String, + localizations: List + ): List { + return transactionalOperator.executeAndAwait { + + val gateway = currencyImplementationRepository.findByGatewayUuid(gatewayUuid)?.awaitSingleOrNull() + ?: throw OpexError.GatewayNotFount.exception() + + localizations.forEach { g -> + if (!g.depositDescription.isNullOrBlank() || !g.withdrawDescription.isNullOrBlank()) + currencyOnChainGatewayLocalizationRepository.upsert( + gatewayId = gateway.id!!, + depositDescription = g.depositDescription, + withdrawDescription = g.withdrawDescription, + language = UserLanguage.safeValueOf(g.language).toString() + ).awaitSingleOrNull() + } + + currencyOnChainGatewayLocalizationRepository.findByGatewayId(gateway.id!!) + .map { it.toCommand() } + .collectList() + .awaitSingleOrNull() + ?: emptyList() + } ?: throw OpexError.BadRequest.exception("Failed to save gateway localizations") + } + + + override suspend fun fetchOnChainGatewayLocalizations(gatewayUuid: String): List { + val gateway = currencyImplementationRepository.findByGatewayUuid(gatewayUuid)?.awaitSingleOrNull() + ?: throw OpexError.GatewayNotFount.exception() + return currencyOnChainGatewayLocalizationRepository.findByGatewayId(gateway.id!!) + .map { it.toCommand() } + .collectList() + .awaitSingleOrNull() + ?: emptyList() + } + + override suspend fun deleteOnChainGatewayLocalizations(id: Long) { + currencyOnChainGatewayLocalizationRepository.deleteById(id).awaitSingleOrNull() + } } diff --git a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/util/Convertor.kt b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/util/Convertor.kt index 2cdc74969..2e6fa1d4a 100644 --- a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/util/Convertor.kt +++ b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/util/Convertor.kt @@ -1,7 +1,9 @@ package co.nilin.opex.bcgateway.ports.postgres.util import co.nilin.opex.bcgateway.core.model.CryptoCurrencyCommand +import co.nilin.opex.bcgateway.core.model.CurrencyOnChainGatewayLocalizationCommand import co.nilin.opex.bcgateway.core.model.CurrencyOnChainGatewayView +import co.nilin.opex.bcgateway.ports.postgres.model.CurrencyOnChainGatewayLocalizationModel import co.nilin.opex.bcgateway.ports.postgres.model.CurrencyOnChainGatewayModel @@ -51,7 +53,7 @@ fun CurrencyOnChainGatewayModel.toDto(): CryptoCurrencyCommand { null,//todo null,//todo displayOrder, - ) + ) } @@ -80,4 +82,13 @@ fun CurrencyOnChainGatewayView.toDto(): CryptoCurrencyCommand { displayOrder, ) +} + +fun CurrencyOnChainGatewayLocalizationModel.toCommand(): CurrencyOnChainGatewayLocalizationCommand { + return CurrencyOnChainGatewayLocalizationCommand( + id = id, + depositDescription = depositDescription, + withdrawDescription = withdrawDescription, + language = language + ) } \ 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 1575bcb5d..9cb07c446 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 @@ -14,5 +14,9 @@ enum class UserLanguage { EN } } + + fun getDefault(): UserLanguage { + return EN + } } } \ No newline at end of file diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/SecurityConfig.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/SecurityConfig.kt index 4443bf142..ad6105aea 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/SecurityConfig.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/config/SecurityConfig.kt @@ -35,6 +35,7 @@ class SecurityConfig(private val webClient: WebClient) { .pathMatchers("/owner/**").authenticated() .pathMatchers("/withdraw").authenticated() .pathMatchers("/currency/localization/**").hasAuthority("ROLE_admin") + .pathMatchers("/offchain-gateway/**").hasAuthority("ROLE_admin") .pathMatchers(HttpMethod.PUT, "/currency/**").hasAuthority("ROLE_admin") .pathMatchers(HttpMethod.POST, "/currency/**").hasAuthority("ROLE_admin") .pathMatchers(HttpMethod.DELETE, "/currency/**").hasAuthority("ROLE_admin") diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/CurrencyController.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/CurrencyController.kt index 42fc2e0b1..08c20da7f 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/CurrencyController.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/CurrencyController.kt @@ -1,6 +1,9 @@ package co.nilin.opex.wallet.app.controller -import co.nilin.opex.wallet.app.dto.* +import co.nilin.opex.wallet.app.dto.CurrenciesDto +import co.nilin.opex.wallet.app.dto.CurrencyDto +import co.nilin.opex.wallet.app.dto.CurrencyLocalizationResponse +import co.nilin.opex.wallet.app.dto.UpdateCurrencyRequest import co.nilin.opex.wallet.app.service.CurrencyServiceV2 import co.nilin.opex.wallet.core.inout.* import co.nilin.opex.wallet.core.model.QuoteCurrency diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/OffChainGatewayLocalizationController.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/OffChainGatewayLocalizationController.kt new file mode 100644 index 000000000..d855ab7d9 --- /dev/null +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/OffChainGatewayLocalizationController.kt @@ -0,0 +1,33 @@ +package co.nilin.opex.wallet.app.controller + +import co.nilin.opex.wallet.app.dto.OffChainGatewayLocalizationResponse +import co.nilin.opex.wallet.core.model.OffChainGatewayLocalizationCommand +import co.nilin.opex.wallet.core.spi.OffChainGatewayLocalizationPersister +import org.springframework.web.bind.annotation.* + +@RestController +@RequestMapping("/offchain-gateway") +class OffChainGatewayLocalizationController( + private val offChainGatewayLocalizationPersister: OffChainGatewayLocalizationPersister, +) { + + @GetMapping("/{gatewayUuid}/localization") + suspend fun getGatewayLocalizations(@PathVariable("gatewayUuid") gatewayUuid: String): OffChainGatewayLocalizationResponse { + val localizations = offChainGatewayLocalizationPersister.fetch(gatewayUuid) + return OffChainGatewayLocalizationResponse(gatewayUuid, localizations) + } + + @PostMapping("/{gatewayUuid}/localization") + suspend fun saveGatewayLocalizations( + @PathVariable("gatewayUuid") gatewayUuid: String, + @RequestBody gatewayLocalizations: List + ): OffChainGatewayLocalizationResponse { + val localizations = offChainGatewayLocalizationPersister.save(gatewayUuid, gatewayLocalizations) + return OffChainGatewayLocalizationResponse(gatewayUuid, localizations) + } + + @DeleteMapping("/localization/{id}") + suspend fun deleteGatewayLocalization(@PathVariable("id") id: Long) { + offChainGatewayLocalizationPersister.delete(id) + } +} \ No newline at end of file diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/OffChainGatewayLocalizationResponse.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/OffChainGatewayLocalizationResponse.kt new file mode 100644 index 000000000..0f2df078a --- /dev/null +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/OffChainGatewayLocalizationResponse.kt @@ -0,0 +1,8 @@ +package co.nilin.opex.wallet.app.dto + +import co.nilin.opex.wallet.core.model.OffChainGatewayLocalizationCommand + +data class OffChainGatewayLocalizationResponse( + val gatewayUuid: String, + val localizations: List +) diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/UpdateCurrencyRequest.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/UpdateCurrencyRequest.kt index c260ca6fe..4eb9f59f8 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/UpdateCurrencyRequest.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/UpdateCurrencyRequest.kt @@ -10,7 +10,7 @@ data class UpdateCurrencyRequest( var isActive: Boolean? = true, var sign: String? = null, var externalUrl: String? = null, - var order: Int? = null, + var displayOrder: Int? = null, var maxOrder: BigDecimal? = null, ) { @@ -23,7 +23,7 @@ data class UpdateCurrencyRequest( isActive = isActive, sign = sign, externalUrl = externalUrl, - displayOrder = order, + displayOrder = displayOrder, maxOrder = maxOrder, ) } diff --git a/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/OffChainGatewayLocalizationCommand.kt b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/OffChainGatewayLocalizationCommand.kt new file mode 100644 index 000000000..96932b628 --- /dev/null +++ b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/model/OffChainGatewayLocalizationCommand.kt @@ -0,0 +1,13 @@ +package co.nilin.opex.wallet.core.model + + +data class OffChainGatewayLocalizationCommand( + var id: Long? = null, + var depositDescription: String? = null, + var withdrawDescription: String? = null, + var language: String +) + + + + diff --git a/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/OffChainGatewayLocalizationPersister.kt b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/OffChainGatewayLocalizationPersister.kt new file mode 100644 index 000000000..dd3f91f9b --- /dev/null +++ b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/OffChainGatewayLocalizationPersister.kt @@ -0,0 +1,20 @@ +package co.nilin.opex.wallet.core.spi + +import co.nilin.opex.wallet.core.model.OffChainGatewayLocalizationCommand + +interface OffChainGatewayLocalizationPersister { + + suspend fun save( + gatewayUuid: String, + localizations: List + ): List + + suspend fun fetch(gatewayUuid: String): List + suspend fun delete(id: Long) +} + + + + + + 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 731d5a384..7ddf89102 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 @@ -1,5 +1,6 @@ package co.nilin.opex.wallet.ports.postgres.dao +import co.nilin.opex.common.data.UserLanguage import co.nilin.opex.wallet.core.inout.CurrencyPrecision import co.nilin.opex.wallet.ports.postgres.dto.CurrencyView import co.nilin.opex.wallet.ports.postgres.model.CurrencyModel @@ -44,7 +45,7 @@ interface CurrencyRepositoryV2 : ReactiveCrudRepository { fun fetchCurrency( uuid: String? = null, symbol: String? = null, - lang: String? = null + lang: String? = UserLanguage.getDefault().toString() ): Mono? @@ -77,7 +78,7 @@ interface CurrencyRepositoryV2 : ReactiveCrudRepository { fun fetchSemiCurrencies( symbol: String? = null, name: String? = null, - lang: String? = null + lang: String? = UserLanguage.getDefault().toString() ): Flux? @@ -119,7 +120,7 @@ interface CurrencyRepositoryV2 : ReactiveCrudRepository { ORDER BY c.display_order """ ) - fun fetchAll(lang: String): Flux + fun fetchAll(lang: String? = UserLanguage.getDefault().toString()): 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/OffChainGatewayLocalizationRepository.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/OffChainGatewayLocalizationRepository.kt new file mode 100644 index 000000000..2df985891 --- /dev/null +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/OffChainGatewayLocalizationRepository.kt @@ -0,0 +1,33 @@ +package co.nilin.opex.wallet.ports.postgres.dao + +import co.nilin.opex.wallet.ports.postgres.model.OffChainGatewayLocalizationModel +import org.springframework.data.r2dbc.repository.Modifying +import org.springframework.data.r2dbc.repository.Query +import org.springframework.data.repository.reactive.ReactiveCrudRepository +import org.springframework.stereotype.Repository +import reactor.core.publisher.Flux +import reactor.core.publisher.Mono + +@Repository +interface OffChainGatewayLocalizationRepository : ReactiveCrudRepository { + + @Modifying + @Query( + """ + INSERT INTO currency_off_chain_gateway_localization (gateway_id, deposit_description, withdraw_description, language) + VALUES (:gatewayId, :depositDescription, :withdrawDescription, :language) + ON CONFLICT (gateway_id, language) + DO UPDATE SET + deposit_description = :depositDescription, + withdraw_description = :withdrawDescription +""" + ) + fun upsert( + gatewayId: Long, + depositDescription: String?, + withdrawDescription: String?, + language: String + ): Mono + + fun findByGatewayId(gatewayId: Long): 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 732c5b46a..fa4f33312 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 @@ -1,6 +1,8 @@ package co.nilin.opex.wallet.ports.postgres.dao +import co.nilin.opex.common.data.UserLanguage import co.nilin.opex.wallet.core.inout.TransferMethod +import co.nilin.opex.wallet.ports.postgres.dto.OffChainGatewayView import co.nilin.opex.wallet.ports.postgres.model.OffChainGatewayModel import org.springframework.data.r2dbc.repository.Query import org.springframework.data.repository.reactive.ReactiveCrudRepository @@ -12,12 +14,61 @@ import reactor.core.publisher.Mono interface OffChainGatewayRepository : ReactiveCrudRepository { fun findByGatewayUuid(uuid: String): Mono? - fun findByGatewayUuidAndCurrencySymbol(uuid: String, symbol: String): Mono? + @Query(""" + select g.id, + g.gateway_uuid, + g.currency_symbol, + g.deposit_allowed, + g.withdraw_fee, + g.withdraw_min, + g.withdraw_max, + g.deposit_min, + g.deposit_max, + g.transfer_method, + g.is_deposit_active, + g.is_withdraw_active, + gl.deposit_description, + gl.withdraw_description, + g.display_order + from currency_off_chain_gateway g + left join currency_off_chain_gateway_localization gl on g.id = gl.gateway_id and gl.language = :lang + where g.currency_symbol = :currencySymbol and g.gateway_uuid = :gatewayUuid + """) + fun findByGatewayUuidAndCurrencySymbol( + uuid: String, + symbol: String, + language: String? = UserLanguage.getDefault().toString() + ): Mono? fun deleteByGatewayUuid(uuid: String): Mono - @Query("select * from currency_off_chain_gateway where (:gatewayUuid is null or gateway_uuid=:gatewayUuid) and (:currencySymbol is null or currency_symbol=:currencySymbol ) order by display_order") - fun findGateways(currencySymbol: String? = null, gatewayUuid: String? = null): Flux? + @Query(""" + select g.id, + g.gateway_uuid, + g.currency_symbol, + g.deposit_allowed, + g.withdraw_fee, + g.withdraw_min, + g.withdraw_max, + g.deposit_min, + g.deposit_max, + g.transfer_method, + g.is_deposit_active, + g.is_withdraw_active, + gl.deposit_description, + gl.withdraw_description, + g.display_order + from currency_off_chain_gateway g + left join currency_off_chain_gateway_localization gl on g.id = gl.gateway_id and gl.language = :lang + where (:currencySymbol is null or g.currency_symbol = :currencySymbol) + and (:gatewayUuid is null or g.gateway_uuid = :gatewayUuid) + order by g.display_order + """) + fun findGateways( + currencySymbol: String? = null, + gatewayUuid: String? = null, + language: String? = UserLanguage.getDefault().toString() + ): Flux? fun findByCurrencySymbolAndAndTransferMethod( currencySymbol: String, 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 351abeae1..30c230dab 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 @@ -1,5 +1,6 @@ package co.nilin.opex.wallet.ports.postgres.dao +import co.nilin.opex.common.data.UserLanguage import co.nilin.opex.wallet.ports.postgres.dto.TerminalView import co.nilin.opex.wallet.ports.postgres.model.TerminalModel import org.springframework.data.r2dbc.repository.Query @@ -30,7 +31,7 @@ interface TerminalRepository : ReactiveCrudRepository { WHERE t.uuid = :uuid; """ ) - fun findByUuid(uuid: String, lang: String? = null): Mono? + fun findByUuid(uuid: String, lang: String? = UserLanguage.getDefault().toString()): Mono? @Query( """ @@ -50,7 +51,7 @@ interface TerminalRepository : ReactiveCrudRepository { order by t.display_order """ ) - fun findAllByOrderByDisplayOrder(lang: String?= null): Flux + fun findAllByOrderByDisplayOrder(lang: String?= UserLanguage.getDefault().toString()): Flux } \ No newline at end of file diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dto/OffChainGatewayView.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dto/OffChainGatewayView.kt new file mode 100644 index 000000000..b3e0af363 --- /dev/null +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dto/OffChainGatewayView.kt @@ -0,0 +1,23 @@ +package co.nilin.opex.wallet.ports.postgres.dto + +import java.math.BigDecimal + + +data class OffChainGatewayView( + var id: Long?, + val gatewayUuid: String, + val currencySymbol: String, var withdrawAllowed: Boolean? = true, + var depositAllowed: Boolean? = true, + var withdrawFee: BigDecimal? = BigDecimal.ZERO, + var withdrawMin: BigDecimal? = BigDecimal.ZERO, + var withdrawMax: BigDecimal? = BigDecimal.ZERO, + var depositMin: BigDecimal? = BigDecimal.ZERO, + var depositMax: BigDecimal? = BigDecimal.ZERO, + var transferMethod: String, + var isDepositActive: Boolean? = true, + var isWithdrawActive: Boolean? = true, + val depositDescription: String?, + val withdrawDescription: String?, + val displayOrder: Int? = null, + + ) \ No newline at end of file diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/OffChainGatewayLocalizationPersisterImpl.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/OffChainGatewayLocalizationPersisterImpl.kt new file mode 100644 index 000000000..3adecc96d --- /dev/null +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/OffChainGatewayLocalizationPersisterImpl.kt @@ -0,0 +1,63 @@ +package co.nilin.opex.wallet.ports.postgres.impl + +import co.nilin.opex.common.OpexError +import co.nilin.opex.common.data.UserLanguage +import co.nilin.opex.wallet.core.model.OffChainGatewayLocalizationCommand +import co.nilin.opex.wallet.core.spi.OffChainGatewayLocalizationPersister +import co.nilin.opex.wallet.ports.postgres.dao.OffChainGatewayLocalizationRepository +import co.nilin.opex.wallet.ports.postgres.dao.OffChainGatewayRepository +import co.nilin.opex.wallet.ports.postgres.util.toCommand +import kotlinx.coroutines.reactor.awaitSingleOrNull +import org.springframework.stereotype.Component +import org.springframework.transaction.reactive.TransactionalOperator +import org.springframework.transaction.reactive.executeAndAwait + +@Component +class OffChainGatewayLocalizationPersisterImpl( + private val offChainGatewayRepository: OffChainGatewayRepository, + private val offChainGatewayLocalizationRepository: OffChainGatewayLocalizationRepository, + private val transactionalOperator: TransactionalOperator +) : OffChainGatewayLocalizationPersister { + + override suspend fun save( + gatewayUuid: String, + localizations: List + ): List { + + return transactionalOperator.executeAndAwait { + + val gateway = offChainGatewayRepository.findByGatewayUuid(gatewayUuid)?.awaitSingleOrNull() + ?: throw OpexError.GatewayNotFount.exception() + + localizations.forEach { g -> + if (!g.depositDescription.isNullOrBlank() || !g.withdrawDescription.isNullOrBlank()) + offChainGatewayLocalizationRepository.upsert( + gatewayId = gateway.id!!, + depositDescription = g.depositDescription, + withdrawDescription = g.withdrawDescription, + language = UserLanguage.safeValueOf(g.language).toString() + ).awaitSingleOrNull() + } + + offChainGatewayLocalizationRepository.findByGatewayId(gateway.id!!) + .map { it.toCommand() } + .collectList() + .awaitSingleOrNull() + ?: emptyList() + } ?: throw OpexError.BadRequest.exception("Failed to save gateway localizations") + } + + override suspend fun fetch(gatewayUuid: String): List { + val gateway = offChainGatewayRepository.findByGatewayUuid(gatewayUuid)?.awaitSingleOrNull() + ?: throw OpexError.GatewayNotFount.exception() + return offChainGatewayLocalizationRepository.findByGatewayId(gateway.id!!) + .map { it.toCommand() } + .collectList() + .awaitSingleOrNull() + ?: emptyList() + } + + override suspend fun delete(id: Long) { + offChainGatewayLocalizationRepository.deleteById(id).awaitSingleOrNull() + } +} \ No newline at end of file diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/OffChainGatewayManagerImpl.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/OffChainGatewayManagerImpl.kt index f489b35e9..0cca73a6c 100644 --- a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/OffChainGatewayManagerImpl.kt +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/OffChainGatewayManagerImpl.kt @@ -1,50 +1,64 @@ package co.nilin.opex.wallet.ports.postgres.impl import co.nilin.opex.common.OpexError +import co.nilin.opex.common.data.UserLanguage +import co.nilin.opex.common.utils.LanguageUtils.getDefaultUserLanguage +import co.nilin.opex.common.utils.LanguageUtils.getUserLanguage import co.nilin.opex.wallet.core.inout.CurrencyGatewayCommand import co.nilin.opex.wallet.core.inout.GatewayData import co.nilin.opex.wallet.core.inout.OffChainGatewayCommand import co.nilin.opex.wallet.core.model.FetchGateways import co.nilin.opex.wallet.core.spi.GatewayPersister +import co.nilin.opex.wallet.ports.postgres.dao.OffChainGatewayLocalizationRepository import co.nilin.opex.wallet.ports.postgres.dao.OffChainGatewayRepository +import co.nilin.opex.wallet.ports.postgres.dto.OffChainGatewayView +import co.nilin.opex.wallet.ports.postgres.model.OffChainGatewayLocalizationModel import co.nilin.opex.wallet.ports.postgres.model.OffChainGatewayModel import co.nilin.opex.wallet.ports.postgres.util.toDto import co.nilin.opex.wallet.ports.postgres.util.toModel import kotlinx.coroutines.reactive.awaitFirstOrNull +import kotlinx.coroutines.reactor.awaitSingleOrNull import org.springframework.stereotype.Service +import org.springframework.transaction.reactive.TransactionalOperator +import org.springframework.transaction.reactive.executeAndAwait @Service("offChainGateway") -class OffChainGatewayManagerImpl(private val offChainGatewayRepository: OffChainGatewayRepository) : GatewayPersister { +class OffChainGatewayManagerImpl( + private val offChainGatewayRepository: OffChainGatewayRepository, + private val offChainGatewayLocalizationRepository: OffChainGatewayLocalizationRepository, + private val transactionalOperator: TransactionalOperator +) : GatewayPersister { override suspend fun createGateway( - currencyGateway: CurrencyGatewayCommand, - internalToken: String? + currencyGateway: CurrencyGatewayCommand, internalToken: String? ): CurrencyGatewayCommand? { val input = currencyGateway as OffChainGatewayCommand offChainGatewayRepository.findByCurrencySymbolAndAndTransferMethod(input.currencySymbol!!, input.transferMethod) - ?.awaitFirstOrNull() - ?.let { throw OpexError.GatewayIsExist.exception() } - return _save(input.toModel())?.toDto() + ?.awaitFirstOrNull()?.let { throw OpexError.GatewayIsExist.exception() } + return _save(currencyGateway)?.toDto() } override suspend fun updateGateway( - currencyGateway: CurrencyGatewayCommand, - internalToken: String? + currencyGateway: CurrencyGatewayCommand, internalToken: String? ): CurrencyGatewayCommand? { val oldGateway = _fetchGateway(currencyGateway.currencySymbol!!, currencyGateway.gatewayUuid!!) ?: throw OpexError.GatewayNotFount.exception() - return _save((currencyGateway as OffChainGatewayCommand).toModel().apply { id = oldGateway.id })?.toDto() + return _update((currencyGateway as OffChainGatewayCommand).toModel().apply { id = oldGateway.id })?.toDto() + return null } override suspend fun fetchGateways(symbol: String?, internalToken: String?): List? { - return _fetchGateways(FetchGateways(currencySymbol = symbol))?.map { it.toDto() } + return _fetchGateways( + FetchGateways(currencySymbol = symbol), + UserLanguage.safeValueOf(getUserLanguage().awaitSingleOrNull()).toString() + )?.map { it.toDto() } } override suspend fun fetchGatewayDetail( - gatewayUuid: String, - currencySymbol: String, - internalToken: String? + gatewayUuid: String, currencySymbol: String, internalToken: String? ): CurrencyGatewayCommand? { - return _fetchGateway(currencySymbol, gatewayUuid)?.toDto() + return _fetchGateway( + currencySymbol, gatewayUuid, UserLanguage.safeValueOf(getUserLanguage().awaitSingleOrNull()).toString() + )?.toDto() } override suspend fun deleteGateway(gatewayUuid: String, currencySymbol: String, internalToken: String?) { @@ -60,17 +74,50 @@ class OffChainGatewayManagerImpl(private val offChainGatewayRepository: OffChain } - private suspend fun _save(currencyGateway: OffChainGatewayModel): OffChainGatewayModel? { - return offChainGatewayRepository.save(currencyGateway)?.awaitFirstOrNull() + private suspend fun _save(currencyGateway: CurrencyGatewayCommand): OffChainGatewayView? { + return transactionalOperator.executeAndAwait { + + val input = currencyGateway as OffChainGatewayCommand + val gateway = offChainGatewayRepository.save(input.toModel()).awaitFirstOrNull() + ?: throw OpexError.BadRequest.exception("Error in saving gateway") + + if (!currencyGateway.depositDescription.isNullOrEmpty() && !currencyGateway.withdrawDescription.isNullOrEmpty()) { + offChainGatewayLocalizationRepository.save( + OffChainGatewayLocalizationModel( + gatewayId = gateway.id!!, + depositDescription = currencyGateway.depositDescription, + withdrawDescription = currencyGateway.withdrawDescription, + language = getDefaultUserLanguage() + ) + ).awaitSingleOrNull() + } + + _fetchGateway(gateway.currencySymbol, gateway.gatewayUuid) + } + } + + private suspend fun _update(currencyGateway: OffChainGatewayModel): OffChainGatewayView? { + val gateway = offChainGatewayRepository.save(currencyGateway).awaitFirstOrNull() + ?: throw OpexError.BadRequest.exception("Error in saving gateway") + return _fetchGateway(gateway.currencySymbol, gateway.gatewayUuid) } - private suspend fun _fetchGateway(currencySymbol: String, gatewayUuid: String): OffChainGatewayModel? { - return offChainGatewayRepository.findByGatewayUuidAndCurrencySymbol(gatewayUuid, currencySymbol) - ?.awaitFirstOrNull() + private suspend fun _fetchGateway( + currencySymbol: String, + gatewayUuid: String, + language: String? = null, + ): OffChainGatewayView? { + return offChainGatewayRepository.findByGatewayUuidAndCurrencySymbol( + gatewayUuid, currencySymbol, language ?: getDefaultUserLanguage() + )?.awaitFirstOrNull() } - private suspend fun _fetchGateways(fetchGateways: FetchGateways): List? { - return offChainGatewayRepository.findGateways(fetchGateways.currencySymbol)?.collectList()?.awaitFirstOrNull() + private suspend fun _fetchGateways( + fetchGateways: FetchGateways, language: String? = null + ): List? { + return offChainGatewayRepository.findGateways( + fetchGateways.currencySymbol, language ?: getDefaultUserLanguage() + )?.collectList()?.awaitFirstOrNull() } } \ No newline at end of file diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/model/OffChainGatewayLocalizationModel.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/model/OffChainGatewayLocalizationModel.kt new file mode 100644 index 000000000..50bc71882 --- /dev/null +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/model/OffChainGatewayLocalizationModel.kt @@ -0,0 +1,13 @@ +package co.nilin.opex.wallet.ports.postgres.model + +import org.springframework.data.annotation.Id +import org.springframework.data.relational.core.mapping.Table + +@Table("currency_off_chain_gateway_localization") +data class OffChainGatewayLocalizationModel( + @Id var id: Long? = null, + var gatewayId: Long, + var depositDescription: String? = null, + var withdrawDescription: String? = null, + var language: String +) diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/model/OffChainGatewayModel.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/model/OffChainGatewayModel.kt index bd2a28f08..4d433192a 100644 --- a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/model/OffChainGatewayModel.kt +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/model/OffChainGatewayModel.kt @@ -21,7 +21,5 @@ data class OffChainGatewayModel( @Column("transfer_method") var transferMethod: String, @Column("is_deposit_active") var isDepositActive: Boolean? = true, @Column("is_withdraw_active") var isWithdrawActive: Boolean? = true, - @Column("deposit_description") val depositDescription: String?, - @Column("withdraw_description") val withdrawDescription: String?, @Column("display_order") val displayOrder: Int? = null, ) diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/util/Convertor.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/util/Convertor.kt index daa8f8cc9..4e9a8bdd1 100644 --- a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/util/Convertor.kt +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/util/Convertor.kt @@ -1,8 +1,10 @@ package co.nilin.opex.wallet.ports.postgres.util import co.nilin.opex.wallet.core.inout.* +import co.nilin.opex.wallet.core.model.OffChainGatewayLocalizationCommand import co.nilin.opex.wallet.core.model.TotalAssetsSnapshot import co.nilin.opex.wallet.ports.postgres.dto.CurrencyView +import co.nilin.opex.wallet.ports.postgres.dto.OffChainGatewayView import co.nilin.opex.wallet.ports.postgres.dto.TerminalView import co.nilin.opex.wallet.ports.postgres.model.* import java.time.ZoneId @@ -141,7 +143,7 @@ fun DepositModel.toDto(): Deposit { } -fun OffChainGatewayModel.toDto(): CurrencyGatewayCommand { +fun OffChainGatewayView.toDto(): CurrencyGatewayCommand { return OffChainGatewayCommand( TransferMethod.valueOf(transferMethod), currencySymbol, @@ -176,12 +178,19 @@ fun OffChainGatewayCommand.toModel(): OffChainGatewayModel { transferMethod.name, isDepositActive, isWithdrawActive, - depositDescription, - withdrawDescription, displayOrder ) } +fun OffChainGatewayLocalizationModel.toCommand(): OffChainGatewayLocalizationCommand { + return OffChainGatewayLocalizationCommand( + id = id, + depositDescription = depositDescription, + withdrawDescription = withdrawDescription, + language = language, + ) +} + fun TerminalCommand.toModel(): TerminalModel { return TerminalModel( null, diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/resources/db/migration/V11__add_gateway_localizations_table.sql b/wallet/wallet-ports/wallet-persister-postgres/src/main/resources/db/migration/V11__add_gateway_localizations_table.sql new file mode 100644 index 000000000..24f54393b --- /dev/null +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/resources/db/migration/V11__add_gateway_localizations_table.sql @@ -0,0 +1,20 @@ +CREATE TABLE IF NOT EXISTS currency_off_chain_gateway_localization +( + id SERIAL PRIMARY KEY, + gateway_id BIGINT NOT NULL REFERENCES currency_off_chain_gateway (id) ON DELETE CASCADE, + deposit_description TEXT, + withdraw_description TEXT, + language VARCHAR(10) NOT NULL, + UNIQUE (gateway_id, language) +); + +INSERT INTO currency_off_chain_gateway_localization (gateway_id, + deposit_description, + withdraw_description, + language) +SELECT id, deposit_description, withdraw_description, 'EN' +FROM currency_off_chain_gateway; + +ALTER TABLE currency_off_chain_gateway + DROP COLUMN deposit_description, + DROP COLUMN withdraw_description; \ No newline at end of file From 10b08678e775e722812cc138edd409f01c894544 Mon Sep 17 00:00:00 2001 From: Amir Rajabi Date: Sat, 2 May 2026 16:29:53 +0330 Subject: [PATCH 3/5] some improvement --- .../ports/postgres/impl/CurrencyHandlerImplV2.kt | 2 +- .../opex/wallet/app/config/WebClientConfig.kt | 15 +++++++++++++++ .../postgres/impl/OffChainGatewayManagerImpl.kt | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/impl/CurrencyHandlerImplV2.kt b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/impl/CurrencyHandlerImplV2.kt index 1b3e68220..489846882 100644 --- a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/impl/CurrencyHandlerImplV2.kt +++ b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/impl/CurrencyHandlerImplV2.kt @@ -94,7 +94,7 @@ class CurrencyHandlerImplV2( request?.gatewayUuid, request?.chain, request?.currencyImplementationName, - language ?: getDefaultUserLanguage() + language ) return resp ?: throw OpexError.ImplNotFound.exception() 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 e65a2ce03..4b6bdd82e 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,5 +1,6 @@ package co.nilin.opex.wallet.app.config +import co.nilin.opex.common.data.UserLanguage import io.netty.channel.ChannelOption import org.springframework.beans.factory.annotation.Qualifier import org.springframework.cloud.client.ServiceInstance @@ -9,9 +10,12 @@ import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Profile import org.springframework.http.client.reactive.ReactorClientHttpConnector +import org.springframework.web.reactive.function.client.ClientRequest +import org.springframework.web.reactive.function.client.ExchangeFilterFunction import org.springframework.web.reactive.function.client.WebClient import org.zalando.logbook.Logbook import org.zalando.logbook.netty.LogbookClientHandler +import reactor.core.publisher.Mono import reactor.netty.http.client.HttpClient import reactor.netty.resources.ConnectionProvider import java.time.Duration @@ -44,6 +48,7 @@ class WebClientConfig(logbook: Logbook) { return WebClient.builder() .filter(ReactorLoadBalancerExchangeFilterFunction(loadBalancerFactory, emptyList())) .clientConnector(ReactorClientHttpConnector(client)) + .filter(languageFilter()) .build() } @@ -53,7 +58,17 @@ class WebClientConfig(logbook: Logbook) { fun webClient(): WebClient { return WebClient.builder() .clientConnector(ReactorClientHttpConnector(client)) + .filter(languageFilter()) .build() } + private fun languageFilter() = ExchangeFilterFunction { request, next -> + Mono.deferContextual { ctx -> + val lang = ctx.getOrDefault("lang", UserLanguage.EN.toString()) + val mutatedRequest = ClientRequest.from(request) + .header("Accept-Language", lang) + .build() + next.exchange(mutatedRequest) + } + } } diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/OffChainGatewayManagerImpl.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/OffChainGatewayManagerImpl.kt index 0cca73a6c..76e78d67f 100644 --- a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/OffChainGatewayManagerImpl.kt +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/OffChainGatewayManagerImpl.kt @@ -117,7 +117,7 @@ class OffChainGatewayManagerImpl( fetchGateways: FetchGateways, language: String? = null ): List? { return offChainGatewayRepository.findGateways( - fetchGateways.currencySymbol, language ?: getDefaultUserLanguage() + currencySymbol = fetchGateways.currencySymbol, language = language ?: getDefaultUserLanguage() )?.collectList()?.awaitFirstOrNull() } } \ No newline at end of file From 6cc331b267c5504f603acf780108403c7666510e Mon Sep 17 00:00:00 2001 From: Amir Rajabi Date: Sat, 2 May 2026 20:29:35 +0330 Subject: [PATCH 4/5] Add terminal admin services to api module --- .../co/nilin/opex/api/core/spi/WalletProxy.kt | 7 ++ .../controller/TerminalAdminController.kt | 64 ++++++++++++++ .../api/ports/proxy/impl/WalletProxyImpl.kt | 84 +++++++++++++++++++ .../controller/CryptoCurrencyController.kt | 2 + .../app/controller/DepositAdminController.kt | 20 +++-- .../wallet/core/spi/GatewayTerminalManager.kt | 3 + .../postgres/dao/GatewayTerminalRepository.kt | 28 ++++++- .../postgres/impl/GatewayTerminalImpl.kt | 9 ++ .../postgres/impl/TerminalManagerImpl.kt | 1 - 9 files changed, 209 insertions(+), 9 deletions(-) create mode 100644 api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TerminalAdminController.kt diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt index dcf8d6c47..a3ec39ab6 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt @@ -236,4 +236,11 @@ interface WalletProxy { ): GatewayLocalizationResponse suspend fun deleteOffChainGatewayLocalization(token: String, id: Long) + suspend fun saveTerminal(token: String, terminal: TerminalCommand): TerminalCommand? + suspend fun updateTerminal(token: String, terminalUuid: String, terminal: TerminalCommand): TerminalCommand? + suspend fun deleteTerminal(token: String, terminalUuid: String) + suspend fun getTerminals(token: String): List? + suspend fun getTerminal(token: String, terminalUuid: String): TerminalCommand? + suspend fun getAssignedGatewayToTerminal(token: String, terminalUuid: String): List? + } \ 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/TerminalAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TerminalAdminController.kt new file mode 100644 index 000000000..5dd555a80 --- /dev/null +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TerminalAdminController.kt @@ -0,0 +1,64 @@ +package co.nilin.opex.api.ports.opex.controller + +import co.nilin.opex.api.core.inout.CurrencyGatewayCommand +import co.nilin.opex.api.core.inout.TerminalCommand +import co.nilin.opex.api.core.spi.WalletProxy +import co.nilin.opex.api.ports.opex.util.jwtAuthentication +import co.nilin.opex.api.ports.opex.util.tokenValue +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.* + +@RestController +@RequestMapping("/opex/v1/admin/terminal") +class TerminalAdminController( + private val walletProxy: WalletProxy, +) { + @PostMapping + suspend fun registerTerminal( + @CurrentSecurityContext securityContext: SecurityContext, @RequestBody body: TerminalCommand + ): TerminalCommand? { + return walletProxy.saveTerminal(securityContext.jwtAuthentication().tokenValue(), body) + } + + + @PutMapping("/{uuid}") + suspend fun updateTerminal( + @CurrentSecurityContext securityContext: SecurityContext, + @PathVariable("uuid") terminalUuid: String, + @RequestBody body: TerminalCommand + ): TerminalCommand? { + return walletProxy.updateTerminal(securityContext.jwtAuthentication().tokenValue(), terminalUuid, body) + } + + @DeleteMapping("/{uuid}") + suspend fun deleteTerminal( + @CurrentSecurityContext securityContext: SecurityContext, + @PathVariable("uuid") terminalUuid: String, + ) { + walletProxy.deleteTerminal(securityContext.jwtAuthentication().tokenValue(), terminalUuid) + } + + @GetMapping + suspend fun getTerminal( + @CurrentSecurityContext securityContext: SecurityContext, + ): List? { + return walletProxy.getTerminals(securityContext.jwtAuthentication().tokenValue()) + } + + @GetMapping("/{uuid}") + suspend fun getTerminal( + @CurrentSecurityContext securityContext: SecurityContext, + @PathVariable("uuid") terminalUuid: String, + ): TerminalCommand? { + return walletProxy.getTerminal(securityContext.jwtAuthentication().tokenValue(), terminalUuid) + } + + @GetMapping("/{uuid}/gateway") + suspend fun getGatewayTerminal( + @CurrentSecurityContext securityContext: SecurityContext, + @PathVariable("uuid") terminalUuid: String, + ): List? { + return walletProxy.getAssignedGatewayToTerminal(securityContext.jwtAuthentication().tokenValue(), terminalUuid) + } +} diff --git a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt index 5e8b87ecc..3146e1aac 100644 --- a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt +++ b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt @@ -927,5 +927,89 @@ class WalletProxyImpl(@Qualifier("generalWebClient") private val webClient: WebC } .awaitBodilessEntity() } + + override suspend fun saveTerminal( + token: String, + terminal: TerminalCommand + ): TerminalCommand? { + return webClient.post() + .uri("$baseUrl/admin/deposit/terminal") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .body(Mono.just(terminal)) + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono() + .awaitFirstOrElse { throw OpexError.BadRequest.exception() } + } + + override suspend fun updateTerminal( + token: String, + terminalUuid: String, + terminal: TerminalCommand + ): TerminalCommand? { + return webClient.put() + .uri("$baseUrl/admin/deposit/terminal/${terminalUuid}") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .body(Mono.just(terminal)) + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono() + .awaitFirstOrElse { throw OpexError.BadRequest.exception() } + } + + override suspend fun deleteTerminal(token: String, terminalUuid: String) { + webClient.delete() + .uri("$baseUrl/admin/deposit/terminal/${terminalUuid}") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .retrieve() + .onStatus({ it.isError }) { response -> + response.createException() + } + .awaitBodilessEntity() + } + + override suspend fun getTerminals(token: String): List? { + return webClient.get() + .uri("$baseUrl/admin/deposit/terminal") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToFlux() + .collectList() + .awaitFirstOrElse { throw OpexError.BadRequest.exception() } + } + + override suspend fun getTerminal( + token: String, + terminalUuid: String + ): TerminalCommand? { + return webClient.get() + .uri("$baseUrl/admin/deposit/terminal/${terminalUuid}") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono() + .awaitFirstOrElse { throw OpexError.BadRequest.exception() } + } + + override suspend fun getAssignedGatewayToTerminal( + token: String, + terminalUuid: String + ): List? { + return webClient.get() + .uri("$baseUrl/admin/deposit/terminal/${terminalUuid}/gateway") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToFlux() + .collectList() + .awaitFirstOrElse { throw OpexError.BadRequest.exception() } + } } diff --git a/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/controller/CryptoCurrencyController.kt b/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/controller/CryptoCurrencyController.kt index bff642370..7c2c6d07f 100644 --- a/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/controller/CryptoCurrencyController.kt +++ b/bc-gateway/bc-gateway-app/src/main/kotlin/co/nilin/opex/bcgateway/app/controller/CryptoCurrencyController.kt @@ -8,6 +8,8 @@ import co.nilin.opex.bcgateway.core.model.FetchGateways import co.nilin.opex.bcgateway.core.model.WithdrawData import co.nilin.opex.bcgateway.core.spi.ChainLoader import co.nilin.opex.bcgateway.core.spi.CryptoCurrencyHandlerV2 +import kotlinx.coroutines.currentCoroutineContext +import kotlinx.coroutines.reactor.ReactorContext import org.springframework.web.bind.annotation.* @RestController diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/DepositAdminController.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/DepositAdminController.kt index 4284252ac..861a8a8f4 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/DepositAdminController.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/DepositAdminController.kt @@ -4,10 +4,8 @@ import co.nilin.opex.wallet.app.dto.AdminSearchDepositRequest import co.nilin.opex.wallet.app.dto.ManualTransferRequest import co.nilin.opex.wallet.app.dto.TerminalLocalizationResponse import co.nilin.opex.wallet.app.service.DepositService -import co.nilin.opex.wallet.core.inout.DepositAdminResponse -import co.nilin.opex.wallet.core.inout.TerminalCommand -import co.nilin.opex.wallet.core.inout.TerminalLocalizationCommand -import co.nilin.opex.wallet.core.inout.TransferResult +import co.nilin.opex.wallet.core.inout.* +import co.nilin.opex.wallet.core.spi.GatewayTerminalManager import co.nilin.opex.wallet.core.spi.TerminalManager import io.swagger.annotations.ApiResponse import io.swagger.annotations.Example @@ -26,7 +24,8 @@ import java.util.* class DepositAdminController( private val depositService: DepositService, - private val terminalManager: TerminalManager + private val terminalManager: TerminalManager, + private val gatewayTerminalManager: GatewayTerminalManager ) { @@ -137,8 +136,15 @@ class DepositAdminController( @GetMapping("/terminal/{uuid}") suspend fun getTerminal( @PathVariable("uuid") terminalUuid: String, - ) { - terminalManager.fetchTerminal(terminalUuid) + ): TerminalCommand? { + return terminalManager.fetchTerminal(terminalUuid) + } + + @GetMapping("/terminal/{uuid}/gateway") + suspend fun getGatewayTerminal( + @PathVariable("uuid") terminalUuid: String, + ): List? { + return gatewayTerminalManager.getAssignedGatewayToTerminal(terminalUuid) } @PostMapping("/terminal/{uuid}/localization") diff --git a/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/GatewayTerminalManager.kt b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/GatewayTerminalManager.kt index ca8b28986..8386c4a09 100644 --- a/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/GatewayTerminalManager.kt +++ b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/spi/GatewayTerminalManager.kt @@ -1,5 +1,6 @@ package co.nilin.opex.wallet.core.spi +import co.nilin.opex.wallet.core.inout.CurrencyGatewayCommand import co.nilin.opex.wallet.core.inout.TerminalCommand interface GatewayTerminalManager { @@ -7,6 +8,8 @@ interface GatewayTerminalManager { suspend fun getAssignedTerminalToGateway(gatewayUuid: String): List? + suspend fun getAssignedGatewayToTerminal(terminalUuid: String): List? + suspend fun revokeTerminalsToGateway(gatewayUuid: String, terminals: List) } \ No newline at end of file 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 fa2a24144..be1bc1949 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 @@ -1,5 +1,7 @@ package co.nilin.opex.wallet.ports.postgres.dao +import co.nilin.opex.common.data.UserLanguage +import co.nilin.opex.wallet.ports.postgres.dto.OffChainGatewayView import co.nilin.opex.wallet.ports.postgres.dto.TerminalView import co.nilin.opex.wallet.ports.postgres.model.GatewayTerminalModel import org.springframework.data.r2dbc.repository.Query @@ -31,5 +33,29 @@ interface GatewayTerminalRepository : ReactiveCrudRepository? + fun findByGatewayId(gatewayId: Long, lang: String? = UserLanguage.getDefault().toString()): Flux? + + + @Query(""" + select g.id, + g.gateway_uuid, + g.currency_symbol, + g.deposit_allowed, + g.withdraw_fee, + g.withdraw_min, + g.withdraw_max, + g.deposit_min, + g.deposit_max, + g.transfer_method, + g.is_deposit_active, + g.is_withdraw_active, + gl.deposit_description, + gl.withdraw_description, + g.display_order + from gateway_terminal gt + left join currency_off_chain_gateway g on gt.gateway_id = g.id + left join currency_off_chain_gateway_localization gl on g.id = gl.gateway_id and gl.language = :lang + where gt.terminal_id = :terminalId + """) + fun findByTerminalId(terminalId: Long, lang: String? = UserLanguage.getDefault().toString()): Flux? } diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/GatewayTerminalImpl.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/GatewayTerminalImpl.kt index 5fde477d8..5031ab389 100644 --- a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/GatewayTerminalImpl.kt +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/GatewayTerminalImpl.kt @@ -3,6 +3,7 @@ package co.nilin.opex.wallet.ports.postgres.impl import co.nilin.opex.common.OpexError import co.nilin.opex.common.data.UserLanguage import co.nilin.opex.common.utils.LanguageUtils.getUserLanguage +import co.nilin.opex.wallet.core.inout.CurrencyGatewayCommand import co.nilin.opex.wallet.core.inout.TerminalCommand import co.nilin.opex.wallet.core.spi.GatewayTerminalManager import co.nilin.opex.wallet.ports.postgres.dao.GatewayTerminalRepository @@ -10,6 +11,7 @@ import co.nilin.opex.wallet.ports.postgres.dao.OffChainGatewayRepository import co.nilin.opex.wallet.ports.postgres.dao.TerminalRepository import co.nilin.opex.wallet.ports.postgres.model.GatewayTerminalModel import co.nilin.opex.wallet.ports.postgres.util.toCommand +import co.nilin.opex.wallet.ports.postgres.util.toDto import kotlinx.coroutines.reactor.awaitSingleOrNull import org.slf4j.LoggerFactory import org.springframework.stereotype.Component @@ -49,6 +51,13 @@ class GatewayTerminalImpl( } ?: throw OpexError.GatewayNotFount.exception() } + override suspend fun getAssignedGatewayToTerminal(terminalUuid: String): List? { + return terminalRepository.findByUuid(terminalUuid)?.awaitSingleOrNull()?.let { terminal -> + gatewayTerminalRepository.findByTerminalId(terminal.id!!)?.map { it.toDto() }?.collectList() + ?.awaitSingleOrNull() + } ?: throw OpexError.TerminalNotFound.exception() + } + override suspend fun revokeTerminalsToGateway(gatewayUuid: String, terminals: List) { gatewayRepository.findByGatewayUuid(gatewayUuid)?.awaitSingleOrNull()?.let { gateway -> terminals.forEach { it -> diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/TerminalManagerImpl.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/TerminalManagerImpl.kt index a29338f7f..bc41de604 100644 --- a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/TerminalManagerImpl.kt +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/TerminalManagerImpl.kt @@ -13,7 +13,6 @@ import co.nilin.opex.wallet.ports.postgres.model.TerminalLocalizationModel import co.nilin.opex.wallet.ports.postgres.model.TerminalModel import co.nilin.opex.wallet.ports.postgres.util.toCommand import co.nilin.opex.wallet.ports.postgres.util.toModel -import kotlinx.coroutines.reactor.awaitSingle import kotlinx.coroutines.reactor.awaitSingleOrNull import org.springframework.stereotype.Component import org.springframework.transaction.reactive.TransactionalOperator From 44fcf02a2505aac2f092e9ece55a044fa1f856dc Mon Sep 17 00:00:00 2001 From: Amir Rajabi Date: Mon, 4 May 2026 15:20:32 +0330 Subject: [PATCH 5/5] Add gateway admin services to api module --- .../co/nilin/opex/api/core/spi/WalletProxy.kt | 19 ++++ .../opex/controller/GatewayAdminController.kt | 63 ++++++++++++ .../controller/TerminalAdminController.kt | 27 +++++ .../api/ports/proxy/impl/WalletProxyImpl.kt | 99 +++++++++++++++++++ .../app/controller/CurrencyController.kt | 6 +- 5 files changed, 211 insertions(+), 3 deletions(-) create mode 100644 api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt index a3ec39ab6..402f8bd21 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt @@ -242,5 +242,24 @@ interface WalletProxy { suspend fun getTerminals(token: String): List? suspend fun getTerminal(token: String, terminalUuid: String): TerminalCommand? suspend fun getAssignedGatewayToTerminal(token: String, terminalUuid: String): List? + suspend fun assignTerminalsToGateway(token: String, gatewayUuid: String, terminal: List) + suspend fun revokeTerminalsToGateway(token: String, gatewayUuid: String, terminal: List) + suspend fun addCurrencyToGateway( + token: String, + currencySymbol: String, + gatewayCommand: CurrencyGatewayCommand + ): CurrencyGatewayCommand? + + suspend fun updateGateway( + token: String, + gatewayUuid: String, + currencySymbol: String, + gatewayCommand: CurrencyGatewayCommand + ): CurrencyGatewayCommand? + + suspend fun getGateway(token: String, gatewayUuid: String, currencySymbol: String): CurrencyGatewayCommand? + + suspend fun deleteGateway(token: String, gatewayUuid: String, currencySymbol: String) + } \ 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 new file mode 100644 index 000000000..8b82f11c0 --- /dev/null +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt @@ -0,0 +1,63 @@ +package co.nilin.opex.api.ports.opex.controller + +import co.nilin.opex.api.core.inout.CurrencyGatewayCommand +import co.nilin.opex.api.core.spi.WalletProxy +import co.nilin.opex.api.ports.opex.util.jwtAuthentication +import co.nilin.opex.api.ports.opex.util.tokenValue +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.* + +@RestController +@RequestMapping("/opex/v1/admin") +class GatewayAdminController( + private val walletProxy: WalletProxy, +) { + @PostMapping("/{currencySymbol}/gateway") + suspend fun addCurrencyToGateway( + @CurrentSecurityContext securityContext: SecurityContext, + @PathVariable("currencySymbol") currencySymbol: String, + @RequestBody body: CurrencyGatewayCommand, + ): CurrencyGatewayCommand? { + return walletProxy.addCurrencyToGateway(securityContext.jwtAuthentication().tokenValue(), currencySymbol, body) + } + + + @PutMapping("/{currencySymbol}/gateway/{uuid}") + suspend fun updateGateway( + @CurrentSecurityContext securityContext: SecurityContext, + @PathVariable("uuid") gatewayUuid: String, + @PathVariable("currencySymbol") currencySymbol: String, + @RequestBody body: CurrencyGatewayCommand + ): CurrencyGatewayCommand? { + return walletProxy.updateGateway( + securityContext.jwtAuthentication().tokenValue(), + gatewayUuid, + currencySymbol, + body + ) + } + + @GetMapping("/{currencySymbol}/gateway/{uuid}") + suspend fun getGateway( + @CurrentSecurityContext securityContext: SecurityContext, + @PathVariable("uuid") gatewayUuid: String, + @PathVariable("currencySymbol") currencySymbol: String, + ): CurrencyGatewayCommand? { + return walletProxy.getGateway( + securityContext.jwtAuthentication().tokenValue(), + gatewayUuid, + currencySymbol + ) + } + + @DeleteMapping("/{currencySymbol}/gateway/{uuid}") + suspend fun deleteGateway( + @CurrentSecurityContext securityContext: SecurityContext, + @PathVariable("uuid") gatewayUuid: String, + @PathVariable("currencySymbol") currencySymbol: String, + ) { + walletProxy.deleteGateway(securityContext.jwtAuthentication().tokenValue(), gatewayUuid, currencySymbol) + } + +} diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TerminalAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TerminalAdminController.kt index 5dd555a80..932733f64 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TerminalAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TerminalAdminController.kt @@ -61,4 +61,31 @@ class TerminalAdminController( ): List? { return walletProxy.getAssignedGatewayToTerminal(securityContext.jwtAuthentication().tokenValue(), terminalUuid) } + + @PostMapping("/gateway/{uuid}") + suspend fun assignTerminalToGateway( + @CurrentSecurityContext securityContext: SecurityContext, + @PathVariable("uuid") gatewayUuid: String, + @RequestBody terminal: List, + ) { + return walletProxy.assignTerminalsToGateway( + securityContext.jwtAuthentication().tokenValue(), + gatewayUuid, + terminal + ) + } + + @DeleteMapping("/gateway/{uuid}") + suspend fun revokeTerminalFromGateway( + @CurrentSecurityContext securityContext: SecurityContext, + @PathVariable("uuid") gatewayUuid: String, + @RequestBody terminal: List, + ) { + return walletProxy.revokeTerminalsToGateway( + securityContext.jwtAuthentication().tokenValue(), + gatewayUuid, + terminal + ) + } + } diff --git a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt index 3146e1aac..3a7928882 100644 --- a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt +++ b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt @@ -15,6 +15,7 @@ import kotlinx.coroutines.withContext import org.springframework.beans.factory.annotation.Qualifier import org.springframework.beans.factory.annotation.Value import org.springframework.http.HttpHeaders +import org.springframework.http.HttpMethod import org.springframework.http.MediaType import org.springframework.stereotype.Component import org.springframework.web.reactive.function.client.* @@ -1011,5 +1012,103 @@ class WalletProxyImpl(@Qualifier("generalWebClient") private val webClient: WebC .collectList() .awaitFirstOrElse { throw OpexError.BadRequest.exception() } } + + override suspend fun assignTerminalsToGateway( + token: String, + gatewayUuid: String, + terminal: List + ) { + webClient.post() + .uri("$baseUrl/currency/gateway/${gatewayUuid}/terminal") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .body(Mono.just(terminal)) + .retrieve() + .onStatus({ it.isError }) { response -> + response.createException() + } + .awaitBodilessEntity() + } + + override suspend fun revokeTerminalsToGateway( + token: String, + gatewayUuid: String, + terminal: List + ) { + webClient.method(HttpMethod.DELETE) + .uri("$baseUrl/currency/gateway/${gatewayUuid}/terminal") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .bodyValue(terminal) + .retrieve() + .onStatus({ it.isError }) { response -> + response.createException() + } + .awaitBodilessEntity() + } + + override suspend fun addCurrencyToGateway( + token: String, + currencySymbol: String, + gatewayCommand: CurrencyGatewayCommand + ): CurrencyGatewayCommand? { + return webClient.post() + .uri("$baseUrl/currency/${currencySymbol}/gateway") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .body(Mono.just(gatewayCommand)) + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono() + .awaitFirstOrElse { throw OpexError.BadRequest.exception() } + } + + override suspend fun updateGateway( + token: String, + gatewayUuid: String, + currencySymbol: String, + gatewayCommand: CurrencyGatewayCommand + ): CurrencyGatewayCommand? { + return webClient.put() + .uri("$baseUrl/currency/${currencySymbol}/gateway/${gatewayUuid}") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .body(Mono.just(gatewayCommand)) + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono() + .awaitFirstOrElse { throw OpexError.BadRequest.exception() } + } + + override suspend fun getGateway( + token: String, + gatewayUuid: String, + currencySymbol: String + ): CurrencyGatewayCommand? { + return webClient.get() + .uri("$baseUrl/currency/${currencySymbol}/gateway/${gatewayUuid}") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono() + .awaitFirstOrElse { throw OpexError.BadRequest.exception() } + } + + override suspend fun deleteGateway( + token: String, + gatewayUuid: String, + currencySymbol: String + ) { + webClient.delete() + .uri("$baseUrl/currency/${currencySymbol}/gateway/${gatewayUuid}") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .retrieve() + .onStatus({ it.isError }) { response -> + response.createException() + } + .awaitBodilessEntity() + } } diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/CurrencyController.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/CurrencyController.kt index 08c20da7f..550a11bd1 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/CurrencyController.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/CurrencyController.kt @@ -75,7 +75,7 @@ class CurrencyController( }) } - @PutMapping("{currencySymbol}/gateway/{gatewayUuid}") + @PutMapping("/{currencySymbol}/gateway/{gatewayUuid}") suspend fun updateGateway( @PathVariable("gatewayUuid") gatewayUuid: String, @PathVariable("currencySymbol") currencySymbol: String, @@ -87,7 +87,7 @@ class CurrencyController( }) } - @GetMapping("{currencySymbol}/gateway/{gatewayUuid}") + @GetMapping("/{currencySymbol}/gateway/{gatewayUuid}") suspend fun getGateway( @PathVariable("gatewayUuid") gatewayUuid: String, @PathVariable("currencySymbol") currencySymbol: String, @@ -95,7 +95,7 @@ class CurrencyController( return currencyService.fetchCurrencyGateway(gatewayUuid, currencySymbol) } - @DeleteMapping("{currencySymbol}/gateway/{gatewayUuid}") + @DeleteMapping("/{currencySymbol}/gateway/{gatewayUuid}") suspend fun deleteGateway( @PathVariable("gatewayUuid") gatewayUuid: String, @PathVariable("currencySymbol") currencySymbol: String,