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 780af5283c4..3260839f07f 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 @@ -217,8 +217,12 @@ import com.wire.kalium.logic.feature.featureConfig.handler.SecondFactorPasswordC import com.wire.kalium.logic.feature.featureConfig.handler.SelfDeletingMessagesConfigHandler import com.wire.kalium.logic.feature.keypackage.KeyPackageManager import com.wire.kalium.logic.feature.keypackage.KeyPackageManagerImpl -import com.wire.kalium.logic.feature.legalhold.LegalHoldRequestUseCase -import com.wire.kalium.logic.feature.legalhold.LegalHoldRequestUseCaseImpl +import com.wire.kalium.logic.feature.legalhold.ObserveLegalHoldRequestUseCase +import com.wire.kalium.logic.feature.legalhold.ObserveLegalHoldRequestUseCaseImpl +import com.wire.kalium.logic.feature.legalhold.ObserveLegalHoldForSelfUserUseCase +import com.wire.kalium.logic.feature.legalhold.ObserveLegalHoldForSelfUserUseCaseImpl +import com.wire.kalium.logic.feature.legalhold.ObserveLegalHoldStateForUserUseCase +import com.wire.kalium.logic.feature.legalhold.ObserveLegalHoldStateForUserUseCaseImpl import com.wire.kalium.logic.feature.message.AddSystemMessageToAllConversationsUseCase import com.wire.kalium.logic.feature.message.AddSystemMessageToAllConversationsUseCaseImpl import com.wire.kalium.logic.feature.message.EphemeralEventsNotificationManagerImpl @@ -1322,6 +1326,12 @@ class UserSessionScope internal constructor( userConfigRepository = userConfigRepository ) + val observeLegalHoldStateForUser: ObserveLegalHoldStateForUserUseCase + get() = ObserveLegalHoldStateForUserUseCaseImpl(clientRepository) + + val observeLegalHoldForSelfUser: ObserveLegalHoldForSelfUserUseCase + get() = ObserveLegalHoldForSelfUserUseCaseImpl(userId, observeLegalHoldStateForUser) + private val fetchSelfClientsFromRemote: FetchSelfClientsFromRemoteUseCase get() = FetchSelfClientsFromRemoteUseCaseImpl( clientRepository = clientRepository, @@ -1738,8 +1748,8 @@ class UserSessionScope internal constructor( } } - val legalHoldRequestUseCase: LegalHoldRequestUseCase - get() = LegalHoldRequestUseCaseImpl( + val observeLegalHoldRequestUseCase: ObserveLegalHoldRequestUseCase + get() = ObserveLegalHoldRequestUseCaseImpl( userConfigRepository = userConfigRepository, preKeyRepository = preKeyRepository ) diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/legalhold/ObserveLegalHoldForSelfUserUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/legalhold/ObserveLegalHoldForSelfUserUseCase.kt new file mode 100644 index 00000000000..f5ffe15de28 --- /dev/null +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/legalhold/ObserveLegalHoldForSelfUserUseCase.kt @@ -0,0 +1,37 @@ +/* + * 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.legalhold + +import com.wire.kalium.logic.data.user.UserId +import kotlinx.coroutines.flow.Flow + +/** + * Use case that allows to observe the legal hold state for the self user. + */ +interface ObserveLegalHoldForSelfUserUseCase { + suspend operator fun invoke(): Flow +} + +internal class ObserveLegalHoldForSelfUserUseCaseImpl internal constructor( + private val selfUserId: UserId, + private val observeLegalHoldStateForUser: ObserveLegalHoldStateForUserUseCase +) : ObserveLegalHoldForSelfUserUseCase { + override suspend fun invoke(): Flow = observeLegalHoldStateForUser( + userId = selfUserId + ) +} diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/legalhold/LegalHoldRequestUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/legalhold/ObserveLegalHoldRequestUseCase.kt similarity index 72% rename from logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/legalhold/LegalHoldRequestUseCase.kt rename to logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/legalhold/ObserveLegalHoldRequestUseCase.kt index 96bdccfb311..4d127a29389 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/legalhold/LegalHoldRequestUseCase.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/legalhold/ObserveLegalHoldRequestUseCase.kt @@ -30,24 +30,24 @@ import kotlinx.coroutines.flow.map /** * Use case that observes the legal hold request. */ -interface LegalHoldRequestUseCase { - operator fun invoke(): Flow +interface ObserveLegalHoldRequestUseCase { + operator fun invoke(): Flow } -internal class LegalHoldRequestUseCaseImpl internal constructor( +internal class ObserveLegalHoldRequestUseCaseImpl internal constructor( val userConfigRepository: UserConfigRepository, val preKeyRepository: PreKeyRepository -) : LegalHoldRequestUseCase { - override fun invoke(): Flow = +) : ObserveLegalHoldRequestUseCase { + override fun invoke(): Flow = userConfigRepository.observeLegalHoldRequest().map { it.fold( { failure -> if (failure is StorageFailure.DataNotFound) { kaliumLogger.i("No legal hold request found") - LegalHoldRequestObserverResult.NoLegalHoldRequest + ObserveLegalHoldRequestUseCaseResult.NoObserveLegalHoldRequest } else { kaliumLogger.i("Legal hold request failure: $failure") - LegalHoldRequestObserverResult.Failure(failure) + ObserveLegalHoldRequestUseCaseResult.Failure(failure) } }, { request -> @@ -56,10 +56,10 @@ internal class LegalHoldRequestUseCaseImpl internal constructor( result.fold( { failure -> kaliumLogger.i("Legal hold request fingerprint failure: $failure") - LegalHoldRequestObserverResult.Failure(failure) + ObserveLegalHoldRequestUseCaseResult.Failure(failure) }, { fingerprint -> - LegalHoldRequestObserverResult.LegalHoldRequestAvailable( + ObserveLegalHoldRequestUseCaseResult.ObserveLegalHoldRequestAvailable( fingerprint ) } @@ -69,13 +69,13 @@ internal class LegalHoldRequestUseCaseImpl internal constructor( } } -sealed class LegalHoldRequestObserverResult { - data class LegalHoldRequestAvailable(val fingerprint: ByteArray) : LegalHoldRequestObserverResult() { +sealed class ObserveLegalHoldRequestUseCaseResult { + data class ObserveLegalHoldRequestAvailable(val fingerprint: ByteArray) : ObserveLegalHoldRequestUseCaseResult() { override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false - other as LegalHoldRequestAvailable + other as ObserveLegalHoldRequestAvailable return fingerprint.contentEquals(other.fingerprint) } @@ -85,6 +85,6 @@ sealed class LegalHoldRequestObserverResult { } } - data object NoLegalHoldRequest : LegalHoldRequestObserverResult() - data class Failure(val failure: CoreFailure) : LegalHoldRequestObserverResult() + data object NoObserveLegalHoldRequest : ObserveLegalHoldRequestUseCaseResult() + data class Failure(val failure: CoreFailure) : ObserveLegalHoldRequestUseCaseResult() } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/legalhold/ObserveLegalHoldStateForUserUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/legalhold/ObserveLegalHoldStateForUserUseCase.kt new file mode 100644 index 00000000000..f78da2fe682 --- /dev/null +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/legalhold/ObserveLegalHoldStateForUserUseCase.kt @@ -0,0 +1,60 @@ +/* + * 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.legalhold + +import com.wire.kalium.logic.data.client.ClientRepository +import com.wire.kalium.logic.data.client.DeviceType +import com.wire.kalium.logic.data.user.UserId +import com.wire.kalium.logic.functional.fold +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +/** + * Use case that allows to observe the legal hold state for a given user. + */ +interface ObserveLegalHoldStateForUserUseCase { + suspend operator fun invoke(userId: UserId): Flow +} + +internal class ObserveLegalHoldStateForUserUseCaseImpl internal constructor( + private val clientRepository: ClientRepository +) : ObserveLegalHoldStateForUserUseCase { + override suspend fun invoke(userId: UserId): Flow = + clientRepository.observeClientsByUserId(userId).map { + it.fold( + { + LegalHoldState.Disabled + }, + { clients -> + val isLegalHoldEnabled = clients.any { otherUserClient -> + otherUserClient.deviceType == DeviceType.LegalHold + } + if (isLegalHoldEnabled) { + LegalHoldState.Enabled + } else { + LegalHoldState.Disabled + } + } + ) + } +} + +sealed class LegalHoldState { + data object Enabled : LegalHoldState() + data object Disabled : LegalHoldState() +} diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/legalhold/ObserveLegalHoldForSelfUserUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/legalhold/ObserveLegalHoldForSelfUserUseCaseTest.kt new file mode 100644 index 00000000000..1c7bfbfc33a --- /dev/null +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/legalhold/ObserveLegalHoldForSelfUserUseCaseTest.kt @@ -0,0 +1,98 @@ +/* + * 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.legalhold + +import com.wire.kalium.logic.framework.TestUser +import io.mockative.Mock +import io.mockative.eq +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 + +class ObserveLegalHoldForSelfUserUseCaseTest { + + @Test + fun givenLegalHoldObserverForUserReturnsEnabled_whenStartingObservingForSelfUser_thenEmitEnabled() = + runTest { + val (arrangement, useCase) = Arrangement() + .withLegalHoldEnabledState() + .arrange() + + val result = useCase() + + assertEquals(LegalHoldState.Enabled, result.first()) + verify(arrangement.observeLegalHoldStateForUser) + .suspendFunction(arrangement.observeLegalHoldStateForUser::invoke) + .with(eq(TestUser.SELF.id)) + .wasInvoked(once) + } + + @Test + fun givenLegalHoldObserverForUserReturnsDisabled_whenStartingObservingForSelfUser_thenEmitDisabled() = + runTest { + val (arrangement, useCase) = Arrangement() + .withLegalHoldDisabledState() + .arrange() + + val result = useCase() + + assertEquals(LegalHoldState.Disabled, result.first()) + verify(arrangement.observeLegalHoldStateForUser) + .suspendFunction(arrangement.observeLegalHoldStateForUser::invoke) + .with(eq(TestUser.SELF.id)) + .wasInvoked(once) + } + + private class Arrangement { + + @Mock + val observeLegalHoldStateForUser = mock(ObserveLegalHoldStateForUserUseCase::class) + + val observeLegalHoldForSelfUser: ObserveLegalHoldForSelfUserUseCase = + ObserveLegalHoldForSelfUserUseCaseImpl( + selfUserId = TestUser.SELF.id, + observeLegalHoldStateForUser = observeLegalHoldStateForUser + ) + + fun arrange() = this to observeLegalHoldForSelfUser + + fun withLegalHoldEnabledState() = apply { + given(observeLegalHoldStateForUser) + .suspendFunction(observeLegalHoldStateForUser::invoke) + .whenInvokedWith(eq(TestUser.SELF.id)) + .then { + flowOf(LegalHoldState.Enabled) + } + } + + fun withLegalHoldDisabledState() = apply { + given(observeLegalHoldStateForUser) + .suspendFunction(observeLegalHoldStateForUser::invoke) + .whenInvokedWith(eq(TestUser.SELF.id)) + .then { + flowOf(LegalHoldState.Disabled) + } + } + } +} diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/legalhold/LegalHoldRequestObserverTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/legalhold/ObserveLegalHoldRequestUseCaseTest.kt similarity index 83% rename from logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/legalhold/LegalHoldRequestObserverTest.kt rename to logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/legalhold/ObserveLegalHoldRequestUseCaseTest.kt index 2061036d44e..7f2ada5ee55 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/legalhold/LegalHoldRequestObserverTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/legalhold/ObserveLegalHoldRequestUseCaseTest.kt @@ -36,54 +36,54 @@ import kotlinx.coroutines.test.runTest import kotlin.test.Test import kotlin.test.assertTrue -class LegalHoldRequestObserverTest { +class ObserveLegalHoldRequestUseCaseTest { @Test fun givenUserConfigRepositoryDataNotFoundFailure_whenObserving_thenPropagateNoLegalHoldRequest() = runTest { - val (_, legalHoldRequestObserver) = Arrangement() + val (_, useCase) = Arrangement() .withUserConfigRepositoryDataNotFound() .arrange() - val result = legalHoldRequestObserver() + val result = useCase() - assertTrue(result.first() is LegalHoldRequestObserverResult.NoLegalHoldRequest) + assertTrue(result.first() is ObserveLegalHoldRequestUseCaseResult.NoObserveLegalHoldRequest) } @Test fun givenUserConfigRepositoryOtherFailure_whenObserving_thenPropagateFailure() = runTest { - val (_, legalHoldRequestObserver) = Arrangement() + val (_, useCase) = Arrangement() .withUserConfigRepositoryFailure() .arrange() - val result = legalHoldRequestObserver() + val result = useCase() - assertTrue(result.first() is LegalHoldRequestObserverResult.Failure) + assertTrue(result.first() is ObserveLegalHoldRequestUseCaseResult.Failure) } @Test fun givenPreKeyRepositoryFailure_whenObserving_thenPropagateFailure() = runTest { - val (_, legalHoldRequestObserver) = Arrangement() + val (_, useCase) = Arrangement() .withUserConfigRepositorySuccess() .withPreKeyRepositoryFailure() .arrange() - val result = legalHoldRequestObserver() + val result = useCase() - assertTrue(result.first() is LegalHoldRequestObserverResult.Failure) + assertTrue(result.first() is ObserveLegalHoldRequestUseCaseResult.Failure) } @Test fun givenPreKeyRepositorySuccess_whenObserving_thenPropagateLegalHoldRequestAvailable() = runTest { - val (_, legalHoldRequestObserver) = Arrangement() + val (_, useCase) = Arrangement() .withUserConfigRepositorySuccess() .withPreKeyRepositorySuccess() .arrange() - val result = legalHoldRequestObserver() + val result = useCase() - assertTrue(result.first() is LegalHoldRequestObserverResult.LegalHoldRequestAvailable) + assertTrue(result.first() is ObserveLegalHoldRequestUseCaseResult.ObserveLegalHoldRequestAvailable) } private class Arrangement { @@ -129,7 +129,7 @@ class LegalHoldRequestObserverTest { .thenReturn(Either.Right(fingerPrint)) } - fun arrange() = this to LegalHoldRequestUseCaseImpl( + fun arrange() = this to ObserveLegalHoldRequestUseCaseImpl( userConfigRepository = userConfigRepository, preKeyRepository = preKeyRepository ) diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/legalhold/ObserveLegalHoldStateForUserUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/legalhold/ObserveLegalHoldStateForUserUseCaseTest.kt new file mode 100644 index 00000000000..6e399e4aa04 --- /dev/null +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/legalhold/ObserveLegalHoldStateForUserUseCaseTest.kt @@ -0,0 +1,134 @@ +/* + * 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.legalhold + +import com.wire.kalium.logic.StorageFailure +import com.wire.kalium.logic.data.client.ClientRepository +import com.wire.kalium.logic.data.client.DeviceType +import com.wire.kalium.logic.framework.TestClient +import com.wire.kalium.logic.framework.TestUser +import com.wire.kalium.logic.functional.Either +import io.mockative.Mock +import io.mockative.any +import io.mockative.given +import io.mockative.mock +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.runTest +import kotlin.test.Test +import kotlin.test.assertEquals + +class ObserveLegalHoldStateForUserUseCaseTest { + + @Test + fun givenClientRepositoryFailure_whenObserving_thenReturnDisabledState() = runTest { + val (_, useCase) = Arrangement() + .withClientRepositoryFailure() + .arrange() + + val result = useCase(TestUser.USER_ID) + + assertEquals(LegalHoldState.Disabled, result.first()) + } + + @Test + fun givenNoClients_whenObserving_thenReturnDisabledState() = runTest { + val (arrangement, useCase) = Arrangement() + .withEmptyClients() + .arrange() + + val result = useCase(TestUser.USER_ID) + + assertEquals(LegalHoldState.Disabled, result.first()) + } + + @Test + fun givenNoClientIsUnderLegalHold_whenObserving_thenReturnDisabledState() = runTest { + val (_, useCase) = Arrangement() + .withNoClientUnderLegalHold() + .arrange() + + val result = useCase(TestUser.USER_ID) + + assertEquals(LegalHoldState.Disabled, result.first()) + } + + @Test + fun givenAClientIsUnderLegalHold_whenObserving_thenReturnEnabledState() = runTest { + val (_, useCase) = Arrangement() + .withClientUnderLegalHold() + .arrange() + + val result = useCase(TestUser.USER_ID) + + assertEquals(LegalHoldState.Enabled, result.first()) + } + + private class Arrangement { + + @Mock + val clientRepository: ClientRepository = mock(ClientRepository::class) + + val observeLegalHoldStateForUser: ObserveLegalHoldStateForUserUseCase = + ObserveLegalHoldStateForUserUseCaseImpl( + clientRepository = clientRepository + ) + + fun arrange() = this to observeLegalHoldStateForUser + + fun withClientRepositoryFailure() = apply { + given(clientRepository) + .suspendFunction(clientRepository::observeClientsByUserId) + .whenInvokedWith(any()) + .then { + flowOf(Either.Left(StorageFailure.DataNotFound)) + } + } + + fun withEmptyClients() = apply { + given(clientRepository) + .suspendFunction(clientRepository::observeClientsByUserId) + .whenInvokedWith(any()) + .then { + flowOf(Either.Right(listOf())) + } + } + + fun withNoClientUnderLegalHold() = apply { + given(clientRepository) + .suspendFunction(clientRepository::observeClientsByUserId) + .whenInvokedWith(any()) + .then { + flowOf(Either.Right(listOf(TestClient.CLIENT))) + } + } + + fun withClientUnderLegalHold() = apply { + given(clientRepository) + .suspendFunction(clientRepository::observeClientsByUserId) + .whenInvokedWith(any()) + .then { + flowOf(Either.Right(listOf(legalHoldClient))) + } + } + } + + companion object { + val legalHoldClient = TestClient.CLIENT.copy(deviceType = DeviceType.LegalHold) + } +}