summaryrefslogtreecommitdiff
path: root/bank/src/main/kotlin/tech/libeufin/bank/params.kt
diff options
context:
space:
mode:
Diffstat (limited to 'bank/src/main/kotlin/tech/libeufin/bank/params.kt')
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/params.kt176
1 files changed, 176 insertions, 0 deletions
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/params.kt b/bank/src/main/kotlin/tech/libeufin/bank/params.kt
new file mode 100644
index 00000000..f0c6e474
--- /dev/null
+++ b/bank/src/main/kotlin/tech/libeufin/bank/params.kt
@@ -0,0 +1,176 @@
+/*
+ * This file is part of LibEuFin.
+ * Copyright (C) 2023 Taler Systems S.A.
+
+ * LibEuFin is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation; either version 3, or
+ * (at your option) any later version.
+
+ * LibEuFin is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General
+ * Public License for more details.
+
+ * You should have received a copy of the GNU Affero General Public
+ * License along with LibEuFin; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>
+ */
+
+package tech.libeufin.bank
+
+import io.ktor.http.*
+import tech.libeufin.common.TalerAmount
+import tech.libeufin.common.TalerErrorCode
+import java.time.OffsetDateTime
+import java.time.ZoneOffset
+import java.time.temporal.TemporalAdjusters
+import java.util.UUID
+
+fun Parameters.expect(name: String): String
+ = get(name) ?: throw badRequest("Missing '$name' parameter", TalerErrorCode.GENERIC_PARAMETER_MISSING)
+fun Parameters.int(name: String): Int?
+ = get(name)?.run { toIntOrNull() ?: throw badRequest("Param '$name' not a number", TalerErrorCode.GENERIC_PARAMETER_MALFORMED) }
+fun Parameters.expectInt(name: String): Int
+ = int(name) ?: throw badRequest("Missing '$name' number parameter", TalerErrorCode.GENERIC_PARAMETER_MISSING)
+fun Parameters.long(name: String): Long?
+ = get(name)?.run { toLongOrNull() ?: throw badRequest("Param '$name' not a number", TalerErrorCode.GENERIC_PARAMETER_MALFORMED) }
+fun Parameters.expectLong(name: String): Long
+ = long(name) ?: throw badRequest("Missing '$name' number parameter", TalerErrorCode.GENERIC_PARAMETER_MISSING)
+fun Parameters.uuid(name: String): UUID? {
+ return get(name)?.run {
+ try {
+ UUID.fromString(this)
+ } catch (e: Exception) {
+ println("$this $e")
+ throw badRequest("Param '$name' not an UUID", TalerErrorCode.GENERIC_PARAMETER_MALFORMED)
+ }
+ }
+}
+fun Parameters.expectUuid(name: String): UUID
+ = uuid(name) ?: throw badRequest("Missing '$name' UUID parameter", TalerErrorCode.GENERIC_PARAMETER_MISSING)
+fun Parameters.amount(name: String): TalerAmount?
+ = get(name)?.run {
+ try {
+ TalerAmount(this)
+ } catch (e: Exception) {
+ throw badRequest("Param '$name' not a taler amount", TalerErrorCode.GENERIC_PARAMETER_MALFORMED)
+ }
+ }
+
+data class MonitorParams(
+ val timeframe: Timeframe,
+ val which: Int?
+) {
+ companion object {
+ val names = Timeframe.entries.map { it.name }
+ val names_fmt = names.joinToString()
+ fun extract(params: Parameters): MonitorParams {
+ val raw = params.get("timeframe") ?: "hour"
+ if (!names.contains(raw)) {
+ throw badRequest("Param 'timeframe' must be one of $names_fmt", TalerErrorCode.GENERIC_PARAMETER_MALFORMED)
+ }
+ val timeframe = Timeframe.valueOf(raw)
+ val which = params.int("which")
+ if (which != null) {
+ val lastDayOfMonth = OffsetDateTime.now(ZoneOffset.UTC).with(TemporalAdjusters.lastDayOfMonth()).dayOfMonth
+ when {
+ timeframe == Timeframe.hour && (0 > which || which > 23) ->
+ throw badRequest("For hour timestamp param 'which' must be between 00 to 23", TalerErrorCode.GENERIC_PARAMETER_MALFORMED)
+ timeframe == Timeframe.day && (1 > which || which > lastDayOfMonth) ->
+ throw badRequest("For day timestamp param 'which' must be between 1 to $lastDayOfMonth", TalerErrorCode.GENERIC_PARAMETER_MALFORMED)
+ timeframe == Timeframe.month && (1 > which || which > 12) ->
+ throw badRequest("For month timestamp param 'which' must be between 1 to 12", TalerErrorCode.GENERIC_PARAMETER_MALFORMED)
+ timeframe == Timeframe.year && (1 > which|| which > 9999) ->
+ throw badRequest("For year timestamp param 'which' must be between 0001 to 9999", TalerErrorCode.GENERIC_PARAMETER_MALFORMED)
+ else -> {}
+ }
+ }
+ return MonitorParams(timeframe, which)
+ }
+ }
+}
+
+data class AccountParams(
+ val page: PageParams, val loginFilter: String
+) {
+ companion object {
+ fun extract(params: Parameters): AccountParams {
+ val loginFilter = params.get("filter_name")?.run { "%$this%" } ?: "%"
+ return AccountParams(PageParams.extract(params), loginFilter)
+ }
+ }
+}
+
+data class PageParams(
+ val delta: Int, val start: Long
+) {
+ companion object {
+ fun extract(params: Parameters): PageParams {
+ val delta: Int = params.int("delta") ?: -20
+ val start: Long = params.long("start") ?: if (delta >= 0) 0L else Long.MAX_VALUE
+ if (start < 0) throw badRequest("Param 'start' must be a positive number", TalerErrorCode.GENERIC_PARAMETER_MALFORMED)
+ // TODO enforce delta limit
+ return PageParams(delta, start)
+ }
+ }
+}
+
+data class PollingParams(
+ val poll_ms: Long
+) {
+ companion object {
+ fun extract(params: Parameters): PollingParams {
+ val poll_ms: Long = params.long("long_poll_ms") ?: 0
+ if (poll_ms < 0) throw badRequest("Param 'long_poll_ms' must be a positive number", TalerErrorCode.GENERIC_PARAMETER_MALFORMED)
+ return PollingParams(poll_ms)
+ }
+ }
+}
+
+data class HistoryParams(
+ val page: PageParams, val polling: PollingParams
+) {
+ companion object {
+ fun extract(params: Parameters): HistoryParams {
+ return HistoryParams(PageParams.extract(params), PollingParams.extract(params))
+ }
+ }
+}
+
+data class RateParams(
+ val debit: TalerAmount?, val credit: TalerAmount?
+) {
+ companion object {
+ fun extract(params: Parameters): RateParams {
+ val debit = params.amount("amount_debit")
+ val credit = params.amount("amount_credit")
+ if (debit == null && credit == null) {
+ throw badRequest("Either param 'amount_debit' or 'amount_credit' is required", TalerErrorCode.GENERIC_PARAMETER_MISSING)
+ } else if (debit != null && credit != null) {
+ throw badRequest("Cannot have both 'amount_debit' and 'amount_credit' params", TalerErrorCode.GENERIC_PARAMETER_MALFORMED)
+ }
+ return RateParams(debit, credit)
+ }
+ }
+}
+
+data class StatusParams(
+ val polling: PollingParams,
+ val old_state: WithdrawalStatus
+) {
+ companion object {
+ val names = WithdrawalStatus.entries.map { it.name }
+ val names_fmt = names.joinToString()
+ fun extract(params: Parameters): StatusParams {
+ val old_state = params.get("old_state") ?: "pending"
+ if (!names.contains(old_state)) {
+ throw badRequest("Param 'old_state' must be one of $names_fmt", TalerErrorCode.GENERIC_PARAMETER_MALFORMED)
+ }
+ return StatusParams(
+ polling = PollingParams.extract(params),
+ old_state = WithdrawalStatus.valueOf(old_state)
+ )
+ }
+ }
+} \ No newline at end of file