summaryrefslogtreecommitdiff
path: root/sandbox
diff options
context:
space:
mode:
authorMS <ms@taler.net>2023-01-20 16:26:34 +0100
committerMS <ms@taler.net>2023-01-20 16:39:59 +0100
commit2a45c348a3506259e835bd0877fad9c3c5f55c4a (patch)
tree4e0a743f50f2d9a51feb5dae678aef02990f7edb /sandbox
parent5b18cb6a663394d6c29c87c62dafbee584964e9e (diff)
downloadlibeufin-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.kt29
-rw-r--r--sandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt41
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 {