From 1f3f75b01c753b2bdd9a1e9c04981ea75e609772 Mon Sep 17 00:00:00 2001 From: Oussama Hassine Date: Fri, 27 Oct 2023 12:18:19 +0200 Subject: [PATCH 1/2] feat: use case for observing team app lock config --- .../com/wire/kalium/logic/data/event/Event.kt | 14 +++ .../kalium/logic/data/event/EventMapper.kt | 7 ++ .../kalium/logic/feature/UserSessionScope.kt | 5 + .../logic/feature/applock/AppLockConfig.kt | 25 +++++ .../AppLockTeamFeatureConfigObserver.kt | 54 +++++++++ .../receiver/FeatureConfigEventReceiver.kt | 8 +- .../AppLockTeamFeatureConfigObserverTest.kt | 103 ++++++++++++++++++ .../asset/GetMessageAssetUseCaseTest.kt | 2 - .../asset/GetPublicAssetUseCaseTest.kt | 2 - ...teAssetMessageDownloadStatusUseCaseTest.kt | 2 - 10 files changed, 210 insertions(+), 12 deletions(-) create mode 100644 logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/AppLockConfig.kt create mode 100644 logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/AppLockTeamFeatureConfigObserver.kt create mode 100644 logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/applock/AppLockTeamFeatureConfigObserverTest.kt diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/event/Event.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/event/Event.kt index 17297a83053..d62ca5dc972 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/event/Event.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/event/Event.kt @@ -29,6 +29,7 @@ import com.wire.kalium.logic.data.conversation.Conversation.Member import com.wire.kalium.logic.data.conversation.Conversation.ReceiptMode import com.wire.kalium.logic.data.conversation.Conversation.TypingIndicatorMode import com.wire.kalium.logic.data.conversation.MutedConversationStatus +import com.wire.kalium.logic.data.featureConfig.AppLockModel import com.wire.kalium.logic.data.featureConfig.ClassifiedDomainsModel import com.wire.kalium.logic.data.featureConfig.ConferenceCallingModel import com.wire.kalium.logic.data.featureConfig.ConfigsStatusModel @@ -609,6 +610,19 @@ sealed class Event(open val id: String, open val transient: Boolean, open val li "config" to model.config ) } + data class AppLockUpdated( + override val id: String, + override val transient: Boolean, + override val live: Boolean, + val model: AppLockModel + ) : FeatureConfig(id, transient, live) { + override fun toLogMap(): Map = mapOf( + typeKey to "FeatureConfig.AppLockUpdated", + idKey to id.obfuscateId(), + featureStatusKey to model.status.name, + "config" to model.config + ) + } data class UnknownFeatureUpdated( override val id: String, diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/event/EventMapper.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/event/EventMapper.kt index 87b49e61b6b..bfcf6570fa8 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/event/EventMapper.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/event/EventMapper.kt @@ -558,6 +558,13 @@ class EventMapper( featureConfigMapper.fromDTO(featureConfigUpdatedDTO.data as FeatureConfigData.E2EI) ) + is FeatureConfigData.AppLock -> Event.FeatureConfig.AppLockUpdated( + id, + transient, + live, + featureConfigMapper.fromDTO(featureConfigUpdatedDTO.data as FeatureConfigData.AppLock) + ) + else -> Event.FeatureConfig.UnknownFeatureUpdated(id, transient, live) } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt index c96785324c9..e1db2305c64 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt @@ -130,6 +130,8 @@ import com.wire.kalium.logic.di.MapperProvider import com.wire.kalium.logic.di.PlatformUserStorageProperties import com.wire.kalium.logic.di.RootPathsProvider import com.wire.kalium.logic.di.UserStorageProvider +import com.wire.kalium.logic.feature.applock.AppLockTeamFeatureConfigObserver +import com.wire.kalium.logic.feature.applock.AppLockTeamFeatureConfigObserverImpl import com.wire.kalium.logic.feature.asset.ValidateAssetMimeTypeUseCase import com.wire.kalium.logic.feature.asset.ValidateAssetMimeTypeUseCaseImpl import com.wire.kalium.logic.feature.auth.AuthenticationScope @@ -1575,6 +1577,9 @@ class UserSessionScope internal constructor( val markGuestLinkFeatureFlagAsNotChanged: MarkGuestLinkFeatureFlagAsNotChangedUseCase get() = MarkGuestLinkFeatureFlagAsNotChangedUseCaseImpl(userConfigRepository) + val appLockTeamFeatureConfigObserver: AppLockTeamFeatureConfigObserver + get() = AppLockTeamFeatureConfigObserverImpl(userConfigRepository) + val markSelfDeletingMessagesAsNotified: MarkSelfDeletionStatusAsNotifiedUseCase get() = MarkSelfDeletionStatusAsNotifiedUseCaseImpl(userConfigRepository) diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/AppLockConfig.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/AppLockConfig.kt new file mode 100644 index 00000000000..1656d9e098c --- /dev/null +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/AppLockConfig.kt @@ -0,0 +1,25 @@ +/* + * Wire + * Copyright (C) 2023 Wire Swiss GmbH + * + * This program 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. + * + * This program 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 this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.feature.applock + +import kotlin.time.Duration + +data class AppLockConfig( + val isEnabled: Boolean, + val timeout: Duration +) diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/AppLockTeamFeatureConfigObserver.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/AppLockTeamFeatureConfigObserver.kt new file mode 100644 index 00000000000..8c516544db8 --- /dev/null +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/AppLockTeamFeatureConfigObserver.kt @@ -0,0 +1,54 @@ +/* + * Wire + * Copyright (C) 2023 Wire Swiss GmbH + * + * This program 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. + * + * This program 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 this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.feature.applock + +import com.wire.kalium.logic.configuration.UserConfigRepository +import com.wire.kalium.logic.functional.fold +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlin.time.Duration.Companion.seconds + +/** + * observe app lock feature flag of the team + */ +interface AppLockTeamFeatureConfigObserver { + operator fun invoke(): Flow +} + +class AppLockTeamFeatureConfigObserverImpl( + private val userConfigRepository: UserConfigRepository +) : AppLockTeamFeatureConfigObserver { + override fun invoke(): Flow = + userConfigRepository.observeAppLockStatus().map { + it.fold({ + AppLockConfig( + isEnabled = false, + timeout = DEFAULT_TIMEOUT + ) + }, { appLockModel -> + AppLockConfig( + isEnabled = appLockModel.enforceAppLock, + timeout = appLockModel.inactivityTimeoutSecs.seconds + ) + }) + } + + companion object { + val DEFAULT_TIMEOUT = 60.seconds + } +} diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/receiver/FeatureConfigEventReceiver.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/receiver/FeatureConfigEventReceiver.kt index ac5c525e3ee..f1efb4a8984 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/receiver/FeatureConfigEventReceiver.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/receiver/FeatureConfigEventReceiver.kt @@ -53,7 +53,7 @@ internal class FeatureConfigEventReceiverImpl internal constructor( private val appLockConfigHandler: AppLockConfigHandler ) : FeatureConfigEventReceiver { - override suspend fun onEvent(event: Event.FeatureConfig): Either { + override suspend fun onEvent(event: Event.FeatureConfig): Either = handleFeatureConfigEvent(event) .onSuccess { kaliumLogger.logEventProcessing( @@ -76,11 +76,6 @@ internal class FeatureConfigEventReceiverImpl internal constructor( ) } } - // TODO: Make sure errors are accounted for. - // onEvent now requires Either, so we can propagate errors. - // Returning Either.Right is the equivalent of how it was originally working. - return Either.Right(Unit) - } @Suppress("LongMethod", "ComplexMethod") private suspend fun handleFeatureConfigEvent(event: Event.FeatureConfig): Either = @@ -93,6 +88,7 @@ internal class FeatureConfigEventReceiverImpl internal constructor( is Event.FeatureConfig.GuestRoomLinkUpdated -> guestRoomConfigHandler.handle(event.model) is Event.FeatureConfig.SelfDeletingMessagesConfig -> selfDeletingMessagesConfigHandler.handle(event.model) is Event.FeatureConfig.MLSE2EIUpdated -> e2EIConfigHandler.handle(event.model) + is Event.FeatureConfig.AppLockUpdated -> appLockConfigHandler.handle(event.model) is Event.FeatureConfig.UnknownFeatureUpdated -> Either.Left(CoreFailure.FeatureNotImplemented) } } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/applock/AppLockTeamFeatureConfigObserverTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/applock/AppLockTeamFeatureConfigObserverTest.kt new file mode 100644 index 00000000000..a688dfaa4ef --- /dev/null +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/applock/AppLockTeamFeatureConfigObserverTest.kt @@ -0,0 +1,103 @@ +/* + * Wire + * Copyright (C) 2023 Wire Swiss GmbH + * + * This program 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. + * + * This program 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 this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.feature.applock + +import com.wire.kalium.logic.StorageFailure +import com.wire.kalium.logic.configuration.UserConfigRepository +import com.wire.kalium.logic.data.featureConfig.AppLockConfigModel +import com.wire.kalium.logic.functional.Either +import io.mockative.Mock +import io.mockative.classOf +import io.mockative.given +import io.mockative.mock +import io.mockative.once +import io.mockative.verify +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.runTest +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.time.Duration.Companion.seconds + +class AppLockTeamFeatureConfigObserverTest { + + @Test + fun givenRepositoryFailure_whenObservingAppLock_thenEmitAppLockConfigWithDisabledStatus() = + runTest { + val expectedAppLockValue = AppLockConfig( + false, + AppLockTeamFeatureConfigObserverImpl.DEFAULT_TIMEOUT + ) + val (arrangement, observer) = Arrangement() + .withFailure() + .arrange() + + val result = observer.invoke() + + verify(arrangement.userConfigRepository) + .function(arrangement.userConfigRepository::observeAppLockStatus) + .wasInvoked(exactly = once) + assertEquals(expectedAppLockValue, result.first()) + } + + @Test + fun givenRepositorySuccess_whenObservingAppLock_thenEmitAppLockConfigWithValueFromRepository() { + runTest { + val expectedAppLockValue = AppLockConfig( + appLockConfigModel.enforceAppLock, + appLockConfigModel.inactivityTimeoutSecs.seconds + ) + val (arrangement, observer) = Arrangement() + .withSuccess() + .arrange() + + val result = observer.invoke() + + verify(arrangement.userConfigRepository) + .function(arrangement.userConfigRepository::observeAppLockStatus) + .wasInvoked(exactly = once) + assertEquals(expectedAppLockValue, result.first()) + } + } + + private class Arrangement { + + @Mock + val userConfigRepository = mock(classOf()) + + fun withFailure(): Arrangement = apply { + given(userConfigRepository) + .function(userConfigRepository::observeAppLockStatus) + .whenInvoked() + .thenReturn(flowOf(Either.Left(StorageFailure.DataNotFound))) + } + + fun withSuccess(): Arrangement = apply { + given(userConfigRepository) + .function(userConfigRepository::observeAppLockStatus) + .whenInvoked() + .thenReturn(flowOf(Either.Right(appLockConfigModel))) + } + + fun arrange() = this to AppLockTeamFeatureConfigObserverImpl(userConfigRepository) + } + + companion object { + val appLockConfigModel = AppLockConfigModel(true, 60) + } +} diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/GetMessageAssetUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/GetMessageAssetUseCaseTest.kt index 18b0faffa6c..30b4a98ba68 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/GetMessageAssetUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/GetMessageAssetUseCaseTest.kt @@ -47,7 +47,6 @@ import io.mockative.matching import io.mockative.mock import io.mockative.once import io.mockative.verify -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import okio.Path @@ -58,7 +57,6 @@ import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue -@OptIn(ExperimentalCoroutinesApi::class) class GetMessageAssetUseCaseTest { private fun getSuccessfulFlowArrangement( diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/GetPublicAssetUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/GetPublicAssetUseCaseTest.kt index e71d56f7b1e..4c15e3dd850 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/GetPublicAssetUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/GetPublicAssetUseCaseTest.kt @@ -35,14 +35,12 @@ import io.mockative.given import io.mockative.mock import io.mockative.once import io.mockative.verify -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import okio.Path.Companion.toPath import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals -@OptIn(ExperimentalCoroutinesApi::class) class GetPublicAssetUseCaseTest { @Mock diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/UpdateAssetMessageDownloadStatusUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/UpdateAssetMessageDownloadStatusUseCaseTest.kt index 3f891b8924e..f9fb08d9bff 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/UpdateAssetMessageDownloadStatusUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/UpdateAssetMessageDownloadStatusUseCaseTest.kt @@ -24,12 +24,10 @@ import com.wire.kalium.logic.data.message.Message import com.wire.kalium.logic.data.message.MessageRepository import com.wire.kalium.logic.functional.Either import io.mockative.* -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import kotlin.test.Test import kotlin.test.assertTrue -@OptIn(ExperimentalCoroutinesApi::class) class UpdateAssetMessageDownloadStatusUseCaseTest { @Test From f148d31d9b9ddc937324a9661136722274847a36 Mon Sep 17 00:00:00 2001 From: Oussama Hassine Date: Fri, 27 Oct 2023 16:03:21 +0200 Subject: [PATCH 2/2] chore: rename Applock data class --- .../applock/{AppLockConfig.kt => AppLockTeamConfig.kt} | 2 +- .../feature/applock/AppLockTeamFeatureConfigObserver.kt | 8 ++++---- .../applock/AppLockTeamFeatureConfigObserverTest.kt | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) rename logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/{AppLockConfig.kt => AppLockTeamConfig.kt} (96%) diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/AppLockConfig.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/AppLockTeamConfig.kt similarity index 96% rename from logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/AppLockConfig.kt rename to logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/AppLockTeamConfig.kt index 1656d9e098c..dcb3cd1b2c5 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/AppLockConfig.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/AppLockTeamConfig.kt @@ -19,7 +19,7 @@ package com.wire.kalium.logic.feature.applock import kotlin.time.Duration -data class AppLockConfig( +data class AppLockTeamConfig( val isEnabled: Boolean, val timeout: Duration ) diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/AppLockTeamFeatureConfigObserver.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/AppLockTeamFeatureConfigObserver.kt index 8c516544db8..58e20b02762 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/AppLockTeamFeatureConfigObserver.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/AppLockTeamFeatureConfigObserver.kt @@ -27,21 +27,21 @@ import kotlin.time.Duration.Companion.seconds * observe app lock feature flag of the team */ interface AppLockTeamFeatureConfigObserver { - operator fun invoke(): Flow + operator fun invoke(): Flow } class AppLockTeamFeatureConfigObserverImpl( private val userConfigRepository: UserConfigRepository ) : AppLockTeamFeatureConfigObserver { - override fun invoke(): Flow = + override fun invoke(): Flow = userConfigRepository.observeAppLockStatus().map { it.fold({ - AppLockConfig( + AppLockTeamConfig( isEnabled = false, timeout = DEFAULT_TIMEOUT ) }, { appLockModel -> - AppLockConfig( + AppLockTeamConfig( isEnabled = appLockModel.enforceAppLock, timeout = appLockModel.inactivityTimeoutSecs.seconds ) diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/applock/AppLockTeamFeatureConfigObserverTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/applock/AppLockTeamFeatureConfigObserverTest.kt index a688dfaa4ef..c51dc60a39b 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/applock/AppLockTeamFeatureConfigObserverTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/applock/AppLockTeamFeatureConfigObserverTest.kt @@ -39,7 +39,7 @@ class AppLockTeamFeatureConfigObserverTest { @Test fun givenRepositoryFailure_whenObservingAppLock_thenEmitAppLockConfigWithDisabledStatus() = runTest { - val expectedAppLockValue = AppLockConfig( + val expectedAppLockValue = AppLockTeamConfig( false, AppLockTeamFeatureConfigObserverImpl.DEFAULT_TIMEOUT ) @@ -58,7 +58,7 @@ class AppLockTeamFeatureConfigObserverTest { @Test fun givenRepositorySuccess_whenObservingAppLock_thenEmitAppLockConfigWithValueFromRepository() { runTest { - val expectedAppLockValue = AppLockConfig( + val expectedAppLockValue = AppLockTeamConfig( appLockConfigModel.enforceAppLock, appLockConfigModel.inactivityTimeoutSecs.seconds )