From 23dd3cd9e783955b2badc5dab850468512e6cae7 Mon Sep 17 00:00:00 2001 From: Iván Ávalos Date: Sun, 12 Feb 2023 20:33:10 -0600 Subject: [wallet] Added serializer for unknown fields in TalerErrorInfo. --- .../net/taler/wallet/backend/WalletBackendApi.kt | 2 +- .../net/taler/wallet/backend/WalletResponse.kt | 63 ++++++++++++---------- .../wallet/peer/OutgoingPullResultComposable.kt | 4 +- .../wallet/peer/OutgoingPushResultComposable.kt | 4 +- .../transactions/TransactionWithdrawalFragment.kt | 2 +- .../wallet/transactions/TransactionsFragment.kt | 16 +++--- 6 files changed, 50 insertions(+), 41 deletions(-) diff --git a/wallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt b/wallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt index 9fc5cac..8ec5873 100644 --- a/wallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt +++ b/wallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt @@ -165,7 +165,7 @@ class WalletBackendApi( WalletResponse.Success(t) } } catch (e: Exception) { - val info = TalerErrorInfo(NONE, "", e.toString(), null) + val info = TalerErrorInfo(NONE, "", e.toString()) WalletResponse.Error(info) } cont.resume(response) diff --git a/wallet/src/main/java/net/taler/wallet/backend/WalletResponse.kt b/wallet/src/main/java/net/taler/wallet/backend/WalletResponse.kt index 414d784..22dcba9 100644 --- a/wallet/src/main/java/net/taler/wallet/backend/WalletResponse.kt +++ b/wallet/src/main/java/net/taler/wallet/backend/WalletResponse.kt @@ -19,13 +19,14 @@ package net.taler.wallet.backend import kotlinx.serialization.KSerializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import kotlinx.serialization.descriptors.PrimitiveKind.STRING -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.builtins.MapSerializer +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.json.JsonDecoder -import kotlinx.serialization.json.JsonObject -import org.json.JSONObject +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.jsonPrimitive @Serializable sealed class WalletResponse { @@ -52,7 +53,7 @@ sealed class WalletResponse { } } -@Serializable +@Serializable(with = TalerErrorInfoDeserializer::class) data class TalerErrorInfo( // Numeric error code defined defined in the // GANA gnu-taler-error-codes registry. @@ -65,42 +66,50 @@ data class TalerErrorInfo( // for the instance of the error. val message: String? = null, - // Error details - @Serializable(JSONObjectDeserializer::class) - val details: JSONObject? = null, - - // KYC URL (in case KYC is required) - val kycUrl: String? = null, + // Error extra details + val extra: Map = mapOf(), ) { val userFacingMsg: String get() { return StringBuilder().apply { hint?.let { append(it) } message?.let { append(" ").append(it) } - details?.let { details -> - if (details.length() > 0) { - append("\n\n") - details.optJSONObject("errorResponse")?.let { errorResponse -> - append(errorResponse.optString("code")).append(" ") - append(errorResponse.optString("hint")) - } ?: append(details.toString(2)) - } - } }.toString() } + + fun getStringExtra(key: String): String? = + extra[key]?.jsonPrimitive?.content } -class JSONObjectDeserializer : KSerializer { +class TalerErrorInfoDeserializer : KSerializer { + private val stringToJsonElementSerializer = MapSerializer(String.serializer(), JsonElement.serializer()) + + override val descriptor: SerialDescriptor + get() = stringToJsonElementSerializer.descriptor + + override fun deserialize(decoder: Decoder): TalerErrorInfo { + // Decoder -> JsonInput + require(decoder is JsonDecoder) + val json = decoder.json + val filtersMap = decoder.decodeSerializableValue(stringToJsonElementSerializer) + + val code = filtersMap["code"]?.let { + json.decodeFromJsonElement(TalerErrorCode.serializer(), it) + } ?: TalerErrorCode.UNKNOWN + val hint = filtersMap["hint"]?.let { + json.decodeFromJsonElement(String.serializer(), it) + } + val message = filtersMap["message"]?.let { + json.decodeFromJsonElement(String.serializer(), it) + } - override val descriptor = PrimitiveSerialDescriptor("JSONObjectDeserializer", STRING) + val knownKeys = setOf("code", "hint", "message") + val unknownFilters = filtersMap.filter { (key, _) -> !knownKeys.contains(key) } - override fun deserialize(decoder: Decoder): JSONObject { - val input = decoder as JsonDecoder - val tree = input.decodeJsonElement() as JsonObject - return JSONObject(tree.toString()) + return TalerErrorInfo(code, hint, message, unknownFilters) } - override fun serialize(encoder: Encoder, value: JSONObject) { + override fun serialize(encoder: Encoder, value: TalerErrorInfo) { error("not supported") } } diff --git a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullResultComposable.kt b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullResultComposable.kt index a68ae16..e6d9ec9 100644 --- a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullResultComposable.kt +++ b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullResultComposable.kt @@ -35,6 +35,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import kotlinx.serialization.json.JsonPrimitive import net.taler.common.QrCodeManager import net.taler.wallet.R import net.taler.wallet.backend.TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED @@ -42,7 +43,6 @@ import net.taler.wallet.backend.TalerErrorInfo import net.taler.wallet.compose.QrCodeUriComposable import net.taler.wallet.compose.TalerSurface import net.taler.wallet.compose.getQrCodeSize -import org.json.JSONObject @Composable fun OutgoingPullResultComposable(state: OutgoingState, onClose: () -> Unit) { @@ -141,7 +141,7 @@ fun PeerPullResponseLandscapePreview() { @Composable fun PeerPullErrorPreview() { Surface { - val json = JSONObject().apply { put("foo", "bar") } + val json = mapOf("foo" to JsonPrimitive("bar")) val response = OutgoingError(TalerErrorInfo(WALLET_WITHDRAWAL_KYC_REQUIRED, "hint", "message", json)) OutgoingPullResultComposable(response) {} } diff --git a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushResultComposable.kt b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushResultComposable.kt index d81ec64..0fb3f2c 100644 --- a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushResultComposable.kt +++ b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushResultComposable.kt @@ -35,6 +35,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import kotlinx.serialization.json.JsonPrimitive import net.taler.common.QrCodeManager import net.taler.wallet.R import net.taler.wallet.backend.TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED @@ -42,7 +43,6 @@ import net.taler.wallet.backend.TalerErrorInfo import net.taler.wallet.compose.QrCodeUriComposable import net.taler.wallet.compose.TalerSurface import net.taler.wallet.compose.getQrCodeSize -import org.json.JSONObject @Composable fun OutgoingPushResultComposable(state: OutgoingState, onClose: () -> Unit) { @@ -141,7 +141,7 @@ fun PeerPushResponseLandscapePreview() { @Composable fun PeerPushErrorPreview() { Surface { - val json = JSONObject().apply { put("foo", "bar") } + val json = mapOf("foo" to JsonPrimitive("bar")) val response = OutgoingError(TalerErrorInfo(WALLET_WITHDRAWAL_KYC_REQUIRED, "hint", "message", json)) OutgoingPushResultComposable(response) {} } diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionWithdrawalFragment.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionWithdrawalFragment.kt index ffc9005..fe255ad 100644 --- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionWithdrawalFragment.kt +++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionWithdrawalFragment.kt @@ -111,7 +111,7 @@ class TransactionWithdrawalFragment : TransactionDetailFragment() { private fun setupActionButton(t: TransactionWithdrawal) { ui.actionButton.visibility = t.handleKyc({ GONE }) { error -> ui.actionButton.setText(R.string.transaction_action_kyc) - error.kycUrl?.let { kycUrl -> + error.getStringExtra("kycUrl")?.let { kycUrl -> ui.actionButton.setOnClickListener { launchInAppBrowser(requireContext(), kycUrl) } diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt index d67d9b3..cd66193 100644 --- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt +++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt @@ -180,17 +180,17 @@ class TransactionsFragment : Fragment(), OnTransactionClickListener, ActionMode. } } - override fun onActionButtonClicked(t: Transaction) { - if (t.error != null) { - t.handleKyc({ error("Unhandled Action Button Event") }) { error -> - error.kycUrl?.let { + override fun onActionButtonClicked(transaction: Transaction) { + if (transaction.error != null) { + transaction.handleKyc({ error("Unhandled Action Button Event") }) { error -> + error.getStringExtra("kycUrl")?.let { launchInAppBrowser(requireContext(), it) } } - } else if (t is TransactionWithdrawal && !t.confirmed) { - if (t.withdrawalDetails is WithdrawalDetails.TalerBankIntegrationApi && - t.withdrawalDetails.bankConfirmationUrl != null) { - launchInAppBrowser(requireContext(), t.withdrawalDetails.bankConfirmationUrl) + } else if (transaction is TransactionWithdrawal && !transaction.confirmed) { + if (transaction.withdrawalDetails is WithdrawalDetails.TalerBankIntegrationApi && + transaction.withdrawalDetails.bankConfirmationUrl != null) { + launchInAppBrowser(requireContext(), transaction.withdrawalDetails.bankConfirmationUrl) } } } -- cgit v1.2.3