Skip to content

Commit

Permalink
fix: update legalhold status when fetching user data (#2708)
Browse files Browse the repository at this point in the history
* fix: update legalhold status when fetching user data

* changes after review

* fix: do not override degraded state

* detekt

* fixes after resolving conflicts
  • Loading branch information
saleniuk authored Apr 24, 2024
1 parent ad5b77b commit 9905140
Show file tree
Hide file tree
Showing 5 changed files with 261 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import com.wire.kalium.logic.functional.mapRight
import com.wire.kalium.logic.functional.onFailure
import com.wire.kalium.logic.functional.onSuccess
import com.wire.kalium.logic.kaliumLogger
import com.wire.kalium.logic.sync.receiver.handler.legalhold.LegalHoldHandler
import com.wire.kalium.logic.wrapApiRequest
import com.wire.kalium.logic.wrapStorageRequest
import com.wire.kalium.network.api.base.authenticated.TeamsApi
Expand Down Expand Up @@ -167,6 +168,7 @@ internal class UserDataSource internal constructor(
private val sessionRepository: SessionRepository,
private val selfUserId: UserId,
private val selfTeamIdProvider: SelfTeamIdProvider,
private val legalHoldHandler: LegalHoldHandler,
private val idMapper: IdMapper = MapperProvider.idMapper(),
private val userMapper: UserMapper = MapperProvider.userMapper(),
private val teamMapper: TeamMapper = MapperProvider.teamMapper(),
Expand Down Expand Up @@ -341,7 +343,7 @@ internal class UserDataSource internal constructor(
private suspend fun persistUsers(
listUserProfileDTO: List<UserProfileDTO>,
listTeamMemberDTO: List<TeamsApi.TeamMemberDTO>,
) = wrapStorageRequest {
): Either<CoreFailure, Unit> {
val mapTeamMemberDTO = listTeamMemberDTO.associateBy { it.nonQualifiedUserId }
val selfUserTeamId = selfTeamIdProvider().getOrNull()?.value
val teamMembers = listUserProfileDTO
Expand Down Expand Up @@ -370,13 +372,22 @@ internal class UserDataSource internal constructor(
)
)
}
if (teamMembers.isNotEmpty()) {
userDAO.upsertUsers(teamMembers)
userDAO.upsertConnectionStatuses(teamMembers.associate { it.id to it.connectionStatus })
}
if (otherUsers.isNotEmpty()) {
userDAO.upsertUsers(otherUsers)
}
return listUserProfileDTO
.map {
legalHoldHandler.handleUserFetch(it.id.toModel(), it.legalHoldStatus == LegalHoldStatusDTO.ENABLED)
}
.foldToEitherWhileRight(Unit) { value, _ -> value }
.flatMap {
wrapStorageRequest {
if (teamMembers.isNotEmpty()) {
userDAO.upsertUsers(teamMembers)
userDAO.upsertConnectionStatuses(teamMembers.associate { it.id to it.connectionStatus })
}
if (otherUsers.isNotEmpty()) {
userDAO.upsertUsers(otherUsers)
}
}
}
}

override suspend fun fetchUsersIfUnknownByIds(ids: Set<UserId>): Either<CoreFailure, Unit> = wrapStorageRequest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,28 @@ class UserSessionScope internal constructor(
messageDraftDAO = userStorage.database.messageDraftDAO,
)

private val slowSyncRepository: SlowSyncRepository by lazy { SlowSyncRepositoryImpl(userStorage.database.metadataDAO) }
private val incrementalSyncRepository: IncrementalSyncRepository by lazy { InMemoryIncrementalSyncRepository() }

private val legalHoldSystemMessagesHandler = LegalHoldSystemMessagesHandlerImpl(
selfUserId = userId,
persistMessage = persistMessage,
conversationRepository = conversationRepository,
messageRepository = messageRepository
)

private val legalHoldHandler = LegalHoldHandlerImpl(
selfUserId = userId,
fetchUsersClientsFromRemote = fetchUsersClientsFromRemote,
fetchSelfClientsFromRemote = fetchSelfClientsFromRemote,
observeLegalHoldStateForUser = observeLegalHoldStateForUser,
membersHavingLegalHoldClient = membersHavingLegalHoldClient,
userConfigRepository = userConfigRepository,
conversationRepository = conversationRepository,
observeSyncState = observeSyncState,
legalHoldSystemMessagesHandler = legalHoldSystemMessagesHandler,
)

private val userRepository: UserRepository = UserDataSource(
userStorage.database.userDAO,
userStorage.database.metadataDAO,
Expand All @@ -750,7 +772,8 @@ class UserSessionScope internal constructor(
authenticatedNetworkContainer.teamsApi,
globalScope.sessionRepository,
userId,
selfTeamId
selfTeamId,
legalHoldHandler
)

private val accountRepository: AccountRepository
Expand Down Expand Up @@ -876,12 +899,6 @@ class UserSessionScope internal constructor(
kaliumFileSystem = kaliumFileSystem
)

private val incrementalSyncRepository: IncrementalSyncRepository by lazy {
InMemoryIncrementalSyncRepository()
}

private val slowSyncRepository: SlowSyncRepository by lazy { SlowSyncRepositoryImpl(userStorage.database.metadataDAO) }

private val eventGatherer: EventGatherer get() = EventGathererImpl(eventRepository, incrementalSyncRepository)

private val eventProcessor: EventProcessor by lazy {
Expand Down Expand Up @@ -1464,13 +1481,6 @@ class UserSessionScope internal constructor(
val membersHavingLegalHoldClient: MembersHavingLegalHoldClientUseCase
get() = MembersHavingLegalHoldClientUseCaseImpl(clientRepository)

private val legalHoldSystemMessagesHandler = LegalHoldSystemMessagesHandlerImpl(
selfUserId = userId,
persistMessage = persistMessage,
conversationRepository = conversationRepository,
messageRepository = messageRepository
)

private val updateSelfClientCapabilityToLegalHoldConsent: UpdateSelfClientCapabilityToLegalHoldConsentUseCase
get() = UpdateSelfClientCapabilityToLegalHoldConsentUseCaseImpl(
clientRemoteRepository = clientRemoteRepository,
Expand All @@ -1480,18 +1490,6 @@ class UserSessionScope internal constructor(
kaliumLogger = userScopedLogger,
)

private val legalHoldHandler = LegalHoldHandlerImpl(
selfUserId = userId,
fetchUsersClientsFromRemote = fetchUsersClientsFromRemote,
fetchSelfClientsFromRemote = fetchSelfClientsFromRemote,
observeLegalHoldStateForUser = observeLegalHoldStateForUser,
membersHavingLegalHoldClient = membersHavingLegalHoldClient,
userConfigRepository = userConfigRepository,
conversationRepository = conversationRepository,
observeSyncState = observeSyncState,
legalHoldSystemMessagesHandler = legalHoldSystemMessagesHandler,
)

private val fetchLegalHoldForSelfUserFromRemoteUseCase: FetchLegalHoldForSelfUserFromRemoteUseCase
get() = FetchLegalHoldForSelfUserFromRemoteUseCaseImpl(
teamRepository = teamRepository,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import com.wire.kalium.logic.functional.Either
import com.wire.kalium.logic.functional.flatMap
import com.wire.kalium.logic.functional.foldToEitherWhileRight
import com.wire.kalium.logic.functional.getOrElse
import com.wire.kalium.logic.functional.getOrNull
import com.wire.kalium.logic.functional.map
import com.wire.kalium.logic.kaliumLogger
import com.wire.kalium.logic.sync.ObserveSyncStateUseCase
Expand All @@ -61,6 +62,7 @@ internal interface LegalHoldHandler {
handleFailure: suspend () -> Either<CoreFailure, Unit>
): Either<CoreFailure, Boolean>
suspend fun handleConversationMembersChanged(conversationId: ConversationId): Either<CoreFailure, Unit>
suspend fun handleUserFetch(userId: UserId, userIsUnderLegalHold: Boolean): Either<CoreFailure, Unit>
}

@Suppress("LongParameterList")
Expand Down Expand Up @@ -197,19 +199,40 @@ internal class LegalHoldHandlerImpl internal constructor(
}
}

override suspend fun handleUserFetch(userId: UserId, userIsUnderLegalHold: Boolean): Either<CoreFailure, Unit> {
val userHasBeenUnderLegalHold = isUserUnderLegalHold(userId)
if (userHasBeenUnderLegalHold != userIsUnderLegalHold) {
processEvent(selfUserId, userId) // fetch and persist current clients for the given user
handleConversationsForUser(userId)
if (userIsUnderLegalHold) {
legalHoldSystemMessagesHandler.handleEnabledForUser(userId, DateTimeUtil.currentIsoDateTimeString())
} else {
legalHoldSystemMessagesHandler.handleDisabledForUser(userId, DateTimeUtil.currentIsoDateTimeString())
}
}

return Either.Right(Unit)
}

private suspend fun isUserUnderLegalHold(userId: UserId): Boolean =
observeLegalHoldStateForUser(userId).firstOrNull() == LegalHoldState.Enabled

@Suppress("NestedBlockDepth")
private suspend fun handleForConversation(
conversationId: ConversationId,
newStatus: Conversation.LegalHoldStatus,
systemMessageTimestampIso: String = DateTimeUtil.currentIsoDateTimeString(),
): Boolean =
if (newStatus != Conversation.LegalHoldStatus.UNKNOWN) {
conversationRepository.updateLegalHoldStatus(conversationId, newStatus)
.getOrElse(false)
.also { isChanged -> // if conversation legal hold status has changed, create system message for it
if (isChanged) {
conversationRepository.observeLegalHoldStatus(conversationId).firstOrNull()?.getOrNull().let { currentStatus ->
if (currentStatus != newStatus) {
val isChanged = when {
currentStatus == Conversation.LegalHoldStatus.DEGRADED && newStatus == Conversation.LegalHoldStatus.ENABLED -> {
true // in case it's already degraded we want to keep it, not change it to enabled but create system messages
}
else -> conversationRepository.updateLegalHoldStatus(conversationId, newStatus).getOrElse(false)
}
if (isChanged) { // if conversation legal hold status has changed, create system message for it
when (newStatus) {
Conversation.LegalHoldStatus.DISABLED ->
legalHoldSystemMessagesHandler.handleDisabledForConversation(conversationId, systemMessageTimestampIso)
Expand All @@ -218,7 +241,9 @@ internal class LegalHoldHandlerImpl internal constructor(
else -> { /* do nothing */ }
}
}
}
isChanged
} else false
}
} else false

private suspend fun handleConversationsForUser(userId: UserId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import com.wire.kalium.logic.framework.TestUser
import com.wire.kalium.logic.framework.TestUser.LIST_USERS_DTO
import com.wire.kalium.logic.functional.Either
import com.wire.kalium.logic.functional.getOrNull
import com.wire.kalium.logic.sync.receiver.handler.legalhold.LegalHoldHandler
import com.wire.kalium.logic.test_util.TestNetworkException
import com.wire.kalium.logic.test_util.TestNetworkException.federationNotEnabled
import com.wire.kalium.logic.test_util.TestNetworkException.generic
Expand Down Expand Up @@ -64,9 +65,9 @@ import com.wire.kalium.persistence.dao.client.ClientDAO
import io.ktor.http.HttpStatusCode
import io.mockative.Mock
import io.mockative.any
import io.mockative.eq
import io.mockative.coEvery
import io.mockative.coVerify
import io.mockative.eq
import io.mockative.every
import io.mockative.matches
import io.mockative.mock
Expand Down Expand Up @@ -821,6 +822,9 @@ class UserRepositoryTest {
@Mock
val selfTeamIdProvider: SelfTeamIdProvider = mock(SelfTeamIdProvider::class)

@Mock
val legalHoldHandler: LegalHoldHandler = mock(LegalHoldHandler::class)

val selfUserId = TestUser.SELF.id

val userRepository: UserRepository by lazy {
Expand All @@ -833,7 +837,8 @@ class UserRepositoryTest {
teamsApi,
sessionRepository,
selfUserId,
selfTeamIdProvider
selfTeamIdProvider,
legalHoldHandler
)
}

Expand Down Expand Up @@ -1033,6 +1038,9 @@ class UserRepositoryTest {
sessionRepository.updateSsoIdAndScimInfo(any(), any(), any())
}.returns(Either.Right(Unit))
withGetTeamMemberSuccess(TestTeam.memberDTO(selfUserId.value))
coEvery {
legalHoldHandler.handleUserFetch(any(), any())
}.returns(Either.Right(Unit))
apply(block)
return this to userRepository
}
Expand Down
Loading

0 comments on commit 9905140

Please sign in to comment.