gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[libeufin] branch master updated (9f500b3 -> c93c130)


From: gnunet
Subject: [libeufin] branch master updated (9f500b3 -> c93c130)
Date: Wed, 22 Apr 2020 18:39:28 +0200

This is an automated email from the git hooks/post-receive script.

marcello pushed a change to branch master
in repository libeufin.

    from 9f500b3  Fix date JSON, and currency parsing.
     new 889a6cb  Get Wire Gateways tests to pass.
     new c93c130  De- duplicator skeleton.

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .idea/compiler.xml                                 |   6 +
 nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt    |  12 +-
 nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt  |  19 +--
 nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt | 127 ++++++++++++++-------
 4 files changed, 99 insertions(+), 65 deletions(-)
 create mode 100644 .idea/compiler.xml

diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..fb7f4a8
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <bytecodeTargetLevel target="11" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt
index af94e1d..fa9c283 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt
@@ -17,7 +17,7 @@ const val ID_MAX_LENGTH = 50
  * in the PAIN-table.
  */
 object TalerRequestedPayments: LongIdTable() {
-    val preparedPayment = TalerIncomingPayments.reference("payment", 
Pain001Table)
+    val preparedPayment = reference("payment", Pain001Table)
     val requestUId = text("request_uid")
     val amount = text("amount")
     val exchangeBaseUrl = text("exchange_base_url")
@@ -80,9 +80,8 @@ class TalerIncomingPaymentEntity(id: EntityID<Long>) : 
LongEntity(id) {
 }
 
 /**
- * This table _assumes_ that all the entries have a BOOK status.  The
- * current code however does only enforces this trusting the C53 response,
- * but never actually checking the appropriate "Sts" field.
+ * This table contains history "elements" as returned by the bank from a
+ * CAMT message.  Therefore, any row could come from a C52/3/4 message 
response.
  */
 object EbicsRawBankTransactionsTable : LongIdTable() {
     val nexusSubscriber = reference("subscriber", EbicsSubscribersTable)
@@ -97,7 +96,7 @@ object EbicsRawBankTransactionsTable : LongIdTable() {
     val debitorName = text("debitorName")
     val counterpartBic = text("counterpartBic")
     val bookingDate = long("bookingDate")
-    val status = text("status") // BOOK, ..
+    val status = text("status") // BOOK or other.
 }
 
 class EbicsRawBankTransactionEntity(id: EntityID<Long>) : LongEntity(id) {
@@ -219,7 +218,8 @@ fun dbCreateTables() {
              EbicsSubscribersTable,
              EbicsAccountsInfoTable,
              EbicsRawBankTransactionsTable,
-             TalerIncomingPayments
+             TalerIncomingPayments,
+             TalerRequestedPayments
          )
     }
 }
\ No newline at end of file
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
index e751c0d..84d42ad 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
@@ -152,7 +152,7 @@ fun getSubscriberDetailsFromBankAccount(bankAccountId: 
String): EbicsClientSubsc
  * Given a subscriber id, returns the _list_ of bank accounts associated to it.
  * @param id the subscriber id
  * @return the query set containing the subscriber's bank accounts.  The result
- * is guaranteed to be non empty.
+ * is guaranteed not to be empty.
  */
 fun getBankAccountsInfoFromId(id: String): 
SizedIterable<EbicsAccountInfoEntity> {
     logger.debug("Looking up bank account of user '$id'")
@@ -162,25 +162,10 @@ fun getBankAccountsInfoFromId(id: String): 
SizedIterable<EbicsAccountInfoEntity>
         }
     }
     if (list.empty()) {
-        if (!isProduction()) {
-            /* make up a bank account info object */
-            transaction {
-                EbicsAccountInfoEntity.new("mocked-bank-account") {
-                    subscriber = EbicsSubscriberEntity.findById(id) ?: throw 
NexusError(
-                        HttpStatusCode.NotFound, "Please create subscriber 
'${id}' first."
-                    )
-                    accountHolder = "Tests runner"
-                    iban = "IBAN-FOR-TESTS"
-                    bankCode = "BIC-FOR-TESTS"
-                }
-            }
-            logger.debug("Faked bank account info object for user '$id'")
-        } else throw NexusError(
+        throw NexusError(
             HttpStatusCode.NotFound,
             "This subscriber '$id' did never fetch its own bank accounts, 
request HTD first."
         )
-        // call this function again now that the database is augmented with 
the mocked information.
-        return getBankAccountsInfoFromId(id)
     }
     return list
 }
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt
index 25f5a1f..a77361e 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt
@@ -12,6 +12,7 @@ import io.ktor.routing.Route
 import io.ktor.routing.get
 import io.ktor.routing.post
 import org.jetbrains.exposed.dao.Entity
