summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntoine A <>2023-12-05 09:25:40 +0000
committerAntoine A <>2023-12-05 09:25:40 +0000
commit93f3157833a87ef7efbd8c6d9efcdb0fa6862c62 (patch)
treeabbf01bacf19d573a7ae4799ad99ecde8fac9291
parent319cdd9ea4003f1d96ab1258d719b42364eebbbc (diff)
downloadlibeufin-93f3157833a87ef7efbd8c6d9efcdb0fa6862c62.tar.gz
libeufin-93f3157833a87ef7efbd8c6d9efcdb0fa6862c62.tar.bz2
libeufin-93f3157833a87ef7efbd8c6d9efcdb0fa6862c62.zip
Add edit-account command
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt41
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/Main.kt67
-rw-r--r--integration/test/IntegrationTest.kt9
3 files changed, 86 insertions, 31 deletions
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt b/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt
index 828c2e77..822f9983 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt
@@ -170,6 +170,27 @@ suspend fun createAccount(db: Database, ctx: BankConfig, req: RegisterAccountReq
return Pair(res, internalPayto)
}
+suspend fun patchAccount(db: Database, ctx: BankConfig, req: AccountReconfiguration, username: String, isAdmin: Boolean): AccountPatchResult {
+ req.debit_threshold?.run { ctx.checkRegionalCurrency(this) }
+
+ if ((req.is_taler_exchange ?: false) == true && username == "admin")
+ throw conflict(
+ "admin account cannot be an exchange",
+ TalerErrorCode.BANK_PATCH_ADMIN_EXCHANGE
+ )
+
+ return db.account.reconfig(
+ login = username,
+ name = req.name,
+ cashoutPayto = req.cashout_payto_uri,
+ emailAddress = req.challenge_contact_data?.email,
+ isTalerExchange = req.is_taler_exchange,
+ phoneNumber = req.challenge_contact_data?.phone,
+ debtLimit = req.debit_threshold,
+ isAdmin = isAdmin
+ )
+}
+
private fun Routing.coreBankAccountsApi(db: Database, ctx: BankConfig) {
authAdmin(db, TokenScope.readwrite, !ctx.allowRegistration) {
post("/accounts") {
@@ -227,25 +248,7 @@ private fun Routing.coreBankAccountsApi(db: Database, ctx: BankConfig) {
auth(db, TokenScope.readwrite, allowAdmin = true) {
patch("/accounts/{USERNAME}") {
val req = call.receive<AccountReconfiguration>()
- req.debit_threshold?.run { ctx.checkRegionalCurrency(this) }
-
- if ((req.is_taler_exchange ?: false) == true && username == "admin")
- throw conflict(
- "admin account cannot be an exchange",
- TalerErrorCode.BANK_PATCH_ADMIN_EXCHANGE
- )
-
- val res = db.account.reconfig(
- login = username,
- name = req.name,
- cashoutPayto = req.cashout_payto_uri,
- emailAddress = req.challenge_contact_data?.email,
- isTalerExchange = req.is_taler_exchange,
- phoneNumber = req.challenge_contact_data?.phone,
- debtLimit = req.debit_threshold,
- isAdmin = isAdmin
- )
- when (res) {
+ when (patchAccount(db, ctx, req, username, isAdmin)) {
AccountPatchResult.Success -> call.respond(HttpStatusCode.NoContent)
AccountPatchResult.UnknownAccount -> throw notFound(
"Account '$username' not found",
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
index 45f59b33..d9cdf9d6 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
@@ -22,6 +22,7 @@ package tech.libeufin.bank
import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.subcommands
+import com.github.ajalt.clikt.parameters.types.*
import com.github.ajalt.clikt.parameters.arguments.*
import com.github.ajalt.clikt.parameters.options.*
import com.github.ajalt.clikt.parameters.groups.*
@@ -217,7 +218,11 @@ class CommonOption: OptionGroup() {
val config by option(
"--config", "-c",
help = "Specifies the configuration file"
- )
+ ).path(
+ mustExist = true,
+ canBeDir = false,
+ mustBeReadable = true,
+ ).convert { it.toString() } // TODO take path to load config
}
class BankDbInit : CliktCommand("Initialize the libeufin-bank database", name = "dbinit") {
@@ -304,8 +309,11 @@ class ServeBank : CliktCommand("Run libeufin-bank HTTP server", name = "serve")
class ChangePw : CliktCommand("Change account password", name = "passwd") {
private val common by CommonOption()
- private val username by argument("username")
- private val password by argument("password")
+ private val username by argument("username", help = "Account username")
+ private val password by argument(
+ "password",
+ help = "Account password used for authentication"
+ )
override fun run() = cliCmd(logger) {
val cfg = talerConfig(common.config)
@@ -325,6 +333,57 @@ class ChangePw : CliktCommand("Change account password", name = "passwd") {
}
}
+
+class EditAccount : CliktCommand(
+ "Edit an existing account",
+ name = "edit-account"
+) {
+ private val common by CommonOption()
+ private val username: String by argument(
+ "username",
+ help = "Account username"
+ )
+ private val name: String? by option(
+ help = "Legal name of the account owner"
+ )
+ private val exchange: Boolean? by option(
+ help = "Make this account a taler exchange"
+ ).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 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) }
+
+ override fun run() = cliCmd(logger) {
+ val cfg = talerConfig(common.config)
+ val ctx = cfg.loadBankConfig()
+ val dbCfg = cfg.loadDbConfig()
+ val db = Database(dbCfg.dbConnStr, ctx.regionalCurrency, ctx.fiatCurrency)
+ runBlocking {
+ val req = AccountReconfiguration(
+ name = name,
+ is_taler_exchange = exchange,
+ challenge_contact_data = ChallengeContactData(
+ email = email,
+ phone = phone,
+ ),
+ cashout_payto_uri = cashout_payto_uri,
+ debit_threshold = debit_threshold
+ )
+ when (patchAccount(db, ctx, req, username, true)) {
+ AccountPatchResult.Success ->
+ logger.info("Account '$username' edited")
+ AccountPatchResult.UnknownAccount ->
+ throw Exception("Account '$username' not found")
+ AccountPatchResult.NonAdminLegalName ->
+ throw Exception("non-admin user cannot change their legal name")
+ AccountPatchResult.NonAdminDebtLimit ->
+ throw Exception("non-admin user cannot change their debt limit")
+ }
+ }
+ }
+}
+
class CreateAccountOption: OptionGroup() {
val username: String by option(
"--username", "-u",
@@ -402,7 +461,7 @@ class CreateAccount : CliktCommand(
class LibeufinBankCommand : CliktCommand() {
init {
versionOption(getVersion())
- subcommands(ServeBank(), BankDbInit(), CreateAccount(), ChangePw(), CliConfigCmd(BANK_CONFIG_SOURCE))
+ subcommands(ServeBank(), BankDbInit(), CreateAccount(), EditAccount(), ChangePw(), CliConfigCmd(BANK_CONFIG_SOURCE))
}
override fun run() = Unit
diff --git a/integration/test/IntegrationTest.kt b/integration/test/IntegrationTest.kt
index 404cd5ce..5820a205 100644
--- a/integration/test/IntegrationTest.kt
+++ b/integration/test/IntegrationTest.kt
@@ -85,6 +85,7 @@ class IntegrationTest {
nexusCmd.run("dbinit -c conf/integration.conf -r")
bankCmd.run("dbinit -c conf/integration.conf -r")
bankCmd.run("passwd admin password -c conf/integration.conf")
+ bankCmd.run("edit-account admin --debit_threshold KUDOS:1000 -c conf/integration.conf")
bankCmd.run("create-account -c conf/integration.conf -u exchange -p password --name 'Mr Money' --exchange")
kotlin.concurrent.thread(isDaemon = true) {
bankCmd.run("serve -c conf/integration.conf")
@@ -128,14 +129,6 @@ class IntegrationTest {
}
}.assertNoContent()
- // Set admin debit threshold
- client.patch("http://0.0.0.0:8090/accounts/admin") {
- basicAuth("admin", "password")
- json {
- "debit_threshold" to "KUDOS:1000"
- }
- }.assertNoContent()
-
// Cashin
repeat(3) { i ->
val reservePub = randBytes(32);