gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-taler-android] branch master updated (35f7ed5 -> 78096ab)


From: gnunet
Subject: [taler-taler-android] branch master updated (35f7ed5 -> 78096ab)
Date: Wed, 05 Aug 2020 20:49:46 +0200

This is an automated email from the git hooks/post-receive script.

torsten-grote pushed a change to branch master
in repository taler-android.

    from 35f7ed5  [pos] Implement new refund API (untested since there is no 
wallet support)
     new b1acd03  [wallet] show more user-friendly error messages for operations
     new 78096ab  [wallet] support Timestamp with "never"

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../main/java/net/taler/common/TimestampMixin.kt   | 12 ++++++
 .../java/net/taler/common/ContractTermsTest.kt     |  5 ++-
 .../src/commonMain/kotlin/net/taler/common/Time.kt | 29 ++++++++++++-
 .../commonTest/kotlin/net/taler/common/TimeTest.kt | 49 ++++++++++++++++++++++
 wallet/src/main/java/net/taler/wallet/Utils.kt     | 17 ++++++++
 .../net/taler/wallet/payment/PaymentManager.kt     |  8 ++--
 .../wallet/pending/PendingOperationsManager.kt     |  2 +-
 .../java/net/taler/wallet/refund/RefundManager.kt  |  1 +
 .../wallet/transactions/TransactionManager.kt      |  5 ++-
 .../wallet/transactions/TransactionsFragment.kt    |  4 +-
 .../net/taler/wallet/withdraw/WithdrawManager.kt   |  4 +-
 wallet/src/main/res/values-fr/strings.xml          |  2 +-
 wallet/src/main/res/values/strings.xml             |  2 +-
 13 files changed, 125 insertions(+), 15 deletions(-)
 create mode 100644 
taler-kotlin-common/src/commonTest/kotlin/net/taler/common/TimeTest.kt

diff --git 
a/taler-kotlin-android/src/main/java/net/taler/common/TimestampMixin.kt 
b/taler-kotlin-android/src/main/java/net/taler/common/TimestampMixin.kt
index 28dbe7f..6c1bebf 100644
--- a/taler-kotlin-android/src/main/java/net/taler/common/TimestampMixin.kt
+++ b/taler-kotlin-android/src/main/java/net/taler/common/TimestampMixin.kt
@@ -17,11 +17,23 @@
 package net.taler.common
 
 import com.fasterxml.jackson.annotation.JsonProperty
+import com.fasterxml.jackson.core.JsonParser
+import com.fasterxml.jackson.databind.DeserializationContext
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer
 
 /**
  * Used to support Jackson serialization along with KotlinX.
  */
 abstract class TimestampMixin(
+    @get:JsonDeserialize(using = NeverDeserializer::class)
     @get:JsonProperty("t_ms")
     val ms: Long
 )
+
+class NeverDeserializer : StdDeserializer<Long>(Long::class.java) {
+    override fun deserialize(p: JsonParser, ctxt: DeserializationContext): 
Long {
+        return if (p.text == "never") -1
+        else p.longValue
+    }
+}
diff --git 
a/taler-kotlin-android/src/test/java/net/taler/common/ContractTermsTest.kt 
b/taler-kotlin-android/src/test/java/net/taler/common/ContractTermsTest.kt
index 79a7598..077ff51 100644
--- a/taler-kotlin-android/src/test/java/net/taler/common/ContractTermsTest.kt
+++ b/taler-kotlin-android/src/test/java/net/taler/common/ContractTermsTest.kt
@@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature
 import com.fasterxml.jackson.databind.ObjectMapper
 import com.fasterxml.jackson.module.kotlin.KotlinModule
 import com.fasterxml.jackson.module.kotlin.readValue
+import net.taler.common.Timestamp.Companion.NEVER
 import org.junit.Assert.assertEquals
 import org.junit.Test
 