+import org.jetbrains.exposed.dao.IdTable
 import org.jetbrains.exposed.sql.*
 import org.jetbrains.exposed.sql.transactions.transaction
 import org.joda.time.DateTime
@@ -34,7 +35,7 @@ class Taler(app: Route) {
     )
     private data class TalerTransferResponse(
         // point in time when the nexus put the payment instruction into the 
database.
-        val timestamp: Long,
+        val timestamp: GnunetTimestamp,
         val row_id: Long
     )
 
@@ -123,7 +124,7 @@ class Taler(app: Route) {
             val (bic, iban, name) = ibanMatch.destructured
             return Payto(name, iban, bic.replace("/", ""))
         }
-        val xTalerBankMatch = 
Regex("payto://x-taler-bank/localhost/([0-9])?").find(paytoUri)
+        val xTalerBankMatch = 
Regex("payto://x-taler-bank/localhost/([0-9]+)").find(paytoUri)
         if (xTalerBankMatch != null) {
             val xTalerBankAcctNo = xTalerBankMatch.destructured.component1()
             return Payto("Taler Exchange", xTalerBankAcctNo, "localhost")
@@ -146,22 +147,28 @@ class Taler(app: Route) {
             this.sortedBy { it.id }
         }
     }
-    private fun getPaytoUri(name: String, iban: String, bic: String): String {
-        return "payto://iban/$iban/$bic?receiver-name=$name"
+
+    /**
+     * NOTE: those payto-builders default all to the x-taler-bank transport.
+     * A mechanism to easily switch transport is needed, as production needs
+     * 'iban'.
+     */
+    private fun buildPaytoUri(name: String, iban: String, bic: String): String 
{
+        return "payto://x-taler-bank/localhost/$iban"
     }
-    private fun getPaytoUri(iban: String, bic: String): String {
-        return "payto://iban/$iban/$bic"
+    private fun buildPaytoUri(iban: String, bic: String): String {
+        return "payto://x-taler-bank/localhost/$iban"
     }
 
     /** Builds the comparison operator for history entries based on the sign 
of 'delta'  */
-    private fun getComparisonOperator(delta: Int, start: Long): Op<Boolean> {
+    private fun getComparisonOperator(delta: Int, start: Long, table: 
IdTable<Long>): Op<Boolean> {
         return if (delta < 0) {
             Expression.build {
-                TalerIncomingPayments.id less start
+                table.id less start
             }
         } else {
             Expression.build {
-                TalerIncomingPayments.id greater start
+                table.id greater start
             }
         }
     }
@@ -196,6 +203,11 @@ class Taler(app: Route) {
         return Gson().toJson(body)
     }
 
+    /** Work in progress */
+    private fun duplicatePayment(entry: EbicsRawBankTransactionEntity): 
Boolean {
+        return false
+    }
+
     /** Attach Taler endpoints to the main Web server */
 
     init {
@@ -272,18 +284,22 @@ class Taler(app: Route) {
             }
             call.respond(
                 HttpStatusCode.OK,
-                TalerTransferResponse(
-                    /**
-                     * Normally should point to the next round where the 
background
-                     * routine will send new PAIN.001 data to the bank; work 
in progress..
-                     */
-                    timestamp = DateTime.now().millis / 1000,
-                    row_id = opaque_row_id
+                TextContent(
+                    customConverter(
+                        TalerTransferResponse(
+                            /**
+                             * Normally should point to the next round where 
the background
+                             * routine will send new PAIN.001 data to the 
bank; work in progress..
+                             */
+                            timestamp = GnunetTimestamp(DateTime.now().millis),
+                            row_id = opaque_row_id
+                        )
+                    ),
+                    ContentType.Application.Json
                 )
             )
             return@post
         }
-
         /** Test-API that creates one new payment addressed to the exchange.  
*/
         app.post("/taler/admin/add-incoming") {
             val exchangeId = 
authenticateRequest(call.request.headers["Authorization"])
@@ -299,7 +315,7 @@ class Taler(app: Route) {
                     currency = amount.currency
                     this.amount = amount.amount.toPlainString()
                     creditorIban = exchangeBankAccount.iban
-                    creditorName = "Exchange's company name"
+                    creditorName = exchangeBankAccount.accountHolder ?: 
"Exchange default name for tests"
                     debitorIban = debtor.iban
                     debitorName = debtor.name
                     counterpartBic = debtor.bic
@@ -374,16 +390,21 @@ class Taler(app: Route) {
             transaction {
                 val subscriberAccount = getBankAccountsInfoFromId(id).first()
                 /**
-                 * Search for fresh INCOMING transactions having a BOOK 
status.  Cancellations and
-                 * other status changes will (1) be _appended_ to the payment 
history, and (2) be
-                 * handled _independently_ by another dedicated routine.
+                 * Search for fresh incoming payments in the raw table, and 
making pointers
+                 * from the Taler incoming payments table to the found fresh 
payments.
                  */
                 val latestIncomingPaymentId: Long = 
TalerIncomingPaymentEntity.getLast()
                 EbicsRawBankTransactionEntity.find {
+                    /** select payments having the exchange as the credited 
party */
                     EbicsRawBankTransactionsTable.creditorIban eq 
subscriberAccount.iban and
                             (EbicsRawBankTransactionsTable.status eq "BOOK") 
and
+                            /** avoid processing old payments from the raw 
table */
                             
(EbicsRawBankTransactionsTable.id.greater(latestIncomingPaymentId))
                 }.forEach {
+                    if (duplicatePayment(it)) {
+                        logger.warn("A duplicate payment situation is 
happening")
+                        throw NexusError(HttpStatusCode.InternalServerError, 
"Duplicate payment situation")
+                    }
                     if 
(CryptoUtil.checkValidEddsaPublicKey(it.unstructuredRemittanceInformation)) {
                         TalerIncomingPaymentEntity.new {
                             payment = it
@@ -432,44 +453,66 @@ class Taler(app: Route) {
             val subscriberId = 
authenticateRequest(call.request.headers["Authorization"])
             val delta: Int = expectInt(call.expectUrlParameter("delta"))
             val start: Long = 
handleStartArgument(call.request.queryParameters["start"], delta)
-            val startCmpOp = getComparisonOperator(delta, start)
+            val startCmpOp = getComparisonOperator(delta, start, 
TalerRequestedPayments)
             /* retrieve database elements */
             val history = TalerOutgoingHistory()
             transaction {
                 /** Retrieve all the outgoing payments from the _clean Taler 
outgoing table_ */
                 val subscriberBankAccount = 
getBankAccountsInfoFromId(subscriberId).first()
-                TalerRequestedPaymentEntity.find {
+                val reqPayments = TalerRequestedPaymentEntity.find {
                     TalerRequestedPayments.rawConfirmed.isNotNull() and 
startCmpOp
-                }.orderTaler(delta).subList(0, abs(delta)).forEach {
-                    history.outgoing_transactions.add(
-                        TalerOutgoingBankTransaction(
-                            row_id = it.id.value,
-                            amount = it.amount,
-                            wtid = it.wtid,
-                            date = 
GnunetTimestamp(it.rawConfirmed?.bookingDate?.div(1000) ?: throw NexusError(
-                                HttpStatusCode.InternalServerError, "Null 
value met after check, VERY strange.")),
-                            credit_account = it.creditAccount,
-                            debit_account = 
getPaytoUri(subscriberBankAccount.iban, subscriberBankAccount.bankCode),
-                            exchange_base_url = 
"FIXME-to-request-along-subscriber-registration"
+                }.orderTaler(delta)
+                if (reqPayments.isNotEmpty()) {
+                    reqPayments.subList(0, min(abs(delta), 
reqPayments.size)).forEach {
+                        history.outgoing_transactions.add(
+                            TalerOutgoingBankTransaction(
+                                row_id = it.id.value,
+                                amount = it.amount,
+                                wtid = it.wtid,
+                                date = 
GnunetTimestamp(it.rawConfirmed?.bookingDate?.div(1000) ?: throw NexusError(
+                                    HttpStatusCode.InternalServerError, "Null 
value met after check, VERY strange.")),
+                                credit_account = it.creditAccount,
+                                debit_account = 
buildPaytoUri(subscriberBankAccount.iban, subscriberBankAccount.bankCode),
+                                exchange_base_url = 
"FIXME-to-request-along-subscriber-registration"
+                            )
                         )
-                    )
+                    }
                 }
             }
             call.respond(
                 HttpStatusCode.OK,
-                history
+                TextContent(customConverter(history), 
ContentType.Application.Json)
             )
             return@get
         }
         /** Responds only with the valid incoming payments */
         app.get("/taler/history/incoming") {
-            val subscriberId = 
authenticateRequest(call.request.headers["Authorization"])
+            val exchangeId = 
authenticateRequest(call.request.headers["Authorization"])
             val delta: Int = expectInt(call.expectUrlParameter("delta"))
             val start: Long = 
handleStartArgument(call.request.queryParameters["start"], delta)
             val history = TalerIncomingHistory()
-            val startCmpOp = getComparisonOperator(delta, start)
+            val startCmpOp = getComparisonOperator(delta, start, 
TalerIncomingPayments)
             transaction {
-                val subscriberBankAccount = 
getBankAccountsInfoFromId(subscriberId)
+                /**
+                 * Below, the test harness creates the exchange's bank account
+                 * object based on the payto:// given as the funds receiver.
+                 *
+                 * This is needed because nexus takes this information from the
+                 * bank - normally - but tests are currently avoiding any 
interaction
+                 * with banks or sandboxes.
+                 */
+                if (! isProduction()) {
+                    val EXCHANGE_BANKACCOUNT_ID = "exchange-bankaccount-id"
+                    if 
(EbicsAccountInfoEntity.findById(EXCHANGE_BANKACCOUNT_ID) == null) {
+                        EbicsAccountInfoEntity.new(id = 
EXCHANGE_BANKACCOUNT_ID) {
+                            subscriber = getSubscriberEntityFromId(exchangeId)
+                            accountHolder = "Test Exchange"
+                            iban = "42"
+                            bankCode = "localhost"
+                        }
+                    }
+                }
+                val exchangeBankAccount = getBankAccountsInfoFromId(exchangeId)
                 val orderedPayments = TalerIncomingPaymentEntity.find {
                     TalerIncomingPayments.valid eq true and startCmpOp
                 }.orderTaler(delta)
@@ -481,11 +524,11 @@ class Taler(app: Route) {
                                 row_id = it.id.value,
                                 amount = 
"${it.payment.currency}:${it.payment.amount}",
                                 reserve_pub = 
it.payment.unstructuredRemittanceInformation,
-                                debit_account = getPaytoUri(
+                                debit_account = buildPaytoUri(
                                     it.payment.debitorName, 
it.payment.debitorIban, it.payment.counterpartBic
                                 ),
-                                credit_account = getPaytoUri(
-                                    it.payment.creditorName, 
it.payment.creditorIban, subscriberBankAccount.first().bankCode
+                                credit_account = buildPaytoUri(
+                                    it.payment.creditorName, 
it.payment.creditorIban, exchangeBankAccount.first().bankCode
                                 )
                             )
                         )

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]