diff --git a/library/sync/src/main/kotlin/org/cru/godtools/sync/task/UserFavoriteToolsSyncTasks.kt b/library/sync/src/main/kotlin/org/cru/godtools/sync/task/UserFavoriteToolsSyncTasks.kt index 1fbe50c0c0..6cd7e74b98 100644 --- a/library/sync/src/main/kotlin/org/cru/godtools/sync/task/UserFavoriteToolsSyncTasks.kt +++ b/library/sync/src/main/kotlin/org/cru/godtools/sync/task/UserFavoriteToolsSyncTasks.kt @@ -6,12 +6,15 @@ import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock +import org.ccci.gto.android.common.base.TimeConstants import org.ccci.gto.android.common.jsonapi.JsonApiConverter import org.ccci.gto.android.common.jsonapi.retrofit2.JsonApiParams import org.ccci.gto.android.common.jsonapi.retrofit2.model.JsonApiRetrofitObject +import org.ccci.gto.android.common.jsonapi.util.Includes import org.cru.godtools.account.GodToolsAccountManager import org.cru.godtools.api.UserApi import org.cru.godtools.api.UserFavoriteToolsApi +import org.cru.godtools.db.repository.LastSyncTimeRepository import org.cru.godtools.db.repository.ToolsRepository import org.cru.godtools.db.repository.UserRepository import org.cru.godtools.model.Tool @@ -22,13 +25,51 @@ import org.cru.godtools.sync.repository.SyncRepository internal class UserFavoriteToolsSyncTasks @Inject constructor( private val accountManager: GodToolsAccountManager, private val favoritesApi: UserFavoriteToolsApi, + private val lastSyncTimeRepository: LastSyncTimeRepository, private val syncRepository: SyncRepository, private val toolsRepository: ToolsRepository, private val userApi: UserApi, private val userRepository: UserRepository, ) : BaseSyncTasks() { + companion object { + private const val SYNC_TIME_FAVORITE_TOOLS = "last_synced.favorite_tools" + private const val STALE_DURATION_FAVORITE_TOOLS = TimeConstants.DAY_IN_MS + + private val INCLUDES_GET_FAVORITE_TOOLS = Includes(User.JSON_FAVORITE_TOOLS) + } + + private val favoriteToolsMutex = Mutex() private val favoritesUpdateMutex = Mutex() + suspend fun syncFavoriteTools(force: Boolean) = favoriteToolsMutex.withLock { + if (!accountManager.isAuthenticated()) return true + val userId = accountManager.userId().orEmpty() + + // short-circuit if we aren't forcing a sync and the data isn't stale + if (!force && + !lastSyncTimeRepository.isLastSyncStale( + SYNC_TIME_FAVORITE_TOOLS, + userId, + staleAfter = STALE_DURATION_FAVORITE_TOOLS + ) + ) { + return true + } + + val params = JsonApiParams() + .includes(INCLUDES_GET_FAVORITE_TOOLS) + .fields(Tool.JSONAPI_TYPE, *Tool.JSONAPI_FIELDS) + val user = userApi.getUser(params).takeIf { it.isSuccessful } + ?.body()?.takeUnless { it.hasErrors } + ?.dataSingle ?: return false + + syncRepository.storeUser(user, INCLUDES_GET_FAVORITE_TOOLS) + lastSyncTimeRepository.resetLastSyncTime(SYNC_TIME_FAVORITE_TOOLS, isPrefix = true) + lastSyncTimeRepository.updateLastSyncTime(SYNC_TIME_FAVORITE_TOOLS, user.id) + + true + } + suspend fun syncDirtyFavoriteTools(): Boolean = favoritesUpdateMutex.withLock { coroutineScope { if (!accountManager.isAuthenticated()) return@coroutineScope true diff --git a/library/sync/src/main/kotlin/org/cru/godtools/sync/task/UserSyncTasks.kt b/library/sync/src/main/kotlin/org/cru/godtools/sync/task/UserSyncTasks.kt index 8e8e45b318..1c543772c9 100644 --- a/library/sync/src/main/kotlin/org/cru/godtools/sync/task/UserSyncTasks.kt +++ b/library/sync/src/main/kotlin/org/cru/godtools/sync/task/UserSyncTasks.kt @@ -6,12 +6,10 @@ import javax.inject.Singleton import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import org.ccci.gto.android.common.base.TimeConstants.WEEK_IN_MS -import org.ccci.gto.android.common.jsonapi.retrofit2.JsonApiParams import org.ccci.gto.android.common.jsonapi.util.Includes import org.cru.godtools.account.GodToolsAccountManager import org.cru.godtools.api.UserApi import org.cru.godtools.db.repository.LastSyncTimeRepository -import org.cru.godtools.model.Tool import org.cru.godtools.model.User import org.cru.godtools.sync.repository.SyncRepository @@ -44,14 +42,11 @@ internal class UserSyncTasks @Inject constructor( return true } - val params = JsonApiParams() - .includes(INCLUDES_GET_USER) - .fields(Tool.JSONAPI_TYPE, *Tool.JSONAPI_FIELDS) - val user = userApi.getUser(params).takeIf { it.isSuccessful } + val user = userApi.getUser().takeIf { it.isSuccessful } ?.body()?.takeUnless { it.hasErrors() } ?.dataSingle ?: return false - syncRepository.storeUser(user, INCLUDES_GET_USER) + syncRepository.storeUser(user) lastSyncTimeRepository.updateLastSyncTime(SYNC_TIME_USER, user.id) true diff --git a/library/sync/src/test/kotlin/org/cru/godtools/sync/task/UserFavoriteToolsSyncTasksTest.kt b/library/sync/src/test/kotlin/org/cru/godtools/sync/task/UserFavoriteToolsSyncTasksTest.kt index 81b58f7c45..2d8a4a8ea3 100644 --- a/library/sync/src/test/kotlin/org/cru/godtools/sync/task/UserFavoriteToolsSyncTasksTest.kt +++ b/library/sync/src/test/kotlin/org/cru/godtools/sync/task/UserFavoriteToolsSyncTasksTest.kt @@ -54,6 +54,7 @@ class UserFavoriteToolsSyncTasksTest { private val tasks = UserFavoriteToolsSyncTasks( accountManager = accountManager, favoritesApi = favoritesApi, + lastSyncTimeRepository = mockk(), syncRepository = syncRepository, toolsRepository = toolsRepository, userApi = userApi, diff --git a/library/sync/src/test/kotlin/org/cru/godtools/sync/task/UserSyncTasksTest.kt b/library/sync/src/test/kotlin/org/cru/godtools/sync/task/UserSyncTasksTest.kt index cfbff82cd8..cd90bb3fdb 100644 --- a/library/sync/src/test/kotlin/org/cru/godtools/sync/task/UserSyncTasksTest.kt +++ b/library/sync/src/test/kotlin/org/cru/godtools/sync/task/UserSyncTasksTest.kt @@ -74,14 +74,14 @@ class UserSyncTasksTest { val startTime = System.currentTimeMillis() val user = User(id = USER_ID) coEvery { userApi.getUser(any()) } returns Response.success(JsonApiObject.of(user)) - coEvery { syncRepository.storeUser(user, UserSyncTasks.INCLUDES_GET_USER) } just Runs + coEvery { syncRepository.storeUser(user, any()) } just Runs assertTrue(tasks.syncUser(force = true)) coVerifyAll { accountManager.isAuthenticated() accountManager.userId() userApi.getUser(any()) - syncRepository.storeUser(user, UserSyncTasks.INCLUDES_GET_USER) + syncRepository.storeUser(user, any()) lastSyncTimeRepository.updateLastSyncTime(SYNC_TIME_USER, USER_ID) } assertTrue(lastSyncTimeRepository.getLastSyncTime(SYNC_TIME_USER, USER_ID) >= startTime) @@ -93,14 +93,14 @@ class UserSyncTasksTest { val user = User(id = USER_ID) coEvery { lastSyncTimeRepository.isLastSyncStale(SYNC_TIME_USER, USER_ID, staleAfter = any()) } returns true coEvery { userApi.getUser(any()) } returns Response.success(JsonApiObject.of(user)) - coEvery { syncRepository.storeUser(user, UserSyncTasks.INCLUDES_GET_USER) } just Runs + coEvery { syncRepository.storeUser(user, any()) } just Runs assertTrue(tasks.syncUser(force = true)) coVerifyAll { accountManager.isAuthenticated() accountManager.userId() userApi.getUser(any()) - syncRepository.storeUser(user, UserSyncTasks.INCLUDES_GET_USER) + syncRepository.storeUser(user, any()) lastSyncTimeRepository.updateLastSyncTime(SYNC_TIME_USER, USER_ID) } assertTrue(lastSyncTimeRepository.getLastSyncTime(SYNC_TIME_USER, USER_ID) >= startTime)