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: New user properties for Analytics [WPB-16121] #3890

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
Open
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
4 changes: 2 additions & 2 deletions app/src/main/kotlin/com/wire/android/WireApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,8 @@ class WireApplication : BaseApp() {

val analyticsResultFlow = ObserveCurrentSessionAnalyticsUseCase(
currentSessionFlow = coreLogic.get().getGlobalScope().session.currentSessionFlow(),
isUserTeamMember = {
coreLogic.get().getSessionScope(it).team.isSelfATeamMember()
getAnalyticsContactsData = {
coreLogic.get().getSessionScope(it).getAnalyticsContactsData()
},
observeAnalyticsTrackingIdentifierStatusFlow = {
coreLogic.get().getSessionScope(it).observeAnalyticsTrackingIdentifierStatus()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
package com.wire.android.analytics

import com.wire.android.datastore.UserDataStoreProvider
import com.wire.android.feature.analytics.model.AnalyticsProfileProperties
import com.wire.android.feature.analytics.model.AnalyticsResult
import com.wire.kalium.logic.configuration.server.ServerConfig
import com.wire.kalium.logic.data.analytics.AnalyticsIdentifierResult
import com.wire.kalium.logic.data.user.UserId
import com.wire.kalium.logic.feature.analytics.AnalyticsContactsData
import com.wire.kalium.logic.feature.analytics.AnalyticsIdentifierManager
import com.wire.kalium.logic.feature.session.CurrentSessionResult
import com.wire.kalium.logic.feature.user.SelfServerConfigUseCase
Expand All @@ -47,7 +49,7 @@ interface ObserveCurrentSessionAnalyticsUseCase {
@Suppress("FunctionNaming", "LongParameterList")
fun ObserveCurrentSessionAnalyticsUseCase(
currentSessionFlow: Flow<CurrentSessionResult>,
isUserTeamMember: suspend (UserId) -> Boolean,
getAnalyticsContactsData: suspend (UserId) -> AnalyticsContactsData,
observeAnalyticsTrackingIdentifierStatusFlow: suspend (UserId) -> Flow<AnalyticsIdentifierResult>,
analyticsIdentifierManagerProvider: (UserId) -> AnalyticsIdentifierManager,
userDataStoreProvider: UserDataStoreProvider,
Expand All @@ -56,12 +58,10 @@ fun ObserveCurrentSessionAnalyticsUseCase(

private var previousAnalyticsResult: AnalyticsIdentifierResult? = null

override fun invoke(): Flow<AnalyticsResult<AnalyticsIdentifierManager>> =
currentSessionFlow
override fun invoke(): Flow<AnalyticsResult<AnalyticsIdentifierManager>> = currentSessionFlow
.flatMapLatest {
if (it is CurrentSessionResult.Success && it.accountInfo.isValid()) {
val userId = it.accountInfo.userId
val isTeamMember = isUserTeamMember(userId)
val analyticsIdentifierManager = analyticsIdentifierManagerProvider(userId)

combine(
Expand All @@ -74,35 +74,48 @@ fun ObserveCurrentSessionAnalyticsUseCase(
currentResult?.identifier != previousResult?.identifier
},
userDataStoreProvider.getOrCreate(userId).isAnonymousUsageDataEnabled()
) { identifierResult, enabled ->
previousAnalyticsResult = identifierResult
) { analyticsIdentifierResult, enabled ->
previousAnalyticsResult = analyticsIdentifierResult

val isProdBackend = when (val serverConfig = currentBackend(userId)) {
is SelfServerConfigUseCase.Result.Success ->
serverConfig.serverLinks.links.api == ServerConfig.PRODUCTION.api
|| serverConfig.serverLinks.links.api == ServerConfig.STAGING.api

is SelfServerConfigUseCase.Result.Failure -> false
}

if (enabled && isProdBackend) {
AnalyticsResult(
identifierResult = identifierResult,
isTeamMember = isTeamMember,
manager = analyticsIdentifierManager
)
val analyticsContactsData = getAnalyticsContactsData(userId)

val identifierResult = if (enabled && isProdBackend) {
analyticsIdentifierResult
} else {
AnalyticsResult(
identifierResult = AnalyticsIdentifierResult.Disabled,
isTeamMember = isTeamMember,
manager = analyticsIdentifierManager
)
AnalyticsIdentifierResult.Disabled
}

AnalyticsResult(
identifierResult = identifierResult,
profileProperties = AnalyticsProfileProperties(
isTeamMember = analyticsContactsData.isTeamMember,
teamId = analyticsContactsData.teamId,
contactsAmount = analyticsContactsData.contactsSize,
teamMembersAmount = analyticsContactsData.teamSize,
isEnterprise = analyticsContactsData.isEnterprise
),
manager = analyticsIdentifierManager
)
}
} else {
flowOf(
AnalyticsResult<AnalyticsIdentifierManager>(
identifierResult = AnalyticsIdentifierResult.Disabled,
isTeamMember = false,
profileProperties = AnalyticsProfileProperties(
isTeamMember = false,
teamId = null,
contactsAmount = null,
teamMembersAmount = null,
isEnterprise = null
),
manager = null
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@ import app.cash.turbine.test
import com.wire.android.assertIs
import com.wire.android.datastore.UserDataStore
import com.wire.android.datastore.UserDataStoreProvider
import com.wire.android.feature.analytics.model.AnalyticsProfileProperties
import com.wire.android.framework.TestUser
import com.wire.kalium.common.error.CoreFailure
import com.wire.kalium.logic.configuration.server.CommonApiVersionType
import com.wire.kalium.logic.configuration.server.ServerConfig
import com.wire.kalium.logic.data.analytics.AnalyticsIdentifierResult
import com.wire.kalium.logic.data.auth.AccountInfo
import com.wire.kalium.logic.data.user.UserId
import com.wire.kalium.logic.feature.analytics.AnalyticsContactsData
import com.wire.kalium.logic.feature.analytics.AnalyticsIdentifierManager
import com.wire.kalium.logic.feature.session.CurrentSessionResult
import com.wire.kalium.logic.feature.user.SelfServerConfigUseCase
Expand Down Expand Up @@ -56,7 +58,7 @@ class ObserveCurrentSessionAnalyticsUseCaseTest {
// then
val item = awaitItem()
assertIs<AnalyticsIdentifierResult.Disabled>(item.identifierResult)
assertEquals(false, item.isTeamMember)
assertEquals(false, item.profileProperties.isTeamMember)
assertEquals(null, item.manager)
}
}
Expand All @@ -68,7 +70,7 @@ class ObserveCurrentSessionAnalyticsUseCaseTest {
.withIsAnonymousUsageDataEnabled(true)
.apply {
setCurrentSession(CurrentSessionResult.Success(AccountInfo.Valid(TestUser.SELF_USER.id)))
setIsTeamMember(TestUser.SELF_USER.id)
setAnalyticsContactsData(TestUser.SELF_USER.id, Arrangement.ANALYTICS_CONTACTS_DATA)
setObservingTrackingIdentifierStatus(AnalyticsIdentifierResult.ExistingIdentifier(Arrangement.CURRENT_TRACKING_IDENTIFIER))
setSelfServerConfig(Arrangement.SERVER_CONFIG_PRODUCTION)
}.arrange()
Expand All @@ -78,7 +80,7 @@ class ObserveCurrentSessionAnalyticsUseCaseTest {
// then
val item = awaitItem()
assertIs<AnalyticsIdentifierResult.ExistingIdentifier>(item.identifierResult)
assertEquals(true, item.isTeamMember)
assertAnalyticsProfileProperties(Arrangement.ANALYTICS_CONTACTS_DATA, item.profileProperties)
}
}

Expand All @@ -89,7 +91,7 @@ class ObserveCurrentSessionAnalyticsUseCaseTest {
.withIsAnonymousUsageDataEnabled(true)
.apply {
setCurrentSession(CurrentSessionResult.Success(AccountInfo.Valid(TestUser.SELF_USER.id)))
setIsTeamMember(TestUser.SELF_USER.id)
setAnalyticsContactsData(TestUser.SELF_USER.id, Arrangement.ANALYTICS_CONTACTS_DATA)
setObservingTrackingIdentifierStatus(AnalyticsIdentifierResult.ExistingIdentifier(Arrangement.CURRENT_TRACKING_IDENTIFIER))
setSelfServerConfig(Arrangement.SERVER_CONFIG_STAGING)
}.arrange()
Expand All @@ -99,7 +101,7 @@ class ObserveCurrentSessionAnalyticsUseCaseTest {
// then
val item = awaitItem()
assertIs<AnalyticsIdentifierResult.ExistingIdentifier>(item.identifierResult)
assertEquals(true, item.isTeamMember)
assertAnalyticsProfileProperties(Arrangement.ANALYTICS_CONTACTS_DATA, item.profileProperties)
}
}

Expand All @@ -111,7 +113,7 @@ class ObserveCurrentSessionAnalyticsUseCaseTest {
.withIsAnonymousUsageDataEnabled(false)
.apply {
setCurrentSession(CurrentSessionResult.Success(AccountInfo.Valid(TestUser.SELF_USER.id)))
setIsTeamMember(TestUser.SELF_USER.id)
setAnalyticsContactsData(TestUser.SELF_USER.id, Arrangement.ANALYTICS_CONTACTS_DATA)
setObservingTrackingIdentifierStatus(
AnalyticsIdentifierResult.ExistingIdentifier(Arrangement.CURRENT_TRACKING_IDENTIFIER)
)
Expand All @@ -123,7 +125,7 @@ class ObserveCurrentSessionAnalyticsUseCaseTest {
// then
val item = awaitItem()
assertIs<AnalyticsIdentifierResult.Disabled>(item.identifierResult)
assertEquals(true, item.isTeamMember)
assertAnalyticsProfileProperties(Arrangement.ANALYTICS_CONTACTS_DATA, item.profileProperties)
assertEquals(true, item.manager != null)
}
}
Expand All @@ -136,7 +138,7 @@ class ObserveCurrentSessionAnalyticsUseCaseTest {
.withIsAnonymousUsageDataEnabled(true)
.apply {
setCurrentSession(CurrentSessionResult.Success(AccountInfo.Valid(TestUser.SELF_USER.id)))
setIsTeamMember(TestUser.SELF_USER.id)
setAnalyticsContactsData(TestUser.SELF_USER.id, Arrangement.ANALYTICS_CONTACTS_DATA)
setObservingTrackingIdentifierStatus(
AnalyticsIdentifierResult.ExistingIdentifier(Arrangement.CURRENT_TRACKING_IDENTIFIER)
)
Expand All @@ -152,7 +154,7 @@ class ObserveCurrentSessionAnalyticsUseCaseTest {
// then
val item = awaitItem()
assertIs<AnalyticsIdentifierResult.Disabled>(item.identifierResult)
assertEquals(true, item.isTeamMember)
assertAnalyticsProfileProperties(Arrangement.ANALYTICS_CONTACTS_DATA, item.profileProperties)
assertEquals(true, item.manager != null)
}
}
Expand All @@ -165,7 +167,7 @@ class ObserveCurrentSessionAnalyticsUseCaseTest {
.withIsAnonymousUsageDataEnabled(true)
.apply {
setCurrentSession(CurrentSessionResult.Success(AccountInfo.Valid(TestUser.SELF_USER.id)))
setIsTeamMember(TestUser.SELF_USER.id)
setAnalyticsContactsData(TestUser.SELF_USER.id, Arrangement.ANALYTICS_CONTACTS_DATA)
setObservingTrackingIdentifierStatus(
AnalyticsIdentifierResult.ExistingIdentifier(Arrangement.CURRENT_TRACKING_IDENTIFIER)
)
Expand All @@ -177,7 +179,7 @@ class ObserveCurrentSessionAnalyticsUseCaseTest {
// then
val item = awaitItem()
assertIs<AnalyticsIdentifierResult.Disabled>(item.identifierResult)
assertEquals(true, item.isTeamMember)
assertAnalyticsProfileProperties(Arrangement.ANALYTICS_CONTACTS_DATA, item.profileProperties)
assertEquals(true, item.manager != null)
}
}
Expand All @@ -189,7 +191,7 @@ class ObserveCurrentSessionAnalyticsUseCaseTest {
.withIsAnonymousUsageDataEnabled(true)
.apply {
setCurrentSession(CurrentSessionResult.Success(AccountInfo.Valid(TestUser.SELF_USER.id)))
setIsTeamMember(TestUser.SELF_USER.id)
setAnalyticsContactsData(TestUser.SELF_USER.id, Arrangement.ANALYTICS_CONTACTS_DATA)
setObservingTrackingIdentifierStatus(AnalyticsIdentifierResult.ExistingIdentifier(Arrangement.CURRENT_TRACKING_IDENTIFIER))
setSelfServerConfig(Arrangement.SERVER_CONFIG_PRODUCTION)
}.arrange()
Expand All @@ -199,7 +201,7 @@ class ObserveCurrentSessionAnalyticsUseCaseTest {
// then
val item = awaitItem()
assertIs<AnalyticsIdentifierResult.ExistingIdentifier>(item.identifierResult)
assertEquals(true, item.isTeamMember)
assertAnalyticsProfileProperties(Arrangement.ANALYTICS_CONTACTS_DATA, item.profileProperties)

// when changing user
arrangement.setCurrentSession(CurrentSessionResult.Success(AccountInfo.Valid(TestUser.OTHER_USER.id)))
Expand All @@ -212,10 +214,17 @@ class ObserveCurrentSessionAnalyticsUseCaseTest {
// then
val nextItem = awaitItem()
assertIs<AnalyticsIdentifierResult.ExistingIdentifier>(nextItem.identifierResult)
assertEquals(false, nextItem.isTeamMember)
}
}

private fun assertAnalyticsProfileProperties(expected: AnalyticsContactsData, actual: AnalyticsProfileProperties) {
assertEquals(expected.teamId, actual.teamId)
assertEquals(expected.isTeamMember, actual.isTeamMember)
assertEquals(expected.isEnterprise, actual.isEnterprise)
assertEquals(expected.contactsSize, actual.contactsAmount)
assertEquals(expected.teamSize, actual.teamMembersAmount)
}

private class Arrangement {

@MockK
Expand All @@ -233,9 +242,11 @@ class ObserveCurrentSessionAnalyticsUseCaseTest {

private val selfServerConfigChannel = Channel<SelfServerConfigUseCase.Result>(Channel.UNLIMITED)

private val teamMembers = mutableSetOf<UserId>()
private var analyticsContactsData: MutableMap<UserId, AnalyticsContactsData> = mutableMapOf()

private val isTeamMember: (UserId) -> Boolean = { teamMembers.contains(it) }
private val getAnalyticsContactsData: (UserId) -> AnalyticsContactsData = {
analyticsContactsData.getOrDefault(it, ANALYTICS_CONTACTS_DATA_DEFAULT)
}

init {
// Tests setup
Expand All @@ -246,8 +257,8 @@ class ObserveCurrentSessionAnalyticsUseCaseTest {
currentSessionChannel.send(result)
}

fun setIsTeamMember(userId: UserId) {
teamMembers.add(userId)
fun setAnalyticsContactsData(userId: UserId, data: AnalyticsContactsData) {
analyticsContactsData[userId] = data
}

suspend fun setObservingTrackingIdentifierStatus(result: AnalyticsIdentifierResult) {
Expand All @@ -265,7 +276,7 @@ class ObserveCurrentSessionAnalyticsUseCaseTest {

var useCase: ObserveCurrentSessionAnalyticsUseCase = ObserveCurrentSessionAnalyticsUseCase(
currentSessionFlow = currentSessionChannel.receiveAsFlow(),
isUserTeamMember = isTeamMember,
getAnalyticsContactsData = getAnalyticsContactsData,
observeAnalyticsTrackingIdentifierStatusFlow = {
analyticsTrackingIdentifierStatusChannel.receiveAsFlow()
},
Expand Down Expand Up @@ -301,6 +312,22 @@ class ObserveCurrentSessionAnalyticsUseCaseTest {
links = ServerConfig.STAGING
)
)

val ANALYTICS_CONTACTS_DATA = AnalyticsContactsData(
teamId = "teamId",
contactsSize = 12,
teamSize = 13,
isEnterprise = true,
isTeamMember = true
)

val ANALYTICS_CONTACTS_DATA_DEFAULT = AnalyticsContactsData(
teamId = null,
contactsSize = null,
teamSize = null,
isEnterprise = null,
isTeamMember = false
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import android.util.Log
import com.wire.android.feature.analytics.handler.AnalyticsMigrationHandler
import com.wire.android.feature.analytics.handler.AnalyticsPropagationHandler
import com.wire.android.feature.analytics.model.AnalyticsEvent
import com.wire.android.feature.analytics.model.AnalyticsProfileProperties
import com.wire.android.feature.analytics.model.AnalyticsResult
import com.wire.android.feature.analytics.model.AnalyticsSettings
import com.wire.kalium.logic.data.analytics.AnalyticsIdentifierResult
Expand Down Expand Up @@ -76,7 +77,7 @@ object AnonymousAnalyticsManagerImpl : AnonymousAnalyticsManager {

handleTrackingIdentifier(
analyticsIdentifierResult = analyticsResult.identifierResult,
isTeamMember = analyticsResult.isTeamMember,
analyticsProfileProperties = analyticsResult.profileProperties,
propagateIdentifier = {
analyticsResult.manager?.let { propagationHandler.propagate(it, result.identifier) }
},
Expand Down Expand Up @@ -133,7 +134,7 @@ object AnonymousAnalyticsManagerImpl : AnonymousAnalyticsManager {

private suspend fun handleTrackingIdentifier(
analyticsIdentifierResult: AnalyticsIdentifierResult,
isTeamMember: Boolean,
analyticsProfileProperties: AnalyticsProfileProperties,
propagateIdentifier: suspend () -> Unit,
migrationComplete: suspend () -> Unit
) {
Expand All @@ -142,7 +143,7 @@ object AnonymousAnalyticsManagerImpl : AnonymousAnalyticsManager {
anonymousAnalyticsRecorder?.setTrackingIdentifierWithoutMerge(
identifier = analyticsIdentifierResult.identifier,
shouldPropagateIdentifier = true,
isTeamMember = isTeamMember,
analyticsProfileProperties = analyticsProfileProperties,
propagateIdentifier = propagateIdentifier
)
}
Expand All @@ -151,15 +152,15 @@ object AnonymousAnalyticsManagerImpl : AnonymousAnalyticsManager {
anonymousAnalyticsRecorder?.setTrackingIdentifierWithoutMerge(
identifier = analyticsIdentifierResult.identifier,
shouldPropagateIdentifier = false,
isTeamMember = isTeamMember,
analyticsProfileProperties = analyticsProfileProperties,
propagateIdentifier = {}
)
}

is AnalyticsIdentifierResult.MigrationIdentifier -> {
anonymousAnalyticsRecorder?.setTrackingIdentifierWithMerge(
identifier = analyticsIdentifierResult.identifier,
isTeamMember = isTeamMember,
analyticsProfileProperties = analyticsProfileProperties,
migrationComplete = migrationComplete
)
}
Expand Down
Loading
Loading