diff options
Diffstat (limited to 'bank/src/main/kotlin/tech/libeufin/bank/db/CashoutDAO.kt')
-rw-r--r-- | bank/src/main/kotlin/tech/libeufin/bank/db/CashoutDAO.kt | 165 |
1 files changed, 21 insertions, 144 deletions
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 bf8be4fb..a7950aa2 100644 --- a/bank/src/main/kotlin/tech/libeufin/bank/db/CashoutDAO.kt +++ b/bank/src/main/kotlin/tech/libeufin/bank/db/CashoutDAO.kt @@ -29,14 +29,14 @@ import tech.libeufin.bank.* class CashoutDAO(private val db: Database) { /** Result of cashout operation creation */ sealed class CashoutCreationResult { - /** Cashout [id] has been created or refreshed. If [tanCode] is not null, use [tanInfo] to send it via [tanChannel] then call [markSent] */ - data class Success(val id: Long, val tanInfo: String, val tanCode: String?): CashoutCreationResult() + data class Success(val id: Long): CashoutCreationResult() object BadConversion: CashoutCreationResult() object AccountNotFound: CashoutCreationResult() object AccountIsExchange: CashoutCreationResult() - object MissingTanInfo: CashoutCreationResult() object BalanceInsufficient: CashoutCreationResult() object RequestUidReuse: CashoutCreationResult() + object NoCashoutPayto: CashoutCreationResult() + object TanRequired: CashoutCreationResult() } /** Create a new cashout operation */ @@ -46,24 +46,20 @@ class CashoutDAO(private val db: Database) { amountDebit: TalerAmount, amountCredit: TalerAmount, subject: String, - tanChannel: TanChannel, - tanCode: String, now: Instant, - retryCounter: Int, - validityPeriod: Duration + is2fa: Boolean ): CashoutCreationResult = db.serializable { conn -> val stmt = conn.prepareStatement(""" SELECT out_bad_conversion, out_account_not_found, out_account_is_exchange, - out_missing_tan_info, out_balance_insufficient, out_request_uid_reuse, - out_cashout_id, - out_tan_info, - out_tan_code - FROM cashout_create(?, ?, (?,?)::taler_amount, (?,?)::taler_amount, ?, ?, ?::tan_enum, ?, ?, ?) + out_no_cashout_payto, + out_tan_required, + out_cashout_id + FROM cashout_create(?,?,(?,?)::taler_amount,(?,?)::taler_amount,?,?,?) """) stmt.setString(1, login) stmt.setBytes(2, requestUid.raw) @@ -73,10 +69,7 @@ class CashoutDAO(private val db: Database) { stmt.setInt(6, amountCredit.frac) stmt.setString(7, subject) stmt.setLong(8, now.toDbMicros() ?: throw faultyTimestampByBank()) - stmt.setString(9, tanChannel.name) - stmt.setString(10, tanCode) - stmt.setInt(11, retryCounter) - stmt.setLong(12, TimeUnit.MICROSECONDS.convert(validityPeriod)) + stmt.setBoolean(9, is2fa) stmt.executeQuery().use { when { !it.next() -> @@ -84,114 +77,11 @@ class CashoutDAO(private val db: Database) { it.getBoolean("out_bad_conversion") -> CashoutCreationResult.BadConversion it.getBoolean("out_account_not_found") -> CashoutCreationResult.AccountNotFound it.getBoolean("out_account_is_exchange") -> CashoutCreationResult.AccountIsExchange - it.getBoolean("out_missing_tan_info") -> CashoutCreationResult.MissingTanInfo it.getBoolean("out_balance_insufficient") -> CashoutCreationResult.BalanceInsufficient it.getBoolean("out_request_uid_reuse") -> CashoutCreationResult.RequestUidReuse - else -> CashoutCreationResult.Success( - id = it.getLong("out_cashout_id"), - tanInfo = it.getString("out_tan_info"), - tanCode = it.getString("out_tan_code") - ) - } - } - } - - /** Mark cashout operation [id] challenge as having being successfully sent [now] and not to be retransmit until after [retransmissionPeriod] */ - suspend fun markSent( - id: Long, - now: Instant, - retransmissionPeriod: Duration, - tanChannel: TanChannel, - tanInfo: String - ) = db.serializable { - it.transaction { conn -> - conn.prepareStatement(""" - SELECT challenge_mark_sent(challenge, ?, ?) - FROM cashout_operations - WHERE cashout_id=? - """).run { - setLong(1, now.toDbMicros() ?: throw faultyTimestampByBank()) - setLong(2, TimeUnit.MICROSECONDS.convert(retransmissionPeriod)) - setLong(3, id) - executeQueryCheck() - } - conn.prepareStatement(""" - UPDATE cashout_operations - SET tan_channel = ?, tan_info = ? - WHERE cashout_id=? - """).run { - setString(1, tanChannel.name) - setString(2, tanInfo) - setLong(3, id) - executeUpdateCheck() - } - } - } - - /** Abort cashout operation [id] owned by [login] */ - suspend fun abort(id: Long, login: String): AbortResult = db.serializable { conn -> - val stmt = conn.prepareStatement(""" - UPDATE cashout_operations - SET aborted = local_transaction IS NULL - FROM bank_accounts JOIN customers ON customer_id=owning_customer_id - WHERE cashout_id=? AND bank_account=bank_account_id AND login=? - RETURNING local_transaction IS NOT NULL - """) - stmt.setLong(1, id) - stmt.setString(2, login) - when (stmt.oneOrNull { it.getBoolean(1) }) { - null -> AbortResult.UnknownOperation - true -> AbortResult.AlreadyConfirmed - false -> AbortResult.Success - } - } - - /** Result status of cashout operation confirmation */ - enum class CashoutConfirmationResult { - SUCCESS, - BAD_CONVERSION, - OP_NOT_FOUND, - BAD_TAN_CODE, - BALANCE_INSUFFICIENT, - NO_RETRY, - NO_CASHOUT_PAYTO, - ABORTED - } - - /** Confirm cashout operation [id] owned by [login] */ - suspend fun confirm( - id: Long, - login: String, - tanCode: String, - timestamp: Instant - ): CashoutConfirmationResult = db.serializable { conn -> - val stmt = conn.prepareStatement(""" - SELECT - out_no_op, - out_bad_conversion, - out_bad_code, - out_balance_insufficient, - out_aborted, - out_no_retry, - out_no_cashout_payto - FROM cashout_confirm(?, ?, ?, ?); - """) - stmt.setLong(1, id) - stmt.setString(2, login) - stmt.setString(3, tanCode) - stmt.setLong(4, timestamp.toDbMicros() ?: throw faultyTimestampByBank()) - stmt.executeQuery().use { - when { - !it.next() -> - throw internalServerError("No result from DB procedure cashout_create") - it.getBoolean("out_no_op") -> CashoutConfirmationResult.OP_NOT_FOUND - it.getBoolean("out_bad_code") -> CashoutConfirmationResult.BAD_TAN_CODE - it.getBoolean("out_balance_insufficient") -> CashoutConfirmationResult.BALANCE_INSUFFICIENT - it.getBoolean("out_aborted") -> CashoutConfirmationResult.ABORTED - it.getBoolean("out_no_retry") -> CashoutConfirmationResult.NO_RETRY - it.getBoolean("out_no_cashout_payto") -> CashoutConfirmationResult.NO_CASHOUT_PAYTO - it.getBoolean("out_bad_conversion") -> CashoutConfirmationResult.BAD_CONVERSION - else -> CashoutConfirmationResult.SUCCESS + it.getBoolean("out_no_cashout_payto") -> CashoutCreationResult.NoCashoutPayto + it.getBoolean("out_tan_required") -> CashoutCreationResult.TanRequired + else -> CashoutCreationResult.Success(it.getLong("out_cashout_id")) } } } @@ -200,12 +90,7 @@ class CashoutDAO(private val db: Database) { suspend fun get(id: Long, login: String): CashoutStatusResponse? = db.conn { conn -> val stmt = conn.prepareStatement(""" SELECT - CASE - WHEN aborted THEN 'aborted' - WHEN local_transaction IS NOT NULL THEN 'confirmed' - ELSE 'pending' - END as status - ,(amount_debit).val as amount_debit_val + (amount_debit).val as amount_debit_val ,(amount_debit).frac as amount_debit_frac ,(amount_credit).val as amount_credit_val ,(amount_credit).frac as amount_credit_frac @@ -213,7 +98,10 @@ class CashoutDAO(private val db: Database) { ,creation_time ,transaction_date as confirmation_date ,tan_channel - ,tan_info + ,CASE tan_channel + WHEN 'sms' THEN phone + WHEN 'email' THEN email + END as tan_info FROM cashout_operations JOIN bank_accounts ON bank_account=bank_account_id JOIN customers ON owning_customer_id=customer_id @@ -224,7 +112,7 @@ class CashoutDAO(private val db: Database) { stmt.setString(2, login) stmt.oneOrNull { CashoutStatusResponse( - status = CashoutStatus.valueOf(it.getString("status")), + status = CashoutStatus.confirmed, amount_debit = it.getAmount("amount_debit", db.bankCurrency), amount_credit = it.getAmount("amount_credit", db.fiatCurrency!!), subject = it.getString("subject"), @@ -245,11 +133,6 @@ class CashoutDAO(private val db: Database) { SELECT cashout_id ,login - ,CASE - WHEN aborted THEN 'aborted' - WHEN local_transaction IS NOT NULL THEN 'confirmed' - ELSE 'pending' - END as status FROM cashout_operations JOIN bank_accounts ON bank_account=bank_account_id JOIN customers ON owning_customer_id=customer_id @@ -258,20 +141,14 @@ class CashoutDAO(private val db: Database) { GlobalCashoutInfo( cashout_id = it.getLong("cashout_id"), username = it.getString("login"), - status = CashoutStatus.valueOf(it.getString("status")) + status = CashoutStatus.confirmed ) } /** Get a page of all cashout operations owned by [login] */ suspend fun pageForUser(params: PageParams, login: String): List<CashoutInfo> = db.page(params, "cashout_id", """ - SELECT - cashout_id - ,CASE - WHEN aborted THEN 'aborted' - WHEN local_transaction IS NOT NULL THEN 'confirmed' - ELSE 'pending' - END as status + SELECT cashout_id FROM cashout_operations JOIN bank_accounts ON bank_account=bank_account_id JOIN customers ON owning_customer_id=customer_id @@ -284,7 +161,7 @@ class CashoutDAO(private val db: Database) { ) { CashoutInfo( cashout_id = it.getLong("cashout_id"), - status = CashoutStatus.valueOf(it.getString("status")) + status = CashoutStatus.confirmed ) } }
\ No newline at end of file |