Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: receive and store composite messages [part-1] #1888

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,14 @@ data class BroadcastMessage(

is MessageContent.Availability -> mutableMapOf(
typeKey to "availability",
"content" to "$content",
)

is MessageContent.Cleared -> mutableMapOf(
typeKey to "cleared",
"content" to "$content",
)

is MessageContent.Reaction -> mutableMapOf(
typeKey to "reaction",
"content" to "$content",
)

is MessageContent.Receipt -> mutableMapOf(
Expand All @@ -84,8 +81,14 @@ data class BroadcastMessage(
)

MessageContent.Ignored -> mutableMapOf(
typeKey to "ignored",
"content" to "$content",
typeKey to "ignored"
)

is MessageContent.ButtonAction -> mutableMapOf(
typeKey to "buttonAction",
)
is MessageContent.ButtonActionConfirmation -> mutableMapOf(
typeKey to "buttonActionConfirmation",
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ sealed interface Message {
is MessageContent.Unknown -> mutableMapOf(
typeKey to "unknown"
)

is MessageContent.Composite -> mutableMapOf(
typeKey to "composite"
)
}

val standardProperties = mapOf(
Expand Down Expand Up @@ -157,6 +161,7 @@ sealed interface Message {
override val isSelfMessage: Boolean,
override val expirationData: ExpirationData?
) : Sendable {
@Suppress("LongMethod")
override fun toLogString(): String {
val typeKey = "type"

Expand Down Expand Up @@ -189,17 +194,14 @@ sealed interface Message {

is MessageContent.Availability -> mutableMapOf(
typeKey to "availability",
"content" to "$content",
)

is MessageContent.Cleared -> mutableMapOf(
typeKey to "cleared",
"content" to "$content",
)

is MessageContent.Reaction -> mutableMapOf(
typeKey to "reaction",
"content" to "$content",
)

is MessageContent.Receipt -> mutableMapOf(
Expand All @@ -209,7 +211,15 @@ sealed interface Message {

MessageContent.Ignored -> mutableMapOf(
typeKey to "ignored",
"content" to "$content",
"content" to content.getType(),
)

is MessageContent.ButtonAction -> mutableMapOf(
typeKey to "buttonAction"
)

is MessageContent.ButtonActionConfirmation -> mutableMapOf(
typeKey to "buttonActionConfirmation"
)
}

Expand Down Expand Up @@ -279,6 +289,7 @@ sealed interface Message {
MessageContent.HistoryLost -> mutableMapOf(
typeKey to "conversationMightLostHistory"
)

is MessageContent.ConversationMessageTimerChanged -> mutableMapOf(
typeKey to "conversationMessageTimerChanged"
)
Expand All @@ -294,7 +305,7 @@ sealed interface Message {

val standardProperties = mapOf(
"id" to id.obfuscateId(),
"conversationId" to "${conversationId.toLogString()}",
"conversationId" to conversationId.toLogString(),
"date" to date,
"senderUserId" to senderUserId.value.obfuscateId(),
"status" to "$status",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ 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 @@ -163,6 +164,54 @@ sealed class MessageContent {

data class Knock(val hotKnock: Boolean) : Regular()

data class Composite(
val textContent: Text?,
val buttonList: List<Button>
) : Regular() {
data class Button(
val text: String,
val id: String,
val isSelected: Boolean
)
}

/**
* Notifies the author of a [Composite] message that a user has
* selected one of its buttons.
* @see Composite
* @see ButtonActionConfirmation
*/
data class ButtonAction(
/**
* The ID of the original composite message.
*/
val referencedMessageId: String,

/**
* ID of the button that was selected.
*/
val buttonId: String
) : Signaling()

/**
* Message sent by the author of a [Composite] to
* notify which button should be marked as selected.
* For example, after we send [ButtonAction], the author might reply
* with [ButtonActionConfirmation] to confirm that the button event was processed.
* @see ButtonAction
* @see Composite
*/
data class ButtonActionConfirmation(
/**
* ID fo the original composite message
*/
val referencedMessageId: String,
/**
* ID of the selected button. Null if no button should be marked as selected.
*/
val buttonId: String?,
) : Signaling()

data class Unknown( // messages that aren't yet handled properly but stored in db in case
val typeName: String? = null,
val encodedData: ByteArray? = null,
Expand Down Expand Up @@ -253,7 +302,6 @@ fun MessageContent?.getType() = when (this) {
is MessageContent.Knock -> "Knock"
is MessageContent.RestrictedAsset -> "RestrictedAsset"
is MessageContent.Text -> "Text"
is MessageContent.Unknown -> "Unknown"
is MessageContent.Availability -> "Availability"
is MessageContent.Calling -> "Calling"
is MessageContent.Cleared -> "Cleared"
Expand All @@ -279,63 +327,69 @@ fun MessageContent?.getType() = when (this) {
is MessageContent.MemberChange.CreationAdded -> "MemberChange.CreationAdded"
is MessageContent.MemberChange.FailedToAdd -> "MemberChange.FailedToAdd"
is MessageContent.MLSWrongEpochWarning -> "MLSWrongEpochWarning"
null -> "Unknown"
is MessageContent.Composite -> "Composite"
is MessageContent.ButtonAction -> "ButtonAction"
is MessageContent.ButtonActionConfirmation -> "ButtonActionConfirmation"
is MessageContent.Unknown -> "Unknown"

null -> "null"
}

sealed class MessagePreviewContent {
sealed interface MessagePreviewContent {

sealed class WithUser(open val username: String?) : MessagePreviewContent() {
sealed interface WithUser : MessagePreviewContent {
val username: String?

data class Text(override val username: String?, val messageBody: String) : WithUser(username)
data class Text(override val username: String?, val messageBody: String) : WithUser

data class Asset(override val username: String?, val type: AssetType) : WithUser(username)
data class Asset(override val username: String?, val type: AssetType) : WithUser

data class MentionedSelf(override val username: String?) : WithUser(username)
data class MentionedSelf(override val username: String?) : WithUser

data class QuotedSelf(override val username: String?) : WithUser(username)
data class QuotedSelf(override val username: String?) : WithUser

data class Knock(override val username: String?) : WithUser(username)
data class Knock(override val username: String?) : WithUser

data class MemberLeft(override val username: String?) : WithUser(username)
data class MemberLeft(override val username: String?) : WithUser

data class MemberJoined(override val username: String?) : WithUser(username)
data class MemberJoined(override val username: String?) : WithUser

data class MembersAdded(
val senderName: String?,
override val username: String?,
val isSelfUserAdded: Boolean,
val otherUserIdList: List<UserId> // TODO add usernames
) : WithUser(senderName)
) : WithUser

data class MembersRemoved(
val senderName: String?,
override val username: String?,
val isSelfUserRemoved: Boolean,
val otherUserIdList: List<UserId> // TODO add usernames
) : WithUser(senderName)
) : WithUser

data class MembersFailedToAdd(
val senderName: String?,
override val username: String?,
val isSelfUserRemoved: Boolean,
val otherUserIdList: List<UserId> // TODO add usernames
) : WithUser(senderName)
) : WithUser

data class MembersCreationAdded(
Comment on lines -304 to 375
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

those had duplicated fields, senderName and userName

val senderName: String?,
override val username: String?,
val isSelfUserRemoved: Boolean,
val otherUserIdList: List<UserId> // TODO add usernames
) : WithUser(senderName)
) : WithUser

data class ConversationNameChange(val adminName: String?) : WithUser(adminName)
data class ConversationNameChange(override val username: String?) : WithUser

data class TeamMemberRemoved(val userName: String?) : WithUser(userName)
data class TeamMemberRemoved(override val username: String?) : WithUser

data class MissedCall(override val username: String?) : WithUser(username)
data class MissedCall(override val username: String?) : WithUser

}

data class Ephemeral(val isGroupConversation: Boolean) : MessagePreviewContent()
data class Ephemeral(val isGroupConversation: Boolean) : MessagePreviewContent

object CryptoSessionReset : MessagePreviewContent()
object CryptoSessionReset : MessagePreviewContent

object Unknown : MessagePreviewContent()
object Unknown : MessagePreviewContent

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import com.wire.kalium.logic.data.notification.LocalNotificationMessageAuthor
import com.wire.kalium.logic.data.user.UserId
import com.wire.kalium.logic.di.MapperProvider
import com.wire.kalium.persistence.dao.message.AssetTypeEntity
import com.wire.kalium.persistence.dao.message.ButtonEntity
import com.wire.kalium.persistence.dao.message.DeliveryStatusEntity
import com.wire.kalium.persistence.dao.message.MessageEntity
import com.wire.kalium.persistence.dao.message.MessageEntityContent
Expand All @@ -52,6 +53,7 @@ interface MessageMapper {
fun toMessageEntityContent(regularMessage: MessageContent.Regular): MessageEntityContent.Regular
}

@Suppress("TooManyFunctions")
class MessageMapperImpl(
private val selfUserId: UserId,
private val messageMentionMapper: MessageMentionMapper = MapperProvider.messageMentionMapper(selfUserId),
Expand Down Expand Up @@ -259,17 +261,13 @@ class MessageMapperImpl(
MessageEntity.ContentType.CONVERSATION_MESSAGE_TIMER_CHANGED -> null
MessageEntity.ContentType.CONVERSATION_CREATED -> null
MessageEntity.ContentType.MLS_WRONG_EPOCH_WARNING -> null
MessageEntity.ContentType.COMPOSITE -> null
}
}

@Suppress("ComplexMethod")
override fun toMessageEntityContent(regularMessage: MessageContent.Regular): MessageEntityContent.Regular = when (regularMessage) {
is MessageContent.Text -> MessageEntityContent.Text(
messageBody = regularMessage.value,
mentions = regularMessage.mentions.map { messageMentionMapper.fromModelToDao(it) },
quotedMessageId = regularMessage.quotedMessageReference?.quotedMessageId,
isQuoteVerified = regularMessage.quotedMessageReference?.isVerified,
)
is MessageContent.Text -> toTextEntity(regularMessage)

is MessageContent.Asset -> with(regularMessage.value) {
val assetWidth = when (metadata) {
Expand Down Expand Up @@ -326,8 +324,23 @@ class MessageMapperImpl(
// We don't care about the content of these messages as they are only used to perform other actions, i.e. update the content of a
// previously stored message, delete the content of a previously stored message, etc... Therefore, we map their content to Unknown
is MessageContent.Knock -> MessageEntityContent.Knock(hotKnock = regularMessage.hotKnock)
is MessageContent.Composite -> MessageEntityContent.Composite(
text = regularMessage.textContent?.let(this::toTextEntity),
trOnk12 marked this conversation as resolved.
Show resolved Hide resolved
buttonList = regularMessage.buttonList.map { ButtonEntity(
id = it.id,
text = it.text,
isSelected = it.isSelected
) },
)
}

private fun toTextEntity(textContent: MessageContent.Text): MessageEntityContent.Text = MessageEntityContent.Text(
messageBody = textContent.value,
mentions = textContent.mentions.map(messageMentionMapper::fromModelToDao),
quotedMessageId = textContent.quotedMessageReference?.quotedMessageId,
isQuoteVerified = textContent.quotedMessageReference?.isVerified,
)

@Suppress("ComplexMethod")
private fun MessageContent.System.toMessageEntityContent(): MessageEntityContent.System = when (this) {
is MessageContent.MemberChange -> {
Expand Down Expand Up @@ -404,6 +417,17 @@ class MessageMapperImpl(
this.senderUserId.toModel(),
ClientId(this.senderClientId.orEmpty())
)

is MessageEntityContent.Composite -> MessageContent.Composite(
this.text?.toMessageContent(hidden) as MessageContent.Text,
this.buttonList.map {
MessageContent.Composite.Button(
text = it.text,
id = it.id,
isSelected = it.isSelected
)
}
)
}

private fun quotedContentFromEntity(it: MessageEntityContent.Text.QuotedMessage) = when {
Expand Down Expand Up @@ -467,25 +491,25 @@ private fun MessagePreviewEntityContent.toMessageContent(): MessagePreviewConten
is MessagePreviewEntityContent.MemberJoined -> MessagePreviewContent.WithUser.MemberJoined(senderName)
is MessagePreviewEntityContent.MemberLeft -> MessagePreviewContent.WithUser.MemberLeft(senderName)
is MessagePreviewEntityContent.MembersAdded -> MessagePreviewContent.WithUser.MembersAdded(
senderName = senderName,
username = senderName,
isSelfUserAdded = isContainSelfUserId,
otherUserIdList = otherUserIdList.map { it.toModel() }
)

is MessagePreviewEntityContent.MembersRemoved -> MessagePreviewContent.WithUser.MembersRemoved(
senderName = senderName,
username = senderName,
isSelfUserRemoved = isContainSelfUserId,
otherUserIdList = otherUserIdList.map { it.toModel() }
)

is MessagePreviewEntityContent.MembersCreationAdded -> MessagePreviewContent.WithUser.MembersCreationAdded(
senderName = senderName,
username = senderName,
isSelfUserRemoved = isContainSelfUserId,
otherUserIdList = otherUserIdList.map { it.toModel() }
)

is MessagePreviewEntityContent.MembersFailedToAdded -> MessagePreviewContent.WithUser.MembersFailedToAdd(
senderName = senderName,
username = senderName,
isSelfUserRemoved = isContainSelfUserId,
otherUserIdList = otherUserIdList.map { it.toModel() }
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,8 @@ internal class PersistMessageUseCaseImpl(
is MessageContent.MemberChange.FailedToAdd -> false
is MessageContent.ConversationCreated -> false
is MessageContent.MLSWrongEpochWarning -> false
is MessageContent.Composite -> true
is MessageContent.ButtonAction -> false
is MessageContent.ButtonActionConfirmation -> false
}
}
Loading
Loading