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: add analytics user profile - Part 1 (WPB-8978) #2868

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 @@ -136,6 +136,7 @@ interface UserConfigRepository {
suspend fun clearE2EISettings()
fun setShouldFetchE2EITrustAnchors(shouldFetch: Boolean)
fun getShouldFetchE2EITrustAnchor(): Boolean
suspend fun setTrackingIdentifier(identifier: String)
}

@Suppress("TooManyFunctions")
Expand Down Expand Up @@ -495,4 +496,10 @@ internal class UserConfigDataSource internal constructor(
}

override fun getShouldFetchE2EITrustAnchor(): Boolean = userConfigStorage.getShouldFetchE2EITrustAnchorHasRun()

override suspend fun setTrackingIdentifier(identifier: String) {
wrapStorageRequest {
userConfigDAO.setTrackingIdentifier(identifier = identifier)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ sealed interface Message {
return "${toLogMap().toJsonElement()}"
}

@Suppress("LongMethod")
@Suppress("LongMethod", "CyclomaticComplexMethod")
override fun toLogMap(): Map<String, Any?> {
val typeKey = "type"

Expand Down Expand Up @@ -240,6 +240,11 @@ sealed interface Message {
is MessageContent.ButtonActionConfirmation -> mutableMapOf(
typeKey to "buttonActionConfirmation"
)

is MessageContent.DataTransfer -> mutableMapOf(
typeKey to "dataTransfer",
"content" to content.toLogMap(),
)
}

val standardProperties = mapOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,18 @@ sealed interface MessageContent {
)
}

data class DataTransfer(
var trackingIdentifier: TrackingIdentifier? = null
) : Signaling {
fun toLogMap(): Map<String, Any> = mapOf(
"identifier" to (trackingIdentifier?.identifier?.obfuscateId() ?: "null")
)

data class TrackingIdentifier(
val identifier: String
)
}

data class DeleteMessage(val messageId: String) : Signaling

data class TextEdited(
Expand Down Expand Up @@ -440,6 +452,7 @@ fun MessageContent?.getType() = when (this) {
is MessageContent.LegalHold.ForConversation.Enabled -> "LegalHold.ForConversation.Enabled"
is MessageContent.LegalHold.ForMembers.Disabled -> "LegalHold.ForMembers.Disabled"
is MessageContent.LegalHold.ForMembers.Enabled -> "LegalHold.ForMembers.Enabled"
is MessageContent.DataTransfer -> "DataTransfer"
null -> "null"
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,5 @@ inline fun MessageContent.FromProto.typeDescription(): String = when (this) {
is MessageContent.Reaction -> "Reaction"
is MessageContent.Receipt -> "Receipt"
is MessageContent.TextEdited -> "TextEdited"
is MessageContent.DataTransfer -> "DataTransfer"
}
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ internal class PersistMessageUseCaseImpl(
is MessageContent.LegalHold -> false
is MessageContent.MemberChange.RemovedFromTeam -> false
is MessageContent.TeamMemberRemoved -> false
is MessageContent.DataTransfer -> false
}

@Suppress("ComplexMethod")
Expand Down Expand Up @@ -179,6 +180,7 @@ internal class PersistMessageUseCaseImpl(
is MessageContent.ConversationStartedUnverifiedWarning,
is MessageContent.LegalHold,
is MessageContent.MemberChange.RemovedFromTeam,
is MessageContent.TeamMemberRemoved -> false
is MessageContent.TeamMemberRemoved,
is MessageContent.DataTransfer -> false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ interface ProtoContentMapper {
fun decodeFromProtobuf(encodedContent: PlainMessageBlob): ProtoContent
}

@Suppress("TooManyFunctions", "LongParameterList")
@Suppress("TooManyFunctions", "LongParameterList", "LargeClass")
class ProtoContentMapperImpl(
private val assetMapper: AssetMapper = MapperProvider.assetMapper(),
private val availabilityMapper: AvailabilityStatusMapper = MapperProvider.availabilityStatusMapper(),
Expand Down Expand Up @@ -137,6 +137,8 @@ class ProtoContentMapperImpl(

is MessageContent.ButtonActionConfirmation -> packButtonActionConfirmation(readableContent)
is MessageContent.Location -> packLocation(readableContent, expectsReadConfirmation, legalHoldStatus)

is MessageContent.DataTransfer -> TODO("Analytics: Not yet implemented")
}
}

Expand Down Expand Up @@ -256,7 +258,8 @@ class ProtoContentMapperImpl(
is MessageContent.Composite,
is MessageContent.ButtonAction,
is MessageContent.ButtonActionConfirmation,
is MessageContent.TextEdited -> throw IllegalArgumentException(
is MessageContent.TextEdited,
is MessageContent.DataTransfer -> throw IllegalArgumentException(
"Unexpected message content type: ${readableContent.getType()}"
)
}
Expand Down Expand Up @@ -351,7 +354,7 @@ class ProtoContentMapperImpl(
is GenericMessage.Content.Cleared -> unpackCleared(protoContent)
is GenericMessage.Content.ClientAction -> MessageContent.ClientAction
is GenericMessage.Content.Confirmation -> unpackReceipt(protoContent)
is GenericMessage.Content.DataTransfer -> MessageContent.Ignored
is GenericMessage.Content.DataTransfer -> unpackDataTransfer(protoContent)
is GenericMessage.Content.Deleted -> MessageContent.DeleteMessage(protoContent.value.messageId)
is GenericMessage.Content.Edited -> unpackEdited(protoContent, typeName, encodedContent, genericMessage)
is GenericMessage.Content.Ephemeral -> unpackEphemeral(protoContent)
Expand Down Expand Up @@ -535,6 +538,14 @@ class ProtoContentMapperImpl(
conversationId = protoContent.value.qualifiedConversationId?.let { idMapper.fromProtoModel(it) }
)

private fun unpackDataTransfer(protoContent: GenericMessage.Content.DataTransfer) = MessageContent.DataTransfer(
trackingIdentifier = protoContent.value.trackingIdentifier?.let { trackingIdentifier ->
MessageContent.DataTransfer.TrackingIdentifier(
identifier = trackingIdentifier.identifier
)
}
)

private fun packCleared(readableContent: MessageContent.Cleared) = GenericMessage.Content.Cleared(
Cleared(
conversationId = readableContent.conversationId.value,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,8 @@ import com.wire.kalium.logic.sync.receiver.handler.CodeDeletedHandler
import com.wire.kalium.logic.sync.receiver.handler.CodeDeletedHandlerImpl
import com.wire.kalium.logic.sync.receiver.handler.CodeUpdateHandlerImpl
import com.wire.kalium.logic.sync.receiver.handler.CodeUpdatedHandler
import com.wire.kalium.logic.sync.receiver.handler.DataTransferEventHandler
import com.wire.kalium.logic.sync.receiver.handler.DataTransferEventHandlerImpl
import com.wire.kalium.logic.sync.receiver.handler.DeleteForMeHandlerImpl
import com.wire.kalium.logic.sync.receiver.handler.DeleteMessageHandlerImpl
import com.wire.kalium.logic.sync.receiver.handler.LastReadContentHandlerImpl
Expand Down Expand Up @@ -1290,6 +1292,12 @@ class UserSessionScope internal constructor(
private val buttonActionConfirmationHandler: ButtonActionConfirmationHandler
get() = ButtonActionConfirmationHandlerImpl(compositeMessageRepository, messageMetadataRepository)

private val dataTransferEventHandler: DataTransferEventHandler
get() = DataTransferEventHandlerImpl(
userId,
userConfigRepository
)

private val applicationMessageHandler: ApplicationMessageHandler
get() = ApplicationMessageHandlerImpl(
userRepository,
Expand All @@ -1315,6 +1323,7 @@ class UserSessionScope internal constructor(
messageEncoder,
receiptMessageHandler,
buttonActionConfirmationHandler,
dataTransferEventHandler,
userId
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,5 +208,6 @@ internal class PersistMigratedMessagesUseCaseImpl(
is MessageContent.ButtonAction -> MessageEntity.Visibility.HIDDEN
is MessageContent.ButtonActionConfirmation -> MessageEntity.Visibility.HIDDEN
is MessageContent.Location -> MessageEntity.Visibility.VISIBLE
is MessageContent.DataTransfer -> MessageEntity.Visibility.HIDDEN
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import com.wire.kalium.logic.kaliumLogger
import com.wire.kalium.logic.sync.receiver.asset.AssetMessageHandler
import com.wire.kalium.logic.sync.receiver.handler.ButtonActionConfirmationHandler
import com.wire.kalium.logic.sync.receiver.handler.ClearConversationContentHandler
import com.wire.kalium.logic.sync.receiver.handler.DataTransferEventHandler
import com.wire.kalium.logic.sync.receiver.handler.DeleteForMeHandler
import com.wire.kalium.logic.sync.receiver.handler.DeleteMessageHandler
import com.wire.kalium.logic.sync.receiver.handler.LastReadContentHandler
Expand Down Expand Up @@ -86,6 +87,7 @@ internal class ApplicationMessageHandlerImpl(
private val messageEncoder: MessageContentEncoder,
private val receiptMessageHandler: ReceiptMessageHandler,
private val buttonActionConfirmationHandler: ButtonActionConfirmationHandler,
private val dataTransferEventHandler: DataTransferEventHandler,
private val selfUserId: UserId
) : ApplicationMessageHandler {

Expand Down Expand Up @@ -161,6 +163,7 @@ internal class ApplicationMessageHandlerImpl(
}
}

@Suppress("CyclomaticComplexMethod")
private suspend fun processSignaling(signaling: Message.Signaling) {
when (val content = signaling.content) {
MessageContent.Ignored -> {
Expand Down Expand Up @@ -215,6 +218,8 @@ internal class ApplicationMessageHandlerImpl(
signaling.senderUserId,
content
)

is MessageContent.DataTransfer -> dataTransferEventHandler.handle(signaling, content)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Wire
* Copyright (C) 2024 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.sync.receiver.handler

import com.wire.kalium.logic.configuration.UserConfigRepository
import com.wire.kalium.logic.data.message.Message
import com.wire.kalium.logic.data.message.MessageContent
import com.wire.kalium.logic.data.user.UserId
import com.wire.kalium.logic.kaliumLogger

internal interface DataTransferEventHandler {
suspend fun handle(
message: Message.Signaling,
messageContent: MessageContent.DataTransfer
)
}

internal class DataTransferEventHandlerImpl(
private val selfUserId: UserId,
private val userConfigRepository: UserConfigRepository
) : DataTransferEventHandler {

override suspend fun handle(
message: Message.Signaling,
messageContent: MessageContent.DataTransfer
) {
kaliumLogger.d("MessageContent.DataTransfer | with Identifier : ${messageContent.trackingIdentifier?.identifier} |end|")
saleniuk marked this conversation as resolved.
Show resolved Hide resolved
// DataTransfer from another user or null tracking identifier shouldn't happen,
// If it happens, it's unnecessary
// and we can squish some performance by skipping it completely
if (message.senderUserId != selfUserId || messageContent.trackingIdentifier == null) return
saleniuk marked this conversation as resolved.
Show resolved Hide resolved

userConfigRepository.setTrackingIdentifier(
identifier = messageContent.trackingIdentifier!!.identifier
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import com.wire.kalium.logic.functional.Either
import com.wire.kalium.logic.sync.receiver.asset.AssetMessageHandler
import com.wire.kalium.logic.sync.receiver.handler.ButtonActionConfirmationHandler
import com.wire.kalium.logic.sync.receiver.handler.ClearConversationContentHandler
import com.wire.kalium.logic.sync.receiver.handler.DataTransferEventHandler
import com.wire.kalium.logic.sync.receiver.handler.DeleteForMeHandler
import com.wire.kalium.logic.sync.receiver.handler.DeleteMessageHandler
import com.wire.kalium.logic.sync.receiver.handler.LastReadContentHandler
Expand Down Expand Up @@ -133,6 +134,44 @@ class ApplicationMessageHandlerTest {
}.wasInvoked(exactly = once)
}

@Test
fun givenDataTransferEventReceived_whenHandling_thenCorrectHandlerIsInvoked() = runTest {
// given
val messageId = "messageId"
val dataTransferContent = MessageContent.DataTransfer(
trackingIdentifier = MessageContent.DataTransfer.TrackingIdentifier(
identifier = "abcd-1234-efgh-5678"
)
)
val protoContent = ProtoContent.Readable(
messageId,
dataTransferContent,
false,
Conversation.LegalHoldStatus.DISABLED
)

val (arrangement, messageHandler) = Arrangement()
.withPersistingMessageReturning(Either.Right(Unit))
.arrange()

val encodedEncryptedContent = Base64.encodeToBase64("Hello".encodeToByteArray())
val messageEvent = TestEvent.newMessageEvent(encodedEncryptedContent.decodeToString())

// when
messageHandler.handleContent(
messageEvent.conversationId,
messageEvent.messageInstant,
messageEvent.senderUserId,
messageEvent.senderClientId,
protoContent
)

// then
coVerify {
arrangement.dataTransferEventHandler.handle(any(), any())
}.wasInvoked(exactly = once)
}

private class Arrangement {
@Mock
val persistMessage = mock(PersistMessageUseCase::class)
Expand Down Expand Up @@ -176,6 +215,9 @@ class ApplicationMessageHandlerTest {
@Mock
val buttonActionConfirmationHandler = mock(ButtonActionConfirmationHandler::class)

@Mock
val dataTransferEventHandler = mock(DataTransferEventHandler::class)

private val applicationMessageHandler = ApplicationMessageHandlerImpl(
userRepository,
messageRepository,
Expand All @@ -191,6 +233,7 @@ class ApplicationMessageHandlerTest {
MessageContentEncoder(),
receiptMessageHandler,
buttonActionConfirmationHandler,
dataTransferEventHandler,
TestUser.SELF.id
)

Expand Down
Loading
Loading