diff options
author | MS <ms@taler.net> | 2023-01-20 16:26:34 +0100 |
---|---|---|
committer | MS <ms@taler.net> | 2023-01-20 16:39:59 +0100 |
commit | 2a45c348a3506259e835bd0877fad9c3c5f55c4a (patch) | |
tree | 4e0a743f50f2d9a51feb5dae678aef02990f7edb /sandbox | |
parent | 5b18cb6a663394d6c29c87c62dafbee584964e9e (diff) | |
download | libeufin-2a45c348a3506259e835bd0877fad9c3c5f55c4a.tar.gz libeufin-2a45c348a3506259e835bd0877fad9c3c5f55c4a.tar.bz2 libeufin-2a45c348a3506259e835bd0877fad9c3c5f55c4a.zip |
Error management.
Blaming the bank when a 'bank account' is not
found for an existing 'customer'.
Diffstat (limited to 'sandbox')
-rw-r--r-- | sandbox/src/main/kotlin/tech/libeufin/sandbox/CircuitApi.kt | 29 | ||||
-rw-r--r-- | sandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt | 41 |
2 files changed, 52 insertions, 18 deletions
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/CircuitApi.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/CircuitApi.kt index 721b3c16..6d067ffd 100644 --- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/CircuitApi.kt +++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/CircuitApi.kt @@ -6,6 +6,7 @@ import io.ktor.http.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* +import io.netty.handler.codec.http.HttpResponseStatus import org.jetbrains.exposed.sql.transactions.transaction import tech.libeufin.sandbox.CashoutOperationsTable.uuid import tech.libeufin.util.* @@ -437,22 +438,25 @@ fun circuitApi(circuitRoute: Route) { throwIfInstitutionalName(resourceName) allowOwnerOrAdmin(username, resourceName) val customer = getCustomer(resourceName) - /** FIXME: the following query can 404, but should 500. - * The reason is that that's the bank's fault if an existing - * customer misses the bank account. Check other calls too, - * for the same error. + /** + * CUSTOMER AND BANK ACCOUNT INVARIANT. + * + * After having found a 'customer' associated with the resourceName + * - see previous line -, the bank must ensure that a 'bank account' + * exist under the same resourceName. If that fails, the bank broke the + * invariant and should respond 500. */ - val bankAccount = getBankAccountFromLabel(resourceName) + val bankAccount = getBankAccountFromLabel(resourceName, withBankFault = true) /** * Throwing when name or cash-out address aren't found ensures * that the customer was indeed added via the Circuit API, as opposed * to the Access API. */ - val potentialError = "$resourceName not managed by the Circuit API." + val maybeError = "$resourceName not managed by the Circuit API." call.respond(CircuitAccountInfo( username = customer.username, - name = customer.name ?: throw notFound(potentialError), - cashout_address = customer.cashout_address ?: throw notFound(potentialError), + name = customer.name ?: throw notFound(maybeError), + cashout_address = customer.cashout_address ?: throw notFound(maybeError), contact_data = CircuitContactData( email = customer.email, phone = customer.phone @@ -480,6 +484,10 @@ fun circuitApi(circuitRoute: Route) { }) } } + if (customers.size == 0) { + call.respond(HttpStatusCode.NoContent) + return@get + } call.respond(object {val customers = customers}) return@get } @@ -597,8 +605,11 @@ fun circuitApi(circuitRoute: Route) { call.request.basicAuth(onlyAdmin = true) val resourceName = call.getUriComponent("resourceName") throwIfInstitutionalName(resourceName) - val bankAccount = getBankAccountFromLabel(resourceName) val customer = getCustomer(resourceName) + val bankAccount = getBankAccountFromLabel( + resourceName, + withBankFault = true // See comment "CUSTOMER AND BANK ACCOUNT INVARIANT". + ) val balance = getBalance(bankAccount) if (balance != BigDecimal.ZERO) throw SandboxError( diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt index 693dc885..de22bf34 100644 --- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt +++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt @@ -302,7 +302,18 @@ fun getBankAccountFromIban(iban: String): BankAccountEntity { ) } -fun getBankAccountFromLabel(label: String, demobank: String = "default"): BankAccountEntity { +/** + * The argument 'withBankFault' represents the case where + * _the bank_ must ensure that a resource (in this case a bank + * account) exists. For example, every 'customer' should have + * a 'bank account', and if a customer is found without a bank + * account, then the bank broke such condition. + */ +fun getBankAccountFromLabel( + label: String, + demobank: String = "default", + withBankFault: Boolean = false +): BankAccountEntity { val maybeDemobank = getDemobank(demobank) if (maybeDemobank == null) { logger.error("Demobank '$demobank' not found") @@ -311,21 +322,33 @@ fun getBankAccountFromLabel(label: String, demobank: String = "default"): BankAc "Demobank '$demobank' not found" ) } - return getBankAccountFromLabel(label, maybeDemobank) + return getBankAccountFromLabel( + label, + maybeDemobank, + withBankFault + ) } -fun getBankAccountFromLabel(label: String, - demobank: DemobankConfigEntity +fun getBankAccountFromLabel( + label: String, + demobank: DemobankConfigEntity, + withBankFault: Boolean = false ): BankAccountEntity { - return transaction { + val maybeBankAccount = transaction { BankAccountEntity.find( BankAccountsTable.label eq label and ( BankAccountsTable.demoBank eq demobank.id ) - ).firstOrNull() ?: throw SandboxError( - HttpStatusCode.NotFound, - "Did not find a bank account for label $label" - ) + ).firstOrNull() } + if (maybeBankAccount == null && withBankFault) + throw internalServerError( + "Bank account $label was not found, but it should." + ) + if (maybeBankAccount == null) + throw notFound( + "Bank account $label was not found." + ) + return maybeBankAccount } fun getBankAccountFromSubscriber(subscriber: EbicsSubscriberEntity): BankAccountEntity { |