libeufin

Integration and sandbox testing for FinTech APIs and data formats
Log | Files | Refs | Submodules | README | LICENSE

commit f07a65e633b2961ef5f0447f086d85e1ec7f8f7d
parent dc723836229868294ea3bfdcaa76550e662bda23
Author: MS <ms@taler.net>
Date:   Mon, 29 Jun 2020 15:08:47 +0200

implement composite primary keys

Diffstat:
Mnexus/src/main/kotlin/tech/libeufin/nexus/DB.kt | 26++++----------------------
Mnexus/src/main/kotlin/tech/libeufin/nexus/bankaccount/BankAccount.kt | 24+++++++++++++-----------
Mnexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt | 14++++++++------
Mnexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt | 20+++++++++++++-------
4 files changed, 38 insertions(+), 46 deletions(-)

diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt @@ -210,32 +210,15 @@ class PaymentInitiationEntity(id: EntityID<Long>) : LongEntity(id) { * This table contains the bank accounts that are offered by the bank. * The bank account label (as assigned by the bank) is the primary key. */ -object OfferedBankAccountsTable : IdTable<String>() { - override val id = text("id").entityId() +object OfferedBankAccountsTable : Table() { + val offeredAccountId = text("id") val bankConnection = reference("bankConnection", NexusBankConnectionsTable) val iban = text("iban") val bankCode = text("bankCode") val accountHolder = text("holderName") val imported = reference("imported", NexusBankAccountsTable).nullable() -} - -class OfferedBankAccountEntity(id: EntityID<String>) : Entity<String>(id) { - companion object : EntityClass<String, OfferedBankAccountEntity>(OfferedBankAccountsTable) - var bankConnection by NexusBankConnectionEntity referencedOn OfferedBankAccountsTable.bankConnection - var iban by OfferedBankAccountsTable.iban - var bankCode by OfferedBankAccountsTable.bankCode - var accountHolder by OfferedBankAccountsTable.accountHolder - var imported by NexusBankAccountEntity optionalReferencedOn OfferedBankAccountsTable.imported -} -object AvailableConnectionsForAccountsTable : IntIdTable() { - val bankAccount = reference("bankAccount", NexusBankAccountsTable) - val bankConnection = reference("bankConnection", NexusBankConnectionsTable) -} -class AvailableConnectionForAccountEntity(id: EntityID<Int>) : IntEntity(id) { - companion object : IntEntityClass<AvailableConnectionForAccountEntity>(AvailableConnectionsForAccountsTable) - var bankAccount by NexusBankAccountEntity referencedOn AvailableConnectionsForAccountsTable.bankAccount - var bankConnection by NexusBankConnectionEntity referencedOn AvailableConnectionsForAccountsTable.bankConnection + override val primaryKey = PrimaryKey(offeredAccountId, bankConnection) } /** @@ -415,8 +398,7 @@ fun dbCreateTables(dbName: String) { FacadesTable, TalerFacadeStateTable, NexusScheduledTasksTable, - OfferedBankAccountsTable, - AvailableConnectionsForAccountsTable + OfferedBankAccountsTable ) } } diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/bankaccount/BankAccount.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/bankaccount/BankAccount.kt @@ -26,9 +26,11 @@ import io.ktor.client.HttpClient import io.ktor.http.HttpStatusCode import org.jetbrains.exposed.sql.SortOrder import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.select import org.jetbrains.exposed.sql.transactions.transaction import org.w3c.dom.Document import tech.libeufin.nexus.* +import tech.libeufin.nexus.OfferedBankAccountsTable.iban import tech.libeufin.nexus.ebics.fetchEbicsBySpec import tech.libeufin.nexus.ebics.submitEbicsPaymentInitiation import tech.libeufin.nexus.server.FetchSpecJson @@ -305,16 +307,20 @@ suspend fun fetchBankAccountTransactions( fun importBankAccount(call: ApplicationCall, offeredBankAccountId: String, nexusBankAccountId: String) { transaction { val conn = requireBankConnection(call, "connid") - val offeredAccount = OfferedBankAccountEntity.findById(offeredBankAccountId) ?: throw NexusError( - HttpStatusCode.NotFound, "Could not found raw bank account '${offeredBankAccountId}'" + // first get handle of the offered bank account + val offeredAccount = OfferedBankAccountsTable.select { + OfferedBankAccountsTable.offeredAccountId eq offeredBankAccountId + }.firstOrNull() ?: throw NexusError( + HttpStatusCode.NotFound, "Could not find raw bank account '${offeredBankAccountId}'" ) // detect name collisions first. NexusBankAccountEntity.findById(nexusBankAccountId).run { val importedAccount = when(this) { is NexusBankAccountEntity -> { - if (this.iban != offeredAccount.iban) { + if (this.iban != offeredAccount[OfferedBankAccountsTable.iban]) { throw NexusError( HttpStatusCode.Conflict, + // different accounts == different IBANs "Cannot import two different accounts under one label: ${nexusBankAccountId}" ) } @@ -322,20 +328,16 @@ fun importBankAccount(call: ApplicationCall, offeredBankAccountId: String, nexus } else -> { val newImportedAccount = NexusBankAccountEntity.new(nexusBankAccountId) { - iban = offeredAccount.iban - bankCode = offeredAccount.bankCode + iban = offeredAccount[OfferedBankAccountsTable.iban] + bankCode = offeredAccount[OfferedBankAccountsTable.bankCode] defaultBankConnection = conn highestSeenBankMessageId = 0 - accountHolder = offeredAccount.accountHolder + accountHolder = offeredAccount[OfferedBankAccountsTable.accountHolder] } - offeredAccount.imported = newImportedAccount + offeredAccount[OfferedBankAccountsTable.imported] = newImportedAccount newImportedAccount } } - AvailableConnectionForAccountEntity.new { - bankAccount = importedAccount - bankConnection = conn - } } } } \ No newline at end of file diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsNexus.kt @@ -43,6 +43,7 @@ import io.ktor.routing.Route import io.ktor.routing.get import io.ktor.routing.post import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.insert import org.jetbrains.exposed.sql.not import org.jetbrains.exposed.sql.statements.api.ExposedBlob import org.jetbrains.exposed.sql.transactions.transaction @@ -344,19 +345,19 @@ suspend fun ebicsFetchAccounts(connId: String, client: HttpClient) { response.orderData.toString(Charsets.UTF_8) ) transaction { - payload.value.partnerInfo.accountInfoList?.forEach { - OfferedBankAccountEntity.new(id = it.id) { - accountHolder = it.accountHolder ?: "NOT-GIVEN" - iban = it.accountNumberList?.filterIsInstance<EbicsTypes.GeneralAccountNumber>() + payload.value.partnerInfo.accountInfoList?.forEach { accountInfo -> + OfferedBankAccountsTable.insert { newRow -> + newRow[accountHolder] = accountInfo.accountHolder ?: "NOT GIVEN" + newRow[iban] = accountInfo.accountNumberList?.filterIsInstance<EbicsTypes.GeneralAccountNumber>() ?.find { it.international }?.value ?: throw NexusError(HttpStatusCode.NotFound, reason = "bank gave no IBAN") - bankCode = it.bankCodeList?.filterIsInstance<EbicsTypes.GeneralBankCode>() + newRow[bankCode] = accountInfo.bankCodeList?.filterIsInstance<EbicsTypes.GeneralBankCode>() ?.find { it.international }?.value ?: throw NexusError( HttpStatusCode.NotFound, reason = "bank gave no BIC" ) - bankConnection = requireBankConnectionInternal(connId) + newRow[bankConnection] = requireBankConnectionInternal(connId).id } } } @@ -373,6 +374,7 @@ fun Route.ebicsBankProtocolRoutes(client: HttpClient) { } } + fun Route.ebicsBankConnectionRoutes(client: HttpClient) { post("/send-ini") { val subscriber = transaction { diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt @@ -49,9 +49,15 @@ import io.ktor.utils.io.ByteReadChannel import io.ktor.utils.io.jvm.javaio.toByteReadChannel import io.ktor.utils.io.jvm.javaio.toInputStream import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.select import org.jetbrains.exposed.sql.transactions.transaction import org.slf4j.event.Level import tech.libeufin.nexus.* +import tech.libeufin.nexus.OfferedBankAccountsTable.accountHolder +import tech.libeufin.nexus.OfferedBankAccountsTable.bankCode +import tech.libeufin.nexus.OfferedBankAccountsTable.iban +import tech.libeufin.nexus.OfferedBankAccountsTable.imported +import tech.libeufin.nexus.OfferedBankAccountsTable.offeredAccountId import tech.libeufin.nexus.bankaccount.* import tech.libeufin.nexus.ebics.* import tech.libeufin.util.* @@ -788,16 +794,16 @@ fun serverMain(dbName: String, host: String) { val ret = mutableListOf<OfferedBankAccount>() transaction { val conn = requireBankConnection(call, "connid") - OfferedBankAccountEntity.find { + OfferedBankAccountsTable.select { OfferedBankAccountsTable.bankConnection eq conn.id.value - }.forEach { + }.forEach {resultRow -> ret.add( OfferedBankAccount( - ownerName = it.accountHolder, - iban = it.iban, - bic = it.bankCode, - offeredAccountId = it.id.value, - nexusBankAccountId = it.imported?.id?.value + ownerName = resultRow[accountHolder], + iban = resultRow[iban], + bic = resultRow[bankCode], + offeredAccountId = resultRow[offeredAccountId], + nexusBankAccountId = resultRow[imported]?.value // is 'value' the id? ) ) }