### feat: erweitere ZNS und SQLDelight-Integration
Desktop CI — Headless Tests & Build / Compose Desktop — Tests (headless) & Build (push) Has been cancelled
Build and Publish Docker Images / build-and-push (., backend/infrastructure/gateway/Dockerfile, api-gateway, api-gateway) (push) Has been cancelled
Build and Publish Docker Images / build-and-push (., backend/services/ping/Dockerfile, ping-service, ping-service) (push) Has been cancelled
Build and Publish Docker Images / build-and-push (., config/docker/caddy/web-app/Dockerfile, web-app, web-app) (push) Has been cancelled
Build and Publish Docker Images / build-and-push (., config/docker/keycloak/Dockerfile, keycloak, keycloak) (push) Has been cancelled
Desktop CI — Headless Tests & Build / Compose Desktop — Tests (headless) & Build (push) Has been cancelled
Build and Publish Docker Images / build-and-push (., backend/infrastructure/gateway/Dockerfile, api-gateway, api-gateway) (push) Has been cancelled
Build and Publish Docker Images / build-and-push (., backend/services/ping/Dockerfile, ping-service, ping-service) (push) Has been cancelled
Build and Publish Docker Images / build-and-push (., config/docker/caddy/web-app/Dockerfile, web-app, web-app) (push) Has been cancelled
Build and Publish Docker Images / build-and-push (., config/docker/keycloak/Dockerfile, keycloak, keycloak) (push) Has been cancelled
- **SQLDelight:** Füge neue Queries (`countVereine`, `maxUpdated...`) zur SQLite-Datenbank hinzu und aktualisiere `DesktopMasterdataRepository`. - **ZNS-Sync:** Passe `ZnsImportState` an, um Pferde- und Funktionärsdaten zu unterstützen. - **Cloud-Sync:** Entferne redundante Auth-Header und setze Limits für Massensynchronisation auf 50.000 Datensätze. - **Masterdata-Service:** Stabilisiere Consul Health-Checks und implementiere Limit-Beschränkungen auf Controller-Ebene.
This commit is contained in:
+12
-6
@@ -12,6 +12,8 @@ data class ZnsImportState(
|
||||
val isFinished: Boolean = false,
|
||||
val remoteResults: List<ZnsRemoteVerein> = emptyList(),
|
||||
val remoteReiterResults: List<ZnsRemoteReiter> = emptyList(),
|
||||
val remoteHorseResults: List<ZnsRemotePferd> = emptyList(),
|
||||
val remoteFunktionaerResults: List<ZnsRemoteFunktionaer> = emptyList(),
|
||||
val isSearching: Boolean = false,
|
||||
val lastSyncVersion: String? = null,
|
||||
val isSyncing: Boolean = false,
|
||||
@@ -59,17 +61,21 @@ interface ZnsImportProvider {
|
||||
fun onFileSelected(path: String)
|
||||
fun startImport(mode: String = "FULL")
|
||||
fun searchRemote(query: String)
|
||||
fun syncFromCloud(onResult: (
|
||||
List<ZnsRemoteVerein>,
|
||||
List<ZnsRemoteReiter>,
|
||||
List<ZnsRemotePferd>,
|
||||
List<ZnsRemoteFunktionaer>
|
||||
) -> Unit)
|
||||
fun syncFromCloud(
|
||||
onResult: (
|
||||
List<ZnsRemoteVerein>,
|
||||
List<ZnsRemoteReiter>,
|
||||
List<ZnsRemotePferd>,
|
||||
List<ZnsRemoteFunktionaer>
|
||||
) -> Unit
|
||||
)
|
||||
|
||||
fun addSyncResults(
|
||||
vereine: List<ZnsRemoteVerein>,
|
||||
reiter: List<ZnsRemoteReiter>,
|
||||
pferde: List<ZnsRemotePferd>,
|
||||
funktionaere: List<ZnsRemoteFunktionaer>
|
||||
)
|
||||
|
||||
fun reset()
|
||||
}
|
||||
|
||||
+24
@@ -151,3 +151,27 @@ DELETE FROM LocalPferd;
|
||||
|
||||
deleteAllFunktionaere:
|
||||
DELETE FROM LocalFunktionaer;
|
||||
|
||||
countVereine:
|
||||
SELECT COUNT(*) FROM LocalVerein;
|
||||
|
||||
countReiter:
|
||||
SELECT COUNT(*) FROM LocalReiter;
|
||||
|
||||
countPferde:
|
||||
SELECT COUNT(*) FROM LocalPferd;
|
||||
|
||||
countFunktionaere:
|
||||
SELECT COUNT(*) FROM LocalFunktionaer;
|
||||
|
||||
maxUpdatedVerein:
|
||||
SELECT MAX(last_updated) FROM LocalVerein;
|
||||
|
||||
maxUpdatedReiter:
|
||||
SELECT MAX(last_updated) FROM LocalReiter;
|
||||
|
||||
maxUpdatedPferd:
|
||||
SELECT MAX(last_updated) FROM LocalPferd;
|
||||
|
||||
maxUpdatedFunktionaer:
|
||||
SELECT MAX(last_updated) FROM LocalFunktionaer;
|
||||
|
||||
+15
-6
@@ -1,18 +1,24 @@
|
||||
package at.mocode.frontend.features.funktionaer.data
|
||||
|
||||
import at.mocode.frontend.core.network.ApiRoutes
|
||||
import at.mocode.frontend.features.funktionaer.domain.Funktionaer
|
||||
import at.mocode.frontend.features.funktionaer.domain.FunktionaerRepository
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.call.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.http.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
||||
class KtorFunktionaerRepository(private val client: HttpClient) : FunktionaerRepository {
|
||||
override fun getFunktionaere(): Flow<List<Funktionaer>> = flow {
|
||||
try {
|
||||
val response: List<Funktionaer> = client.get("/api/v1/masterdata/funktionaere").body()
|
||||
emit(response)
|
||||
val response = client.get(ApiRoutes.Masterdata.FUNKTIONAERE)
|
||||
if (response.status.isSuccess()) {
|
||||
emit(response.body())
|
||||
} else {
|
||||
emit(emptyList())
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
emit(emptyList())
|
||||
}
|
||||
@@ -20,9 +26,10 @@ class KtorFunktionaerRepository(private val client: HttpClient) : FunktionaerRep
|
||||
|
||||
override suspend fun searchFunktionaere(query: String): List<Funktionaer> {
|
||||
return try {
|
||||
client.get("/api/v1/masterdata/funktionaere/search") {
|
||||
val response = client.get("${ApiRoutes.Masterdata.FUNKTIONAERE}/search") {
|
||||
parameter("q", query)
|
||||
}.body()
|
||||
}
|
||||
if (response.status.isSuccess()) response.body() else emptyList()
|
||||
} catch (_: Exception) {
|
||||
emptyList()
|
||||
}
|
||||
@@ -30,14 +37,16 @@ class KtorFunktionaerRepository(private val client: HttpClient) : FunktionaerRep
|
||||
|
||||
override suspend fun getFunktionaerById(id: Long): Funktionaer? {
|
||||
return try {
|
||||
client.get("/api/v1/masterdata/funktionaere/$id").body()
|
||||
val response = client.get("${ApiRoutes.Masterdata.FUNKTIONAERE}/$id")
|
||||
if (response.status.isSuccess()) response.body() else null
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun saveFunktionaer(funktionaer: Funktionaer) {
|
||||
client.post("/api/v1/masterdata/funktionaere") {
|
||||
client.post(ApiRoutes.Masterdata.FUNKTIONAERE) {
|
||||
contentType(ContentType.Application.Json)
|
||||
setBody(funktionaer)
|
||||
}
|
||||
}
|
||||
|
||||
+15
-6
@@ -1,18 +1,24 @@
|
||||
package at.mocode.frontend.features.pferde.data
|
||||
|
||||
import at.mocode.frontend.core.network.ApiRoutes
|
||||
import at.mocode.frontend.features.pferde.domain.Pferd
|
||||
import at.mocode.frontend.features.pferde.domain.PferdRepository
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.call.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.http.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
||||
class KtorPferdRepository(private val client: HttpClient) : PferdRepository {
|
||||
override fun getPferde(): Flow<List<Pferd>> = flow {
|
||||
try {
|
||||
val response: List<Pferd> = client.get("/api/v1/masterdata/pferde").body()
|
||||
emit(response)
|
||||
val response = client.get(ApiRoutes.Masterdata.PFERDE)
|
||||
if (response.status.isSuccess()) {
|
||||
emit(response.body())
|
||||
} else {
|
||||
emit(emptyList())
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
emit(emptyList())
|
||||
}
|
||||
@@ -20,9 +26,10 @@ class KtorPferdRepository(private val client: HttpClient) : PferdRepository {
|
||||
|
||||
override suspend fun searchPferde(query: String): List<Pferd> {
|
||||
return try {
|
||||
client.get("/api/v1/masterdata/pferde/search") {
|
||||
val response = client.get("${ApiRoutes.Masterdata.PFERDE}/search") {
|
||||
parameter("q", query)
|
||||
}.body()
|
||||
}
|
||||
if (response.status.isSuccess()) response.body() else emptyList()
|
||||
} catch (_: Exception) {
|
||||
emptyList()
|
||||
}
|
||||
@@ -30,14 +37,16 @@ class KtorPferdRepository(private val client: HttpClient) : PferdRepository {
|
||||
|
||||
override suspend fun getPferdById(id: String): Pferd? {
|
||||
return try {
|
||||
client.get("/api/v1/masterdata/pferde/$id").body()
|
||||
val response = client.get("${ApiRoutes.Masterdata.PFERDE}/$id")
|
||||
if (response.status.isSuccess()) response.body() else null
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun savePferd(pferd: Pferd) {
|
||||
client.post("/api/v1/masterdata/pferde") {
|
||||
client.post(ApiRoutes.Masterdata.PFERDE) {
|
||||
contentType(ContentType.Application.Json)
|
||||
setBody(pferd)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ fun ReiterScreen(
|
||||
Spacer(Modifier.height(16.dp))
|
||||
ReiterCard(
|
||||
reiter = uiState.selectedReiter,
|
||||
onEdit = { viewModel.selectReiter(uiState.selectedReiter!!) }
|
||||
onEdit = { viewModel.selectReiter(uiState.selectedReiter) }
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
||||
+60
-52
@@ -8,7 +8,7 @@ import androidx.lifecycle.viewModelScope
|
||||
import at.mocode.frontend.core.auth.data.local.AuthTokenManager
|
||||
import at.mocode.frontend.core.domain.repository.MasterdataRepository
|
||||
import at.mocode.frontend.core.domain.zns.*
|
||||
import at.mocode.frontend.core.network.NetworkConfig
|
||||
import at.mocode.frontend.core.network.ApiRoutes
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.request.forms.*
|
||||
@@ -98,10 +98,8 @@ class ZnsImportViewModel(
|
||||
)
|
||||
try {
|
||||
println("[ZNS] Starte Import Mode=$mode Datei=$fileName")
|
||||
val token = authTokenManager.authState.value.token
|
||||
val response: HttpResponse = httpClient.post("${NetworkConfig.baseUrl}/api/v1/import/zns") {
|
||||
val response: HttpResponse = httpClient.post("/api/v1/import/zns") {
|
||||
parameter("mode", mode)
|
||||
if (token != null) header(HttpHeaders.Authorization, "Bearer $token")
|
||||
val contentType =
|
||||
if (fileName.endsWith(".zip", ignoreCase = true)) "application/zip" else "application/octet-stream"
|
||||
setBody(MultiPartFormDataContent(formData {
|
||||
@@ -140,20 +138,18 @@ class ZnsImportViewModel(
|
||||
viewModelScope.launch {
|
||||
state = state.copy(isSearching = true)
|
||||
try {
|
||||
val token = authTokenManager.authState.value.token
|
||||
val response: HttpResponse = httpClient.get("${NetworkConfig.baseUrl}/api/v1/masterdata/verein/search") {
|
||||
val response: HttpResponse = httpClient.get(ApiRoutes.Masterdata.VEREINE + "/search") {
|
||||
parameter("q", query)
|
||||
if (token != null) header(HttpHeaders.Authorization, "Bearer $token")
|
||||
}
|
||||
|
||||
if (response.status.isSuccess()) {
|
||||
val responseText = response.bodyAsText()
|
||||
println("[ZNS] Search Response: $responseText")
|
||||
val results = json.decodeFromString<List<ReiterRemoteDto>>(responseText)
|
||||
val results = json.decodeFromString<List<VereinRemoteDto>>(responseText)
|
||||
state = state.copy(
|
||||
isSearching = false,
|
||||
remoteReiterResults = results.map {
|
||||
ZnsRemoteReiter(it.reiterId, it.satznummer, it.nachname, it.vorname, it.reiterLizenz, it.lizenzKlasse)
|
||||
remoteResults = results.map {
|
||||
ZnsRemoteVerein(it.vereinId, it.name, it.vereinsNummer, it.ort, it.bundesland)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
@@ -174,64 +170,79 @@ class ZnsImportViewModel(
|
||||
viewModelScope.launch {
|
||||
state = state.copy(isSyncing = true, errorMessage = null)
|
||||
try {
|
||||
val token = authTokenManager.authState.value.token
|
||||
|
||||
// 1. Vereine
|
||||
val vResponse: HttpResponse = httpClient.get("${NetworkConfig.baseUrl}/api/v1/masterdata/verein") {
|
||||
parameter("limit", 1000)
|
||||
if (token != null) header(HttpHeaders.Authorization, "Bearer $token")
|
||||
// 1. Vereine (Erhöhtes Limit für Initial-Sync)
|
||||
val vResponse: HttpResponse = httpClient.get(ApiRoutes.Masterdata.VEREINE) {
|
||||
parameter("limit", 50000)
|
||||
}
|
||||
val vResults = if (vResponse.status.isSuccess()) {
|
||||
json.decodeFromString<List<VereinRemoteDto>>(vResponse.bodyAsText()).map {
|
||||
val text = vResponse.bodyAsText()
|
||||
println("[ZNS] Sync Vereine: Received ${text.length} chars")
|
||||
json.decodeFromString<List<VereinRemoteDto>>(text).map {
|
||||
ZnsRemoteVerein(it.vereinId, it.name, it.vereinsNummer, it.ort, it.bundesland)
|
||||
}
|
||||
} else emptyList()
|
||||
} else {
|
||||
println("[ZNS] Sync Vereine failed: ${vResponse.status}")
|
||||
emptyList()
|
||||
}
|
||||
|
||||
// 2. Reiter
|
||||
val rResponse: HttpResponse = httpClient.get("${NetworkConfig.baseUrl}/api/v1/masterdata/reiter") {
|
||||
parameter("limit", 1000)
|
||||
if (token != null) header(HttpHeaders.Authorization, "Bearer $token")
|
||||
val rResponse: HttpResponse = httpClient.get(ApiRoutes.Masterdata.REITER) {
|
||||
parameter("limit", 50000)
|
||||
}
|
||||
val rResults = if (rResponse.status.isSuccess()) {
|
||||
json.decodeFromString<List<ReiterRemoteDto>>(rResponse.bodyAsText()).map {
|
||||
val text = rResponse.bodyAsText()
|
||||
println("[ZNS] Sync Reiter: Received ${text.length} chars")
|
||||
json.decodeFromString<List<ReiterRemoteDto>>(text).map {
|
||||
ZnsRemoteReiter(it.reiterId, it.satznummer, it.nachname, it.vorname, it.reiterLizenz, it.lizenzKlasse)
|
||||
}
|
||||
} else emptyList()
|
||||
} else {
|
||||
println("[ZNS] Sync Reiter failed: ${rResponse.status}")
|
||||
emptyList()
|
||||
}
|
||||
|
||||
// 3. Pferde
|
||||
val pResponse: HttpResponse = httpClient.get(ApiRoutes.Masterdata.PFERDE) {
|
||||
parameter("limit", 50000)
|
||||
}
|
||||
val pResults = if (pResponse.status.isSuccess()) {
|
||||
val text = pResponse.bodyAsText()
|
||||
println("[ZNS] Sync Pferde: Received ${text.length} chars")
|
||||
json.decodeFromString<List<HorseRemoteDto>>(text).map {
|
||||
ZnsRemotePferd(it.pferdId, it.kopfnummer, it.pferdeName, it.lebensnummer, it.geschlecht)
|
||||
}
|
||||
} else {
|
||||
println("[ZNS] Sync Pferde failed: ${pResponse.status}")
|
||||
emptyList()
|
||||
}
|
||||
|
||||
// 4. Funktionäre
|
||||
val fResponse: HttpResponse = httpClient.get(ApiRoutes.Masterdata.FUNKTIONAERE) {
|
||||
parameter("limit", 1000)
|
||||
}
|
||||
val fResults = if (fResponse.status.isSuccess()) {
|
||||
val text = fResponse.bodyAsText()
|
||||
println("[ZNS] Sync Funktionäre: Received ${text.length} chars")
|
||||
json.decodeFromString<List<FunktionaerRemoteDto>>(text).map {
|
||||
ZnsRemoteFunktionaer(it.funktionaerId, it.satzId, it.satzNummer, it.name, it.qualifikationen)
|
||||
}
|
||||
} else {
|
||||
println("[ZNS] Sync Funktionäre failed: ${fResponse.status}")
|
||||
emptyList()
|
||||
}
|
||||
|
||||
state = state.copy(
|
||||
remoteResults = vResults,
|
||||
remoteReiterResults = rResults,
|
||||
isSyncing = false,
|
||||
isFinished = true
|
||||
)
|
||||
val pResponse: HttpResponse = httpClient.get("${NetworkConfig.baseUrl}/api/v1/masterdata/horse") {
|
||||
parameter("limit", 1000)
|
||||
if (token != null) header(HttpHeaders.Authorization, "Bearer $token")
|
||||
}
|
||||
val pResults = if (pResponse.status.isSuccess()) {
|
||||
json.decodeFromString<List<HorseRemoteDto>>(pResponse.bodyAsText()).map {
|
||||
ZnsRemotePferd(it.pferdId, it.kopfnummer, it.pferdeName, it.lebensnummer, it.geschlecht)
|
||||
}
|
||||
} else emptyList()
|
||||
|
||||
// 4. Funktionäre
|
||||
val fResponse: HttpResponse = httpClient.get("${NetworkConfig.baseUrl}/api/v1/masterdata/funktionaer") {
|
||||
parameter("limit", 1000)
|
||||
if (token != null) header(HttpHeaders.Authorization, "Bearer $token")
|
||||
}
|
||||
val fResults = if (fResponse.status.isSuccess()) {
|
||||
json.decodeFromString<List<FunktionaerRemoteDto>>(fResponse.bodyAsText()).map {
|
||||
ZnsRemoteFunktionaer(it.funktionaerId, it.satzId, it.satzNummer, it.name, it.qualifikationen)
|
||||
}
|
||||
} else emptyList()
|
||||
|
||||
state = state.copy(
|
||||
remoteHorseResults = pResults,
|
||||
remoteFunktionaerResults = fResults,
|
||||
isSyncing = false,
|
||||
isFinished = true
|
||||
)
|
||||
onResult(vResults, rResults, pResults, fResults)
|
||||
|
||||
} catch (e: Exception) {
|
||||
println("[ZNS] Sync Error: ${e.message}")
|
||||
e.printStackTrace()
|
||||
state = state.copy(isSyncing = false, errorMessage = "Fehler beim Cloud-Sync: ${e.message}")
|
||||
}
|
||||
}
|
||||
@@ -242,10 +253,7 @@ class ZnsImportViewModel(
|
||||
pollingJob = viewModelScope.launch {
|
||||
while (true) {
|
||||
try {
|
||||
val token = authTokenManager.authState.value.token
|
||||
val response: HttpResponse = httpClient.get("${NetworkConfig.baseUrl}/api/v1/import/zns/$jobId/status") {
|
||||
if (token != null) header(HttpHeaders.Authorization, "Bearer $token")
|
||||
}
|
||||
val response: HttpResponse = httpClient.get("/api/v1/import/zns/$jobId/status")
|
||||
if (response.status.isSuccess()) {
|
||||
val status = json.decodeFromString<JobStatusResponse>(response.bodyAsText())
|
||||
state = state.copy(
|
||||
|
||||
+15
-11
@@ -19,6 +19,7 @@ class DesktopMasterdataRepository(
|
||||
private val queries = db.meldestelleDbQueries
|
||||
|
||||
override fun saveVereine(vereine: List<ZnsRemoteVerein>) {
|
||||
if (vereine.isEmpty()) return
|
||||
println("[Repository] Speichere ${vereine.size} Vereine in SQLite")
|
||||
val now = System.currentTimeMillis()
|
||||
runBlocking {
|
||||
@@ -30,7 +31,7 @@ class DesktopMasterdataRepository(
|
||||
oebs_nummer = remote.oepsNummer,
|
||||
name = remote.name,
|
||||
ort = remote.ort,
|
||||
plz = null, // Falls vom Backend geliefert, hier mappen
|
||||
plz = null,
|
||||
bundesland = remote.bundesland,
|
||||
is_active = 1,
|
||||
last_updated = now
|
||||
@@ -55,6 +56,7 @@ class DesktopMasterdataRepository(
|
||||
}
|
||||
|
||||
override fun saveReiter(reiter: List<ZnsRemoteReiter>) {
|
||||
if (reiter.isEmpty()) return
|
||||
println("[Repository] Speichere ${reiter.size} Reiter in SQLite")
|
||||
val now = System.currentTimeMillis()
|
||||
runBlocking {
|
||||
@@ -66,7 +68,7 @@ class DesktopMasterdataRepository(
|
||||
zns_nummer = remote.satznummer,
|
||||
vorname = remote.vorname,
|
||||
nachname = remote.nachname,
|
||||
jahrgang = null, // Backend liefert aktuell kein Jahrgang direkt in ZnsRemoteReiter?
|
||||
jahrgang = null,
|
||||
geschlecht = null,
|
||||
nation = remote.nation ?: "AUT",
|
||||
is_active = 1,
|
||||
@@ -94,6 +96,7 @@ class DesktopMasterdataRepository(
|
||||
}
|
||||
|
||||
override fun savePferde(pferde: List<ZnsRemotePferd>) {
|
||||
if (pferde.isEmpty()) return
|
||||
println("[Repository] Speichere ${pferde.size} Pferde in SQLite")
|
||||
val now = System.currentTimeMillis()
|
||||
runBlocking {
|
||||
@@ -130,6 +133,7 @@ class DesktopMasterdataRepository(
|
||||
}
|
||||
|
||||
override fun saveFunktionaere(funktionaere: List<ZnsRemoteFunktionaer>) {
|
||||
if (funktionaere.isEmpty()) return
|
||||
println("[Repository] Speichere ${funktionaere.size} Funktionäre in SQLite")
|
||||
val now = System.currentTimeMillis()
|
||||
runBlocking {
|
||||
@@ -169,20 +173,20 @@ class DesktopMasterdataRepository(
|
||||
}
|
||||
|
||||
override fun getStats(): MasterdataStats {
|
||||
val vereinCount = queries.selectAllVereine().executeAsList().size.toLong()
|
||||
val reiterCount = queries.selectAllReiter().executeAsList().size.toLong()
|
||||
val pferdCount = queries.selectAllPferde().executeAsList().size.toLong()
|
||||
val funktionaerCount = queries.selectAllFunktionaere().executeAsList().size.toLong()
|
||||
val vereinCount = queries.countVereine().executeAsOne()
|
||||
val reiterCount = queries.countReiter().executeAsOne()
|
||||
val pferdCount = queries.countPferde().executeAsOne()
|
||||
val funktionaerCount = queries.countFunktionaere().executeAsOne()
|
||||
|
||||
val lastUpdate = listOf(
|
||||
queries.selectAllVereine().executeAsList().maxOfOrNull { it.last_updated } ?: 0L,
|
||||
queries.selectAllReiter().executeAsList().maxOfOrNull { it.last_updated } ?: 0L,
|
||||
queries.selectAllPferde().executeAsList().maxOfOrNull { it.last_updated } ?: 0L,
|
||||
queries.selectAllFunktionaere().executeAsList().maxOfOrNull { it.last_updated } ?: 0L
|
||||
queries.maxUpdatedVerein().executeAsOne().MAX ?: 0L,
|
||||
queries.maxUpdatedReiter().executeAsOne().MAX ?: 0L,
|
||||
queries.maxUpdatedPferd().executeAsOne().MAX ?: 0L,
|
||||
queries.maxUpdatedFunktionaer().executeAsOne().MAX ?: 0L
|
||||
).maxOrNull() ?: 0L
|
||||
|
||||
val lastImportStr = if (lastUpdate > 0) {
|
||||
val dt = LocalDateTime.now() // Vereinfacht, idealerweise aus lastUpdate-Zeitstempeln
|
||||
val dt = LocalDateTime.ofInstant(java.time.Instant.ofEpochMilli(lastUpdate), java.time.ZoneId.systemDefault())
|
||||
dt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
|
||||
} else "Nie"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user