aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntoine A <>2023-12-19 15:58:48 +0000
committerAntoine A <>2023-12-19 16:09:13 +0000
commitcf1456b82766a7c13338a59c84f6d8b1f38e9ad9 (patch)
tree684a81f8ac23980962034a1ea993d29588ea90e6
parent14941dc6d049dd24ac9eba76561cf01d0002f746 (diff)
downloadlibeufin-cf1456b82766a7c13338a59c84f6d8b1f38e9ad9.tar.gz
libeufin-cf1456b82766a7c13338a59c84f6d8b1f38e9ad9.tar.bz2
libeufin-cf1456b82766a7c13338a59c84f6d8b1f38e9ad9.zip
Add tan_channel fields to bank accounts
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt10
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/Main.kt3
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/TalerMessage.kt2
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt23
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/db/CashoutDAO.kt2
-rw-r--r--bank/src/test/kotlin/CoreBankApiTest.kt18
-rw-r--r--database-versioning/libeufin-bank-0002.sql3
7 files changed, 52 insertions, 9 deletions
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt b/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt
index 9966edf5..fc344a80 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt
@@ -205,6 +205,7 @@ suspend fun patchAccount(db: Database, ctx: BankConfig, req: AccountReconfigurat
cashoutPayto = req.cashout_payto_uri,
email = contactData?.email ?: Option.None,
phone = contactData?.phone ?: Option.None,
+ tan_channel = req.tan_channel,
isPublic = req.is_public,
debtLimit = req.debit_threshold,
isAdmin = isAdmin,
@@ -267,7 +268,10 @@ private fun Routing.coreBankAccountsApi(db: Database, ctx: BankConfig) {
auth(db, TokenScope.readwrite, allowAdmin = true) {
patch("/accounts/{USERNAME}") {
val req = call.receive<AccountReconfiguration>()
- when (patchAccount(db, ctx, req, username, isAdmin)) {
+ val res = patchAccount(db, ctx, req, username, isAdmin)
+ println(req)
+ println(res)
+ when (res) {
AccountPatchResult.Success -> call.respond(HttpStatusCode.NoContent)
AccountPatchResult.UnknownAccount -> throw unknownAccount(username)
AccountPatchResult.NonAdminName -> throw conflict(
@@ -286,6 +290,10 @@ private fun Routing.coreBankAccountsApi(db: Database, ctx: BankConfig) {
"non-admin user cannot change their contact info",
TalerErrorCode.BANK_NON_ADMIN_PATCH_CONTACT
)
+ AccountPatchResult.MissingTanInfo -> throw conflict(
+ "missing info for tan channel ${req.tan_channel.get()}",
+ TalerErrorCode.BANK_MISSING_TAN_INFO
+ )
}
}
patch("/accounts/{USERNAME}/auth") {
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
index 908c3234..154fcf9b 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
@@ -364,6 +364,7 @@ class EditAccount : CliktCommand(
).boolean()
private val email: String? by option(help = "E-Mail address used for TAN transmission")
private val phone: String? by option(help = "Phone number used for TAN transmission")
+ private val tan_channel: String? by option(help = "which channel TAN challenges should be sent to")
private val cashout_payto_uri: IbanPayTo? by option(help = "Payto URI of a fiant account who receive cashout amount").convert { IbanPayTo(it) }
private val debit_threshold: TalerAmount? by option(help = "Max debit allowed for this account").convert { TalerAmount(it) }
@@ -390,6 +391,8 @@ class EditAccount : CliktCommand(
logger.info("Account '$username' edited")
AccountPatchResult.UnknownAccount ->
throw Exception("Account '$username' not found")
+ AccountPatchResult.MissingTanInfo ->
+ throw Exception("missing info for tan channel ${req.tan_channel.get()}")
AccountPatchResult.NonAdminName,
AccountPatchResult.NonAdminCashout,
AccountPatchResult.NonAdminDebtLimit,
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/TalerMessage.kt b/bank/src/main/kotlin/tech/libeufin/bank/TalerMessage.kt
index 72633c73..61621847 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/TalerMessage.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/TalerMessage.kt
@@ -176,6 +176,7 @@ data class AccountReconfiguration(
val name: String? = null,
val is_public: Boolean? = null,
val debit_threshold: TalerAmount? = null,
+ val tan_channel: Option<TanChannel?> = Option.None,
// TODO remove
val challenge_contact_data: ChallengeContactData? = null,
val is_taler_exchange: Boolean? = null,
@@ -347,6 +348,7 @@ data class AccountData(
val debit_threshold: TalerAmount,
val contact_data: ChallengeContactData? = null,
val cashout_payto_uri: String? = null,
+ val tan_channel: TanChannel? = null,
val is_public: Boolean,
val is_taler_exchange: Boolean
)
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt b/bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt
index 276e5e56..830d5bb0 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt
@@ -92,7 +92,8 @@ class AccountDAO(private val db: Database) {
,email
,phone
,cashout_payto
- ) VALUES (?, ?, ?, ?, ?, ?)
+ ,tan_channel
+ ) VALUES (?, ?, ?, ?, ?, ?, NULL)
RETURNING customer_id
"""
).run {
@@ -200,6 +201,7 @@ class AccountDAO(private val db: Database) {
NonAdminCashout,
NonAdminDebtLimit,
NonAdminContact,
+ MissingTanInfo,
Success
}
@@ -210,6 +212,7 @@ class AccountDAO(private val db: Database) {
cashoutPayto: Option<IbanPayTo?>,
phone: Option<String?>,
email: Option<String?>,
+ tan_channel: Option<TanChannel?>,
isPublic: Boolean?,
debtLimit: TalerAmount?,
isAdmin: Boolean,
@@ -226,11 +229,16 @@ class AccountDAO(private val db: Database) {
val customer_id = conn.prepareStatement("""
SELECT
customer_id
- ,(${ if (checkName) "name != ? " else "false" }) as name_change
+ ,(${ if (checkName) "name != ?" else "false" }) as name_change
,(${ if (checkCashout) "cashout_payto IS DISTINCT FROM ?" else "false" }) as cashout_change
,(${ if (checkDebtLimit) "max_debt != (?, ?)::taler_amount" else "false" }) as debt_limit_change
- ,(${ if (checkPhone) "phone IS DISTINCT FROM ?" else "false" }) as phone_change
- ,(${ if (checkEmail) "email IS DISTINCT FROM ?" else "false" }) as email_change
+ ,(${ if (checkPhone) "phone IS DISTINCT FROM ?" else "false" }) as phone_change
+ ,(${ if (checkEmail) "email IS DISTINCT FROM ?" else "false" }) as email_change
+ ,(${ when (tan_channel.get()) {
+ null -> "false"
+ TanChannel.sms -> if (phone.get() != null) "false" else "phone IS NULL"
+ TanChannel.email -> if (email.get() != null) "false" else "email IS NULL"
+ }}) as missing_tan_info
FROM customers
JOIN bank_accounts
ON customer_id=owning_customer_id
@@ -262,6 +270,7 @@ class AccountDAO(private val db: Database) {
it.getBoolean("debt_limit_change") -> return@transaction AccountPatchResult.NonAdminDebtLimit
it.getBoolean("phone_change") -> return@transaction AccountPatchResult.NonAdminContact
it.getBoolean("email_change") -> return@transaction AccountPatchResult.NonAdminContact
+ it.getBoolean("missing_tan_info") -> return@transaction AccountPatchResult.MissingTanInfo
else -> it.getLong("customer_id")
}
}
@@ -289,6 +298,7 @@ class AccountDAO(private val db: Database) {
cashoutPayto.some { yield("cashout_payto=?") }
phone.some { yield("phone=?") }
email.some { yield("email=?") }
+ tan_channel.some { yield("tan_channel=?::tan_enum") }
name?.let { yield("name=?") }
},
"WHERE customer_id = ?",
@@ -296,6 +306,7 @@ class AccountDAO(private val db: Database) {
cashoutPayto.some { yield(it?.canonical) }
phone.some { yield(it) }
email.some { yield(it) }
+ tan_channel.some { yield(it?.name) }
name?.let { yield(it) }
yield(customer_id)
}
@@ -388,6 +399,7 @@ class AccountDAO(private val db: Database) {
name
,email
,phone
+ ,tan_channel
,cashout_payto
,internal_payto_uri
,(balance).val AS balance_val
@@ -398,7 +410,7 @@ class AccountDAO(private val db: Database) {
,is_public
,is_taler_exchange
FROM customers
- JOIN bank_accounts
+ JOIN bank_accounts
ON customer_id=owning_customer_id
WHERE login=?
""")
@@ -410,6 +422,7 @@ class AccountDAO(private val db: Database) {
email = Option.Some(it.getString("email")),
phone = Option.Some(it.getString("phone"))
),
+ tan_channel = it.getString("tan_channel")?.run { TanChannel.valueOf(this) },
cashout_payto_uri = it.getString("cashout_payto"),
payto_uri = it.getString("internal_payto_uri"),
balance = Balance(
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/db/CashoutDAO.kt b/bank/src/main/kotlin/tech/libeufin/bank/db/CashoutDAO.kt
index d5c89c55..58d2ca03 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/db/CashoutDAO.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/db/CashoutDAO.kt
@@ -211,7 +211,7 @@ class CashoutDAO(private val db: Database) {
,cashout_operations.subject
,creation_time
,transaction_date as confirmation_date
- ,tan_channel
+ ,cashout_operations.tan_channel
,tan_info
FROM cashout_operations
JOIN bank_accounts ON bank_account=bank_account_id
diff --git a/bank/src/test/kotlin/CoreBankApiTest.kt b/bank/src/test/kotlin/CoreBankApiTest.kt
index 7f101c82..3fb4a1d1 100644
--- a/bank/src/test/kotlin/CoreBankApiTest.kt
+++ b/bank/src/test/kotlin/CoreBankApiTest.kt
@@ -400,7 +400,7 @@ class CoreBankAccountsApiTest {
fun reconfig() = bankSetup { _ ->
authRoutine(HttpMethod.Patch, "/accounts/merchant", withAdmin = true)
- // Successful attempt now.
+ // Successful attempt now
val cashout = IbanPayTo(genIbanPaytoUri())
val req = obj {
"cashout_payto_uri" to cashout.canonical
@@ -410,10 +410,24 @@ class CoreBankAccountsApiTest {
client.patchA("/accounts/merchant") {
json(req)
}.assertNoContent()
- // Checking idempotence.
+ // Checking idempotence
client.patchA("/accounts/merchant") {
json(req)
}.assertNoContent()
+
+ // Check tan info
+ client.patchA("/accounts/merchant") {
+ json {
+ "tan_channel" to "sms"
+ "email" to "mail@test.com"
+ }
+ }.assertErr(TalerErrorCode.BANK_MISSING_TAN_INFO)
+ client.patchA("/accounts/merchant") {
+ json {
+ "tan_channel" to "email"
+ "phone" to "+99"
+ }
+ }.assertErr(TalerErrorCode.BANK_MISSING_TAN_INFO)
checkAdminOnly(
obj(req) { "debit_threshold" to "KUDOS:100" },
diff --git a/database-versioning/libeufin-bank-0002.sql b/database-versioning/libeufin-bank-0002.sql
index 54a48ef0..cd26bd5c 100644
--- a/database-versioning/libeufin-bank-0002.sql
+++ b/database-versioning/libeufin-bank-0002.sql
@@ -21,6 +21,9 @@ SET search_path TO libeufin_bank;
-- TODO remove challenges table
-- TODO remove challenge and status columns from cashout_operations
+ALTER TABLE customers
+ ADD tan_channel tan_enum NULL;
+
CREATE TABLE tan_challenges
(challenge_id INT8 GENERATED BY DEFAULT AS IDENTITY UNIQUE
,body TEXT NOT NULL