@@ -29,6 +30,7 @@ class ContractTermsTest {
         .registerModule(KotlinModule())
         .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
         .addMixIn(Amount::class.java, AmountMixin::class.java)
+        .addMixIn(Timestamp::class.java, TimestampMixin::class.java)
 
     @Test
     fun test() {
@@ -40,7 +42,7 @@ class ContractTermsTest {
               },
               
"fulfillment_url":"https://shop.test.taler.net/essay/1._The_Free_Software_Definition";,
               "summary":"Essay: 1. The Free Software Definition",
-              "refund_deadline":{"t_ms":1596128414000},
+              "refund_deadline":{"t_ms":"never"},
               "wire_transfer_deadline":{"t_ms":1596128564000},
               "products":[],
               
"h_wire":"KV40K023N8EC1F5100TYNS23C4XN68Y1Z3PTJSWFGTMCNYD54KT4S791V2VQ91SZANN86VDAA369M4VEZ0KR6DN71EVRRZA71K681M0",
@@ -69,6 +71,7 @@ class ContractTermsTest {
         """.trimIndent()
         val contractTerms: ContractTerms = mapper.readValue(json)
         assertEquals("Essay: 1. The Free Software Definition", 
contractTerms.summary)
+        assertEquals(Timestamp(NEVER), contractTerms.refundDeadline)
     }
 
 }
diff --git a/taler-kotlin-common/src/commonMain/kotlin/net/taler/common/Time.kt 
b/taler-kotlin-common/src/commonMain/kotlin/net/taler/common/Time.kt
index 962e004..37b6606 100644
--- a/taler-kotlin-common/src/commonMain/kotlin/net/taler/common/Time.kt
+++ b/taler-kotlin-common/src/commonMain/kotlin/net/taler/common/Time.kt
@@ -18,6 +18,12 @@ package net.taler.common
 
 import kotlinx.serialization.SerialName
 import kotlinx.serialization.Serializable
+import kotlinx.serialization.builtins.serializer
+import kotlinx.serialization.json.JsonElement
+import kotlinx.serialization.json.JsonPrimitive
+import kotlinx.serialization.json.JsonTransformingSerializer
+import kotlinx.serialization.json.contentOrNull
+import kotlinx.serialization.json.longOrNull
 import net.taler.common.Duration.Companion.FOREVER
 import kotlin.math.max
 
@@ -26,11 +32,12 @@ expect fun nowMillis(): Long
 @Serializable
 data class Timestamp(
     @SerialName("t_ms")
+    @Serializable(NeverSerializer::class)
     val ms: Long
 ) : Comparable<Timestamp> {
 
     companion object {
-        const val NEVER: Long = -1  // TODO or UINT64_MAX?
+        const val NEVER: Long = -1
         fun now(): Timestamp = Timestamp(nowMillis())
     }
 
@@ -73,9 +80,27 @@ data class Duration(
      * Duration in milliseconds.
      */
     @SerialName("d_ms")
+    @Serializable(ForeverSerializer::class)
     val ms: Long
 ) {
     companion object {
-        const val FOREVER: Long = -1  // TODO or UINT64_MAX?
+        const val FOREVER: Long = -1
     }
 }
+
+abstract class MinusOneSerializer(private val keyword: String) :
+    JsonTransformingSerializer<Long>(Long.serializer(), keyword) {
+
+    override fun readTransform(element: JsonElement): JsonElement {
+        return if (element.contentOrNull == keyword) return JsonPrimitive(-1)
+        else super.readTransform(element)
+    }
+
+    override fun writeTransform(element: JsonElement): JsonElement {
+        return if (element.longOrNull == -1L) return JsonPrimitive(keyword)
+        else element
+    }
+}
+
+object NeverSerializer : MinusOneSerializer("never")
+object ForeverSerializer : MinusOneSerializer("forever")
diff --git 
a/taler-kotlin-common/src/commonTest/kotlin/net/taler/common/TimeTest.kt 
b/taler-kotlin-common/src/commonTest/kotlin/net/taler/common/TimeTest.kt
new file mode 100644
index 0000000..3ee0a99
--- /dev/null
+++ b/taler-kotlin-common/src/commonTest/kotlin/net/taler/common/TimeTest.kt
@@ -0,0 +1,49 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2020 Taler Systems S.A.
+ *
+ * GNU Taler is free software; you can redistribute it and/or modify it under 
the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 3, or (at your option) any later version.
+ *
+ * GNU Taler 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+package net.taler.common
+
+import kotlinx.serialization.UnstableDefault
+import kotlinx.serialization.json.Json.Default.parse
+import kotlinx.serialization.json.Json.Default.stringify
+import net.taler.common.Timestamp.Companion.NEVER
+import kotlin.random.Random
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+// TODO test other functionality of Timestamp and Duration
+@UnstableDefault
+class TimeTest {
+
+    @Test
+    fun testSerialize() {
+        for (i in 0 until 42) {
+            val t = Random.nextLong()
+            assertEquals("""{"t_ms":$t}""", stringify(Timestamp.serializer(), 
Timestamp(t)))
+        }
+        assertEquals("""{"t_ms":"never"}""", stringify(Timestamp.serializer(), 
Timestamp(NEVER)))
+    }
+
+    @Test
+    fun testDeserialize() {
+        for (i in 0 until 42) {
+            val t = Random.nextLong()
+            assertEquals(Timestamp(t), parse(Timestamp.serializer(), """{ 
"t_ms": $t }"""))
+        }
+        assertEquals(Timestamp(NEVER), parse(Timestamp.serializer(), """{ 
"t_ms": "never" }"""))
+    }
+
+}
diff --git a/wallet/src/main/java/net/taler/wallet/Utils.kt 
b/wallet/src/main/java/net/taler/wallet/Utils.kt
index e299245..ea01552 100644
--- a/wallet/src/main/java/net/taler/wallet/Utils.kt
+++ b/wallet/src/main/java/net/taler/wallet/Utils.kt
@@ -30,6 +30,7 @@ import android.widget.Toast
 import android.widget.Toast.LENGTH_LONG
 import androidx.annotation.RequiresApi
 import com.google.zxing.integration.android.IntentIntegrator
+import org.json.JSONObject
 
 fun scanQrCode(activity: Activity) {
     IntentIntegrator(activity).apply {
@@ -90,6 +91,22 @@ private fun connectToWifiDeprecated(context: Context, ssid: 
String) {
     }
 }
 
+fun getErrorString(json: JSONObject): String {
+    return StringBuilder().apply {
+        append(json.getString("talerErrorCode"))
+        append(" ")
+        append(json.getString("message"))
+        json.optJSONObject("details")?.let { details ->
+            details.optJSONObject("errorResponse")?.let { errorResponse ->
+                append("\n\n")
+                append(errorResponse.optString("code"))
+                append(" ")
+                append(errorResponse.optString("hint"))
+            }
+        }
+    }.toString()
+}
+
 fun cleanExchange(exchange: String) = exchange.let {
     if (it.startsWith("https://";)) it.substring(8) else it
 }.trimEnd('/')
diff --git a/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt 
b/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt
index 2427afb..db21da4 100644
--- a/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/payment/PaymentManager.kt
@@ -26,6 +26,7 @@ import net.taler.common.Amount
 import net.taler.common.ContractTerms
 import net.taler.wallet.TAG
 import net.taler.wallet.backend.WalletBackendApi
+import net.taler.wallet.getErrorString
 import net.taler.wallet.payment.PayStatus.AlreadyPaid
 import net.taler.wallet.payment.PayStatus.InsufficientBalance
 import net.taler.wallet.payment.PreparePayResponse.AlreadyConfirmedResponse
@@ -71,7 +72,7 @@ class PaymentManager(
         val args = JSONObject(mapOf("talerPayUri" to url))
         walletBackendApi.sendRequest("preparePay", args) { isError, result ->
             if (isError) {
-                handleError("preparePay", result.toString(2))
+                handleError("preparePay", getErrorString(result))
                 return@sendRequest
             }
             val response: PreparePayResponse = 
mapper.readValue(result.toString())
@@ -84,6 +85,7 @@ class PaymentManager(
         }
     }
 
+    // TODO validate product images (or leave to wallet-core?)
     private fun getContractTerms(json: JSONObject): ContractTerms {
         val terms: ContractTerms = 
mapper.readValue(json.getString("contractTermsRaw"))
         // validate product images
@@ -101,7 +103,7 @@ class PaymentManager(
         val args = JSONObject(mapOf("proposalId" to proposalId))
         walletBackendApi.sendRequest("confirmPay", args) { isError, result ->
             if (isError) {
-                handleError("preparePay", result.toString())
+                handleError("preparePay", getErrorString(result))
                 return@sendRequest
             }
             mPayStatus.postValue(PayStatus.Success(currency))
@@ -124,7 +126,7 @@ class PaymentManager(
 
         walletBackendApi.sendRequest("abortProposal", args) { isError, result 
->
             if (isError) {
-                handleError("abortProposal", result.toString(2))
+                handleError("abortProposal", getErrorString(result))
                 Log.e(TAG, "received error response to abortProposal")
                 return@sendRequest
             }
diff --git 
a/wallet/src/main/java/net/taler/wallet/pending/PendingOperationsManager.kt 
b/wallet/src/main/java/net/taler/wallet/pending/PendingOperationsManager.kt
index 7027687..df778ed 100644
--- a/wallet/src/main/java/net/taler/wallet/pending/PendingOperationsManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/pending/PendingOperationsManager.kt
@@ -34,7 +34,7 @@ class PendingOperationsManager(private val walletBackendApi: 
WalletBackendApi) {
     internal fun getPending() {
         walletBackendApi.sendRequest("getPendingOperations") { isError, result 
->
             if (isError) {
-                Log.i(TAG, "got getPending error result: $result")
+                Log.i(TAG, "got getPending error result: 
${result.toString(2)}")
                 return@sendRequest
             }
             Log.i(TAG, "got getPending result")
diff --git a/wallet/src/main/java/net/taler/wallet/refund/RefundManager.kt 
b/wallet/src/main/java/net/taler/wallet/refund/RefundManager.kt
index 21c634e..5593486 100644
--- a/wallet/src/main/java/net/taler/wallet/refund/RefundManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/refund/RefundManager.kt
@@ -36,6 +36,7 @@ class RefundManager(private val walletBackendApi: 
WalletBackendApi) {
         walletBackendApi.sendRequest("applyRefund", args) { isError, result ->
             if (isError) {
                 Log.e(TAG, "Refund Error: $result")
+                // TODO show error string
                 liveData.postValue(RefundStatus.Error)
             } else {
                 Log.e(TAG, "Refund Success: $result")
diff --git 
a/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt 
b/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
index bd37b37..8ec3914 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionManager.kt
@@ -27,12 +27,13 @@ import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 import net.taler.wallet.backend.WalletBackendApi
+import net.taler.wallet.getErrorString
 import org.json.JSONObject
 import java.util.HashMap
 import java.util.LinkedList
 
 sealed class TransactionsResult {
-    object Error : TransactionsResult()
+    class Error(val msg: String) : TransactionsResult()
     class Success(val transactions: List<Transaction>) : TransactionsResult()
 }
 
@@ -72,7 +73,7 @@ class TransactionManager(
         searchQuery?.let { request.put("search", it) }
         walletBackendApi.sendRequest("getTransactions", request) { isError, 
result ->
             if (isError) {
-                liveData.postValue(TransactionsResult.Error)
+                
liveData.postValue(TransactionsResult.Error(getErrorString(result)))
                 mProgress.postValue(false)
             } else {
                 val currencyToUpdate = if (searchQuery == null) currency else 
null
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 2ae58c3..8d47a3f 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
@@ -160,9 +160,9 @@ class TransactionsFragment : Fragment(), 
OnTransactionClickListener, ActionMode.
     }
 
     private fun onTransactionsResult(result: TransactionsResult) = when 
(result) {
-        TransactionsResult.Error -> {
+        is TransactionsResult.Error -> {
             list.fadeOut()
-            emptyState.text = getString(R.string.transactions_error)
+            emptyState.text = getString(R.string.transactions_error, 
result.msg)
             emptyState.fadeIn()
         }
         is TransactionsResult.Success -> {
diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt 
b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt
index e14a747..6fb9390 100644
--- a/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/withdraw/WithdrawManager.kt
@@ -26,6 +26,7 @@ import net.taler.wallet.TAG
 import net.taler.wallet.backend.WalletBackendApi
 import net.taler.wallet.exchanges.ExchangeFees
 import net.taler.wallet.exchanges.ExchangeItem
+import net.taler.wallet.getErrorString
 import net.taler.wallet.withdraw.WithdrawStatus.ReceivedDetails
 import org.json.JSONObject
 
@@ -196,8 +197,7 @@ class WithdrawManager(
     @UiThread
     private fun handleError(operation: String, result: JSONObject) {
         Log.e(TAG, "Error $operation ${result.toString(2)}")
-        val message = if (result.has("message")) result.getString("message") 
else null
-        withdrawStatus.value = WithdrawStatus.Error(message)
+        withdrawStatus.value = WithdrawStatus.Error(getErrorString(result))
     }
 
 }
diff --git a/wallet/src/main/res/values-fr/strings.xml 
b/wallet/src/main/res/values-fr/strings.xml
index c4cac45..a96e23a 100644
--- a/wallet/src/main/res/values-fr/strings.xml
+++ b/wallet/src/main/res/values-fr/strings.xml
@@ -26,7 +26,7 @@
     <string name="balances_inbound_label">entrant</string>
     <string name="transactions_title">Transactions</string>
     <string name="transactions_empty">Vous n\'avez aucune transaction</string>
-    <string name="transactions_error">Impossible de charger les 
transactions</string>
+    <string name="transactions_error">Impossible de charger les 
transactions\n\n%s</string>
     <string name="transactions_detail_title">Transaction</string>
     <string name="transactions_detail_title_balance">Solde : %s</string>
     <string name="transactions_delete">Supprimer</string>
diff --git a/wallet/src/main/res/values/strings.xml 
b/wallet/src/main/res/values/strings.xml
index 1e629a6..1715ab3 100644
--- a/wallet/src/main/res/values/strings.xml
+++ b/wallet/src/main/res/values/strings.xml
@@ -70,7 +70,7 @@ GNU Taler is immune against many types of fraud, such as 
phishing of credit card
     <string name="transactions_title">Transactions</string>
     <string name="transactions_empty">You don\'t have any transactions</string>
     <string name="transactions_empty_search">No transactions found. Try a 
different search.</string>
-    <string name="transactions_error">Could not load transactions</string>
+    <string name="transactions_error">Could not load 
transactions\n\n%s</string>
     <string name="transactions_detail_title">Transaction</string>
     <string name="transactions_detail_title_balance">Balance: %s</string>
     <string name="transactions_delete">Delete</string>

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]