gnunet-svn
[Top][All Lists]
Advanced

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

[libeufin] branch master updated (64c2d251 -> 6726bb63)


From: gnunet
Subject: [libeufin] branch master updated (64c2d251 -> 6726bb63)
Date: Wed, 08 Feb 2023 14:32:16 +0100

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

ms pushed a change to branch master
in repository libeufin.

    from 64c2d251 switching to Logback 1.4.5
     new 3376028b help message
     new 2fa10d5f EBICS subscriber creation.
     new e218a12b comments
     new 38e33673 Tests environment.
     new c696a374 background jobs
     new 3f175df5 implementing #7521
     new e60dd718 tests: needed to specify a correct EBICS host ID.
     new 6726bb63 testing the implementation of #7521

The 8 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:
 cli/bin/libeufin-cli                               |  5 +-
 nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt  | 10 ++-
 .../main/kotlin/tech/libeufin/nexus/Scheduling.kt  | 88 ++++++++++------------
 nexus/src/test/kotlin/MakeEnv.kt                   |  3 +-
 nexus/src/test/kotlin/SandboxCircuitApiTest.kt     | 35 +++++++++
 nexus/src/test/kotlin/SandboxLegacyApiTest.kt      |  2 +-
 .../kotlin/tech/libeufin/sandbox/CircuitApi.kt     |  7 +-
 .../tech/libeufin/sandbox/EbicsProtocolBackend.kt  |  2 +
 .../src/main/kotlin/tech/libeufin/sandbox/Main.kt  | 17 +++--
 9 files changed, 108 insertions(+), 61 deletions(-)

diff --git a/cli/bin/libeufin-cli b/cli/bin/libeufin-cli
index 68c38e2b..ebd16ebf 100755
--- a/cli/bin/libeufin-cli
+++ b/cli/bin/libeufin-cli
@@ -1164,7 +1164,8 @@ def sandbox_ebicsbankaccount(ctx):
 
 
 @sandbox_ebicsbankaccount.command(
-    "create", help="Create a bank account for a EBICS subscriber."
+    "create",
+    help="Create a bank account for an existing EBICS subscriber.  This 
operation is deprecated because it doesn't associate any user profile to the 
bank account being created."
 )
 @click.option("--iban", help="IBAN", required=True)
 @click.option("--bic", help="BIC", required=True)
@@ -1376,7 +1377,7 @@ def sandbox_demobank_register(obj, public, name, iban):
     check_response_status(resp)
 
 @sandbox_demobank.command("new-ebicssubscriber",
-    help="Associate a new Ebics subscriber to a existing bank account."
+    help="Associate a new Ebics subscriber to an existing bank account."
 )
 @click.option("--host-id", help="Ebics host ID", required=True)
 @click.option("--partner-id", help="Ebics partner ID", required=True)
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
index 6795f8e0..f09a152b 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
@@ -30,6 +30,10 @@ import com.github.ajalt.clikt.parameters.types.int
 import execThrowableOrTerminate
 import com.github.ajalt.clikt.core.*
 import com.github.ajalt.clikt.parameters.options.*
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.newSingleThreadContext
 import startServer
 import tech.libeufin.nexus.iso20022.parseCamtMessage
 import tech.libeufin.nexus.server.client
