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: composite messages #1916

Merged
merged 27 commits into from
Jul 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
bbf47e8
feat: receive and store composite messages [part-1] (#1888)
MohamadJaara Jul 19, 2023
787e880
Merge branch 'develop' into feat/composit_messages/epic
MohamadJaara Jul 20, 2023
709e72e
feat: use case to send Message Button Action [part-2] (#1896)
MohamadJaara Jul 24, 2023
be085c9
feat: handle composite action confermation message [part-3] (#1901)
MohamadJaara Jul 24, 2023
33b9e99
feat: composite message preview [part-4] (#1908)
MohamadJaara Jul 24, 2023
0e80206
Merge branch 'develop' into feat/composit_messages/epic
MohamadJaara Jul 24, 2023
0de5c75
fix: composite messages are not included in the getLastMessages query…
MohamadJaara Jul 24, 2023
487d9ab
feat: composit messages backup [part-6] (#1914)
MohamadJaara Jul 24, 2023
e400ad6
Merge branch 'develop' into feat/composit_messages/epic
MohamadJaara Jul 24, 2023
73c4105
merge issues
MohamadJaara Jul 24, 2023
53bde82
Merge branch 'develop' into feat/composit_messages/epic
MohamadJaara Jul 24, 2023
d7dcc83
Merge branch 'develop' into feat/composit_messages/epic
MohamadJaara Jul 24, 2023
7307849
unit test
MohamadJaara Jul 25, 2023
462fbd4
merge issues
MohamadJaara Jul 25, 2023
09c28e6
ignore Confirmation messages that are not fom the original message se…
MohamadJaara Jul 25, 2023
52d50a0
test
MohamadJaara Jul 25, 2023
60b4feb
cleanup
MohamadJaara Jul 25, 2023
0906e7c
detekt
MohamadJaara Jul 25, 2023
3e6a494
typo
MohamadJaara Jul 25, 2023
fa5fa19
typo
MohamadJaara Jul 25, 2023
9500332
Merge branch 'develop' into feat/composit_messages/epic
MohamadJaara Jul 25, 2023
a8335e9
Merge branch 'develop' into feat/composit_messages/epic
MohamadJaara Jul 26, 2023
8532357
PR comments
MohamadJaara Jul 26, 2023
67514c7
Merge branch 'develop' into feat/composit_messages/epic
MohamadJaara Jul 26, 2023
0501a00
trigger CI
MohamadJaara Jul 26, 2023
09c9aba
empty
tmspzz Jul 26, 2023
7646aec
Merge branch 'develop' into feat/composit_messages/epic
MohamadJaara Jul 27, 2023
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 @@ -67,6 +67,12 @@ sealed interface CoreFailure {
*/
object OnlySystemMessageAllowed : FeatureFailure()

/**
* The sender ID of the event is invalid.
* usually happens with events that alter a message state [ButtonActionConfirmation]
* when the sender ID is not the same are the original message sender id
*/
object InvalidEventSenderID : FeatureFailure()
/**
* This operation is not supported by proteus conversations
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ import com.wire.kalium.logic.sync.receiver.EventReceiver
import com.wire.kalium.logic.sync.receiver.conversation.MemberJoinEventHandler
import com.wire.kalium.logic.sync.receiver.conversation.MemberLeaveEventHandler

interface CommitBundleEventReceiver : EventReceiver<Event.Conversation>
internal interface CommitBundleEventReceiver : EventReceiver<Event.Conversation>

class CommitBundleEventReceiverImpl(
internal class CommitBundleEventReceiverImpl(
private val memberJoinEventHandler: MemberJoinEventHandler,
private val memberLeaveEventHandler: MemberLeaveEventHandler
) : CommitBundleEventReceiver {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ private fun CoreFailure.getStrategy(retryOnClientMismatch: Boolean = true): Comm
}

@Suppress("TooManyFunctions", "LongParameterList")
class MLSConversationDataSource(
internal class MLSConversationDataSource(
private val keyPackageRepository: KeyPackageRepository,
private val mlsClientProvider: MLSClientProvider,
private val mlsMessageApi: MLSMessageApi,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,6 @@ data class QualifiedClientID(
val clientId: ClientId,
val userId: UserId
)

typealias MessageId = String
typealias MessageButtonId = String
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
@@ -0,0 +1,65 @@
/*
* 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.message

import com.wire.kalium.logic.StorageFailure
import com.wire.kalium.logic.data.id.ConversationId
import com.wire.kalium.logic.data.id.MessageId
import com.wire.kalium.logic.data.id.toDao
import com.wire.kalium.logic.functional.Either
import com.wire.kalium.logic.wrapStorageRequest
import com.wire.kalium.persistence.dao.message.CompositeMessageDAO

interface CompositeMessageRepository {
suspend fun markSelected(
messageId: MessageId,
conversationId: ConversationId,
buttonId: String
): Either<StorageFailure, Unit>

suspend fun resetSelection(
messageId: MessageId,
conversationId: ConversationId
): Either<StorageFailure, Unit>
}

internal class CompositeMessageDataSource internal constructor(
private val compositeMessageDAO: CompositeMessageDAO
) : CompositeMessageRepository {
override suspend fun markSelected(
messageId: MessageId,
conversationId: ConversationId,
buttonId: String
): Either<StorageFailure, Unit> = wrapStorageRequest {
compositeMessageDAO.markAsSelected(
messageId = messageId,
conversationId = conversationId.toDao(),
buttonId = buttonId
)
}

override suspend fun resetSelection(
messageId: MessageId,
conversationId: ConversationId
): Either<StorageFailure, Unit> = wrapStorageRequest {
compositeMessageDAO.resetSelection(
messageId = messageId,
conversationId = conversationId.toDao()
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,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 @@ -163,6 +167,7 @@ sealed interface Message {
override val isSelfMessage: Boolean,
override val expirationData: ExpirationData?
) : Sendable {
@Suppress("LongMethod")
override fun toLogString(): String {
return "${toLogMap().toJsonElement()}"
}
Expand Down Expand Up @@ -200,17 +205,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 @@ -220,7 +222,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 @@ -294,6 +304,7 @@ sealed interface Message {
MessageContent.HistoryLost -> mutableMapOf(
typeKey to "conversationMightLostHistory"
)

is MessageContent.ConversationMessageTimerChanged -> mutableMapOf(
typeKey to "conversationMessageTimerChanged"
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,13 @@ package com.wire.kalium.logic.data.message
import com.wire.kalium.logger.obfuscateId
import com.wire.kalium.logic.data.conversation.ClientId
import com.wire.kalium.logic.data.id.ConversationId
import com.wire.kalium.logic.data.id.MessageButtonId
import com.wire.kalium.logic.data.id.MessageId
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 +166,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: MessageId,

/**
* ID of the button that was selected.
*/
val buttonId: MessageButtonId
) : 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: MessageId,
/**
* ID of the selected button. Null if no button should be marked as selected.
*/
val buttonId: MessageButtonId?,
) : 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 @@ -255,7 +306,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 Down Expand Up @@ -283,63 +333,70 @@ fun MessageContent?.getType() = when (this) {
is MessageContent.MLSWrongEpochWarning -> "MLSWrongEpochWarning"
is MessageContent.ConversationDegradedMLS -> "ConversationVerification.Degraded.MLS"
is MessageContent.ConversationDegradedProteus -> "ConversationVerification.Degraded.Proteus"
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 interface WithUser : MessagePreviewContent {
val username: String?

sealed class WithUser(open val username: String?) : MessagePreviewContent() {
data class Text(override val username: String?, val messageBody: String) : WithUser

data class Text(override val username: String?, val messageBody: String) : WithUser(username)
data class Composite(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(
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

}
Loading
Loading