Added Upload feature. Database will be uploaded to Hetzner Server. Database already encrypted with AES256. Database will be deleted from the app after uploading database.
This commit is contained in:
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@ -53,4 +53,13 @@ dependencies {
|
||||
implementation("androidx.room:room-ktx:$room_version")
|
||||
implementation ("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
|
||||
implementation ("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4")
|
||||
|
||||
// SQLCipher
|
||||
implementation ("net.zetetic:android-database-sqlcipher:4.5.3@aar")
|
||||
implementation ("androidx.sqlite:sqlite:2.1.0")
|
||||
implementation ("androidx.sqlite:sqlite-framework:2.1.0")
|
||||
|
||||
// Server Upload
|
||||
implementation("com.squareup.okhttp3:okhttp:4.12.0")
|
||||
|
||||
}
|
||||
@ -1,6 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
|
||||
<application
|
||||
android:name=".MyApp"
|
||||
@ -12,6 +14,7 @@
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.Test1"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
tools:targetApi="31">
|
||||
|
||||
<provider
|
||||
|
||||
88
app/src/main/java/com/dano/test1/DatabaseUploader.kt
Normal file
88
app/src/main/java/com/dano/test1/DatabaseUploader.kt
Normal file
@ -0,0 +1,88 @@
|
||||
package com.dano.test1
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import okhttp3.*
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import kotlin.system.exitProcess
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.RequestBody.Companion.asRequestBody
|
||||
|
||||
object DatabaseUploader {
|
||||
|
||||
private const val DB_NAME = "questionnaire_database"
|
||||
private const val ENCRYPTED_FILE_NAME = "exported_encrypted_database.db"
|
||||
private const val SERVER_UPLOAD_URL = "http://49.13.157.44/upload.php"
|
||||
|
||||
private val client = OkHttpClient()
|
||||
|
||||
fun uploadEncryptedDatabase(context: Context) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
Log.d("UPLOAD", "Upload gestartet")
|
||||
|
||||
val dbFile = context.getDatabasePath(DB_NAME)
|
||||
Log.d("UPLOAD", "Pfad zur DB: ${dbFile.absolutePath}, existiert: ${dbFile.exists()}")
|
||||
|
||||
if (!dbFile.exists()) {
|
||||
Log.e("UPLOAD", "Datenbankdatei existiert nicht.")
|
||||
return@launch
|
||||
}
|
||||
|
||||
val exportFile = File(context.cacheDir, ENCRYPTED_FILE_NAME)
|
||||
dbFile.copyTo(exportFile, overwrite = true)
|
||||
|
||||
Log.d("UPLOAD", "Datei kopiert: ${exportFile.absolutePath}")
|
||||
|
||||
uploadFile(context, exportFile, dbFile)
|
||||
|
||||
} catch (e: Exception) {
|
||||
Log.e("UPLOAD", "Fehler beim Hochladen der DB", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun uploadFile(context: Context, file: File, originalDbFile: File) {
|
||||
val requestBody = MultipartBody.Builder()
|
||||
.setType(MultipartBody.FORM)
|
||||
.addFormDataPart(
|
||||
"file", file.name,
|
||||
file.asRequestBody("application/octet-stream".toMediaTypeOrNull())
|
||||
)
|
||||
.build()
|
||||
|
||||
val request = Request.Builder()
|
||||
.url(SERVER_UPLOAD_URL)
|
||||
.post(requestBody)
|
||||
.build()
|
||||
|
||||
client.newCall(request).enqueue(object : Callback {
|
||||
override fun onFailure(call: Call, e: IOException) {
|
||||
Log.e("UPLOAD", "Upload fehlgeschlagen: ${e.message}")
|
||||
}
|
||||
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
if (response.isSuccessful) {
|
||||
Log.d("UPLOAD", "Upload erfolgreich: ${response.message}")
|
||||
|
||||
// Lokale DB-Datei löschen
|
||||
if (originalDbFile.delete()) {
|
||||
Log.d("UPLOAD", "Lokale Datenbank erfolgreich gelöscht.")
|
||||
|
||||
// App schließen
|
||||
Log.d("UPLOAD", "App wird beendet.")
|
||||
exitProcess(0)
|
||||
} else {
|
||||
Log.e("UPLOAD", "Löschen der lokalen Datenbank fehlgeschlagen.")
|
||||
}
|
||||
} else {
|
||||
Log.e("UPLOAD", "Upload fehlgeschlagen: ${response.code} ${response.message}")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -10,6 +10,7 @@ import kotlinx.coroutines.*
|
||||
import org.json.JSONArray
|
||||
import android.util.Log
|
||||
|
||||
|
||||
var INTEGRATION_INDEX_POINTS: Int? = null
|
||||
|
||||
class HandlerOpeningScreen(private val activity: MainActivity) {
|
||||
@ -22,6 +23,7 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
|
||||
private lateinit var buttonLoad: Button
|
||||
private lateinit var saveButton: Button
|
||||
private lateinit var editButton: Button
|
||||
private lateinit var uploadButton: Button
|
||||
|
||||
private val dynamicButtons = mutableListOf<Button>()
|
||||
private val questionnaireFiles = mutableMapOf<Button, String>()
|
||||
@ -40,6 +42,7 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
|
||||
setupLoadButton()
|
||||
setupSaveButton()
|
||||
setupEditButton()
|
||||
setupUploadButton()
|
||||
|
||||
if (!editText.text.isNullOrBlank()) {
|
||||
buttonLoad.performClick()
|
||||
@ -54,6 +57,7 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
|
||||
buttonLoad = activity.findViewById(R.id.loadButton)
|
||||
saveButton = activity.findViewById(R.id.saveButton)
|
||||
editButton = activity.findViewById(R.id.editButton)
|
||||
uploadButton = activity.findViewById(R.id.uploadButton)
|
||||
|
||||
val tag = editText.tag as? String ?: ""
|
||||
editText.hint = LanguageManager.getText(languageID, tag)
|
||||
@ -233,7 +237,7 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
|
||||
val conditionMet = when (condition.operator) {
|
||||
"!=" -> answerValue != condition.value
|
||||
"==" -> answerValue == condition.value
|
||||
else -> true // fallback: zeige Fragebogen
|
||||
else -> true
|
||||
}
|
||||
|
||||
if (conditionMet) break
|
||||
@ -488,26 +492,6 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
|
||||
return y
|
||||
}
|
||||
|
||||
private fun enableCompletedQuestionnaireButtons(clientCode: String) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val completedEntries = MyApp.database.completedQuestionnaireDao().getAllForClient(clientCode)
|
||||
|
||||
val completedFiles = completedEntries
|
||||
.filter { it.isDone }
|
||||
.map { it.questionnaireId.lowercase() }
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
questionnaireFiles.forEach { (button, fileName) ->
|
||||
val isCompleted = completedFiles.any { fileName.lowercase().contains(it) }
|
||||
if (isCompleted) {
|
||||
button.isEnabled = true
|
||||
button.alpha = 1.0f
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupSaveButton() {
|
||||
saveButton.text = LanguageManager.getText(languageID, "save")
|
||||
saveButton.setOnClickListener {
|
||||
@ -560,4 +544,17 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupUploadButton() {
|
||||
uploadButton.text = "Upload"
|
||||
uploadButton.setOnClickListener {
|
||||
val clientCode = editText.text.toString().trim()
|
||||
|
||||
GlobalValues.LAST_CLIENT_CODE = clientCode
|
||||
|
||||
Toast.makeText(activity, "Datenbank wird verschlüsselt...", Toast.LENGTH_SHORT).show()
|
||||
DatabaseUploader.uploadEncryptedDatabase(activity)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -44,7 +44,6 @@
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/textView" />
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/loadButton"
|
||||
android:layout_width="72dp"
|
||||
@ -54,6 +53,15 @@
|
||||
app:layout_constraintStart_toStartOf="@id/editText"
|
||||
app:layout_constraintTop_toBottomOf="@id/editText" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/uploadButton"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="42dp"
|
||||
android:layout_marginTop="52dp"
|
||||
app:layout_constraintEnd_toEndOf="@id/editText"
|
||||
app:layout_constraintStart_toStartOf="@id/editText"
|
||||
app:layout_constraintTop_toBottomOf="@id/editText" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/editButton"
|
||||
android:layout_width="72dp"
|
||||
|
||||
6
app/src/main/res/xml/network_security_config.xml
Normal file
6
app/src/main/res/xml/network_security_config.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config>
|
||||
<domain-config cleartextTrafficPermitted="true">
|
||||
<domain includeSubdomains="true">49.13.157.44</domain>
|
||||
</domain-config>
|
||||
</network-security-config>
|
||||
Reference in New Issue
Block a user