added passwort for login and download, token-system
This commit is contained in:
@ -16,21 +16,24 @@ import javax.crypto.spec.SecretKeySpec
|
|||||||
object DatabaseDownloader {
|
object DatabaseDownloader {
|
||||||
|
|
||||||
private const val DB_NAME = "questionnaire_database"
|
private const val DB_NAME = "questionnaire_database"
|
||||||
private const val API_TOKEN = "MEIN_SUPER_GEHEIMES_TOKEN_12345"
|
private const val SERVER_DOWNLOAD_URL = "http://49.13.157.44/downloadFull.php"
|
||||||
private const val SERVER_DOWNLOAD_URL = "http://49.13.157.44/downloadFull.php?token=$API_TOKEN"
|
|
||||||
|
|
||||||
// AES-256 Key (muss exakt 32 Bytes lang sein)
|
// AES-256 Key (muss exakt 32 Bytes lang sein)
|
||||||
private const val AES_KEY = "12345678901234567890123456789012"
|
private const val AES_KEY = "12345678901234567890123456789012"
|
||||||
|
|
||||||
private val client = OkHttpClient()
|
private val client = OkHttpClient()
|
||||||
|
|
||||||
fun downloadAndReplaceDatabase(context: Context) {
|
/**
|
||||||
|
* Startet den Download und Austausch der DB, benötigt gültiges Token
|
||||||
|
*/
|
||||||
|
fun downloadAndReplaceDatabase(context: Context, token: String) {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
try {
|
try {
|
||||||
Log.d("DOWNLOAD", "Download gestartet: $SERVER_DOWNLOAD_URL")
|
Log.d("DOWNLOAD", "Download gestartet: $SERVER_DOWNLOAD_URL")
|
||||||
|
|
||||||
val request = Request.Builder()
|
val request = Request.Builder()
|
||||||
.url(SERVER_DOWNLOAD_URL)
|
.url(SERVER_DOWNLOAD_URL)
|
||||||
|
.header("Authorization", "Bearer $token")
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val response = client.newCall(request).execute()
|
val response = client.newCall(request).execute()
|
||||||
|
|||||||
@ -20,14 +20,32 @@ import kotlin.system.exitProcess
|
|||||||
object DatabaseUploader {
|
object DatabaseUploader {
|
||||||
|
|
||||||
private const val DB_NAME = "questionnaire_database"
|
private const val DB_NAME = "questionnaire_database"
|
||||||
// TODO entferne uploadDeltaTest2.php
|
private const val SERVER_DELTA_URL = "http://49.13.157.44/uploadDeltaTest4.php"
|
||||||
private const val SERVER_DELTA_URL = "http://49.13.157.44/uploadDeltaTest3.php"
|
|
||||||
private const val SERVER_CHECK_URL = "http://49.13.157.44/checkDatabaseExists.php"
|
private const val SERVER_CHECK_URL = "http://49.13.157.44/checkDatabaseExists.php"
|
||||||
private const val API_TOKEN = "MEIN_SUPER_GEHEIMES_TOKEN_12345"
|
|
||||||
|
|
||||||
private val client = OkHttpClient()
|
private val client = OkHttpClient()
|
||||||
|
|
||||||
fun uploadDatabase(context: Context) {
|
/**
|
||||||
|
* Startet den Upload mit Login über LoginManager.
|
||||||
|
* @param context Android Context
|
||||||
|
* @param password Vom User eingegebenes Passwort
|
||||||
|
*/
|
||||||
|
fun uploadDatabaseWithLogin(context: Context, password: String) {
|
||||||
|
LoginManager.loginUser(context, password,
|
||||||
|
onSuccess = { token ->
|
||||||
|
Log.d("UPLOAD", "Login erfolgreich, Token erhalten")
|
||||||
|
uploadDatabase(context, token)
|
||||||
|
},
|
||||||
|
onError = { errorMsg ->
|
||||||
|
Log.e("UPLOAD", "Login fehlgeschlagen: $errorMsg")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interner Upload, benötigt gültiges Token
|
||||||
|
*/
|
||||||
|
private fun uploadDatabase(context: Context, token: String) {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
try {
|
try {
|
||||||
val dbFile = context.getDatabasePath(DB_NAME)
|
val dbFile = context.getDatabasePath(DB_NAME)
|
||||||
@ -45,9 +63,7 @@ object DatabaseUploader {
|
|||||||
)
|
)
|
||||||
db.rawQuery("PRAGMA wal_checkpoint(FULL);", null).use { cursor ->
|
db.rawQuery("PRAGMA wal_checkpoint(FULL);", null).use { cursor ->
|
||||||
if (cursor.moveToFirst()) {
|
if (cursor.moveToFirst()) {
|
||||||
try {
|
try { Log.d("UPLOAD", "WAL-Checkpoint result: ${cursor.getInt(0)}") } catch (_: Exception) {}
|
||||||
Log.d("UPLOAD", "WAL-Checkpoint result: ${cursor.getInt(0)}")
|
|
||||||
} catch (_: Exception) {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
db.close()
|
db.close()
|
||||||
@ -59,12 +75,12 @@ object DatabaseUploader {
|
|||||||
val exists = checkDatabaseExists()
|
val exists = checkDatabaseExists()
|
||||||
if (exists) {
|
if (exists) {
|
||||||
Log.d("UPLOAD", "Server-Datenbank vorhanden → Delta-Upload")
|
Log.d("UPLOAD", "Server-Datenbank vorhanden → Delta-Upload")
|
||||||
uploadPseudoDelta(context, dbFile)
|
|
||||||
} else {
|
} else {
|
||||||
Log.d("UPLOAD", "Keine Server-Datenbank → Delta-Upload")
|
Log.d("UPLOAD", "Keine Server-Datenbank → Delta-Upload")
|
||||||
uploadPseudoDelta(context, dbFile)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uploadPseudoDelta(context, dbFile, token)
|
||||||
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e("UPLOAD", "Fehler beim Hochladen der DB", e)
|
Log.e("UPLOAD", "Fehler beim Hochladen der DB", e)
|
||||||
}
|
}
|
||||||
@ -97,15 +113,7 @@ object DatabaseUploader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private fun uploadPseudoDelta(context: Context, file: File, token: String) {
|
||||||
* Wichtig: Diese Funktion wurde erweitert, sodass:
|
|
||||||
* - die DB als JSON in eine temporäre Datei geschrieben wird,
|
|
||||||
* - diese JSON-Datei AES-verschlüsselt wird (mit AES256Helper.encryptFile),
|
|
||||||
* - die verschlüsselte Datei als Multipart 'file' an den Server gesendet wird.
|
|
||||||
*
|
|
||||||
* (Funktionalität: gleiche Signatur wie vorher behalten)
|
|
||||||
*/
|
|
||||||
private fun uploadPseudoDelta(context: Context, file: File) {
|
|
||||||
try {
|
try {
|
||||||
val db = SQLiteDatabase.openDatabase(file.absolutePath, null, SQLiteDatabase.OPEN_READONLY)
|
val db = SQLiteDatabase.openDatabase(file.absolutePath, null, SQLiteDatabase.OPEN_READONLY)
|
||||||
|
|
||||||
@ -125,25 +133,21 @@ object DatabaseUploader {
|
|||||||
|
|
||||||
db.close()
|
db.close()
|
||||||
|
|
||||||
// Schreibe JSON in temporäre Datei
|
|
||||||
val tmpJson = File(context.cacheDir, "payload.json")
|
val tmpJson = File(context.cacheDir, "payload.json")
|
||||||
tmpJson.writeText(data.toString())
|
tmpJson.writeText(data.toString())
|
||||||
|
|
||||||
// Verschlüssele JSON -> tmpEnc
|
|
||||||
val tmpEnc = File(context.cacheDir, "payload.enc")
|
val tmpEnc = File(context.cacheDir, "payload.enc")
|
||||||
try {
|
try {
|
||||||
AES256Helper.encryptFile(tmpJson, tmpEnc)
|
AES256Helper.encryptFile(tmpJson, tmpEnc)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e("UPLOAD", "Fehler bei der Verschlüsselung der JSON-Datei", e)
|
Log.e("UPLOAD", "Fehler bei der Verschlüsselung der JSON-Datei", e)
|
||||||
// cleanup
|
|
||||||
tmpJson.delete()
|
tmpJson.delete()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val requestBody = MultipartBody.Builder()
|
val requestBody = MultipartBody.Builder()
|
||||||
.setType(MultipartBody.FORM)
|
.setType(MultipartBody.FORM)
|
||||||
.addFormDataPart("token", API_TOKEN)
|
.addFormDataPart("token", token) // Token vom Login
|
||||||
// Datei-Feld "file" mit verschlüsselter Payload
|
|
||||||
.addFormDataPart(
|
.addFormDataPart(
|
||||||
"file",
|
"file",
|
||||||
"payload.enc",
|
"payload.enc",
|
||||||
@ -159,31 +163,19 @@ object DatabaseUploader {
|
|||||||
client.newCall(request).enqueue(object : Callback {
|
client.newCall(request).enqueue(object : Callback {
|
||||||
override fun onFailure(call: Call, e: IOException) {
|
override fun onFailure(call: Call, e: IOException) {
|
||||||
Log.e("UPLOAD", "Delta-Upload fehlgeschlagen: ${e.message}")
|
Log.e("UPLOAD", "Delta-Upload fehlgeschlagen: ${e.message}")
|
||||||
// cleanup
|
|
||||||
tmpJson.delete()
|
tmpJson.delete()
|
||||||
tmpEnc.delete()
|
tmpEnc.delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResponse(call: Call, response: Response) {
|
override fun onResponse(call: Call, response: Response) {
|
||||||
val body = try {
|
val body = try { response.body?.string() ?: "Keine Response" } catch (e: Exception) {
|
||||||
response.body?.string() ?: "Keine Response"
|
|
||||||
} catch (e: Exception) {
|
|
||||||
"Fehler beim Lesen der Response: ${e.message}"
|
"Fehler beim Lesen der Response: ${e.message}"
|
||||||
}
|
}
|
||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
Log.d("UPLOAD", "Delta-Upload erfolgreich: $body")
|
Log.d("UPLOAD", "Delta-Upload erfolgreich: $body")
|
||||||
// Lösche Hauptdatenbank
|
if (file.delete()) Log.d("UPLOAD", "Lokale DB gelöscht.") else Log.e("UPLOAD", "Löschen der lokalen DB fehlgeschlagen.")
|
||||||
if (file.delete()) {
|
|
||||||
Log.d("UPLOAD", "Lokale DB gelöscht.")
|
|
||||||
} else {
|
|
||||||
Log.e("UPLOAD", "Löschen der lokalen DB fehlgeschlagen.")
|
|
||||||
}
|
|
||||||
// Lösche Journal-Datei
|
|
||||||
val journalFile = File(file.parent, file.name + "-journal")
|
val journalFile = File(file.parent, file.name + "-journal")
|
||||||
if (journalFile.exists() && journalFile.delete()) {
|
if (journalFile.exists() && journalFile.delete()) Log.d("UPLOAD", "Journal-Datei gelöscht.")
|
||||||
Log.d("UPLOAD", "Journal-Datei gelöscht.")
|
|
||||||
}
|
|
||||||
// cleanup temp files
|
|
||||||
tmpJson.delete()
|
tmpJson.delete()
|
||||||
tmpEnc.delete()
|
tmpEnc.delete()
|
||||||
exitProcess(0)
|
exitProcess(0)
|
||||||
|
|||||||
@ -69,10 +69,9 @@ class HandlerClientCoachCode(
|
|||||||
val clientCode = clientCodeField.text.toString()
|
val clientCode = clientCodeField.text.toString()
|
||||||
val coachCode = coachCodeField.text.toString()
|
val coachCode = coachCodeField.text.toString()
|
||||||
|
|
||||||
// Prüfen, ob die Datenbank-Dateien vor dem Klick existieren
|
// Prüfen, ob die DB-Datei vor dem Zugriff existiert
|
||||||
val dbFile = layout.context.getDatabasePath("questionnaire_database")
|
val dbPath = layout.context.getDatabasePath("questionnaire_database")
|
||||||
val dbJournalFile = layout.context.getDatabasePath("questionnaire_database-journal")
|
val dbExistedBefore = dbPath.exists()
|
||||||
val dbExisted = dbFile.exists() || dbJournalFile.exists()
|
|
||||||
|
|
||||||
// Check if client code already exists asynchronously
|
// Check if client code already exists asynchronously
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
@ -86,18 +85,20 @@ class HandlerClientCoachCode(
|
|||||||
} else {
|
} else {
|
||||||
// Either no existing client or re-using previous code
|
// Either no existing client or re-using previous code
|
||||||
saveAnswers(clientCode, coachCode)
|
saveAnswers(clientCode, coachCode)
|
||||||
|
|
||||||
// Datenbank-Dateien löschen, wenn sie vorher NICHT existierten
|
|
||||||
if (!dbExisted) {
|
|
||||||
dbFile.delete()
|
|
||||||
dbJournalFile.delete()
|
|
||||||
}
|
|
||||||
|
|
||||||
goToNextQuestion()
|
goToNextQuestion()
|
||||||
|
|
||||||
|
// Lösche DB-Dateien nur, wenn sie vorher nicht existierten
|
||||||
|
if (!dbExistedBefore) {
|
||||||
|
MyApp.database.close()
|
||||||
|
dbPath.delete()
|
||||||
|
val journalFile = layout.context.getDatabasePath("questionnaire_database-journal")
|
||||||
|
journalFile.delete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Handle Previous button click
|
// Handle Previous button click
|
||||||
private fun onPreviousClicked(clientCodeField: EditText, coachCodeField: EditText) {
|
private fun onPreviousClicked(clientCodeField: EditText, coachCodeField: EditText) {
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import android.util.Log
|
|||||||
import com.dano.test1.data.CompletedQuestionnaire
|
import com.dano.test1.data.CompletedQuestionnaire
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
var INTEGRATION_INDEX_POINTS: Int? = null
|
var RHS_POINTS: Int? = null
|
||||||
|
|
||||||
class HandlerOpeningScreen(private val activity: MainActivity) {
|
class HandlerOpeningScreen(private val activity: MainActivity) {
|
||||||
|
|
||||||
@ -342,13 +342,12 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
|
|||||||
MyApp.database.completedQuestionnaireDao().getAllForClient(clientCode)
|
MyApp.database.completedQuestionnaireDao().getAllForClient(clientCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fülle buttonPoints & INTEGRATION_INDEX_POINTS
|
|
||||||
buttonPoints.clear()
|
buttonPoints.clear()
|
||||||
for (entry in completedEntries) {
|
for (entry in completedEntries) {
|
||||||
if (entry.isDone) {
|
if (entry.isDone) {
|
||||||
buttonPoints[entry.questionnaireId] = entry.sumPoints ?: 0
|
buttonPoints[entry.questionnaireId] = entry.sumPoints ?: 0
|
||||||
if (entry.questionnaireId.contains("questionnaire_3_integration_index", ignoreCase = true)) {
|
if (entry.questionnaireId.contains("questionnaire_2_rhs", ignoreCase = true)) {
|
||||||
INTEGRATION_INDEX_POINTS = entry.sumPoints
|
RHS_POINTS = entry.sumPoints
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -682,38 +681,78 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
|
|||||||
uploadButton.setOnClickListener {
|
uploadButton.setOnClickListener {
|
||||||
val clientCode = editText.text.toString().trim()
|
val clientCode = editText.text.toString().trim()
|
||||||
|
|
||||||
|
if (clientCode.isBlank()) {
|
||||||
|
val message = LanguageManager.getText(languageID, "please_client_code")
|
||||||
|
Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
|
||||||
|
return@setOnClickListener
|
||||||
|
}
|
||||||
|
|
||||||
GlobalValues.LAST_CLIENT_CODE = clientCode
|
GlobalValues.LAST_CLIENT_CODE = clientCode
|
||||||
|
|
||||||
Toast.makeText(activity, "Datenbank wird hochgeladen...", Toast.LENGTH_SHORT).show()
|
// Passwort-Eingabe-Popup
|
||||||
DatabaseUploader.uploadDatabase(activity)
|
val input = EditText(activity).apply {
|
||||||
|
hint = "Server-Passwort"
|
||||||
|
}
|
||||||
|
|
||||||
|
android.app.AlertDialog.Builder(activity)
|
||||||
|
.setTitle("Login erforderlich")
|
||||||
|
.setView(input)
|
||||||
|
.setPositiveButton("OK") { _, _ ->
|
||||||
|
val password = input.text.toString()
|
||||||
|
if (password.isNotBlank()) {
|
||||||
|
Toast.makeText(activity, "Login wird überprüft...", Toast.LENGTH_SHORT).show()
|
||||||
|
// Login + Upload starten
|
||||||
|
DatabaseUploader.uploadDatabaseWithLogin(activity, password)
|
||||||
|
} else {
|
||||||
|
Toast.makeText(activity, "Bitte Passwort eingeben", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.setNegativeButton("Abbrechen", null)
|
||||||
|
.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Füge diese Funktion in deine Klasse ein ---
|
|
||||||
private fun isDatabasePopulated(): Boolean {
|
|
||||||
return try {
|
|
||||||
val db = MyApp.database.openHelper.readableDatabase
|
|
||||||
val cursor = db.query(
|
|
||||||
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name != 'room_master_table'"
|
|
||||||
)
|
|
||||||
cursor.use { it.count > 0 }
|
|
||||||
} catch (e: Exception) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupDownloadButton() {
|
private fun setupDownloadButton() {
|
||||||
downloadButton.text = "Download"
|
downloadButton.text = "Download"
|
||||||
downloadButton.setOnClickListener {
|
downloadButton.setOnClickListener {
|
||||||
val clientCode = editText.text.toString().trim()
|
val clientCode = editText.text.toString().trim()
|
||||||
|
|
||||||
GlobalValues.LAST_CLIENT_CODE = clientCode
|
GlobalValues.LAST_CLIENT_CODE = clientCode
|
||||||
|
|
||||||
Toast.makeText(activity, "Datenbank wird heruntergeladen...", Toast.LENGTH_SHORT).show()
|
// Eingabe-Popup für Passwort anzeigen
|
||||||
DatabaseDownloader.downloadAndReplaceDatabase(activity)
|
val input = EditText(activity).apply {
|
||||||
|
hint = "Server-Passwort"
|
||||||
|
}
|
||||||
|
|
||||||
|
android.app.AlertDialog.Builder(activity)
|
||||||
|
.setTitle("Login erforderlich")
|
||||||
|
.setView(input)
|
||||||
|
.setPositiveButton("OK") { _, _ ->
|
||||||
|
val password = input.text.toString()
|
||||||
|
if (password.isNotBlank()) {
|
||||||
|
// Login starten
|
||||||
|
LoginManager.loginUser(
|
||||||
|
context = activity,
|
||||||
|
password = password,
|
||||||
|
onSuccess = { token ->
|
||||||
|
Toast.makeText(activity, "Login erfolgreich", Toast.LENGTH_SHORT).show()
|
||||||
|
DatabaseDownloader.downloadAndReplaceDatabase(activity, token)
|
||||||
updateMainButtonsState(true)
|
updateMainButtonsState(true)
|
||||||
|
},
|
||||||
|
onError = { error ->
|
||||||
|
Toast.makeText(activity, error, Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Toast.makeText(activity, "Bitte Passwort eingeben", Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.setNegativeButton("Abbrechen", null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun updateMainButtonsState(isDatabaseAvailable: Boolean) {
|
private fun updateMainButtonsState(isDatabaseAvailable: Boolean) {
|
||||||
val buttons = listOf(buttonLoad, saveButton, editButton)
|
val buttons = listOf(buttonLoad, saveButton, editButton)
|
||||||
|
|||||||
@ -17,7 +17,7 @@ object LanguageManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun injectDynamicValues(text: String): String {
|
private fun injectDynamicValues(text: String): String {
|
||||||
val points = INTEGRATION_INDEX_POINTS ?: 0
|
val points = RHS_POINTS ?: 0
|
||||||
val color = when (points) {
|
val color = when (points) {
|
||||||
in 1..12 -> "#4CAF50" // Grün
|
in 1..12 -> "#4CAF50" // Grün
|
||||||
in 13..36 -> "#FFEB3B" // Gelb
|
in 13..36 -> "#FFEB3B" // Gelb
|
||||||
@ -26,7 +26,7 @@ object LanguageManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val coloredPoints = "<b><font color='$color'>$points</font></b>"
|
val coloredPoints = "<b><font color='$color'>$points</font></b>"
|
||||||
return text.replace("INTEGRATION_INDEX_POINTS", coloredPoints)
|
return text.replace("RHS_POINTS", coloredPoints)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sprachdatenbank: Map<Sprachcode, Map<Text-ID, Text>>
|
// Sprachdatenbank: Map<Sprachcode, Map<Text-ID, Text>>
|
||||||
@ -285,7 +285,7 @@ object LanguageManager {
|
|||||||
"select_one_answer_per_row" to "Bitte wählen Sie eine Antwort pro Reihe aus!",
|
"select_one_answer_per_row" to "Bitte wählen Sie eine Antwort pro Reihe aus!",
|
||||||
"no_next_question_defined" to "Keine Weiterleitungsseite definiert",
|
"no_next_question_defined" to "Keine Weiterleitungsseite definiert",
|
||||||
"date_consultation_health_interview_result" to "Datum Beratungsgespräch (zum Ergebnis Gesundheitsinterview grün/gelb/rot)",
|
"date_consultation_health_interview_result" to "Datum Beratungsgespräch (zum Ergebnis Gesundheitsinterview grün/gelb/rot)",
|
||||||
"consultation_decision" to "Beratungsentscheidung (INTEGRATION_INDEX_POINTS)",
|
"consultation_decision" to "Beratungsentscheidung (RHS_POINTS)",
|
||||||
"consent_conversation_in_6_months" to "Einverständnis Gespräch in 6 Monaten:",
|
"consent_conversation_in_6_months" to "Einverständnis Gespräch in 6 Monaten:",
|
||||||
"participation_in_coaching" to "Teilnahme am Coaching",
|
"participation_in_coaching" to "Teilnahme am Coaching",
|
||||||
"decision_after_reflection_period" to "Entscheidung am .............. (Datum) nach Bedenkzeit",
|
"decision_after_reflection_period" to "Entscheidung am .............. (Datum) nach Bedenkzeit",
|
||||||
@ -580,7 +580,7 @@ object LanguageManager {
|
|||||||
"select_one_answer_per_row" to "Please select one answer per row!",
|
"select_one_answer_per_row" to "Please select one answer per row!",
|
||||||
"no_next_question_defined" to "No forwarding page defined",
|
"no_next_question_defined" to "No forwarding page defined",
|
||||||
"date_consultation_health_interview_result" to "Date of counseling interview (health interview result green/yellow/red)",
|
"date_consultation_health_interview_result" to "Date of counseling interview (health interview result green/yellow/red)",
|
||||||
"consultation_decision" to "Counseling decision (INTEGRATION_INDEX_POINTS)",
|
"consultation_decision" to "Counseling decision (RHS_POINTS)",
|
||||||
"consent_conversation_in_6_months" to "Consent for conversation in 6 months:",
|
"consent_conversation_in_6_months" to "Consent for conversation in 6 months:",
|
||||||
"participation_in_coaching" to "Participation in coaching",
|
"participation_in_coaching" to "Participation in coaching",
|
||||||
"decision_after_reflection_period" to "Decision on .............. (date) after reflection period",
|
"decision_after_reflection_period" to "Decision on .............. (date) after reflection period",
|
||||||
@ -878,7 +878,7 @@ object LanguageManager {
|
|||||||
"select_one_answer_per_row" to "Veuillez sélectionner une réponse par ligne !",
|
"select_one_answer_per_row" to "Veuillez sélectionner une réponse par ligne !",
|
||||||
"no_next_question_defined" to "Aucune page de redirection définie",
|
"no_next_question_defined" to "Aucune page de redirection définie",
|
||||||
"date_consultation_health_interview_result" to "Date de l’entretien de conseil (résultat de l’entretien santé vert/jaune/rouge)",
|
"date_consultation_health_interview_result" to "Date de l’entretien de conseil (résultat de l’entretien santé vert/jaune/rouge)",
|
||||||
"consultation_decision" to "Décision de conseil (INTEGRATION_INDEX_POINTS)",
|
"consultation_decision" to "Décision de conseil (RHS_POINTS)",
|
||||||
"consent_conversation_in_6_months" to "Consentement pour entretien dans 6 mois :",
|
"consent_conversation_in_6_months" to "Consentement pour entretien dans 6 mois :",
|
||||||
"participation_in_coaching" to "Participation au coaching",
|
"participation_in_coaching" to "Participation au coaching",
|
||||||
"decision_after_reflection_period" to "Décision le .............. (date) après période de réflexion",
|
"decision_after_reflection_period" to "Décision le .............. (date) après période de réflexion",
|
||||||
@ -1172,7 +1172,7 @@ object LanguageManager {
|
|||||||
"select_one_answer_per_row" to "Пожалуйста, выберите один ответ в каждой строке!",
|
"select_one_answer_per_row" to "Пожалуйста, выберите один ответ в каждой строке!",
|
||||||
"no_next_question_defined" to "Следующая страница не определена",
|
"no_next_question_defined" to "Следующая страница не определена",
|
||||||
"date_consultation_health_interview_result" to "Дата консультации (результат медицинского интервью: зеленый/желтый/красный)",
|
"date_consultation_health_interview_result" to "Дата консультации (результат медицинского интервью: зеленый/желтый/красный)",
|
||||||
"consultation_decision" to "Решение по консультации (INTEGRATION_INDEX_POINTS)",
|
"consultation_decision" to "Решение по консультации (RHS_POINTS)",
|
||||||
"consent_conversation_in_6_months" to "Согласие на разговор через 6 месяцев:",
|
"consent_conversation_in_6_months" to "Согласие на разговор через 6 месяцев:",
|
||||||
"participation_in_coaching" to "Участие в коучинге",
|
"participation_in_coaching" to "Участие в коучинге",
|
||||||
"decision_after_reflection_period" to "Решение от .............. (дата) после периода раздумий",
|
"decision_after_reflection_period" to "Решение от .............. (дата) после периода раздумий",
|
||||||
@ -1470,7 +1470,7 @@ object LanguageManager {
|
|||||||
"select_one_answer_per_row" to "Будь ласка, оберіть по одній відповіді в кожному рядку!",
|
"select_one_answer_per_row" to "Будь ласка, оберіть по одній відповіді в кожному рядку!",
|
||||||
"no_next_question_defined" to "Наступна сторінка не визначена",
|
"no_next_question_defined" to "Наступна сторінка не визначена",
|
||||||
"date_consultation_health_interview_result" to "Дата консультації (результат медичного інтерв’ю зелений/жовтий/червоний)",
|
"date_consultation_health_interview_result" to "Дата консультації (результат медичного інтерв’ю зелений/жовтий/червоний)",
|
||||||
"consultation_decision" to "Рішення консультації (INTEGRATION_INDEX_POINTS)",
|
"consultation_decision" to "Рішення консультації (RHS_POINTS)",
|
||||||
"consent_conversation_in_6_months" to "Згода на розмову через 6 місяців:",
|
"consent_conversation_in_6_months" to "Згода на розмову через 6 місяців:",
|
||||||
"participation_in_coaching" to "Участь у коучингу",
|
"participation_in_coaching" to "Участь у коучингу",
|
||||||
"decision_after_reflection_period" to "Рішення .............. (дата) після періоду роздумів",
|
"decision_after_reflection_period" to "Рішення .............. (дата) після періоду роздумів",
|
||||||
@ -1768,7 +1768,7 @@ object LanguageManager {
|
|||||||
"select_one_answer_per_row" to "Lütfen her satır için bir cevap seçin!",
|
"select_one_answer_per_row" to "Lütfen her satır için bir cevap seçin!",
|
||||||
"no_next_question_defined" to "Bir yönlendirme sayfası tanımlanmadı",
|
"no_next_question_defined" to "Bir yönlendirme sayfası tanımlanmadı",
|
||||||
"date_consultation_health_interview_result" to "Danışma görüşmesi tarihi (sağlık görüşmesi sonucu yeşil/sarı/kırmızı)",
|
"date_consultation_health_interview_result" to "Danışma görüşmesi tarihi (sağlık görüşmesi sonucu yeşil/sarı/kırmızı)",
|
||||||
"consultation_decision" to "Danışma kararı (INTEGRATION_INDEX_POINTS)",
|
"consultation_decision" to "Danışma kararı (RHS_POINTS)",
|
||||||
"consent_conversation_in_6_months" to "6 ay içinde görüşme onayı:",
|
"consent_conversation_in_6_months" to "6 ay içinde görüşme onayı:",
|
||||||
"participation_in_coaching" to "Koçluğa katılım",
|
"participation_in_coaching" to "Koçluğa katılım",
|
||||||
"decision_after_reflection_period" to "Karar .............. (tarih) tarihinde düşünme süresinden sonra verildi",
|
"decision_after_reflection_period" to "Karar .............. (tarih) tarihinde düşünme süresinden sonra verildi",
|
||||||
@ -2066,7 +2066,7 @@ object LanguageManager {
|
|||||||
"select_one_answer_per_row" to "Proszę wybrać jedną odpowiedź w każdym wierszu!",
|
"select_one_answer_per_row" to "Proszę wybrać jedną odpowiedź w każdym wierszu!",
|
||||||
"no_next_question_defined" to "Nie zdefiniowano strony przekierowania",
|
"no_next_question_defined" to "Nie zdefiniowano strony przekierowania",
|
||||||
"date_consultation_health_interview_result" to "Data rozmowy doradczej (wynik wywiadu zdrowotnego: zielony/żółty/czerwony)",
|
"date_consultation_health_interview_result" to "Data rozmowy doradczej (wynik wywiadu zdrowotnego: zielony/żółty/czerwony)",
|
||||||
"consultation_decision" to "Decyzja doradcza (INTEGRATION_INDEX_POINTS)",
|
"consultation_decision" to "Decyzja doradcza (RHS_POINTS)",
|
||||||
"consent_conversation_in_6_months" to "Zgoda na rozmowę za 6 miesięcy:",
|
"consent_conversation_in_6_months" to "Zgoda na rozmowę za 6 miesięcy:",
|
||||||
"participation_in_coaching" to "Udział w coachingu",
|
"participation_in_coaching" to "Udział w coachingu",
|
||||||
"decision_after_reflection_period" to "Decyzja dnia .............. (data) po czasie do namysłu",
|
"decision_after_reflection_period" to "Decyzja dnia .............. (data) po czasie do namysłu",
|
||||||
@ -2662,7 +2662,7 @@ object LanguageManager {
|
|||||||
"select_one_answer_per_row" to "Vă rugăm să selectați un răspuns pe rând!",
|
"select_one_answer_per_row" to "Vă rugăm să selectați un răspuns pe rând!",
|
||||||
"no_next_question_defined" to "Nu este definită o pagină de redirecționare",
|
"no_next_question_defined" to "Nu este definită o pagină de redirecționare",
|
||||||
"date_consultation_health_interview_result" to "Data consilierii (rezultatul interviului de sănătate verde/galben/roșu)",
|
"date_consultation_health_interview_result" to "Data consilierii (rezultatul interviului de sănătate verde/galben/roșu)",
|
||||||
"consultation_decision" to "Decizia consilierii (INTEGRATION_INDEX_POINTS)",
|
"consultation_decision" to "Decizia consilierii (RHS_POINTS)",
|
||||||
"consent_conversation_in_6_months" to "Consimțământ discuție peste 6 luni:",
|
"consent_conversation_in_6_months" to "Consimțământ discuție peste 6 luni:",
|
||||||
"participation_in_coaching" to "Participare la coaching",
|
"participation_in_coaching" to "Participare la coaching",
|
||||||
"decision_after_reflection_period" to "Decizie la .............. (dată) după perioada de reflecție",
|
"decision_after_reflection_period" to "Decizie la .............. (dată) după perioada de reflecție",
|
||||||
@ -2960,7 +2960,7 @@ object LanguageManager {
|
|||||||
"select_one_answer_per_row" to "Por favor, seleccione una respuesta por fila.",
|
"select_one_answer_per_row" to "Por favor, seleccione una respuesta por fila.",
|
||||||
"no_next_question_defined" to "No se definió ninguna pregunta de continuación",
|
"no_next_question_defined" to "No se definió ninguna pregunta de continuación",
|
||||||
"date_consultation_health_interview_result" to "Fecha de la entrevista de orientación (sobre el resultado de la entrevista de salud: verde/amarillo/rojo)",
|
"date_consultation_health_interview_result" to "Fecha de la entrevista de orientación (sobre el resultado de la entrevista de salud: verde/amarillo/rojo)",
|
||||||
"consultation_decision" to "Decisión de orientación (INTEGRATION_INDEX_POINTS)",
|
"consultation_decision" to "Decisión de orientación (RHS_POINTS)",
|
||||||
"consent_conversation_in_6_months" to "Consentimiento para entrevista en 6 meses:",
|
"consent_conversation_in_6_months" to "Consentimiento para entrevista en 6 meses:",
|
||||||
"participation_in_coaching" to "Participación en el coaching",
|
"participation_in_coaching" to "Participación en el coaching",
|
||||||
"decision_after_reflection_period" to "Decisión tomada el .............. (fecha) después del período de reflexión",
|
"decision_after_reflection_period" to "Decisión tomada el .............. (fecha) después del período de reflexión",
|
||||||
|
|||||||
72
app/src/main/java/com/dano/test1/LoginManager.kt
Normal file
72
app/src/main/java/com/dano/test1/LoginManager.kt
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
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 kotlinx.coroutines.withContext
|
||||||
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
|
import org.json.JSONObject
|
||||||
|
|
||||||
|
object LoginManager {
|
||||||
|
|
||||||
|
private const val SERVER_LOGIN_URL = "http://49.13.157.44/login.php"
|
||||||
|
private val client = OkHttpClient()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Startet den Login-Prozess.
|
||||||
|
*
|
||||||
|
* @param context Android Context
|
||||||
|
* @param password Vom User eingegebenes Passwort
|
||||||
|
* @param onSuccess Callback mit dem Token wenn Login erfolgreich
|
||||||
|
* @param onError Callback mit Fehlermeldung
|
||||||
|
*/
|
||||||
|
fun loginUser(
|
||||||
|
context: Context,
|
||||||
|
password: String,
|
||||||
|
onSuccess: (String) -> Unit,
|
||||||
|
onError: (String) -> Unit
|
||||||
|
) {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
try {
|
||||||
|
val requestBody = """{"password":"$password"}"""
|
||||||
|
.toRequestBody("application/json".toMediaType())
|
||||||
|
|
||||||
|
val request = Request.Builder()
|
||||||
|
.url(SERVER_LOGIN_URL)
|
||||||
|
.post(requestBody)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val response = client.newCall(request).execute()
|
||||||
|
val responseText = response.body?.string()
|
||||||
|
|
||||||
|
if (response.isSuccessful && responseText != null) {
|
||||||
|
val json = JSONObject(responseText)
|
||||||
|
if (json.getBoolean("success")) {
|
||||||
|
val token = json.getString("token")
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
onSuccess(token)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
onError("Login fehlgeschlagen")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
onError("Fehler beim Login (${response.code})")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("LOGIN", "Exception beim Login", e)
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
onError("Exception: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user