Added EventHandler for User & Addresses.
This commit is contained in:
parent
65a6e83a4f
commit
e6e1912330
|
@ -20,8 +20,8 @@ package ch.protonmail.android.activities;
|
|||
|
||||
import static ch.protonmail.android.settings.pin.ValidatePinActivityKt.EXTRA_FRAGMENT_TITLE;
|
||||
import static ch.protonmail.android.settings.pin.ValidatePinActivityKt.EXTRA_PIN_VALID;
|
||||
import static ch.protonmail.android.worker.FetchUserInfoWorkerKt.FETCH_USER_INFO_WORKER_NAME;
|
||||
import static ch.protonmail.android.worker.FetchUserInfoWorkerKt.FETCH_USER_INFO_WORKER_RESULT;
|
||||
import static ch.protonmail.android.worker.FetchUserWorkerKt.FETCH_USER_INFO_WORKER_NAME;
|
||||
import static ch.protonmail.android.worker.FetchUserWorkerKt.FETCH_USER_INFO_WORKER_RESULT;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.BroadcastReceiver;
|
||||
|
@ -38,13 +38,10 @@ import android.view.WindowManager;
|
|||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.activity.ComponentActivity;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.work.WorkManager;
|
||||
|
||||
import com.birbit.android.jobqueue.JobManager;
|
||||
|
@ -77,7 +74,7 @@ import ch.protonmail.android.utils.AppUtil;
|
|||
import ch.protonmail.android.utils.CustomLocale;
|
||||
import ch.protonmail.android.utils.INetworkConfiguratorCallback;
|
||||
import ch.protonmail.android.worker.FetchMailSettingsWorker;
|
||||
import ch.protonmail.android.worker.FetchUserInfoWorker;
|
||||
import ch.protonmail.android.worker.FetchUserWorker;
|
||||
import dagger.hilt.android.AndroidEntryPoint;
|
||||
import timber.log.Timber;
|
||||
|
||||
|
@ -118,7 +115,7 @@ public abstract class BaseActivity extends AppCompatActivity implements INetwork
|
|||
@Inject
|
||||
protected WorkManager workManager;
|
||||
@Inject
|
||||
protected FetchUserInfoWorker.Enqueuer fetchUserInfoWorkerEnqueuer;
|
||||
protected FetchUserWorker.Enqueuer fetchUserInfoWorkerEnqueuer;
|
||||
@Inject
|
||||
protected FetchMailSettingsWorker.Enqueuer fetchMailSettingsWorkerEnqueuer;
|
||||
|
||||
|
@ -401,6 +398,7 @@ public abstract class BaseActivity extends AppCompatActivity implements INetwork
|
|||
});
|
||||
btnClose.setOnClickListener(v -> finish());
|
||||
btnCheckAgain.setOnClickListener(v -> {
|
||||
// TODO: Remove fetchUserInfoWorkerEnqueuer, not adapted for this usage.
|
||||
fetchUserInfoWorkerEnqueuer.invoke(user.getId());
|
||||
workManager.getWorkInfosForUniqueWorkLiveData(FETCH_USER_INFO_WORKER_NAME)
|
||||
.observe(this, workInfo -> {
|
||||
|
|
|
@ -59,6 +59,8 @@ import ch.protonmail.android.utils.AppUtil
|
|||
import ch.protonmail.android.utils.MessageUtils
|
||||
import ch.protonmail.android.worker.FetchContactsDataWorker
|
||||
import ch.protonmail.android.worker.FetchContactsEmailsWorker
|
||||
import ch.protonmail.android.worker.FetchUserAddressesWorker
|
||||
import ch.protonmail.android.worker.FetchUserWorker
|
||||
import com.google.gson.JsonSyntaxException
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
|
@ -72,6 +74,8 @@ class EventHandler @AssistedInject constructor(
|
|||
private val messageDetailsRepositoryFactory: MessageDetailsRepository.AssistedFactory,
|
||||
private val fetchContactEmails: FetchContactsEmailsWorker.Enqueuer,
|
||||
private val fetchContactsData: FetchContactsDataWorker.Enqueuer,
|
||||
private val fetchUserWorkerEnqueuer: FetchUserWorker.Enqueuer,
|
||||
private val fetchUserAddressesWorkerEnqueuer: FetchUserAddressesWorker.Enqueuer,
|
||||
private val databaseProvider: DatabaseProvider,
|
||||
private val launchInitialDataFetch: LaunchInitialDataFetch,
|
||||
@Assisted val userId: Id
|
||||
|
@ -240,12 +244,12 @@ class EventHandler @AssistedInject constructor(
|
|||
writeMailSettings(context, mailSettings)
|
||||
}
|
||||
if (user != null) {
|
||||
// TODO: Refresh User.
|
||||
AppUtil.postEventOnUi(RefreshDrawerEvent())
|
||||
// Core is the source of truth. Workaround: Force refresh Core.
|
||||
fetchUserWorkerEnqueuer(userId)
|
||||
}
|
||||
if (addresses != null) {
|
||||
// TODO: Refresh Addresses.
|
||||
AppUtil.postEventOnUi(RefreshDrawerEvent())
|
||||
// Core is the source of truth. Workaround: Force refresh Core.
|
||||
fetchUserAddressesWorkerEnqueuer(userId)
|
||||
}
|
||||
if (counts != null) {
|
||||
writeUnreadUpdates(counts)
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Proton Technologies AG
|
||||
*
|
||||
* This file is part of ProtonMail.
|
||||
*
|
||||
* ProtonMail is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonMail is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonMail. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
package ch.protonmail.android.worker
|
||||
|
||||
import android.content.Context
|
||||
import androidx.hilt.work.HiltWorker
|
||||
import androidx.work.Constraints
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.Data
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.NetworkType
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.WorkRequest
|
||||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import ch.protonmail.android.attachments.KEY_INPUT_DATA_USER_ID_STRING
|
||||
import ch.protonmail.android.domain.entity.Id
|
||||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.user.domain.UserManager
|
||||
import me.proton.core.util.kotlin.takeIfNotBlank
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import javax.inject.Inject
|
||||
|
||||
// region constants
|
||||
const val FETCH_ADDRESSES_WORKER_NAME = "FetchUserAddressesWorker"
|
||||
// endregion
|
||||
|
||||
@HiltWorker
|
||||
class FetchUserAddressesWorker @AssistedInject constructor(
|
||||
@Assisted context: Context,
|
||||
@Assisted params: WorkerParameters,
|
||||
private val userManager: UserManager,
|
||||
private val oldUserManager: ch.protonmail.android.core.UserManager
|
||||
) : CoroutineWorker(context, params) {
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
val userIdString = inputData.getString(KEY_INPUT_DATA_USER_ID_STRING)?.takeIfNotBlank()
|
||||
?: return Result.failure(workDataOf(KEY_WORKER_ERROR_DESCRIPTION to "Cannot proceed with empty user id"))
|
||||
|
||||
return runCatching {
|
||||
userManager.getAddresses(UserId(userIdString), refresh = true).also {
|
||||
oldUserManager.clearCache()
|
||||
}
|
||||
}.fold(
|
||||
onSuccess = { Result.success() },
|
||||
onFailure = { Result.failure() }
|
||||
)
|
||||
}
|
||||
|
||||
class Enqueuer @Inject constructor(private val workManager: WorkManager) {
|
||||
|
||||
operator fun invoke(userId: Id): WorkRequest {
|
||||
val constraints = Constraints.Builder()
|
||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||
.build()
|
||||
|
||||
val data = Data.Builder()
|
||||
.putString(KEY_INPUT_DATA_USER_ID_STRING, userId.s)
|
||||
.build()
|
||||
|
||||
val request = OneTimeWorkRequestBuilder<FetchUserAddressesWorker>()
|
||||
.setConstraints(constraints)
|
||||
.setInputData(data)
|
||||
.build()
|
||||
|
||||
workManager.enqueueUniqueWork(FETCH_ADDRESSES_WORKER_NAME, ExistingWorkPolicy.KEEP, request)
|
||||
return request
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,29 +33,23 @@ import androidx.work.WorkerParameters
|
|||
import androidx.work.workDataOf
|
||||
import ch.protonmail.android.attachments.KEY_INPUT_DATA_USER_ID_STRING
|
||||
import ch.protonmail.android.domain.entity.Id
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.user.domain.UserManager
|
||||
import me.proton.core.user.domain.entity.Delinquent
|
||||
import me.proton.core.util.kotlin.takeIfNotBlank
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* A `Worker` that handles fetching user info.
|
||||
*
|
||||
* @author Stefanija Boshkovska
|
||||
*/
|
||||
|
||||
// region constants
|
||||
const val FETCH_USER_INFO_WORKER_NAME = "FetchUserInfoWorker"
|
||||
const val FETCH_USER_INFO_WORKER_RESULT = "FetchUserInfoWorkerResult"
|
||||
const val FETCH_USER_INFO_WORKER_EXCEPTION_MESSAGE = "FetchUserInfoWorkerExceptionMessage"
|
||||
// endregion
|
||||
|
||||
@Deprecated("Remove this worker, its not needed and not adapted for the current usage.")
|
||||
@Deprecated("Refactor resultData + BaseActivity.checkDelinquency")
|
||||
@HiltWorker
|
||||
class FetchUserInfoWorker @AssistedInject constructor(
|
||||
class FetchUserWorker @AssistedInject constructor(
|
||||
@Assisted context: Context,
|
||||
@Assisted params: WorkerParameters,
|
||||
private val userManager: UserManager,
|
||||
|
@ -71,12 +65,11 @@ class FetchUserInfoWorker @AssistedInject constructor(
|
|||
oldUserManager.clearCache()
|
||||
}
|
||||
}.map { user ->
|
||||
// TODO: Remove this result.
|
||||
workDataOf(FETCH_USER_INFO_WORKER_RESULT to (user.delinquent != Delinquent.None))
|
||||
}.fold(
|
||||
onSuccess = { resultData -> Result.success(resultData) },
|
||||
onFailure = { exception ->
|
||||
Result.failure(workDataOf(FETCH_USER_INFO_WORKER_EXCEPTION_MESSAGE to exception.message))
|
||||
}
|
||||
onFailure = { Result.failure() }
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -91,7 +84,7 @@ class FetchUserInfoWorker @AssistedInject constructor(
|
|||
.putString(KEY_INPUT_DATA_USER_ID_STRING, userId.s)
|
||||
.build()
|
||||
|
||||
val request = OneTimeWorkRequestBuilder<FetchUserInfoWorker>()
|
||||
val request = OneTimeWorkRequestBuilder<FetchUserWorker>()
|
||||
.setConstraints(constraints)
|
||||
.setInputData(data)
|
||||
.build()
|
|
@ -24,37 +24,28 @@ import android.text.TextUtils
|
|||
import androidx.work.ListenableWorker
|
||||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import ch.protonmail.android.api.ProtonMailApiManager
|
||||
import ch.protonmail.android.api.models.User
|
||||
import ch.protonmail.android.api.models.UserInfo
|
||||
import ch.protonmail.android.api.models.address.AddressesResponse
|
||||
import ch.protonmail.android.api.segments.RESPONSE_CODE_UNAUTHORIZED
|
||||
import ch.protonmail.android.core.Constants
|
||||
import ch.protonmail.android.core.UserManager
|
||||
import io.mockk.MockKAnnotations
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.every
|
||||
import io.mockk.impl.annotations.MockK
|
||||
import io.mockk.impl.annotations.RelaxedMockK
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.runs
|
||||
import io.mockk.spyk
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import me.proton.core.test.kotlin.TestDispatcherProvider
|
||||
import java.io.IOException
|
||||
import me.proton.core.network.domain.ApiException
|
||||
import me.proton.core.user.domain.UserManager
|
||||
import me.proton.core.user.domain.entity.Delinquent
|
||||
import kotlin.test.BeforeTest
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
/**
|
||||
* Tests the functionality of [FetchUserInfoWorker].
|
||||
* Tests the functionality of [FetchUserWorker].
|
||||
*
|
||||
* @author Stefanija Boshkovska
|
||||
*/
|
||||
|
||||
class FetchUserInfoWorkerTest {
|
||||
class FetchUserWorkerTest {
|
||||
|
||||
@RelaxedMockK
|
||||
private lateinit var context: Context
|
||||
|
@ -62,13 +53,13 @@ class FetchUserInfoWorkerTest {
|
|||
@RelaxedMockK
|
||||
private lateinit var parameters: WorkerParameters
|
||||
|
||||
@MockK
|
||||
private lateinit var protonMailApiManager: ProtonMailApiManager
|
||||
|
||||
@MockK
|
||||
private lateinit var userManager: UserManager
|
||||
|
||||
private lateinit var worker: FetchUserInfoWorker
|
||||
@MockK
|
||||
private lateinit var oldUserManager: ch.protonmail.android.core.UserManager
|
||||
|
||||
private lateinit var worker: FetchUserWorker
|
||||
|
||||
@BeforeTest
|
||||
fun setUp() {
|
||||
|
@ -77,36 +68,23 @@ class FetchUserInfoWorkerTest {
|
|||
mockkStatic(TextUtils::class)
|
||||
every { TextUtils.isEmpty(any()) } returns false
|
||||
|
||||
worker = FetchUserInfoWorker(
|
||||
worker = FetchUserWorker(
|
||||
context,
|
||||
parameters,
|
||||
protonMailApiManager,
|
||||
userManager,
|
||||
TestDispatcherProvider
|
||||
oldUserManager
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return new user delinquency data when both API calls are successful`() {
|
||||
runBlocking {
|
||||
val mockUser = spyk<User> {
|
||||
every { delinquent } returns false
|
||||
val mockUser = spyk<me.proton.core.user.domain.entity.User> {
|
||||
every { delinquent } returns Delinquent.None
|
||||
every { name } returns "name"
|
||||
every { setAddresses(any()) } just runs
|
||||
}
|
||||
val mockUserInfoResponse = mockk<UserInfo> {
|
||||
every { code } returns Constants.RESPONSE_CODE_OK
|
||||
every { user } returns mockUser
|
||||
}
|
||||
val mockAddressesResponse = mockk<AddressesResponse> {
|
||||
every { code } returns Constants.RESPONSE_CODE_OK
|
||||
every { addresses } returns mockk()
|
||||
}
|
||||
|
||||
coEvery { protonMailApiManager.fetchUserInfo() } returns mockUserInfoResponse
|
||||
coEvery { protonMailApiManager.fetchAddresses() } returns mockAddressesResponse
|
||||
|
||||
every { userManager.currentLegacyUser } returns mockUser
|
||||
coEvery { userManager.getUser(any(), any()) } returns mockUser
|
||||
|
||||
val expectedResult = ListenableWorker.Result.success(workDataOf(FETCH_USER_INFO_WORKER_RESULT to false))
|
||||
|
||||
|
@ -121,20 +99,11 @@ class FetchUserInfoWorkerTest {
|
|||
@Test
|
||||
fun `should return old user delinquency data when at least one of the API calls responds with error code`() {
|
||||
runBlocking {
|
||||
val mockUser = spyk<User> {
|
||||
every { delinquent } returns true
|
||||
}
|
||||
val mockUserInfoResponse = mockk<UserInfo> {
|
||||
every { code } returns Constants.RESPONSE_CODE_OK
|
||||
}
|
||||
val mockAddressesResponse = mockk<AddressesResponse> {
|
||||
every { code } returns RESPONSE_CODE_UNAUTHORIZED
|
||||
val mockUser = spyk<me.proton.core.user.domain.entity.User> {
|
||||
every { delinquent } returns Delinquent.InvoiceDelinquent
|
||||
}
|
||||
|
||||
coEvery { protonMailApiManager.fetchUserInfo() } returns mockUserInfoResponse
|
||||
coEvery { protonMailApiManager.fetchAddresses() } returns mockAddressesResponse
|
||||
|
||||
every { userManager.currentLegacyUser } returns mockUser
|
||||
coEvery { userManager.getUser(any(), any()) } returns mockUser
|
||||
|
||||
val expectedResult = ListenableWorker.Result.success(workDataOf(FETCH_USER_INFO_WORKER_RESULT to true))
|
||||
|
||||
|
@ -149,17 +118,14 @@ class FetchUserInfoWorkerTest {
|
|||
@Test
|
||||
fun `should return failure result when at least one of the API calls throws an exception`() {
|
||||
runBlocking {
|
||||
val mockUserInfoResponse = mockk<UserInfo> {
|
||||
every { code } returns Constants.RESPONSE_CODE_OK
|
||||
}
|
||||
val mockException = spyk<IOException> {
|
||||
val mockException = spyk<ApiException> {
|
||||
every { message } returns "exception"
|
||||
}
|
||||
|
||||
coEvery { protonMailApiManager.fetchUserInfo() } returns mockUserInfoResponse
|
||||
coEvery { protonMailApiManager.fetchAddresses() } throws mockException
|
||||
coEvery { userManager.getUser(any(), any()) } throws mockException
|
||||
|
||||
val expectedResult = ListenableWorker.Result.failure(workDataOf(FETCH_USER_INFO_WORKER_EXCEPTION_MESSAGE to "exception"))
|
||||
val expectedResult =
|
||||
ListenableWorker.Result.failure(workDataOf(FETCH_USER_INFO_WORKER_EXCEPTION_MESSAGE to "exception"))
|
||||
|
||||
// when
|
||||
val workerResult = worker.doWork()
|
Loading…
Reference in New Issue