summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMS <ms@taler.net>2023-09-18 15:24:14 +0200
committerMS <ms@taler.net>2023-09-18 15:24:14 +0200
commitf632635b3292df19b5c204861eab7f74be07731b (patch)
treeae7b76eb55ba2ea7fe6c2833b786e292a96c38de
parent2b8d626e65aca06c214776211f12272576542022 (diff)
downloadlibeufin-f632635b3292df19b5c204861eab7f74be07731b.tar.gz
libeufin-f632635b3292df19b5c204861eab7f74be07731b.tar.bz2
libeufin-f632635b3292df19b5c204861eab7f74be07731b.zip
Implementing GET /transactions.
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/Database.kt34
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/transactionsHandlers.kt48
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/types.kt7
-rw-r--r--bank/src/test/kotlin/DatabaseTest.kt5
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())
}