Skip to content

Commit

Permalink
feat: local state cleanup after federation delete [WPB-1816] (#1930)
Browse files Browse the repository at this point in the history
* feat: clean up after federation delete event

* feat: get user ids with one of two domain

* Work in progress

* feat: clean local state after federation events

* merge fixes

* detekt fix

* detekt fix

* review fixes, removed federation message preview

* detekt fix

* Test fixes

* class rename

* migration fix

* event transient fix

* temporary disable handling delete conversation event

* test: federation delete [WPB-1816] (#1966)

* chore: federation delete tests

* test: federation delete events

* fix: system message in oneOnOne conversations

* Update persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/member/MemberDAO.kt

Co-authored-by: Yamil Medina <yamilmedina@users.noreply.github.com>

* Update persistence/src/commonTest/kotlin/com/wire/kalium/persistence/dao/MemberDAOTest.kt

Co-authored-by: Yamil Medina <yamilmedina@users.noreply.github.com>

* detekt fix

---------

Co-authored-by: Yamil Medina <yamilmedina@users.noreply.github.com>

* ignore monkey test

* detekt fix

* test fix

---------

Co-authored-by: Yamil Medina <yamilmedina@users.noreply.github.com>
  • Loading branch information
Garzas and yamilmedina authored Aug 16, 2023
1 parent f261df5 commit 5f27bcd
Show file tree
Hide file tree
Showing 67 changed files with 1,684 additions and 234 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ interface ConnectionRepository {
suspend fun observeConnectionRequestsForNotification(): Flow<List<ConversationDetails>>
suspend fun setConnectionAsNotified(userId: UserId)
suspend fun setAllConnectionsAsNotified()
suspend fun deleteConnection(conversationId: ConversationId): Either<StorageFailure, Unit>
}

@Suppress("LongParameterList", "TooManyFunctions")
Expand Down Expand Up @@ -227,6 +228,7 @@ internal class ConnectionDataSource(
)
)
insertConversationFromConnection(connection)
// should we insert first user before creating conversation ?
userDAO.insertUser(userEntity)
connectionDAO.insertConnection(connectionMapper.modelToDao(connection))
}
Expand Down Expand Up @@ -274,7 +276,7 @@ internal class ConnectionDataSource(
}
}

