Merge pull request #8031 from vector-im/feature/bma/fixPosthog

Do not send any request to Posthog if no consent is provided.
This commit is contained in:
Benoit Marty 2023-01-30 17:11:30 +01:00 committed by GitHub
commit 156f4f71f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 36 additions and 4 deletions

1
changelog.d/8031.bugfix Normal file
View File

@ -0,0 +1 @@
Do not send any request to Posthog if no consent is provided.

View File

@ -31,6 +31,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import org.matrix.android.sdk.api.extensions.orFalse
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -60,6 +61,9 @@ class DefaultVectorAnalytics @Inject constructor(
private var userConsent: Boolean? = null private var userConsent: Boolean? = null
private var analyticsId: String? = null private var analyticsId: String? = null
// Cache for the properties to send
private var pendingUserProperties: UserProperties? = null
override fun init() { override fun init() {
observeUserConsent() observeUserConsent()
observeAnalyticsId() observeAnalyticsId()
@ -112,6 +116,7 @@ class DefaultVectorAnalytics @Inject constructor(
private suspend fun identifyPostHog() { private suspend fun identifyPostHog() {
val id = analyticsId ?: return val id = analyticsId ?: return
if (!userConsent.orFalse()) return
if (id.isEmpty()) { if (id.isEmpty()) {
Timber.tag(analyticsTag.value).d("reset") Timber.tag(analyticsTag.value).d("reset")
posthog?.reset() posthog?.reset()
@ -126,7 +131,7 @@ class DefaultVectorAnalytics @Inject constructor(
.onEach { consent -> .onEach { consent ->
Timber.tag(analyticsTag.value).d("User consent updated to $consent") Timber.tag(analyticsTag.value).d("User consent updated to $consent")
userConsent = consent userConsent = consent
optOutPostHog() initOrStopPostHog()
initOrStopSentry() initOrStopSentry()
} }
.launchIn(globalScope) .launchIn(globalScope)
@ -141,8 +146,22 @@ class DefaultVectorAnalytics @Inject constructor(
} }
} }
private fun optOutPostHog() { private suspend fun initOrStopPostHog() {
userConsent?.let { posthog?.optOut(!it) } userConsent?.let { _userConsent ->
when (_userConsent) {
true -> {
posthog?.optOut(false)
identifyPostHog()
pendingUserProperties?.let { doUpdateUserProperties(it) }
pendingUserProperties = null
}
false -> {
// When opting out, ensure that the queue is flushed first, or it will be flushed later (after user has revoked consent)
posthog?.flush()
posthog?.optOut(true)
}
}
}
} }
override fun capture(event: VectorAnalyticsEvent) { override fun capture(event: VectorAnalyticsEvent) {
@ -160,7 +179,17 @@ class DefaultVectorAnalytics @Inject constructor(
} }
override fun updateUserProperties(userProperties: UserProperties) { override fun updateUserProperties(userProperties: UserProperties) {
posthog?.identify(REUSE_EXISTING_ID, userProperties.getProperties()?.toPostHogUserProperties(), IGNORED_OPTIONS) if (userConsent == true) {
doUpdateUserProperties(userProperties)
} else {
pendingUserProperties = userProperties
}
}
private fun doUpdateUserProperties(userProperties: UserProperties) {
posthog
?.takeIf { userConsent == true }
?.identify(REUSE_EXISTING_ID, userProperties.getProperties()?.toPostHogUserProperties(), IGNORED_OPTIONS)
} }
private fun Map<String, Any?>?.toPostHogProperties(): Properties? { private fun Map<String, Any?>?.toPostHogProperties(): Properties? {

View File

@ -97,6 +97,7 @@ class DefaultVectorAnalyticsTest {
@Test @Test
fun `given lateinit user properties when valid analytics id updates then identify with lateinit properties`() = runTest { fun `given lateinit user properties when valid analytics id updates then identify with lateinit properties`() = runTest {
fakeLateInitUserPropertiesFactory.givenCreatesProperties(A_LATE_INIT_USER_PROPERTIES) fakeLateInitUserPropertiesFactory.givenCreatesProperties(A_LATE_INIT_USER_PROPERTIES)
fakeAnalyticsStore.givenUserContent(true)
fakeAnalyticsStore.givenAnalyticsId(AN_ANALYTICS_ID) fakeAnalyticsStore.givenAnalyticsId(AN_ANALYTICS_ID)
@ -106,6 +107,7 @@ class DefaultVectorAnalyticsTest {
@Test @Test
fun `when signing out then resets posthog and closes Sentry`() = runTest { fun `when signing out then resets posthog and closes Sentry`() = runTest {
fakeAnalyticsStore.allowSettingAnalyticsIdToCallBackingFlow() fakeAnalyticsStore.allowSettingAnalyticsIdToCallBackingFlow()
fakeAnalyticsStore.givenUserContent(true)
defaultVectorAnalytics.onSignOut() defaultVectorAnalytics.onSignOut()