commit 3d8ad9ef15c56c172e8603eb6aafa73201ad7298
parent ff301b9ba07375920e6c17ad9372bb61fe943075
Author: Florian Dold <florian.dold@gmail.com>
Date: Mon, 15 Jun 2020 12:56:17 +0530
towards implementing spec-based fetching
Diffstat:
3 files changed, 67 insertions(+), 86 deletions(-)
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt
@@ -101,11 +101,10 @@ fun getEbicsSubscriberDetailsInternal(subscriber: EbicsSubscriberEntity): EbicsC
}
/**
- * Retrieve Ebics subscriber details given a Transport
- * object and handling the default case (when this latter is null).
+ * Retrieve Ebics subscriber details given a bank connection.
*/
-fun getEbicsSubscriberDetails(userId: String, transportId: String): EbicsClientSubscriberDetails {
- val transport = NexusBankConnectionEntity.findById(transportId)
+fun getEbicsSubscriberDetails(bankConnectionId: String): EbicsClientSubscriberDetails {
+ val transport = NexusBankConnectionEntity.findById(bankConnectionId)
if (transport == null) {
throw NexusError(HttpStatusCode.NotFound, "transport not found")
}
@@ -195,10 +194,40 @@ fun ingestBankMessagesIntoAccount(
}
}
+private data class EbicsFetchSpec(
+ val orderType: String,
+ val orderParams: EbicsOrderParams
+)
+
+suspend fun fetchEbicsBySpec(fetchSpec: FetchSpecJson, client: HttpClient, bankConnectionId: String) {
+ val subscriberDetails = getEbicsSubscriberDetails(bankConnectionId)
+ val specs = mutableListOf<EbicsFetchSpec>()
+ when (fetchSpec) {
+ is FetchSpecLatestJson -> {
+ val p = EbicsStandardOrderParams()
+ when (fetchSpec.level) {
+ FetchLevel.ALL -> {
+ specs.add(EbicsFetchSpec("C52", p))
+ specs.add(EbicsFetchSpec("C53", p))
+ }
+ FetchLevel.REPORT -> {
+ specs.add(EbicsFetchSpec("C52", p))
+ }
+ FetchLevel.STATEMENT -> {
+ specs.add(EbicsFetchSpec("C53", p))
+ }
+ }
+ }
+ }
+ for (spec in specs) {
+ fetchEbicsC5x(spec.orderType, client, bankConnectionId, spec.orderParams, subscriberDetails)
+ }
+}
+
/**
* Fetch EBICS C5x and store it locally, but do not update bank accounts.
*/
-suspend fun fetchEbicsC5x(
+private suspend fun fetchEbicsC5x(
historyType: String,
client: HttpClient,
bankConnectionId: String,
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt
@@ -135,16 +135,18 @@ enum class FetchLevel(@get:JsonValue val jsonName: String) {
@JsonSubTypes(
JsonSubTypes.Type(value = FetchSpecLatestJson::class, name = "latest"),
JsonSubTypes.Type(value = FetchSpecAllJson::class, name = "all"),
- JsonSubTypes.Type(value = FetchSpecPreviousDaysJson::class, name = "previousDays")
+ JsonSubTypes.Type(value = FetchSpecPreviousDaysJson::class, name = "previous-days") ,
+ JsonSubTypes.Type(value = FetchSpecSinceLastJson::class, name = "since-last")
)
abstract class FetchSpecJson(
val level: FetchLevel,
val bankConnection: String?
)
-class FetchSpecLatestJson(level: FetchLevel, bankConnection: String) : FetchSpecJson(level, bankConnection)
-class FetchSpecAllJson(level: FetchLevel, bankConnection: String) : FetchSpecJson(level, bankConnection)
-class FetchSpecPreviousDaysJson(level: FetchLevel, bankConnection: String, val number: Int) :
+class FetchSpecLatestJson(level: FetchLevel, bankConnection: String?) : FetchSpecJson(level, bankConnection)
+class FetchSpecAllJson(level: FetchLevel, bankConnection: String?) : FetchSpecJson(level, bankConnection)
+class FetchSpecSinceLastJson(level: FetchLevel, bankConnection: String?) : FetchSpecJson(level, bankConnection)
+class FetchSpecPreviousDaysJson(level: FetchLevel, bankConnection: String?, val number: Int) :
FetchSpecJson(level, bankConnection)
@JsonTypeInfo(
@@ -199,13 +201,6 @@ data class Transactions(
val transactions: MutableList<BankTransaction> = mutableListOf()
)
-/** Request type of "POST /collected-transactions" */
-data class CollectedTransaction(
- val transport: String? = null,
- val start: String? = null,
- val end: String? = null
-)
-
data class BankProtocolsResponse(
val protocols: List<String>
)
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
@@ -273,8 +273,13 @@ fun moreFrequentBackgroundTasks(httpClient: HttpClient) {
GlobalScope.launch {
while (true) {
logger.debug("Running more frequent background jobs")
- reportAndIgnoreErrors { downloadTalerFacadesTransactions(httpClient, "C53") }
- reportAndIgnoreErrors { downloadTalerFacadesTransactions(httpClient, "C52") }
+ reportAndIgnoreErrors {
+ downloadTalerFacadesTransactions(
+ httpClient,
+ FetchSpecLatestJson(FetchLevel.ALL, null)
+ )
+ }
+ // FIXME: should be done automatically after raw ingestion
reportAndIgnoreErrors { ingestTalerTransactions() }
reportAndIgnoreErrors { submitPreparedPaymentsViaEbics() }
logger.debug("More frequent background jobs done")
@@ -301,7 +306,7 @@ fun lessFrequentBackgroundTasks(httpClient: HttpClient) {
}
/** Crawls all the facades, and requests history for each of its creators. */
-suspend fun downloadTalerFacadesTransactions(httpClient: HttpClient, type: String) {
+suspend fun downloadTalerFacadesTransactions(httpClient: HttpClient, fetchSpec: FetchSpecJson) {
val work = mutableListOf<Pair<String, String>>()
transaction {
TalerFacadeStateEntity.all().forEach {
@@ -312,7 +317,7 @@ suspend fun downloadTalerFacadesTransactions(httpClient: HttpClient, type: Strin
work.forEach {
fetchTransactionsInternal(
client = httpClient,
- type = type,
+ fetchSpec = fetchSpec,
userId = it.first,
accountid = it.second
)
@@ -333,7 +338,7 @@ fun ApplicationCall.expectUrlParameter(name: String): String {
private suspend fun fetchTransactionsInternal(
client: HttpClient,
- type: String, // C53 or C52
+ fetchSpec: FetchSpecJson,
userId: String,
accountid: String
) {
@@ -352,23 +357,19 @@ private suspend fun fetchTransactionsInternal(
"No default bank connection (explicit connection not yet supported)"
)
}
- val subscriberDetails = getEbicsSubscriberDetails(userId, conn.id.value)
return@transaction object {
val connectionType = conn.type
val connectionName = conn.id.value
- val subscriberDetails = subscriberDetails
}
}
when (res.connectionType) {
"ebics" -> {
// FIXME(dold): Support fetching not only the latest transactions.
// It's not clear what's the nicest way to support this.
- fetchEbicsC5x(
- type,
+ fetchEbicsBySpec(
+ fetchSpec,
client,
- res.connectionName,
- EbicsStandardOrderParams(),
- res.subscriberDetails
+ res.connectionName
)
ingestBankMessagesIntoAccount(res.connectionName, accountid)
}
@@ -569,7 +570,7 @@ fun serverMain(dbName: String) {
}
val defaultBankConnection = bankAccount.defaultBankConnection
?: throw NexusError(HttpStatusCode.NotFound, "needs a default connection")
- val subscriberDetails = getEbicsSubscriberDetails(user.id.value, defaultBankConnection.id.value)
+ val subscriberDetails = getEbicsSubscriberDetails(defaultBankConnection.id.value)
return@transaction object {
val pain001document = createPain001document(preparedPayment)
val bankConnectionType = defaultBankConnection.type
@@ -677,14 +678,14 @@ fun serverMain(dbName: String) {
)
}
val user = transaction { authenticateRequest(call.request) }
- val ct = if (call.request.hasBody()) {
- call.receive<CollectedTransaction>()
+ val fetchSpec = if (call.request.hasBody()) {
+ call.receive<FetchSpecJson>()
} else {
- CollectedTransaction(null, null, null)
+ FetchSpecLatestJson(FetchLevel.ALL, null)
}
fetchTransactionsInternal(
client,
- "C53",
+ fetchSpec,
user.id.value,
accountid
)
@@ -776,7 +777,7 @@ fun serverMain(dbName: String) {
"bank connection is not of type 'ebics' (but '${conn.type}')"
)
}
- val ebicsSubscriber = getEbicsSubscriberDetails(user.id.value, conn.id.value)
+ val ebicsSubscriber = getEbicsSubscriberDetails(conn.id.value)
val mapper = ObjectMapper()
val details = mapper.createObjectNode()
details.put("ebicsUrl", ebicsSubscriber.ebicsUrl)
@@ -799,7 +800,7 @@ fun serverMain(dbName: String) {
val conn = requireBankConnection(call, "connid")
when (conn.type) {
"ebics" -> {
- val subscriber = getEbicsSubscriberDetails(user.id.value, conn.id.value)
+ val subscriber = getEbicsSubscriberDetails(conn.id.value)
EbicsKeysBackupJson(
type = "ebics",
userID = subscriber.userId,
@@ -851,7 +852,7 @@ fun serverMain(dbName: String) {
"bank connection is not of type 'ebics' (but '${conn.type}')"
)
}
- getEbicsSubscriberDetails(user.id.value, conn.id.value)
+ getEbicsSubscriberDetails(conn.id.value)
}
if (subscriber.bankAuthPub != null && subscriber.bankEncPub != null) {
call.respond(object {
@@ -932,50 +933,6 @@ fun serverMain(dbName: String) {
call.respondBytes(ret.msgContent, ContentType("application", "xml"))
}
- post("/bank-connections/{connid}/ebics/fetch-c53") {
- val ebicsOrderParams = if (call.request.hasBody()) {
- call.receive<EbicsOrderParamsJson>().toOrderParams()
- } else {
- EbicsStandardOrderParams()
- }
- val ret = transaction {
- val user = authenticateRequest(call.request)
- val conn = requireBankConnection(call, "connid")
- if (conn.type != "ebics") {
- throw NexusError(HttpStatusCode.BadRequest, "bank connection is not of type 'ebics'")
- }
- object {
- val subscriber = getEbicsSubscriberDetails(user.id.value, conn.id.value)
- val connId = conn.id.value
- }
-
- }
- fetchEbicsC5x("C53", client, ret.connId, ebicsOrderParams, ret.subscriber)
- call.respond(object {})
- }
-
- post("/bank-connections/{connid}/ebics/fetch-c52") {
- val ebicsOrderParams = if (call.request.hasBody()) {
- call.receive<EbicsOrderParamsJson>().toOrderParams()
- } else {
- EbicsStandardOrderParams()
- }
- val ret = transaction {
- val user = authenticateRequest(call.request)
- val conn = requireBankConnection(call, "connid")
- if (conn.type != "ebics") {
- throw NexusError(HttpStatusCode.BadRequest, "bank connection is not of type 'ebics'")
- }
- object {
- val subscriber = getEbicsSubscriberDetails(user.id.value, conn.id.value)
- val connId = conn.id.value
- }
-
- }
- fetchEbicsC5x("C52", client, ret.connId, ebicsOrderParams, ret.subscriber)
- call.respond(object {})
- }
-
post("/bank-connections/{connid}/ebics/send-ini") {
val subscriber = transaction {
val user = authenticateRequest(call.request)
@@ -986,7 +943,7 @@ fun serverMain(dbName: String) {
"bank connection is not of type 'ebics' (but '${conn.type}')"
)
}
- getEbicsSubscriberDetails(user.id.value, conn.id.value)
+ getEbicsSubscriberDetails(conn.id.value)
}
val resp = doEbicsIniRequest(client, subscriber)
call.respond(resp)
@@ -999,7 +956,7 @@ fun serverMain(dbName: String) {
if (conn.type != "ebics") {
throw NexusError(HttpStatusCode.BadRequest, "bank connection is not of type 'ebics'")
}
- getEbicsSubscriberDetails(user.id.value, conn.id.value)
+ getEbicsSubscriberDetails(conn.id.value)
}
val resp = doEbicsHiaRequest(client, subscriber)
call.respond(resp)
@@ -1012,7 +969,7 @@ fun serverMain(dbName: String) {
if (conn.type != "ebics") {
throw NexusError(HttpStatusCode.BadRequest, "bank connection is not of type 'ebics'")
}
- getEbicsSubscriberDetails(user.id.value, conn.id.value)
+ getEbicsSubscriberDetails(conn.id.value)
}
val resp = doEbicsHostVersionQuery(client, subscriber.ebicsUrl, subscriber.hostId)
call.respond(resp)
@@ -1025,7 +982,7 @@ fun serverMain(dbName: String) {
if (conn.type != "ebics") {
throw NexusError(HttpStatusCode.BadRequest, "bank connection is not of type 'ebics'")
}
- getEbicsSubscriberDetails(user.id.value, conn.id.value)
+ getEbicsSubscriberDetails(conn.id.value)
}
val hpbData = doEbicsHpbRequest(client, subscriberDetails)
transaction {
@@ -1048,7 +1005,7 @@ fun serverMain(dbName: String) {
if (conn.type != "ebics") {
throw NexusError(HttpStatusCode.BadRequest, "bank connection is not of type 'ebics'")
}
- getEbicsSubscriberDetails(user.id.value, conn.id.value)
+ getEbicsSubscriberDetails(conn.id.value)
}
val response = doEbicsDownloadTransaction(
client, subscriberDetails, "HTD", EbicsStandardOrderParams()
@@ -1103,7 +1060,7 @@ fun serverMain(dbName: String) {
if (conn.type != "ebics") {
throw NexusError(HttpStatusCode.BadRequest, "bank connection is not of type 'ebics'")
}
- getEbicsSubscriberDetails(user.id.value, conn.id.value)
+ getEbicsSubscriberDetails(conn.id.value)
}
val response = doEbicsDownloadTransaction(
client,