From c90711ff141b7fd7e3320ac7574e729ba9a15ccf Mon Sep 17 00:00:00 2001 From: Amir Rajabi Date: Sun, 4 Jan 2026 12:31:29 +0330 Subject: [PATCH 1/2] add services --- .../opex/api/core/CompleteProfileRequest.kt | 16 ++ .../api/core/ContactUpdateConfirmRequest.kt | 7 + .../opex/api/core/ContactUpdateRequest.kt | 6 + .../api/core/ProfileApprovalUserResponse.kt | 10 ++ .../core/inout/AddAddressBookItemRequest.kt | 7 + .../api/core/inout/AddBankAccountRequest.kt | 7 + .../api/core/inout/AddressBookResponse.kt | 8 + .../api/core/inout/BankAccountResponse.kt | 16 ++ .../nilin/opex/api/core/spi/ProfileProxy.kt | 24 ++- .../ports/binance/config/SecurityConfig.kt | 1 + .../opex/controller/AddressBookController.kt | 48 +++++ .../opex/controller/BankAccountController.kt | 40 +++++ .../opex/controller/ProfileAdminController.kt | 2 +- .../opex/controller/ProfileController.kt | 57 ++++++ .../api/ports/proxy/impl/ProfileProxyImpl.kt | 170 +++++++++++++++++- .../app/controller/ProfileController.kt | 1 - 16 files changed, 416 insertions(+), 4 deletions(-) create mode 100644 api/api-core/src/main/kotlin/co/nilin/opex/api/core/CompleteProfileRequest.kt create mode 100644 api/api-core/src/main/kotlin/co/nilin/opex/api/core/ContactUpdateConfirmRequest.kt create mode 100644 api/api-core/src/main/kotlin/co/nilin/opex/api/core/ContactUpdateRequest.kt create mode 100644 api/api-core/src/main/kotlin/co/nilin/opex/api/core/ProfileApprovalUserResponse.kt create mode 100644 api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/AddAddressBookItemRequest.kt create mode 100644 api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/AddBankAccountRequest.kt create mode 100644 api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/AddressBookResponse.kt create mode 100644 api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/BankAccountResponse.kt create mode 100644 api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/AddressBookController.kt create mode 100644 api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt create mode 100644 api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileController.kt diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/CompleteProfileRequest.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/CompleteProfileRequest.kt new file mode 100644 index 000000000..0fd875bf1 --- /dev/null +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/CompleteProfileRequest.kt @@ -0,0 +1,16 @@ +package co.nilin.opex.api.core + +import co.nilin.opex.api.core.inout.Gender +import co.nilin.opex.api.core.inout.NationalityType + +data class CompleteProfileRequest( + var firstName: String, + var lastName: String, + var address: String? = null, + var telephone: String? = null, + var postalCode: String? = null, + var nationality: NationalityType, + var identifier: String, + var gender: Gender, + var birthDate: Long, +) diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/ContactUpdateConfirmRequest.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/ContactUpdateConfirmRequest.kt new file mode 100644 index 000000000..34a6a196b --- /dev/null +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/ContactUpdateConfirmRequest.kt @@ -0,0 +1,7 @@ +package co.nilin.opex.api.core + +data class ContactUpdateConfirmRequest( + val email: String? = null, + val mobile: String? = null, + val otpCode: String, +) \ No newline at end of file diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/ContactUpdateRequest.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/ContactUpdateRequest.kt new file mode 100644 index 000000000..8cacb4785 --- /dev/null +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/ContactUpdateRequest.kt @@ -0,0 +1,6 @@ +package co.nilin.opex.api.core + +data class ContactUpdateRequest( + val email: String? = null, + val mobile: String? = null +) \ No newline at end of file diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/ProfileApprovalUserResponse.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/ProfileApprovalUserResponse.kt new file mode 100644 index 000000000..2bb98507f --- /dev/null +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/ProfileApprovalUserResponse.kt @@ -0,0 +1,10 @@ +package co.nilin.opex.api.core + +import co.nilin.opex.api.core.inout.ProfileApprovalRequestStatus +import java.time.LocalDateTime + +data class ProfileApprovalUserResponse( + var status: ProfileApprovalRequestStatus, + var createDate: LocalDateTime, + var description: String? = null +) diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/AddAddressBookItemRequest.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/AddAddressBookItemRequest.kt new file mode 100644 index 000000000..3135d699d --- /dev/null +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/AddAddressBookItemRequest.kt @@ -0,0 +1,7 @@ +package co.nilin.opex.api.core.inout + +data class AddAddressBookItemRequest( + var name: String, + var address: String, + var addressType: String, +) diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/AddBankAccountRequest.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/AddBankAccountRequest.kt new file mode 100644 index 000000000..1f1ea2235 --- /dev/null +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/AddBankAccountRequest.kt @@ -0,0 +1,7 @@ +package co.nilin.opex.api.core.inout + +data class AddBankAccountRequest( + val name: String? = null, + val cardNumber: String? = null, + val iban: String? = null, +) diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/AddressBookResponse.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/AddressBookResponse.kt new file mode 100644 index 000000000..2f9975bc6 --- /dev/null +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/AddressBookResponse.kt @@ -0,0 +1,8 @@ +package co.nilin.opex.api.core.inout + +data class AddressBookResponse( + var id: Long? = null, + var name: String, + var address: String, + var addressType: String, +) diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/BankAccountResponse.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/BankAccountResponse.kt new file mode 100644 index 000000000..156a92269 --- /dev/null +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/BankAccountResponse.kt @@ -0,0 +1,16 @@ +package co.nilin.opex.api.core.inout + + +data class BankAccountResponse( + var id: Long? = null, + var name: String? = null, + var cardNumber: String? = null, + var iban: String? = null, + var accountNumber: String? = null, + var bank: String? = null, + var status: BankAccountStatus, +) + +enum class BankAccountStatus { + WAITING, VERIFIED, REJECTED +} \ No newline at end of file diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/ProfileProxy.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/ProfileProxy.kt index 130b0332b..7a21cb94e 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/ProfileProxy.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/ProfileProxy.kt @@ -1,11 +1,21 @@ package co.nilin.opex.api.core.spi +import co.nilin.opex.api.core.CompleteProfileRequest +import co.nilin.opex.api.core.ContactUpdateConfirmRequest +import co.nilin.opex.api.core.ContactUpdateRequest +import co.nilin.opex.api.core.ProfileApprovalUserResponse import co.nilin.opex.api.core.inout.* interface ProfileProxy { + suspend fun getProfile(token: String): Profile + suspend fun completeProfile(token: String, request: CompleteProfileRequest): Profile? + suspend fun requestContactUpdate(token: String, request: ContactUpdateRequest): TempOtpResponse + suspend fun confirmContactUpdate(token: String, request: ContactUpdateConfirmRequest) + suspend fun getUserProfileApprovalRequest(token: String): ProfileApprovalUserResponse + // Admin suspend fun getProfiles(token: String, profileRequest: ProfileRequest): List - suspend fun getProfile(token: String, uuid: String): Profile + suspend fun getProfileAdmin(token: String, uuid: String): Profile suspend fun getProfileHistory(token: String, uuid: String, limit: Int, offset: Int): List suspend fun getProfileApprovalRequests( token: String, @@ -17,4 +27,16 @@ interface ProfileProxy { token: String, request: UpdateApprovalRequestBody ): ProfileApprovalAdminResponse + + + // Address Book + suspend fun addAddressBook(token: String, request: AddAddressBookItemRequest): AddressBookResponse + suspend fun getAllAddressBooks(token: String): List + suspend fun deleteAddressBook(token: String, id: Long) + suspend fun updateAddressBook(token: String, id: Long, request: AddAddressBookItemRequest): AddressBookResponse + + //Bank Account + suspend fun addBankAccount(token: String, request: AddBankAccountRequest): BankAccountResponse + suspend fun getBankAccounts(token: String): List + suspend fun deleteBankAccount(token: String, id: Long) } \ No newline at end of file diff --git a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt index 972a90826..7715a6121 100644 --- a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt +++ b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt @@ -63,6 +63,7 @@ class SecurityConfig( .pathMatchers(HttpMethod.PUT, "/opex/v1/otc/rate").hasAnyAuthority("ROLE_admin", "ROLE_rate_bot") .pathMatchers(HttpMethod.GET, "/opex/v1/otc/**").permitAll() .pathMatchers("/opex/v1/otc/**").hasAuthority("ROLE_admin") + .pathMatchers("/opex/v1/bank-account/**").hasAuthority("PERM_bank_account:write") .anyExchange().authenticated() } .addFilterBefore(apiKeyFilter as WebFilter, SecurityWebFiltersOrder.AUTHENTICATION) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/AddressBookController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/AddressBookController.kt new file mode 100644 index 000000000..369111929 --- /dev/null +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/AddressBookController.kt @@ -0,0 +1,48 @@ +package co.nilin.opex.api.ports.opex.controller + +import co.nilin.opex.api.core.inout.AddAddressBookItemRequest +import co.nilin.opex.api.core.inout.AddressBookResponse +import co.nilin.opex.api.core.spi.ProfileProxy +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/address-book") +class AddressBookController( + val profileProxy: ProfileProxy, +) { + + @PostMapping + suspend fun addAddressBook( + @RequestBody request: AddAddressBookItemRequest, + @CurrentSecurityContext securityContext: SecurityContext + ): AddressBookResponse { + return profileProxy.addAddressBook(securityContext.jwtAuthentication().tokenValue(), request) + } + + @GetMapping + suspend fun getAddressBook(@CurrentSecurityContext securityContext: SecurityContext): List { + return profileProxy.getAllAddressBooks(securityContext.jwtAuthentication().tokenValue()) + } + + @DeleteMapping("/{id}") + suspend fun deleteAddressBook( + @PathVariable("id") id: Long, + @CurrentSecurityContext securityContext: SecurityContext + ) { + profileProxy.deleteAddressBook(securityContext.jwtAuthentication().tokenValue(), id) + } + + @PutMapping("/{id}") + suspend fun updateAddressBook( + @PathVariable("id") id: Long, + @RequestBody request: AddAddressBookItemRequest, + @CurrentSecurityContext securityContext: SecurityContext + ): AddressBookResponse { + return profileProxy.updateAddressBook(securityContext.jwtAuthentication().tokenValue(), id, request) + } + +} \ No newline at end of file diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt new file mode 100644 index 000000000..e704894c7 --- /dev/null +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt @@ -0,0 +1,40 @@ +package co.nilin.opex.api.ports.opex.controller + +import co.nilin.opex.api.core.inout.AddBankAccountRequest +import co.nilin.opex.api.core.inout.BankAccountResponse +import co.nilin.opex.api.core.spi.ProfileProxy +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/bank-account") +class BankAccountController( + val profileProxy: ProfileProxy, +) { + + @PostMapping + suspend fun addBankAccount( + @RequestBody request: AddBankAccountRequest, + @CurrentSecurityContext securityContext: SecurityContext + ): BankAccountResponse { + return profileProxy.addBankAccount(securityContext.jwtAuthentication().tokenValue(), request) + } + + @GetMapping + suspend fun getBankAccounts(@CurrentSecurityContext securityContext: SecurityContext): List { + return profileProxy.getBankAccounts(securityContext.jwtAuthentication().tokenValue()) + } + + @DeleteMapping("/{id}") + suspend fun deleteBankAccount( + @PathVariable("id") id: Long, + @CurrentSecurityContext securityContext: SecurityContext + ) { + profileProxy.deleteBankAccount(securityContext.jwtAuthentication().tokenValue(), id) + } + + +} \ 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/ProfileAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileAdminController.kt index 95e3b5ca1..4606f77dc 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileAdminController.kt @@ -28,7 +28,7 @@ class ProfileAdminController(private val profileProxy: ProfileProxy) { @PathVariable uuid: String, @CurrentSecurityContext securityContext: SecurityContext, ): Profile { - return profileProxy.getProfile(securityContext.jwtAuthentication().tokenValue(), uuid) + return profileProxy.getProfileAdmin(securityContext.jwtAuthentication().tokenValue(), uuid) } @GetMapping("/history/{uuid}") diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileController.kt new file mode 100644 index 000000000..17a5bd7da --- /dev/null +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileController.kt @@ -0,0 +1,57 @@ +package co.nilin.opex.api.ports.opex.controller + +import co.nilin.opex.api.core.CompleteProfileRequest +import co.nilin.opex.api.core.ContactUpdateConfirmRequest +import co.nilin.opex.api.core.ContactUpdateRequest +import co.nilin.opex.api.core.ProfileApprovalUserResponse +import co.nilin.opex.api.core.inout.Profile +import co.nilin.opex.api.core.inout.TempOtpResponse +import co.nilin.opex.api.core.spi.ProfileProxy +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/profile") + +class ProfileController( + val profileProxy: ProfileProxy, +) { + + @GetMapping("/personal-data") + suspend fun getProfile(@CurrentSecurityContext securityContext: SecurityContext): Profile { + return profileProxy.getProfile(securityContext.jwtAuthentication().tokenValue()) + } + + @PutMapping("/completion") + suspend fun completeProfile( + @RequestBody completeProfileRequest: CompleteProfileRequest, + @CurrentSecurityContext securityContext: SecurityContext + ): Profile? { + return profileProxy.completeProfile(securityContext.jwtAuthentication().tokenValue(), completeProfileRequest) + } + + @PostMapping("/contact/update/otp-request") + suspend fun requestContactUpdate( + @RequestBody request: ContactUpdateRequest, + @CurrentSecurityContext securityContext: SecurityContext + ): TempOtpResponse { + return profileProxy.requestContactUpdate(securityContext.jwtAuthentication().tokenValue(), request) + } + + @PatchMapping("/contact/update/otp-verification") + suspend fun confirmContactUpdate( + @RequestBody request: ContactUpdateConfirmRequest, + @CurrentSecurityContext securityContext: SecurityContext + ) { + profileProxy.confirmContactUpdate(securityContext.jwtAuthentication().tokenValue(), request) + + } + + @GetMapping("/approval-request") + suspend fun getApprovalRequest(@CurrentSecurityContext securityContext: SecurityContext): ProfileApprovalUserResponse { + return profileProxy.getUserProfileApprovalRequest(securityContext.jwtAuthentication().tokenValue()) + } +} \ 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/ProfileProxyImpl.kt b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/ProfileProxyImpl.kt index c6ae04c95..01ec82e0f 100644 --- a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/ProfileProxyImpl.kt +++ b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/ProfileProxyImpl.kt @@ -1,5 +1,9 @@ package co.nilin.opex.api.ports.proxy.impl +import co.nilin.opex.api.core.CompleteProfileRequest +import co.nilin.opex.api.core.ContactUpdateConfirmRequest +import co.nilin.opex.api.core.ContactUpdateRequest +import co.nilin.opex.api.core.ProfileApprovalUserResponse import co.nilin.opex.api.core.inout.* import co.nilin.opex.api.core.spi.ProfileProxy import co.nilin.opex.common.OpexError @@ -11,6 +15,7 @@ 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.awaitBodilessEntity import org.springframework.web.reactive.function.client.body import org.springframework.web.reactive.function.client.bodyToMono import reactor.core.publisher.Mono @@ -38,7 +43,7 @@ class ProfileProxyImpl(@Qualifier("generalWebClient") private val webClient: Web .awaitFirstOrElse { throw OpexError.BadRequest.exception("Failed to get profiles") } } - override suspend fun getProfile(token: String, uuid: String): Profile { + override suspend fun getProfileAdmin(token: String, uuid: String): Profile { return webClient.get() .uri("$baseUrl/admin/profile/$uuid") .accept(MediaType.APPLICATION_JSON) @@ -108,5 +113,168 @@ class ProfileProxyImpl(@Qualifier("generalWebClient") private val webClient: Web .bodyToMono() .awaitFirstOrElse { throw OpexError.BadRequest.exception("Failed to update profile approval request ${request.id}") } } + + override suspend fun addAddressBook( + token: String, + request: AddAddressBookItemRequest + ): AddressBookResponse { + return webClient.post() + .uri("$baseUrl/address-book") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .body(Mono.just(request)) + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono() + .awaitFirstOrElse { throw OpexError.BadRequest.exception("Failed to add address book") } + } + + override suspend fun getAllAddressBooks(token: String): List { + return webClient.get() + .uri("$baseUrl/address-book`") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono>() + .awaitFirstOrElse { throw OpexError.BadRequest.exception("Failed to get address books") } + } + + override suspend fun deleteAddressBook( + token: String, + id: Long + ) { + webClient.delete() + .uri("$baseUrl/address-book/$id") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .retrieve() + .onStatus({ it.isError }) { response -> + response.createException() + } + .awaitBodilessEntity() + } + + override suspend fun updateAddressBook( + token: String, + id: Long, + request: AddAddressBookItemRequest + ): AddressBookResponse { + return webClient.put() + .uri("$baseUrl/address-book/$id") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .body(Mono.just(request)) + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono() + .awaitFirstOrElse { throw OpexError.BadRequest.exception("Failed to update address book") } + } + + override suspend fun addBankAccount( + token: String, + request: AddBankAccountRequest + ): BankAccountResponse { + return webClient.post() + .uri("$baseUrl/bank-account") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .body(Mono.just(request)) + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono() + .awaitFirstOrElse { throw OpexError.BadRequest.exception("Failed to add bank account") } + } + + override suspend fun getBankAccounts(token: String): List { + return webClient.get() + .uri("$baseUrl/bank-account`") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono>() + .awaitFirstOrElse { throw OpexError.BadRequest.exception("Failed to get bank accounts") } + } + + override suspend fun deleteBankAccount(token: String, id: Long) { + webClient.delete() + .uri("$baseUrl/bank-account/$id") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .retrieve() + .onStatus({ it.isError }) { response -> + response.createException() + } + .awaitBodilessEntity() + } + + override suspend fun getProfile(token: String): Profile { + return webClient.get() + .uri("$baseUrl/personal-data") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono() + .awaitFirstOrElse { throw OpexError.BadRequest.exception("Failed to get profile") } + } + + override suspend fun completeProfile( + token: String, + request: CompleteProfileRequest + ): Profile? { + return webClient.put() + .uri("$baseUrl/completion") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .body(Mono.just(request)) + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono() + .awaitFirstOrElse { throw OpexError.BadRequest.exception("Failed to complete profile") } + } + + override suspend fun requestContactUpdate( + token: String, + request: ContactUpdateRequest + ): TempOtpResponse { + return webClient.post() + .uri("$baseUrl/contact/update/otp-request") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .body(Mono.just(request)) + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono() + .awaitFirstOrElse { throw OpexError.BadRequest.exception("Failed to request contact update") } + } + + override suspend fun confirmContactUpdate( + token: String, + request: ContactUpdateConfirmRequest + ) { + webClient.patch() + .uri("$baseUrl/contact/update/otp-verification") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .bodyValue(request) + .retrieve() + .onStatus({ it.isError }) { response -> + response.createException() + } + .awaitBodilessEntity() + } + + override suspend fun getUserProfileApprovalRequest(token: String): ProfileApprovalUserResponse { + return webClient.get() + .uri("$baseUrl/approval-request") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono() + .awaitFirstOrElse { throw OpexError.BadRequest.exception("Failed to get profile approval request") } + } } diff --git a/profile/profile-app/src/main/kotlin/co/nilin/opex/profile/app/controller/ProfileController.kt b/profile/profile-app/src/main/kotlin/co/nilin/opex/profile/app/controller/ProfileController.kt index 8ff7a8e2b..2b0513676 100644 --- a/profile/profile-app/src/main/kotlin/co/nilin/opex/profile/app/controller/ProfileController.kt +++ b/profile/profile-app/src/main/kotlin/co/nilin/opex/profile/app/controller/ProfileController.kt @@ -9,7 +9,6 @@ import co.nilin.opex.profile.core.data.otp.TempOtpResponse import co.nilin.opex.profile.core.data.profile.CompleteProfileRequest import co.nilin.opex.profile.core.data.profile.Profile import co.nilin.opex.profile.core.data.profile.ProfileApprovalUserResponse -import kotlinx.coroutines.reactive.awaitFirstOrNull import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.* From 4cae201fa1b6812703020a05eba78639d1f3fae6 Mon Sep 17 00:00:00 2001 From: Amir Rajabi Date: Sun, 4 Jan 2026 17:41:35 +0330 Subject: [PATCH 2/2] add swap services --- .../{ => inout}/CompleteProfileRequest.kt | 5 +- .../ContactUpdateConfirmRequest.kt | 2 +- .../core/{ => inout}/ContactUpdateRequest.kt | 2 +- .../ProfileApprovalRequestUser.kt} | 7 ++- .../ProfileApprovalRequestUserResponse.kt | 7 +++ .../opex/api/core/inout/ProfileResponse.kt | 24 ++++++++++ .../core/inout/ReservedTransferResponse.kt | 20 ++++++++ .../opex/api/core/inout/TerminalCommand.kt | 13 ++++++ .../api/core/inout/TransferReserveRequest.kt | 11 +++++ .../nilin/opex/api/core/spi/ProfileProxy.kt | 10 ++-- .../co/nilin/opex/api/core/spi/WalletProxy.kt | 4 ++ .../ports/opex/controller/MarketController.kt | 7 +++ .../opex/controller/ProfileController.kt | 19 ++++---- .../ports/opex/controller/SwapController.kt | 40 ++++++++++++++++ .../ports/opex/util/ConvertorExtenstions.kt | 36 ++++++++++++++- .../api/ports/proxy/impl/ProfileProxyImpl.kt | 12 ++--- .../api/ports/proxy/impl/WalletProxyImpl.kt | 46 +++++++++++++++++++ .../opex/wallet/core/inout/TerminalCommand.kt | 2 +- 18 files changed, 233 insertions(+), 34 deletions(-) rename api/api-core/src/main/kotlin/co/nilin/opex/api/core/{ => inout}/CompleteProfileRequest.kt (70%) rename api/api-core/src/main/kotlin/co/nilin/opex/api/core/{ => inout}/ContactUpdateConfirmRequest.kt (77%) rename api/api-core/src/main/kotlin/co/nilin/opex/api/core/{ => inout}/ContactUpdateRequest.kt (72%) rename api/api-core/src/main/kotlin/co/nilin/opex/api/core/{ProfileApprovalUserResponse.kt => inout/ProfileApprovalRequestUser.kt} (52%) create mode 100644 api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/ProfileApprovalRequestUserResponse.kt create mode 100644 api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/ProfileResponse.kt create mode 100644 api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/ReservedTransferResponse.kt create mode 100644 api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/TerminalCommand.kt create mode 100644 api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/TransferReserveRequest.kt create mode 100644 api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/SwapController.kt diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/CompleteProfileRequest.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/CompleteProfileRequest.kt similarity index 70% rename from api/api-core/src/main/kotlin/co/nilin/opex/api/core/CompleteProfileRequest.kt rename to api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/CompleteProfileRequest.kt index 0fd875bf1..f12be7dcc 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/CompleteProfileRequest.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/CompleteProfileRequest.kt @@ -1,7 +1,4 @@ -package co.nilin.opex.api.core - -import co.nilin.opex.api.core.inout.Gender -import co.nilin.opex.api.core.inout.NationalityType +package co.nilin.opex.api.core.inout data class CompleteProfileRequest( var firstName: String, diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/ContactUpdateConfirmRequest.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/ContactUpdateConfirmRequest.kt similarity index 77% rename from api/api-core/src/main/kotlin/co/nilin/opex/api/core/ContactUpdateConfirmRequest.kt rename to api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/ContactUpdateConfirmRequest.kt index 34a6a196b..78059c4b9 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/ContactUpdateConfirmRequest.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/ContactUpdateConfirmRequest.kt @@ -1,4 +1,4 @@ -package co.nilin.opex.api.core +package co.nilin.opex.api.core.inout data class ContactUpdateConfirmRequest( val email: String? = null, diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/ContactUpdateRequest.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/ContactUpdateRequest.kt similarity index 72% rename from api/api-core/src/main/kotlin/co/nilin/opex/api/core/ContactUpdateRequest.kt rename to api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/ContactUpdateRequest.kt index 8cacb4785..90a77978d 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/ContactUpdateRequest.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/ContactUpdateRequest.kt @@ -1,4 +1,4 @@ -package co.nilin.opex.api.core +package co.nilin.opex.api.core.inout data class ContactUpdateRequest( val email: String? = null, diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/ProfileApprovalUserResponse.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/ProfileApprovalRequestUser.kt similarity index 52% rename from api/api-core/src/main/kotlin/co/nilin/opex/api/core/ProfileApprovalUserResponse.kt rename to api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/ProfileApprovalRequestUser.kt index 2bb98507f..1cc8b19f1 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/ProfileApprovalUserResponse.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/ProfileApprovalRequestUser.kt @@ -1,10 +1,9 @@ -package co.nilin.opex.api.core +package co.nilin.opex.api.core.inout -import co.nilin.opex.api.core.inout.ProfileApprovalRequestStatus import java.time.LocalDateTime -data class ProfileApprovalUserResponse( +data class ProfileApprovalRequestUser( var status: ProfileApprovalRequestStatus, var createDate: LocalDateTime, var description: String? = null -) +) \ No newline at end of file diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/ProfileApprovalRequestUserResponse.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/ProfileApprovalRequestUserResponse.kt new file mode 100644 index 000000000..48af7b292 --- /dev/null +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/ProfileApprovalRequestUserResponse.kt @@ -0,0 +1,7 @@ +package co.nilin.opex.api.core.inout + +data class ProfileApprovalRequestUserResponse( + var status: ProfileApprovalRequestStatus, + var createDate: Long, + var description: String? = null +) \ No newline at end of file diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/ProfileResponse.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/ProfileResponse.kt new file mode 100644 index 000000000..41d4eab88 --- /dev/null +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/ProfileResponse.kt @@ -0,0 +1,24 @@ +package co.nilin.opex.api.core.inout + +data class ProfileResponse( + var email: String?, + var userId: String?, + var firstName: String? = null, + var lastName: String? = null, + var address: String? = null, + var mobile: String? = null, + var telephone: String? = null, + var postalCode: String? = null, + var nationality: NationalityType? = null, + var identifier: String? = null, + var gender: Gender? = null, + var birthDate: Long? = null, + var status: ProfileStatus? = null, + var createDate: Long? = null, + var lastUpdateDate: Long? = null, + var creator: String? = null, + var kycLevel: KycLevel? = null, + var mobileIdentityMatch: Boolean? = null, + var personalIdentityMatch: Boolean? = null + +) \ No newline at end of file diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/ReservedTransferResponse.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/ReservedTransferResponse.kt new file mode 100644 index 000000000..31ad0bbec --- /dev/null +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/ReservedTransferResponse.kt @@ -0,0 +1,20 @@ +package co.nilin.opex.api.core.inout + +import java.math.BigDecimal +import java.time.LocalDateTime + +data class ReservedTransferResponse( + var reserveNumber: String, + var sourceSymbol: String, + var destSymbol: String, + var receiverUuid: String, + var sourceAmount: BigDecimal, + var guaranteedDestAmount: BigDecimal, + var reserveDate: LocalDateTime? = LocalDateTime.now(), + var expDate: LocalDateTime? = null, + var status: ReservedStatus? = null +) + + + + 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 new file mode 100644 index 000000000..bb0d1f943 --- /dev/null +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/TerminalCommand.kt @@ -0,0 +1,13 @@ +package co.nilin.opex.api.core.inout + +data class TerminalCommand( + var uuid: String?, + var owner: String, + var identifier: String, + var active: Boolean? = true, + var type: TransferMethod, + var metaData: String, + var description : String?, + var displayOrder: Int? = null, + +) diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/TransferReserveRequest.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/TransferReserveRequest.kt new file mode 100644 index 000000000..3fb3262e3 --- /dev/null +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/TransferReserveRequest.kt @@ -0,0 +1,11 @@ +package co.nilin.opex.api.core.inout + +import java.math.BigDecimal + +data class TransferReserveRequest( + val sourceAmount: BigDecimal, + val sourceSymbol: String, + val destSymbol: String, + var senderUuid: String?, + val receiverUuid: String, +) \ No newline at end of file diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/ProfileProxy.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/ProfileProxy.kt index 7a21cb94e..85b1bec2e 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/ProfileProxy.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/ProfileProxy.kt @@ -1,9 +1,9 @@ package co.nilin.opex.api.core.spi -import co.nilin.opex.api.core.CompleteProfileRequest -import co.nilin.opex.api.core.ContactUpdateConfirmRequest -import co.nilin.opex.api.core.ContactUpdateRequest -import co.nilin.opex.api.core.ProfileApprovalUserResponse +import co.nilin.opex.api.core.inout.CompleteProfileRequest +import co.nilin.opex.api.core.inout.ContactUpdateConfirmRequest +import co.nilin.opex.api.core.inout.ContactUpdateRequest +import co.nilin.opex.api.core.inout.ProfileApprovalRequestUser import co.nilin.opex.api.core.inout.* interface ProfileProxy { @@ -11,7 +11,7 @@ interface ProfileProxy { suspend fun completeProfile(token: String, request: CompleteProfileRequest): Profile? suspend fun requestContactUpdate(token: String, request: ContactUpdateRequest): TempOtpResponse suspend fun confirmContactUpdate(token: String, request: ContactUpdateConfirmRequest) - suspend fun getUserProfileApprovalRequest(token: String): ProfileApprovalUserResponse + suspend fun getUserProfileApprovalRequest(token: String): ProfileApprovalRequestUser // Admin suspend fun getProfiles(token: String, profileRequest: ProfileRequest): List 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 7726d3940..b3602585e 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 @@ -197,4 +197,8 @@ interface WalletProxy { amount: BigDecimal, request: ManualTransferRequest ): TransferResult + + suspend fun reserveSwap(token: String, request: TransferReserveRequest) :ReservedTransferResponse + suspend fun finalizeSwap(token: String,reserveUuid: String,description: String?,transferRef: String?) : TransferResult + suspend fun getGatewayTerminal(gatewayUuid: 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/MarketController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/MarketController.kt index 037565ee5..d5ca4d56d 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/MarketController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/MarketController.kt @@ -277,6 +277,13 @@ class MarketController( return accountantProxy.getWithdrawLimitConfigs() } + @GetMapping("/gateway/{gatewayUuid}/terminal") + suspend fun getGatewayTerminal( + @PathVariable("gatewayUuid") gatewayUuid: String, + ): List? { + return walletProxy.getGatewayTerminal(gatewayUuid) + } + private fun getValidLimit(limit: Int?): Int = when { limit == null -> 100 limit > 1000 -> 1000 diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileController.kt index 17a5bd7da..9679d60e4 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileController.kt @@ -1,13 +1,10 @@ package co.nilin.opex.api.ports.opex.controller -import co.nilin.opex.api.core.CompleteProfileRequest -import co.nilin.opex.api.core.ContactUpdateConfirmRequest -import co.nilin.opex.api.core.ContactUpdateRequest -import co.nilin.opex.api.core.ProfileApprovalUserResponse -import co.nilin.opex.api.core.inout.Profile -import co.nilin.opex.api.core.inout.TempOtpResponse +import co.nilin.opex.api.core.inout.* import co.nilin.opex.api.core.spi.ProfileProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication +import co.nilin.opex.api.ports.opex.util.toProfileApprovalRequestUserResponse +import co.nilin.opex.api.ports.opex.util.toProfileResponse import co.nilin.opex.api.ports.opex.util.tokenValue import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext @@ -21,16 +18,17 @@ class ProfileController( ) { @GetMapping("/personal-data") - suspend fun getProfile(@CurrentSecurityContext securityContext: SecurityContext): Profile { - return profileProxy.getProfile(securityContext.jwtAuthentication().tokenValue()) + suspend fun getProfile(@CurrentSecurityContext securityContext: SecurityContext): ProfileResponse { + return profileProxy.getProfile(securityContext.jwtAuthentication().tokenValue()).toProfileResponse() } @PutMapping("/completion") suspend fun completeProfile( @RequestBody completeProfileRequest: CompleteProfileRequest, @CurrentSecurityContext securityContext: SecurityContext - ): Profile? { + ): ProfileResponse? { return profileProxy.completeProfile(securityContext.jwtAuthentication().tokenValue(), completeProfileRequest) + ?.toProfileResponse() } @PostMapping("/contact/update/otp-request") @@ -51,7 +49,8 @@ class ProfileController( } @GetMapping("/approval-request") - suspend fun getApprovalRequest(@CurrentSecurityContext securityContext: SecurityContext): ProfileApprovalUserResponse { + suspend fun getApprovalRequest(@CurrentSecurityContext securityContext: SecurityContext): ProfileApprovalRequestUserResponse { return profileProxy.getUserProfileApprovalRequest(securityContext.jwtAuthentication().tokenValue()) + .toProfileApprovalRequestUserResponse() } } \ 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/SwapController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/SwapController.kt new file mode 100644 index 000000000..29330c9dd --- /dev/null +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/SwapController.kt @@ -0,0 +1,40 @@ +package co.nilin.opex.api.ports.opex.controller + +import co.nilin.opex.api.core.inout.ReservedTransferResponse +import co.nilin.opex.api.core.inout.TransferReserveRequest +import co.nilin.opex.api.core.inout.TransferResult +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/swap") +class SwapController( + val walletProxy: WalletProxy, +) { + @PostMapping("/reserve") + suspend fun reserve( + @RequestBody request: TransferReserveRequest, + @CurrentSecurityContext securityContext: SecurityContext + ): ReservedTransferResponse { + return walletProxy.reserveSwap(securityContext.jwtAuthentication().tokenValue(), request) + } + + @PostMapping("/finalize/{reserveUuid}") + suspend fun finalizeTransfer( + @PathVariable reserveUuid: String, + @RequestParam description: String?, + @RequestParam transferRef: String?, + @CurrentSecurityContext securityContext: SecurityContext + ): TransferResult { + return walletProxy.finalizeSwap( + securityContext.jwtAuthentication().tokenValue(), + reserveUuid, + description, + transferRef + ) + } +} \ No newline at end of file diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/util/ConvertorExtenstions.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/util/ConvertorExtenstions.kt index ca232e74b..5c92b0d75 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/util/ConvertorExtenstions.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/util/ConvertorExtenstions.kt @@ -1,8 +1,8 @@ package co.nilin.opex.api.ports.opex.util -import co.nilin.opex.api.core.inout.OrderData -import co.nilin.opex.api.core.inout.OrderStatus +import co.nilin.opex.api.core.inout.* import co.nilin.opex.api.ports.opex.data.OrderDataResponse +import java.time.ZoneId fun OrderData.toResponse(): OrderDataResponse { return OrderDataResponse( @@ -20,4 +20,36 @@ fun OrderData.toResponse(): OrderDataResponse { createDate = this.createDate, updateDate = this.updateDate, ) +} + +fun Profile.toProfileResponse(): ProfileResponse { + return ProfileResponse( + email = this.email, + userId = this.userId, + firstName = this.firstName, + lastName = this.lastName, + address = this.address, + mobile = this.mobile, + telephone = this.telephone, + postalCode = this.postalCode, + nationality = this.nationality, + identifier = this.identifier, + gender = this.gender, + birthDate = this.birthDate?.atZone(ZoneId.systemDefault())?.toInstant()?.toEpochMilli(), + status = this.status, + createDate = this.createDate?.atZone(ZoneId.systemDefault())?.toInstant()?.toEpochMilli(), + lastUpdateDate = this.lastUpdateDate?.atZone(ZoneId.systemDefault())?.toInstant()?.toEpochMilli(), + creator = this.creator, + kycLevel = this.kycLevel, + mobileIdentityMatch = this.mobileIdentityMatch, + personalIdentityMatch = this.personalIdentityMatch + ) +} + +fun ProfileApprovalRequestUser.toProfileApprovalRequestUserResponse(): ProfileApprovalRequestUserResponse { + return ProfileApprovalRequestUserResponse( + status = this.status, + createDate = this.createDate.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(), + description = this.description, + ) } \ 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/ProfileProxyImpl.kt b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/ProfileProxyImpl.kt index 01ec82e0f..68dd031c8 100644 --- a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/ProfileProxyImpl.kt +++ b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/ProfileProxyImpl.kt @@ -1,9 +1,9 @@ package co.nilin.opex.api.ports.proxy.impl -import co.nilin.opex.api.core.CompleteProfileRequest -import co.nilin.opex.api.core.ContactUpdateConfirmRequest -import co.nilin.opex.api.core.ContactUpdateRequest -import co.nilin.opex.api.core.ProfileApprovalUserResponse +import co.nilin.opex.api.core.inout.CompleteProfileRequest +import co.nilin.opex.api.core.inout.ContactUpdateConfirmRequest +import co.nilin.opex.api.core.inout.ContactUpdateRequest +import co.nilin.opex.api.core.inout.ProfileApprovalRequestUser import co.nilin.opex.api.core.inout.* import co.nilin.opex.api.core.spi.ProfileProxy import co.nilin.opex.common.OpexError @@ -266,14 +266,14 @@ class ProfileProxyImpl(@Qualifier("generalWebClient") private val webClient: Web .awaitBodilessEntity() } - override suspend fun getUserProfileApprovalRequest(token: String): ProfileApprovalUserResponse { + override suspend fun getUserProfileApprovalRequest(token: String): ProfileApprovalRequestUser { return webClient.get() .uri("$baseUrl/approval-request") .accept(MediaType.APPLICATION_JSON) .header(HttpHeaders.AUTHORIZATION, "Bearer $token") .retrieve() .onStatus({ t -> t.isError }, { it.createException() }) - .bodyToMono() + .bodyToMono() .awaitFirstOrElse { throw OpexError.BadRequest.exception("Failed to get profile approval request") } } } 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 65740dbb7..3db1c6b95 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 @@ -719,5 +719,51 @@ class WalletProxyImpl(@Qualifier("generalWebClient") private val webClient: WebC .bodyToMono() .awaitFirstOrElse { throw OpexError.BadRequest.exception() } } + + override suspend fun reserveSwap( + token: String, + request: TransferReserveRequest + ): ReservedTransferResponse { + return webClient.post() + .uri("$baseUrl/v3/transfer/reserve") + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer $token") + .body(Mono.just(request)) + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono() + .awaitFirstOrElse { throw OpexError.BadRequest.exception() } + } + + override suspend fun finalizeSwap( + token: String, + reserveUuid: String, + description: String?, + transferRef: String? + ): TransferResult { + return webClient.post() + .uri("$baseUrl/v3/transfer/{$reserveUuid}") { + it.queryParam("description", description) + it.queryParam("transferRef", transferRef) + it.build() + } + .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 getGatewayTerminal(gatewayUuid: String): List { + return webClient.get() + .uri("$baseUrl/gateway/{$gatewayUuid}/terminal") + .accept(MediaType.APPLICATION_JSON) + .retrieve() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono>() + .awaitFirstOrElse { throw OpexError.WithdrawNotFound.exception() } + + } } diff --git a/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/TerminalCommand.kt b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/TerminalCommand.kt index d4283abea..f6760e689 100644 --- a/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/TerminalCommand.kt +++ b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/TerminalCommand.kt @@ -1,6 +1,6 @@ package co.nilin.opex.wallet.core.inout -data class TerminalCommand( +data class TerminalCommand( var uuid: String?, var owner: String, var identifier: String,