diff options
author | MS <ms@taler.net> | 2023-09-18 15:24:14 +0200 |
---|---|---|
committer | MS <ms@taler.net> | 2023-09-18 15:24:14 +0200 |
commit | f632635b3292df19b5c204861eab7f74be07731b (patch) | |
tree | ae7b76eb55ba2ea7fe6c2833b786e292a96c38de | |
parent | 2b8d626e65aca06c214776211f12272576542022 (diff) | |
download | libeufin-f632635b3292df19b5c204861eab7f74be07731b.tar.gz libeufin-f632635b3292df19b5c204861eab7f74be07731b.tar.bz2 libeufin-f632635b3292df19b5c204861eab7f74be07731b.zip |
Implementing GET /transactions.
4 files changed, 77 insertions, 17 deletions
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Database.kt b/bank/src/main/kotlin/tech/libeufin/bank/Database.kt index be196676..34689a47 100644 --- a/bank/src/main/kotlin/tech/libeufin/bank/Database.kt +++ b/bank/src/main/kotlin/tech/libeufin/bank/Database.kt @@ -25,6 +25,7 @@ import java.sql.DriverManager import java.sql.PreparedStatement import java.sql.SQLException import java.util.* +import kotlin.math.abs private const val DB_CTR_LIMIT = 1000000 @@ -485,14 +486,19 @@ class Database(private val dbConfig: String) { ) } } - - fun bankTransactionGetForHistoryPage( - upperBound: Long, + private data class HistoryParams( + val cmpOp: String, // < or > + val orderBy: String // ASC or DESC + ) + fun bankTransactionGetHistory( + start: Long, + delta: Long, bankAccountId: Long, - fromMs: Long, - toMs: Long ): List<BankAccountTransaction> { reconnect() + val ops = if (delta < 0) + HistoryParams("<", "DESC") else + HistoryParams(">", "ASC") val stmt = prepare(""" SELECT creditor_payto_uri @@ -508,15 +514,15 @@ class Database(private val dbConfig: String) { ,end_to_end_id ,direction ,bank_account_id + ,bank_transaction_id FROM bank_account_transactions - WHERE bank_transaction_id < ? - AND bank_account_id=? - AND transaction_date BETWEEN ? AND ? + WHERE bank_transaction_id ${ops.cmpOp} ? AND bank_account_id=? + ORDER BY bank_transaction_id ${ops.orderBy} + LIMIT ? """) - stmt.setLong(1, upperBound) + stmt.setLong(1, start) stmt.setLong(2, bankAccountId) - stmt.setLong(3, fromMs) - stmt.setLong(4, toMs) + stmt.setLong(3, abs(delta)) val rs = stmt.executeQuery() rs.use { val ret = mutableListOf<BankAccountTransaction>() @@ -544,9 +550,9 @@ class Database(private val dbConfig: String) { bankAccountId = it.getLong("bank_account_id"), paymentInformationId = it.getString("payment_information_id"), subject = it.getString("subject"), - transactionDate = it.getLong("transaction_date") - ) - ) + transactionDate = it.getLong("transaction_date"), + dbRowId = it.getLong("bank_transaction_id") + )) } while (it.next()) return ret } diff --git a/bank/src/main/kotlin/tech/libeufin/bank/transactionsHandlers.kt b/bank/src/main/kotlin/tech/libeufin/bank/transactionsHandlers.kt index 0fe3ad69..2e315bdd 100644 --- a/bank/src/main/kotlin/tech/libeufin/bank/transactionsHandlers.kt +++ b/bank/src/main/kotlin/tech/libeufin/bank/transactionsHandlers.kt @@ -2,14 +2,62 @@ package tech.libeufin.bank import io.ktor.http.* import io.ktor.server.application.* +import io.ktor.server.plugins.* import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* import net.taler.common.errorcodes.TalerErrorCode import tech.libeufin.util.getNowUs import tech.libeufin.util.parsePayto +import kotlin.math.abs fun Routing.transactionsHandlers() { + get("/accounts/{USERNAME}/transactions") { + val c = call.myAuth(TokenScope.readonly) ?: throw unauthorized() + val resourceName = call.expectUriComponent("USERNAME") + if (c.login != resourceName && c.login != "admin") throw forbidden() + // Collecting params. + val deltaParam: String = call.request.queryParameters["delta"] ?: throw MissingRequestParameterException("Parameter 'delta' not found") + val delta: Long = try { + deltaParam.toLong() + } catch (e: Exception) { + logger.error(e.message) + throw badRequest("Param 'delta' not a number") + } + // Note: minimum 'start' is zero, as database IDs start from 1. + val start: Long = when (val param = call.request.queryParameters["start"]) { + null -> if (delta >= 0) 0L else Long.MAX_VALUE + else -> try { + param.toLong() + } catch (e: Exception) { + logger.error(e.message) + throw badRequest("Param 'start' not a number") + } + } + logger.info("Param long_poll_ms not supported") + // Making the query. + val bankAccount = db.bankAccountGetFromOwnerId(c.expectRowId()) + ?: throw internalServerError("Customer '${c.login}' lacks bank account.") + val bankAccountId = bankAccount.bankAccountId + ?: throw internalServerError("Bank account lacks row ID.") + val history: List<BankAccountTransaction> = db.bankTransactionGetHistory(bankAccountId, start, delta) + val res = BankAccountTransactionsResponse(transactions = mutableListOf()) + history.forEach { + res.transactions.add(BankAccountTransactionInfo( + debtor_payto_uri = it.debtorPaytoUri, + creditor_payto_uri = it.creditorPaytoUri, + subject = it.subject, + amount = it.amount.toString(), + direction = it.direction, + date = it.transactionDate, + row_id = it.dbRowId ?: throw internalServerError( + "Transaction timestamped with '${it.transactionDate}' did not have row ID" + ) + )) + } + call.respond(res) + return@get + } // Creates a bank transaction. post("/accounts/{USERNAME}/transactions") { val c = call.myAuth(TokenScope.readwrite) ?: throw unauthorized() diff --git a/bank/src/main/kotlin/tech/libeufin/bank/types.kt b/bank/src/main/kotlin/tech/libeufin/bank/types.kt index d0d7d2c6..fd65d244 100644 --- a/bank/src/main/kotlin/tech/libeufin/bank/types.kt +++ b/bank/src/main/kotlin/tech/libeufin/bank/types.kt @@ -289,6 +289,8 @@ data class BankAccountTransaction( * bank account of the payer. */ val bankAccountId: Long, + // Null if this type is used to _create_ one transaction. + val dbRowId: Long? = null, // Following are ISO20022 specific. val accountServicerReference: String, val paymentInformationId: String, @@ -372,4 +374,9 @@ data class BankAccountTransactionInfo( val subject: String, val row_id: Long, // is T_ID val date: Long +) + +@Serializable +data class BankAccountTransactionsResponse( + val transactions: MutableList<BankAccountTransactionInfo> )
\ No newline at end of file diff --git a/bank/src/test/kotlin/DatabaseTest.kt b/bank/src/test/kotlin/DatabaseTest.kt index 290d0d19..fc2a4f54 100644 --- a/bank/src/test/kotlin/DatabaseTest.kt +++ b/bank/src/test/kotlin/DatabaseTest.kt @@ -223,11 +223,10 @@ class DatabaseTest { @Test fun historyTest() { val db = initDb() - val res = db.bankTransactionGetForHistoryPage( + val res = db.bankTransactionGetHistory( 10L, 1L, - fromMs = 0, - toMs = Long.MAX_VALUE + 1L ) assert(res.isEmpty()) } |