Sync Flag lifecycle
This commit is contained in:
@@ -14,6 +14,7 @@ import com.nextcloud.android.sso.api.NextcloudAPI
|
|||||||
import com.nextcloud.android.sso.exceptions.NextcloudHttpRequestFailedException
|
import com.nextcloud.android.sso.exceptions.NextcloudHttpRequestFailedException
|
||||||
import com.nextcloud.android.sso.exceptions.TokenMismatchException
|
import com.nextcloud.android.sso.exceptions.TokenMismatchException
|
||||||
import com.nextcloud.android.sso.helper.SingleAccountHelper
|
import com.nextcloud.android.sso.helper.SingleAccountHelper
|
||||||
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Deferred
|
import kotlinx.coroutines.Deferred
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -176,14 +177,22 @@ class CowspentServerSyncHelper private constructor(private val dbHelper: Cowspen
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun execute(): SyncTask {
|
fun execute(): SyncTask {
|
||||||
deferred = scope.async {
|
|
||||||
syncActive = true
|
syncActive = true
|
||||||
|
deferred = scope.async {
|
||||||
|
try {
|
||||||
val status = withContext(Dispatchers.IO) {
|
val status = withContext(Dispatchers.IO) {
|
||||||
doWork()
|
doWork()
|
||||||
}
|
}
|
||||||
onPostExecute(status)
|
onPostExecute(status)
|
||||||
syncActive = false
|
|
||||||
status
|
status
|
||||||
|
} catch (e: CancellationException) {
|
||||||
|
syncActive = false
|
||||||
|
throw e
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "Sync failed for ${project.remoteId}", e)
|
||||||
|
syncActive = false
|
||||||
|
LoginStatus.CONNECTION_FAILED
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
@@ -293,12 +302,8 @@ class CowspentServerSyncHelper private constructor(private val dbHelper: Cowspen
|
|||||||
null, null, null, null, null
|
null, null, null, null, null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} catch (e: IOException) {
|
} catch (e: Exception) {
|
||||||
if (e.message == "{\"message\": \"Internal Server Error\"}") {
|
Log.e(TAG, "EDIT MEMBER FAILED for ${mToEdit.name}", e)
|
||||||
Log.d(TAG, "EDIT MEMBER FAILED : it does not exist remotely")
|
|
||||||
} else {
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1048,6 +1053,8 @@ class CowspentServerSyncHelper private constructor(private val dbHelper: Cowspen
|
|||||||
for (localMember in dbHelper.getMembersOfProject(project.id, null)) {
|
for (localMember in dbHelper.getMembersOfProject(project.id, null)) {
|
||||||
if (remoteMembersByRemoteId.containsKey(localMember.remoteId)) continue
|
if (remoteMembersByRemoteId.containsKey(localMember.remoteId)) continue
|
||||||
|
|
||||||
|
if (localMember.state != DBBill.STATE_OK) continue
|
||||||
|
|
||||||
// A member still named by a bill cannot be removed without orphaning it.
|
// A member still named by a bill cannot be removed without orphaning it.
|
||||||
if (dbHelper.getBillsOfMember(localMember.id).isEmpty() &&
|
if (dbHelper.getBillsOfMember(localMember.id).isEmpty() &&
|
||||||
dbHelper.getBillowersOfMember(localMember.id).isEmpty()
|
dbHelper.getBillowersOfMember(localMember.id).isEmpty()
|
||||||
@@ -1514,12 +1521,19 @@ class CowspentServerSyncHelper private constructor(private val dbHelper: Cowspen
|
|||||||
fun execute(): SyncAccountProjectsTask {
|
fun execute(): SyncAccountProjectsTask {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
syncAccountProjectsActive = true
|
syncAccountProjectsActive = true
|
||||||
|
try {
|
||||||
val status = withContext(Dispatchers.IO) {
|
val status = withContext(Dispatchers.IO) {
|
||||||
doWork()
|
doWork()
|
||||||
}
|
}
|
||||||
onPostExecute(status)
|
onPostExecute(status)
|
||||||
|
} catch (e: CancellationException) {
|
||||||
|
throw e
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "Account projects sync failed", e)
|
||||||
|
} finally {
|
||||||
syncAccountProjectsActive = false
|
syncAccountProjectsActive = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1547,20 +1561,25 @@ class CowspentServerSyncHelper private constructor(private val dbHelper: Cowspen
|
|||||||
|
|
||||||
val response = client.getAccountProjects(useOcsApi)
|
val response = client.getAccountProjects(useOcsApi)
|
||||||
val remoteAccountProjects = response.getAccountProjects(url)
|
val remoteAccountProjects = response.getAccountProjects(url)
|
||||||
|
val forgotten = forgottenAccountProjects(preferences)
|
||||||
dbHelper.clearAccountProjects()
|
dbHelper.clearAccountProjects()
|
||||||
for (remoteAccountProject in remoteAccountProjects) {
|
for (remoteAccountProject in remoteAccountProjects) {
|
||||||
dbHelper.addAccountProject(remoteAccountProject)
|
dbHelper.addAccountProject(remoteAccountProject)
|
||||||
Log.v(TAG, "received account project $remoteAccountProject")
|
Log.v(TAG, "received account project $remoteAccountProject")
|
||||||
val existingProj = localProjects.find {
|
val existingProj = localProjects.find {
|
||||||
it.remoteId == remoteAccountProject.remoteId &&
|
it.remoteId == remoteAccountProject.remoteId &&
|
||||||
it.serverUrl?.replace("/+$".toRegex(), "") == remoteAccountProject.ncUrl.replace("/+$".toRegex(), "") + "/index.php/apps/cospend"
|
it.serverUrl?.replace("/+$".toRegex(), "") == remoteAccountProject.ncUrl.replace("/+$".toRegex(), "") + COSPEND_PATH
|
||||||
}
|
}
|
||||||
if (existingProj == null) {
|
if (existingProj == null) {
|
||||||
|
if (accountProjectKey(remoteAccountProject.remoteId, remoteAccountProject.ncUrl) in forgotten) {
|
||||||
|
Log.d(TAG, "skipping ${remoteAccountProject.remoteId}, deleted on this device")
|
||||||
|
continue
|
||||||
|
}
|
||||||
val newProj = DBProject(0,
|
val newProj = DBProject(0,
|
||||||
remoteAccountProject.remoteId,
|
remoteAccountProject.remoteId,
|
||||||
"",
|
"",
|
||||||
remoteAccountProject.name,
|
remoteAccountProject.name,
|
||||||
remoteAccountProject.ncUrl.replace("/+$".toRegex(), "") + "/index.php/apps/cospend",
|
remoteAccountProject.ncUrl.replace("/+$".toRegex(), "") + COSPEND_PATH,
|
||||||
"",
|
"",
|
||||||
null,
|
null,
|
||||||
ProjectType.COSPEND,
|
ProjectType.COSPEND,
|
||||||
@@ -1896,6 +1915,34 @@ class CowspentServerSyncHelper private constructor(private val dbHelper: Cowspen
|
|||||||
preferences.getBoolean(AccountActivity.SETTINGS_USE_SSO, false)
|
preferences.getBoolean(AccountActivity.SETTINGS_USE_SSO, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** The path a Cospend project's URL carries on top of its Nextcloud server URL. */
|
||||||
|
const val COSPEND_PATH = "/index.php/apps/cospend"
|
||||||
|
|
||||||
|
private const val FORGOTTEN_ACCOUNT_PROJECTS = "forgottenAccountProjects"
|
||||||
|
|
||||||
|
private fun trimSlashes(url: String) = url.replace("/+$".toRegex(), "")
|
||||||
|
|
||||||
|
/** Names one project an account offers, by server and remote id, with no local row needed. */
|
||||||
|
private fun accountProjectKey(remoteId: String, ncUrl: String) = "${trimSlashes(ncUrl)}|$remoteId"
|
||||||
|
|
||||||
|
/** The same key for a stored project, or null when it is not one an account can offer. */
|
||||||
|
private fun accountProjectKey(project: DBProject): String? {
|
||||||
|
val url = trimSlashes(project.serverUrl.orEmpty())
|
||||||
|
if (!url.endsWith(COSPEND_PATH)) return null
|
||||||
|
return accountProjectKey(project.remoteId, url.removeSuffix(COSPEND_PATH))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun forgottenAccountProjects(preferences: SharedPreferences): Set<String> =
|
||||||
|
preferences.getStringSet(FORGOTTEN_ACCOUNT_PROJECTS, emptySet()).orEmpty()
|
||||||
|
|
||||||
|
fun forgetAccountProject(context: Context, project: DBProject) {
|
||||||
|
val key = accountProjectKey(project) ?: return
|
||||||
|
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
preferences.edit {
|
||||||
|
putStringSet(FORGOTTEN_ACCOUNT_PROJECTS, forgottenAccountProjects(preferences) + key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun getNextcloudAccountServerUrl(context: Context): String {
|
fun getNextcloudAccountServerUrl(context: Context): String {
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
return if (preferences.getBoolean(AccountActivity.SETTINGS_USE_SSO, false)) {
|
return if (preferences.getBoolean(AccountActivity.SETTINGS_USE_SSO, false)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user