[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.
- [libeufin] branch master updated (64c2d251 -> 6726bb63),
gnunet <=
- [libeufin] 05/08: background jobs, gnunet, 2023/02/08
- [libeufin] 02/08: EBICS subscriber creation., gnunet, 2023/02/08
- [libeufin] 01/08: help message, gnunet, 2023/02/08
- [libeufin] 03/08: comments, gnunet, 2023/02/08
- [libeufin] 04/08: Tests environment., gnunet, 2023/02/08
- [libeufin] 06/08: implementing #7521, gnunet, 2023/02/08
- [libeufin] 07/08: tests: needed to specify a correct EBICS host ID., gnunet, 2023/02/08
- [libeufin] 08/08: testing the implementation of #7521, gnunet, 2023/02/08