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 f40cbf385a2..0aa88385fdc 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 @@ -1578,6 +1580,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/AppLockTeamConfig.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/AppLockTeamConfig.kt new file mode 100644 index 00000000000..dcb3cd1b2c5 --- /dev/null +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/applock/AppLockTeamConfig.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 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 new file mode 100644 index 00000000000..58e20b02762 --- /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({ + AppLockTeamConfig( + isEnabled = false, + timeout = DEFAULT_TIMEOUT + ) + }, { appLockModel -> + AppLockTeamConfig( + 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..c51dc60a39b --- /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 = AppLockTeamConfig( + 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 = AppLockTeamConfig( + 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