@@ -70,10 +74,8 @@ class Serve : CliktCommand("Run nexus HTTP server") {
     private val logLevel by option()
     override fun run() {
         setLogLevel(logLevel)
-        execThrowableOrTerminate {
-            dbCreateTables(getDbConnFromEnv(NEXUS_DB_ENV_VAR_NAME))
-        }
-        startOperationScheduler(client)
+        execThrowableOrTerminate { 
dbCreateTables(getDbConnFromEnv(NEXUS_DB_ENV_VAR_NAME)) }
+        CoroutineScope(Dispatchers.IO).launch(fallback) { 
startOperationScheduler(client) }
         if (withUnixSocket != null) {
             startServer(
                 withUnixSocket!!,
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Scheduling.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/Scheduling.kt
index d4420db6..86c86a37 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Scheduling.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Scheduling.kt
@@ -24,9 +24,8 @@ import com.cronutils.model.time.ExecutionTime
 import com.cronutils.parser.CronParser
 import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
 import io.ktor.client.HttpClient
-import kotlinx.coroutines.CoroutineExceptionHandler
-import kotlinx.coroutines.GlobalScope
-import kotlinx.coroutines.launch
+import kotlinx.coroutines.*
+import kotlinx.coroutines.GlobalScope.coroutineContext
 import kotlinx.coroutines.time.delay
 import org.jetbrains.exposed.sql.transactions.transaction
 import tech.libeufin.nexus.bankaccount.fetchBankAccountTransactions
@@ -36,6 +35,7 @@ import java.lang.IllegalArgumentException
 import java.time.Duration
 import java.time.Instant
 import java.time.ZonedDateTime
+import kotlin.coroutines.coroutineContext
 import kotlin.system.exitProcess
 
 private data class TaskSchedule(
@@ -96,59 +96,53 @@ object NexusCron {
         CronParser(cronDefinition)
     }
 }
-/**
- * Fails whenever a unmanaged Throwable reaches the root coroutine.
- */
+
+// Fails whenever a unmanaged Throwable reaches the root coroutine.
 val fallback = CoroutineExceptionHandler { _, err ->
     logger.error(err.stackTraceToString())
     exitProcess(1)
 }
-fun startOperationScheduler(httpClient: HttpClient) {
-    GlobalScope.launch(fallback) {
-        while (true) {
-            // First, assign next execution time stamps to all tasks that need 
them
-            transaction {
-                NexusScheduledTaskEntity.find {
-                    NexusScheduledTasksTable.nextScheduledExecutionSec.isNull()
-                }.forEach {
-                    val cron = try {
-                        NexusCron.parser.parse(it.taskCronspec)
-                    } catch (e: IllegalArgumentException) {
-                        logger.error("invalid cronspec in schedule 
${it.resourceType}/${it.resourceId}/${it.taskName}")
-                        return@forEach
-                    }
-                    val zonedNow = ZonedDateTime.now()
-                    val et = ExecutionTime.forCron(cron)
-                    val next = et.nextExecution(zonedNow)
-                    logger.info("scheduling task ${it.taskName} at $next (now 
is $zonedNow)")
-                    it.nextScheduledExecutionSec = next.get().toEpochSecond()
+suspend fun startOperationScheduler(httpClient: HttpClient) {
+    while (true) {
+        // First, assign next execution time stamps to all tasks that need them
+        transaction {
+            NexusScheduledTaskEntity.find {
+                NexusScheduledTasksTable.nextScheduledExecutionSec.isNull()
+            }.forEach {
+                val cron = try {
+                    NexusCron.parser.parse(it.taskCronspec)
+                } catch (e: IllegalArgumentException) {
+                    logger.error("invalid cronspec in schedule 
${it.resourceType}/${it.resourceId}/${it.taskName}")
+                    return@forEach
                 }
+                val zonedNow = ZonedDateTime.now()
+                val et = ExecutionTime.forCron(cron)
+                val next = et.nextExecution(zonedNow)
+                logger.info("scheduling task ${it.taskName} at $next (now is 
$zonedNow)")
+                it.nextScheduledExecutionSec = next.get().toEpochSecond()
             }
-
-            val nowSec = Instant.now().epochSecond
-            // Second, find tasks that are due
-            val dueTasks = transaction {
-                NexusScheduledTaskEntity.find {
-                    NexusScheduledTasksTable.nextScheduledExecutionSec lessEq 
nowSec
-                }.map {
-                    TaskSchedule(it.id.value, it.taskName, it.taskType, 
it.resourceType, it.resourceId, it.taskParams)
-                }
+        }
+        val nowSec = Instant.now().epochSecond
+        // Second, find tasks that are due
+        val dueTasks = transaction {
+            NexusScheduledTaskEntity.find {
+                NexusScheduledTasksTable.nextScheduledExecutionSec lessEq 
nowSec
+            }.map {
+                TaskSchedule(it.id.value, it.taskName, it.taskType, 
it.resourceType, it.resourceId, it.taskParams)
             }
-            // Execute those due tasks
-            dueTasks.forEach {
-                runTask(httpClient, it)
-                transaction {
-                    val t = NexusScheduledTaskEntity.findById(it.taskId)
-                    if (t != null) {
-                        // Reset next scheduled execution
-                        t.nextScheduledExecutionSec = null
-                        t.prevScheduledExecutionSec = nowSec
-                    }
+        } // Execute those due tasks
+        dueTasks.forEach {
+            runTask(httpClient, it)
+            transaction {
+                val t = NexusScheduledTaskEntity.findById(it.taskId)
+                if (t != null) {
+                    // Reset next scheduled execution
+                    t.nextScheduledExecutionSec = null
+                    t.prevScheduledExecutionSec = nowSec
                 }
             }
-
-            // Wait a bit
-            delay(Duration.ofSeconds(1))
         }
+        // Wait a bit
+        delay(Duration.ofSeconds(1))
     }
 }
\ No newline at end of file
diff --git a/nexus/src/test/kotlin/MakeEnv.kt b/nexus/src/test/kotlin/MakeEnv.kt
index b8adad2d..52e5dd35 100644
--- a/nexus/src/test/kotlin/MakeEnv.kt
+++ b/nexus/src/test/kotlin/MakeEnv.kt
@@ -1,6 +1,7 @@
 import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
 import org.jetbrains.exposed.sql.Database
 import org.jetbrains.exposed.sql.statements.api.ExposedBlob
+import org.jetbrains.exposed.sql.transactions.TransactionManager
 import org.jetbrains.exposed.sql.transactions.transaction
 import org.jetbrains.exposed.sql.transactions.transactionManager
 import tech.libeufin.nexus.*
@@ -63,7 +64,7 @@ fun withTestDatabase(f: () -> Unit) {
         }
     }
     Database.connect("jdbc:sqlite:$TEST_DB_FILE")
-    // ).transactionManager.defaultIsolationLevel = 
java.sql.Connection.TRANSACTION_SERIALIZABLE
+    TransactionManager.manager.defaultIsolationLevel = 
java.sql.Connection.TRANSACTION_SERIALIZABLE
     dbDropTables(TEST_DB_CONN)
     tech.libeufin.sandbox.dbDropTables(TEST_DB_CONN)
     try { f() }
diff --git a/nexus/src/test/kotlin/SandboxCircuitApiTest.kt 
b/nexus/src/test/kotlin/SandboxCircuitApiTest.kt
index 85a41714..31955ff4 100644
--- a/nexus/src/test/kotlin/SandboxCircuitApiTest.kt
+++ b/nexus/src/test/kotlin/SandboxCircuitApiTest.kt
@@ -122,6 +122,41 @@ class SandboxCircuitApiTest {
         }
     }
 
+    // Testing that only the admin can change an account legal name.
+    @Test
+    fun patchPerm() {
+        withTestDatabase {
+            prepSandboxDb()
+            testApplication {
+                application(sandboxApp)
+                val R 
=client.patch("/demobanks/default/circuit-api/accounts/foo") {
+                    contentType(ContentType.Application.Json)
+                    basicAuth("foo", "foo")
+                    expectSuccess = false
+                    setBody("""
+                        {
+                          "name": "new name",
+                          "contact_data": {},
+                          "cashout_address": "payto://iban/OUTSIDE"
+                        }
+                    """.trimIndent())
+                }
+                assert(R.status.value == HttpStatusCode.Forbidden.value)
+                client.patch("/demobanks/default/circuit-api/accounts/foo") {
+                    contentType(ContentType.Application.Json)
+                    basicAuth("admin", "foo")
+                    expectSuccess = true
+                    setBody("""
+                        {
+                          "name": "new name",
+                          "contact_data": {},
+                          "cashout_address": "payto://iban/OUTSIDE"
+                        }
+                    """.trimIndent())
+                }
+            }
+        }
+    }
     // Tests the creation and confirmation of a cash-out operation.
     @Test
     fun cashout() {
diff --git a/nexus/src/test/kotlin/SandboxLegacyApiTest.kt 
b/nexus/src/test/kotlin/SandboxLegacyApiTest.kt
index 5b0ed407..bd8b0248 100644
--- a/nexus/src/test/kotlin/SandboxLegacyApiTest.kt
+++ b/nexus/src/test/kotlin/SandboxLegacyApiTest.kt
@@ -37,7 +37,7 @@ class SandboxLegacyApiTest {
                      * and conflict detection.
                      */
                     var body = mapper.writeValueAsString(object {
-                        val hostID = "foo"
+                        val hostID = "eufinSandbox"
                         val userID = "foo"
                         val systemID = "foo"
                         val partnerID = "foo"
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/CircuitApi.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/CircuitApi.kt
index 0f64efa6..992346a1 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/CircuitApi.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/CircuitApi.kt
@@ -66,7 +66,8 @@ data class CircuitContactData(
 
 data class CircuitAccountReconfiguration(
     val contact_data: CircuitContactData,
-    val cashout_address: String
+    val cashout_address: String,
+    val name: String? = null
 )
 
 data class AccountPasswordChange(
@@ -530,6 +531,10 @@ fun circuitApi(circuitRoute: Route) {
         allowOwnerOrAdmin(username, resourceName)
         // account found and authentication succeeded
         val req = call.receive<CircuitAccountReconfiguration>()
+        // Only admin's allowed to change the legal name
+        if (req.name != null && username != "admin") throw forbidden(
+            "Only admin can change the user legal name"
+        )
         if ((req.contact_data.email != null) && 
(!checkEmailAddress(req.contact_data.email)))
             throw badRequest("Invalid e-mail address: 
${req.contact_data.email}")
         if ((req.contact_data.phone != null) && 
(!checkPhoneNumber(req.contact_data.phone)))
diff --git 
a/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt
index d820f44f..86bb8f18 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt
@@ -1426,6 +1426,7 @@ suspend fun ApplicationCall.ebicsweb() {
             )
             respondText(strResp, ContentType.Application.Xml, 
HttpStatusCode.OK)
         }
+        // FIXME: should check subscriber state?
         "ebicsNoPubKeyDigestsRequest" -> {
             val requestObject = requestDocument.toObject<EbicsNpkdRequest>()
             val hostInfo = ensureEbicsHost(requestObject.header.static.hostID)
@@ -1434,6 +1435,7 @@ suspend fun ApplicationCall.ebicsweb() {
                 else -> throw EbicsInvalidXmlError()
             }
         }
+        // FIXME: must check subscriber state.
         "ebicsRequest" -> {
             val requestObject = requestDocument.toObject<EbicsRequest>()
             val responseXmlStr = 
transaction(Connection.TRANSACTION_SERIALIZABLE, repetitionAttempts = 10) {
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
index 072a5acc..56e2ddb1 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
@@ -132,11 +132,11 @@ class Config : CliktCommand("Insert one configuration 
(a.k.a. demobank) into the
     private val usersDebtLimitOption by 
option("--users-debt-limit").int().default(1000)
     private val allowRegistrationsOption by option(
         "--with-registrations",
-        help = "(default: true)" /* mentioning here as help message did not.  
*/
+        help = "(defaults to allow registrations)" /* mentioning here as help 
message did not.  */
     ).flag("--without-registrations", default = true)
     private val withSignupBonusOption by option(
         "--with-signup-bonus",
-        help = "Award new customers with 100 units of currency! (default: 
false)"
+        help = "Award new customers with 100 units of currency! (defaults to 
NO bonus)"
     ).flag("--without-signup-bonus", default = false)
 
     override fun run() {
@@ -937,13 +937,16 @@ val sandboxApp: Application.() -> Unit = {
             call.request.basicAuth(onlyAdmin = true)
             val body = call.receive<EbicsSubscriberObsoleteApi>()
             transaction {
+                // Check the host ID exists.
+                val maybeHostId = EbicsHostEntity.find {
+                    EbicsHostsTable.hostID eq body.hostID
+                }.firstOrNull() ?: throw notFound("Host ID ${body.hostID} not 
found.")
                 // Check it exists first.
                 val maybeSubscriber = EbicsSubscriberEntity.find {
                     EbicsSubscribersTable.userId eq body.userID and (
                             EbicsSubscribersTable.partnerId eq body.partnerID
-                            ) and (
-                            EbicsSubscribersTable.systemId eq body.systemID
-                                    )
+                            ) and (EbicsSubscribersTable.systemId eq 
body.systemID) and
+                            (EbicsSubscribersTable.hostId eq body.hostID)
                 }.firstOrNull()
                 if (maybeSubscriber != null) throw conflict("EBICS subscriber 
exists already")
                 EbicsSubscriberEntity.new {
@@ -1581,6 +1584,10 @@ val sandboxApp: Application.() -> Unit = {
                     val body = call.receive<EbicsSubscriberInfo>()
                     // Create or get the Ebics subscriber that is found.
                     transaction {
+                        // Check that host ID exists
+                        EbicsHostEntity.find {
+                            EbicsHostsTable.hostID eq body.hostID
+                        }.firstOrNull() ?: throw notFound("Host ID 
${body.hostID} not found.")
                         val subscriber: EbicsSubscriberEntity = 
EbicsSubscriberEntity.find {
                             (EbicsSubscribersTable.partnerId eq 
body.partnerID).and(
                                 EbicsSubscribersTable.userId eq body.userID

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

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