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

fix(glean): add user opt-out setting #70

Merged
merged 8 commits into from Oct 25, 2023
Merged

Conversation

wtfluckey
Copy link

@wtfluckey wtfluckey commented Oct 24, 2023

Goal

Add a new privacy setting so that users can opt out of analytics tracking
MOSOWEB-42

To Do:

  • Add new Settings -> Privacy link & index page (show only in devMode)
  • Add allowGlean to PreferencesSettings (true by default)
  • Update Glean initialization to respect the allowGlean user setting
  • Verify that logging out persists the setting (as long as you don't clear local storage)

Implementation Decisions

I did not do the toggle switch that is designed in the ticket/figma. For the sake of time and consistency, I went with the existing checkbox pattern that Settings -> Preferences uses

Screenshots/Gifs

user-opt-out

@wtfluckey wtfluckey requested a review from a team as a code owner October 24, 2023 23:53
@@ -43,5 +43,5 @@ export function getPreferences<T extends keyof PreferencesSettings>(userSettings

export function togglePreferences(key: keyof PreferencesSettings) {
const flag = usePreferences(key)
flag.value = !flag.value
return flag.value = !flag.value
Copy link
Author

Choose a reason for hiding this comment

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

Added this explicit return so that I could use it in the toggleOptOut() function later, will call it out

Choose a reason for hiding this comment

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

Returning a variable assignment expression is a new one to me. Buut if it works, it works 👍

Copy link
Author

Choose a reason for hiding this comment

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

I'm such a rubyist at heart. In Ruby, every method (function) returns the evaluated result of the last line that is executed. And it was my first modern language, so I often forget that javascript doesn't do what I think it should do sometimes, but really I'm just remembering back to my ruby days.

Comment on lines +14 to +20
const env = useAppConfig().env
const devMode = env === ('dev' || 'canary' || 'preview')
const userSettings = useUserSettings()
const allowGlean = getPreferences(userSettings.value, 'allowGlean')
const uploadEnabled = devMode && allowGlean

Glean.initialize(GLEAN_APP_ID, uploadEnabled, {})
Glean.initialize(GLEAN_APP_ID, uploadEnabled, { channel: env })
Copy link
Author

Choose a reason for hiding this comment

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

  1. Updated uploadEnabled to check for allowGlean user setting
  2. Pass through env as the channel when initializing Glean - this is just a little bit more of identifying information (see appChannel in the glean initializing docs)

Comment on lines +19 to +24
// reset identifiers if user opts back in
if (user && allowGlean) {
mastodonAccountHandle.set(user.account.acct)
mastodonAccountId.set(user.account.id)
userAgent.set(navigator.userAgent)
}
Copy link
Author

Choose a reason for hiding this comment

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

Needed to add this because these identifiers were not getting reset when the user would opt out and then opt back in again.

const userSettings = useUserSettings()

function toggleOptOut() {
const allowGlean = togglePreferences('allowGlean')
Copy link
Author

Choose a reason for hiding this comment

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

This is where I'm using that explicit return from togglePreferences. For some reason calling getPreferences after doing the toggle wasn't returning the correct value and I didn't have the time or mental space to explore why

Choose a reason for hiding this comment

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

Just wondering, did you try calling getPreferences before doing the toggle?

Copy link
Author

Choose a reason for hiding this comment

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

yes! and it frustratingly returns the same value both before the toggle and after the toggle.

import StringMetricType from "@mozilla/glean/private/metrics/string";
import EventMetricType from "@mozilla/glean/private/metrics/event";
Copy link
Author

Choose a reason for hiding this comment

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

I swear these two generated files keep flipping back and forth even though they are supposed to be being ignored by eslint. A problem for another day...

Copy link

@jpezninjo jpezninjo left a comment

Choose a reason for hiding this comment

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

I checked out the branch and tried to break it but could not 😞 . Nice work!

const devMode = env === ('dev' || 'canary' || 'preview')
const userSettings = useUserSettings()
const allowGlean = getPreferences(userSettings.value, 'allowGlean')
const uploadEnabled = devMode && allowGlean

Choose a reason for hiding this comment

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

Should this be an OR instead of AND?

Copy link
Author

Choose a reason for hiding this comment

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

Right now, no - keeping the uploadEnabled for dev only until we are ready to start collecting events in production

<MainContent back-on-small-screen no-beta-label>
<template #title>
<div text-lg font-bold flex items-center gap-2 @click="$scrollToTop">
<span>{{ $t('settings.interface.label') }}</span>

Choose a reason for hiding this comment

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

This translation string should settings.privacy.label (Right now it renders as Interface)

Copy link
Author

Choose a reason for hiding this comment

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

Good catch! fixed

Copy link

@anthony-liddle anthony-liddle left a comment

Choose a reason for hiding this comment

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

I'm noticing a weird bug where you can't navigate to this page directly. I'm not sure if it should block this from releasing since it'll be hidden behind a flag, but it's strange.

To reproduce:

  1. Navigate to /settings/privacy
  2. Refresh page
  3. Profit Error

UPDATE
Determined the cause. Looks like there's a server error due to calling the window object

ReferenceError: window is not defined

So we may want to use the onMounted callback for this

@wtfluckey
Copy link
Author

@anthony-liddle re: the refresh bug - I've done some investigating and it's the Glean.setUploadEnabled(allowGlean) line that's causing this issue. I looked into onMounted, but couldn't get it working quickly and through more digging, I found that this error is bubbling up from Glean itself. So now I'm not sure if this is something we are causing or if this is a bug in glean. But it's line 187 in the screenshot below that's causing the issue.
Screenshot 2023-10-25 at 2 26 39 PM

@wtfluckey wtfluckey merged commit 0e9a393 into main Oct 25, 2023
3 checks passed
@wtfluckey wtfluckey deleted the fix/user-setting-glean branch October 25, 2023 19:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants