gnunet-svn
[Top][All Lists]
Advanced

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

[taler-taler-android] 02/03: [wallet] Proper DB import/export functional


From: gnunet
Subject: [taler-taler-android] 02/03: [wallet] Proper DB import/export functionality
Date: Tue, 28 Nov 2023 18:33:01 +0100

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

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

commit ba51b5e541d888cafdbf479a7e03a116af7050c5
Author: Iván Ávalos <avalos@disroot.org>
AuthorDate: Tue Nov 14 14:13:51 2023 -0600

    [wallet] Proper DB import/export functionality
---
 .../main/java/net/taler/wallet/MainViewModel.kt    |  2 +-
 .../net/taler/wallet/backend/WalletBackendApi.kt   | 23 ++++++
 .../net/taler/wallet/settings/SettingsFragment.kt  | 17 +++-
 .../net/taler/wallet/settings/SettingsManager.kt   | 91 ++++++++++++++++++----
 wallet/src/main/res/drawable/ic_archive.xml        | 21 +++++
 wallet/src/main/res/values/strings.xml             |  6 +-
 wallet/src/main/res/xml/settings_main.xml          |  8 ++
 7 files changed, 150 insertions(+), 18 deletions(-)

diff --git a/wallet/src/main/java/net/taler/wallet/MainViewModel.kt 
b/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
index 15fe7e4..4614474 100644
--- a/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
+++ b/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
@@ -83,7 +83,7 @@ class MainViewModel(
     val refundManager = RefundManager(api, viewModelScope)
     val exchangeManager: ExchangeManager = ExchangeManager(api, viewModelScope)
     val peerManager: PeerManager = PeerManager(api, exchangeManager, 
viewModelScope)
-    val settingsManager: SettingsManager = 
SettingsManager(app.applicationContext, viewModelScope)
+    val settingsManager: SettingsManager = 
SettingsManager(app.applicationContext, api, viewModelScope)
     val accountManager: AccountManager = AccountManager(api, viewModelScope)
     val depositManager: DepositManager = DepositManager(api, viewModelScope)
 
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 bf6f371..ea58dd7 100644
--- a/wallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt
+++ b/wallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt
@@ -23,6 +23,7 @@ import kotlinx.coroutines.GlobalScope
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 import kotlinx.serialization.KSerializer
+import kotlinx.serialization.json.JsonObject
 import kotlinx.serialization.json.decodeFromJsonElement
 import net.taler.wallet.backend.TalerErrorCode.NONE
 import org.json.JSONObject
@@ -86,4 +87,26 @@ class WalletBackendApi(
             WalletResponse.Error(info)
         }
     }
+
+    // Returns raw JSON response instead of serialized object
+    suspend inline fun rawRequest(
+        operation: String,
+        noinline args: (JSONObject.() -> JSONObject)? = null,
+    ): WalletResponse<JsonObject> = withContext(Dispatchers.Default) {
+        val json = BackendManager.json
+        try {
+            when (val response = sendRequest(operation, 
args?.invoke(JSONObject()))) {
+                is ApiResponse.Response -> {
+                    WalletResponse.Success(response.result)
+                }
+                is ApiResponse.Error -> {
+                    val error: TalerErrorInfo = 
json.decodeFromJsonElement(response.error)
+                    WalletResponse.Error(error)
+                }
+            }
+        } catch (e: Exception) {
+            val info = TalerErrorInfo(NONE, "", e.toString())
+            WalletResponse.Error(info)
+        }
+    }
 }
diff --git a/wallet/src/main/java/net/taler/wallet/settings/SettingsFragment.kt 
b/wallet/src/main/java/net/taler/wallet/settings/SettingsFragment.kt
index f5826c9..54d6dc0 100644
--- a/wallet/src/main/java/net/taler/wallet/settings/SettingsFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/settings/SettingsFragment.kt
@@ -18,6 +18,7 @@ package net.taler.wallet.settings
 
 import android.os.Bundle
 import android.view.View
+import androidx.activity.result.contract.ActivityResultContracts.OpenDocument
 import androidx.activity.result.contract.ActivityResultContracts.CreateDocument
 import androidx.fragment.app.activityViewModels
 import androidx.preference.Preference
@@ -47,6 +48,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
     private lateinit var prefWithdrawTest: Preference
     private lateinit var prefLogcat: Preference
     private lateinit var prefExportDb: Preference
+    private lateinit var prefImportDb: Preference
     private lateinit var prefVersionApp: Preference
     private lateinit var prefVersionCore: Preference
     private lateinit var prefVersionExchange: Preference
@@ -58,6 +60,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
             prefWithdrawTest,
             prefLogcat,
             prefExportDb,
+            prefImportDb,
             prefVersionApp,
             prefVersionCore,
             prefVersionExchange,