private suspend fun deleteCancelledConnection(conversationId: ConversationId) = wrapStorageRequest {
override suspend fun deleteConnection(conversationId: ConversationId) = wrapStorageRequest {
connectionDAO.deleteConnectionDataAndConversation(conversationId.toDao())
}

Expand All @@ -297,7 +299,7 @@ internal class ConnectionDataSource(
private suspend fun handleUserConnectionStatusPersistence(connection: Connection): Either<CoreFailure, Unit> =
when (connection.status) {
MISSING_LEGALHOLD_CONSENT, NOT_CONNECTED, PENDING, SENT, BLOCKED, IGNORED -> persistConnection(connection)
CANCELLED -> deleteCancelledConnection(connection.qualifiedConversationId)
CANCELLED -> deleteConnection(connection.qualifiedConversationId)
ACCEPTED -> updateConversationMemberFromConnection(connection)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,8 @@ internal class ConversationMapperImpl(
previewPicture = previewAssetId?.toModel(),
teamId = teamId?.let { TeamId(it) },
connectionStatus = connectionStatusMapper.fromDaoModel(connectionStatus),
expiresAt = null
expiresAt = null,
defederated = userDefederated ?: false
),
legalHoldStatus = LegalHoldStatus.DISABLED,
userType = domainUserTypeMapper.fromUserTypeEntity(userType),
Expand Down Expand Up @@ -247,7 +248,8 @@ internal class ConversationMapperImpl(
completePicture = previewAssetId?.toModel(),
previewPicture = previewAssetId?.toModel(),
teamId = teamId?.let { TeamId(it) },
expiresAt = null
expiresAt = null,
defederated = userDefederated ?: false
)

ConversationDetails.Connection(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import com.wire.kalium.logic.data.id.toApi
import com.wire.kalium.logic.data.id.toCrypto
import com.wire.kalium.logic.data.id.toDao
import com.wire.kalium.logic.data.id.toModel
import com.wire.kalium.logic.data.member.ConversationsWithMembers
import com.wire.kalium.logic.data.message.MessageMapper
import com.wire.kalium.logic.data.message.UnreadEventType
import com.wire.kalium.logic.data.user.UserId
Expand Down Expand Up @@ -206,6 +207,11 @@ interface ConversationRepository {
conversationId: ConversationId,
isInformed: Boolean
): Either<StorageFailure, Unit>

suspend fun getConversationsWithMembersWithBothDomains(
firstDomain: String,
secondDomain: String
): Either<CoreFailure, ConversationsWithMembers>
}

@Suppress("LongParameterList", "TooManyFunctions")
Expand Down Expand Up @@ -777,6 +783,17 @@ internal class ConversationDataSource internal constructor(
conversationMetaDataDAO.setInformedAboutDegradedMLSVerificationFlag(conversationId.toDao(), isInformed)
}

override suspend fun getConversationsWithMembersWithBothDomains(
firstDomain: String,
secondDomain: String
): Either<CoreFailure, ConversationsWithMembers> = wrapStorageRequest {
val entity = memberDAO.getConversationWithUserIdsWithBothDomains(firstDomain, secondDomain)
ConversationsWithMembers(
oneOnOne = entity.oneOnOne.mapKeys { it.key.toModel() }.mapValues { it.value.map { userIdEntity -> userIdEntity.toModel() } },
group = entity.group.mapKeys { it.key.toModel() }.mapValues { it.value.map { userIdEntity -> userIdEntity.toModel() } }
)
}

private suspend fun persistIncompleteConversations(
conversationsFailed: List<NetworkQualifiedId>
): Either<CoreFailure, Unit> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,38 @@ sealed class Event(open val id: String, open val transient: Boolean) {
"cause" to cause
)
}

sealed class Federation(
id: String,
override val transient: Boolean,
) : Event(id, transient) {

data class Delete(
override val id: String,
override val transient: Boolean,
val domain: String,
) : Federation(id, transient) {
override fun toLogMap(): Map<String, Any?> = mapOf(
typeKey to "Federation.Delete",
idKey to id.obfuscateId(),
"transient" to "$transient",
"domain" to domain
)
}

data class ConnectionRemoved(
override val id: String,
override val transient: Boolean,
val domains: List<String>,
) : Federation(id, transient) {
override fun toLogMap(): Map<String, Any?> = mapOf(
typeKey to "Federation.ConnectionRemoved",
idKey to id.obfuscateId(),
"transient" to "$transient",
"domains" to domains
)
}
}
}

internal enum class EventLoggingStatus {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,22 @@ class EventMapper(
is EventContentDTO.UserProperty.PropertiesDeleteDTO -> deleteUserProperties(id, eventContentDTO, transient)
is EventContentDTO.Conversation.ReceiptModeUpdate -> conversationReceiptModeUpdate(id, eventContentDTO, transient)
is EventContentDTO.Conversation.MessageTimerUpdate -> conversationMessageTimerUpdate(id, eventContentDTO, transient)
is EventContentDTO.Federation -> federationTerminated(id, eventContentDTO, transient)
}

private fun federationTerminated(id: String, eventContentDTO: EventContentDTO.Federation, transient: Boolean): Event =
when (eventContentDTO) {
is EventContentDTO.Federation.FederationConnectionRemovedDTO -> Event.Federation.ConnectionRemoved(
id,
transient,
eventContentDTO.domains
)

is EventContentDTO.Federation.FederationDeleteDTO -> Event.Federation.Delete(
id,
transient,
eventContentDTO.domain
)
}

@OptIn(InternalSerializationApi::class, ExperimentalSerializationApi::class)
Expand Down
Original file line number Diff line number Diff line change
@@ -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.data.member

import com.wire.kalium.logic.data.id.QualifiedID

data class ConversationsWithMembers(
val oneOnOne: Map<QualifiedID, List<QualifiedID>>,
val group: Map<QualifiedID, List<QualifiedID>>
)
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ sealed interface Message {
return "${toLogMap().toJsonElement()}"
}

@Suppress("LongMethod", "ComplexMethod")
fun toLogMap(): Map<String, Any?> {
val typeKey = "type"
val properties: MutableMap<String, String> = when (content) {
Expand Down Expand Up @@ -323,6 +324,13 @@ sealed interface Message {
is MessageContent.ConversationDegradedProteus -> mutableMapOf(
typeKey to "conversationDegradedProteus"
)

is MessageContent.FederationStopped.ConnectionRemoved -> mutableMapOf(
typeKey to "federationConnectionRemoved"
)
is MessageContent.FederationStopped.Removed -> mutableMapOf(
typeKey to "federationRemoved"
)
}

val standardProperties = mapOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import com.wire.kalium.logic.data.message.mention.MessageMention
import com.wire.kalium.logic.data.message.receipt.ReceiptType
import com.wire.kalium.logic.data.user.UserAvailabilityStatus
import com.wire.kalium.logic.data.user.UserId
import com.wire.kalium.protobuf.messages.Button
import kotlinx.datetime.Instant

sealed class MessageContent {
Expand Down Expand Up @@ -232,6 +231,7 @@ sealed class MessageContent {
data class Removed(override val members: List<UserId>) : MemberChange(members)
data class FailedToAdd(override val members: List<UserId>) : MemberChange(members)
data class CreationAdded(override val members: List<UserId>) : MemberChange(members)
data class FederationRemoved(override val members: List<UserId>) : MemberChange(members)
}

data class LastRead(
Expand Down Expand Up @@ -293,6 +293,10 @@ sealed class MessageContent {
object ConversationCreated : System()
object ConversationDegradedMLS : System()
object ConversationDegradedProteus : System()
sealed class FederationStopped : System() {
data class Removed(val domain: String) : FederationStopped()
data class ConnectionRemoved(val domainList: List<String>) : FederationStopped()
}
}

/**
Expand Down Expand Up @@ -336,6 +340,9 @@ fun MessageContent?.getType() = when (this) {
is MessageContent.Composite -> "Composite"
is MessageContent.ButtonAction -> "ButtonAction"
is MessageContent.ButtonActionConfirmation -> "ButtonActionConfirmation"
is MessageContent.MemberChange.FederationRemoved -> "MemberChange.FederationRemoved"
is MessageContent.FederationStopped.ConnectionRemoved -> "Federation.ConnectionRemoved"
is MessageContent.FederationStopped.Removed -> "Federation.Removed"
is MessageContent.Unknown -> "Unknown"
null -> "null"
}
Expand Down Expand Up @@ -395,6 +402,11 @@ sealed interface MessagePreviewContent {

data class Ephemeral(val isGroupConversation: Boolean) : MessagePreviewContent

data class FederatedMembersRemoved(
val isSelfUserRemoved: Boolean,
val otherUserIdList: List<UserId>
) : MessagePreviewContent

object CryptoSessionReset : MessagePreviewContent

object Unknown : MessagePreviewContent
Expand Down
Loading

0 comments on commit 5f27bcd

Please sign in to comment.