@@ -71,9 +74,13 @@ class SettingsFragment : PreferenceFragmentCompat() {
         settingsManager.exportLogcat(uri)
     }
     private val dbExportLauncher =
-        registerForActivityResult(CreateDocument("application/x-sqlite3")) { 
uri ->
+        registerForActivityResult(CreateDocument("application/json")) { uri ->
             settingsManager.exportDb(uri)
         }
+    private val dbImportLauncher =
+        registerForActivityResult(OpenDocument()) { uri ->
+            settingsManager.importDb(uri)
+        }
 
     override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: 
String?) {
         setPreferencesFromResource(R.xml.settings_main, rootKey)
@@ -81,6 +88,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
         prefWithdrawTest = findPreference("pref_testkudos")!!
         prefLogcat = findPreference("pref_logcat")!!
         prefExportDb = findPreference("pref_export_db")!!
+        prefImportDb = findPreference("pref_import_db")!!
         prefVersionApp = findPreference("pref_version_app")!!
         prefVersionCore = findPreference("pref_version_core")!!
         prefVersionExchange = 
findPreference("pref_version_protocol_exchange")!!
@@ -127,10 +135,13 @@ class SettingsFragment : PreferenceFragmentCompat() {
             true
         }
         prefExportDb.setOnPreferenceClickListener {
-            
dbExportLauncher.launch("taler-wallet-db-${currentTimeMillis()}.sql")
+            
dbExportLauncher.launch("taler-wallet-db-${currentTimeMillis()}.json")
+            true
+        }
+        prefImportDb.setOnPreferenceClickListener {
+            dbImportLauncher.launch(arrayOf("application/json"))
             true
         }
-
         prefTest.setOnPreferenceClickListener {
             model.runIntegrationTest()
             true
diff --git a/wallet/src/main/java/net/taler/wallet/settings/SettingsManager.kt 
b/wallet/src/main/java/net/taler/wallet/settings/SettingsManager.kt
index 349c7b1..0b4cbe9 100644
--- a/wallet/src/main/java/net/taler/wallet/settings/SettingsManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/settings/SettingsManager.kt
@@ -25,14 +25,19 @@ import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
+import kotlinx.serialization.encodeToString
+import kotlinx.serialization.json.Json
 import net.taler.wallet.R
-import net.taler.wallet.backend.WALLET_DB
+import net.taler.wallet.backend.WalletBackendApi
+import net.taler.wallet.backend.WalletResponse.Error
+import net.taler.wallet.backend.WalletResponse.Success
+import org.json.JSONObject
 
 class SettingsManager(
     private val context: Context,
+    private val api: WalletBackendApi,
     private val scope: CoroutineScope,
 ) {
-
     fun exportLogcat(uri: Uri?) {
         if (uri == null) {
             onLogExportError()
@@ -65,20 +70,76 @@ class SettingsManager(
             onDbExportError()
             return
         }
+
         scope.launch(Dispatchers.IO) {
-            try {
-                context.contentResolver.openOutputStream(uri, "wt")?.use { 
outputStream ->
-                    context.openFileInput(WALLET_DB).use { inputStream ->
-                        inputStream.copyTo(outputStream)
+            when (val response = api.rawRequest("exportDb")) {
+                is Success -> {
+                    try {
+                        context.contentResolver.openOutputStream(uri, 
"wt")?.use { outputStream ->
+                            val data = Json.encodeToString(response.result)
+                            val writer = outputStream.bufferedWriter()
+                            writer.write(data)
+                            writer.close()
+                        }
+                    } catch(e: Exception) {
+                        Log.e(SettingsManager::class.simpleName, "Error 
exporting db: ", e)
+                        withContext(Dispatchers.Main) {
+                            onDbExportError()
+                        }
+                        return@launch
                     }
-                } ?: onDbExportError()
-            } catch (e: Exception) {
-                Log.e(SettingsManager::class.simpleName, "Error exporting db: 
", e)
-                onDbExportError()
-                return@launch
+
+                    withContext(Dispatchers.Main) {
+                        Toast.makeText(context, 
R.string.settings_db_export_success, LENGTH_LONG).show()
+                    }
+                }
+                is Error -> {
+                    Log.e(SettingsManager::class.simpleName, "Error exporting 
db: ${response.error}")
+                    withContext(Dispatchers.Main) {
+                        onDbExportError()
+                    }
+                    return@launch
+                }
             }
-            withContext(Dispatchers.Main) {
-                Toast.makeText(context, R.string.settings_db_export_success, 
LENGTH_LONG).show()
+        }
+    }
+
+    fun importDb(uri: Uri?) {
+        if (uri == null) {
+            onDbImportError()
+            return
+        }
+
+        scope.launch(Dispatchers.IO) {
+            context.contentResolver.openInputStream(uri)?.use {  inputStream ->
+                try {
+                    val reader = inputStream.bufferedReader()
+                    val strData = reader.readText()
+                    reader.close()
+                    val jsonData = JSONObject(strData)
+                    when (val response = api.rawRequest("importDb") {
+                        put("dump", jsonData)
+                    }) {
+                        is Success -> {
+                            withContext(Dispatchers.Main) {
+                                Toast.makeText(context, 
R.string.settings_db_import_success, LENGTH_LONG).show()
+                            }
+                        }
+                        is Error -> {
+                            Log.e(SettingsManager::class.simpleName, "Error 
importing db: ${response.error}")
+                            withContext(Dispatchers.Main) {
+                                onDbImportError()
+                            }
+                            return@launch
+                        }
+                    }
+                } catch (e: Exception) {
+                    Log.e(SettingsManager::class.simpleName, "Error importing 
db: ", e)
+                    withContext(Dispatchers.Main) {
+                        onDbImportError()
+                    }
+                    return@launch
+                }
             }
         }
     }
@@ -87,4 +148,8 @@ class SettingsManager(
         Toast.makeText(context, R.string.settings_db_export_error, 
LENGTH_LONG).show()
     }
 
+    private fun onDbImportError() {
+        Toast.makeText(context, R.string.settings_db_import_error, 
LENGTH_LONG).show()
+    }
+
 }
diff --git a/wallet/src/main/res/drawable/ic_archive.xml 
b/wallet/src/main/res/drawable/ic_archive.xml
new file mode 100644
index 0000000..58a032c
--- /dev/null
+++ b/wallet/src/main/res/drawable/ic_archive.xml
@@ -0,0 +1,21 @@
+<!--
+  ~ This file is part of GNU Taler
+  ~ (C) 2023 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/>
+  -->
+
+<vector android:height="24dp" android:tint="?attr/colorControlNormal"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="24dp" 
xmlns:android="http://schemas.android.com/apk/res/android";>
+    <path android:fillColor="@android:color/white" 
android:pathData="M20.54,5.23l-1.39,-1.68C18.88,3.21 18.47,3 18,3H6c-0.47,0 
-0.88,0.21 -1.16,0.55L3.46,5.23C3.17,5.57 3,6.02 3,6.5V19c0,1.1 0.9,2 
2,2h14c1.1,0 2,-0.9 2,-2V6.5c0,-0.48 -0.17,-0.93 
-0.46,-1.27zM12,17.5L6.5,12H10v-2h4v2h3.5L12,17.5zM5.12,5l0.81,-1h12l0.94,1H5.12z"/>
+</vector>
diff --git a/wallet/src/main/res/values/strings.xml 
b/wallet/src/main/res/values/strings.xml
index 3b05ae9..2533820 100644
--- a/wallet/src/main/res/values/strings.xml
+++ b/wallet/src/main/res/values/strings.xml
@@ -257,10 +257,14 @@ GNU Taler is immune against many types of fraud, such as 
phishing of credit card
     <string name="settings_logcat_summary">Save internal log</string>
     <string name="settings_logcat_error">Error exporting log</string>
     <string name="settings_logcat_success">Log exported to file</string>
-    <string name="settings_db_export">Database</string>
+    <string name="settings_db_export">Export database</string>
     <string name="settings_db_export_summary">Save internal database</string>
+    <string name="settings_db_import">Import database</string>
+    <string name="settings_db_import_summary">Restore database from 
file</string>
     <string name="settings_db_export_error">Error exporting database</string>
+    <string name="settings_db_import_error">Error importing database</string>
     <string name="settings_db_export_success">Database exported to 
file</string>
+    <string name="settings_db_import_success">Database imported from 
file</string>
     <string name="settings_version_app">App Version</string>
     <string name="settings_version_core">Wallet Core Version</string>
     <string name="settings_version_protocol_exchange">Supported Exchange 
Versions</string>
diff --git a/wallet/src/main/res/xml/settings_main.xml 
b/wallet/src/main/res/xml/settings_main.xml
index 3a6d991..739e119 100644
--- a/wallet/src/main/res/xml/settings_main.xml
+++ b/wallet/src/main/res/xml/settings_main.xml
@@ -55,6 +55,14 @@
         app:title="@string/settings_db_export"
         tools:isPreferenceVisible="true" />
 
+    <Preference
+        app:icon="@drawable/ic_archive"
+        app:isPreferenceVisible="false"
+        app:key="pref_import_db"
+        app:summary="@string/settings_db_import_summary"
+        app:title="@string/settings_db_import"
+        tools:isPreferenceVisible="true" />
+
     <Preference
         app:icon="@drawable/ic_account_balance_wallet"
         app:isPreferenceVisible="false"

-- 
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]