Merge pull request #3053 from element-hq/robin/posthog-logout

Enable analytics only while authenticated
This commit is contained in:
Robin
2025-03-24 10:14:48 -04:00
committed by GitHub
7 changed files with 30 additions and 32 deletions

View File

@@ -50,7 +50,7 @@ export type ValidClientState = {
reactions: boolean; reactions: boolean;
thumbnails: boolean; thumbnails: boolean;
}; };
setClient: (params?: SetClientParams) => void; setClient: (client: MatrixClient, session: Session) => void;
}; };
export type AuthenticatedClient = { export type AuthenticatedClient = {
@@ -65,11 +65,6 @@ export type ErrorState = {
error: Error; error: Error;
}; };
export type SetClientParams = {
client: MatrixClient;
session: Session;
};
const ClientContext = createContext<ClientState | undefined>(undefined); const ClientContext = createContext<ClientState | undefined>(undefined);
export const ClientContextProvider = ClientContext.Provider; export const ClientContextProvider = ClientContext.Provider;
@@ -79,7 +74,7 @@ export const useClientState = (): ClientState | undefined =>
export function useClient(): { export function useClient(): {
client?: MatrixClient; client?: MatrixClient;
setClient?: (params?: SetClientParams) => void; setClient?: (client: MatrixClient, session: Session) => void;
} { } {
let client; let client;
let setClient; let setClient;
@@ -96,7 +91,7 @@ export function useClient(): {
// Plain representation of the `ClientContext` as a helper for old components that expected an object with multiple fields. // Plain representation of the `ClientContext` as a helper for old components that expected an object with multiple fields.
export function useClientLegacy(): { export function useClientLegacy(): {
client?: MatrixClient; client?: MatrixClient;
setClient?: (params?: SetClientParams) => void; setClient?: (client: MatrixClient, session: Session) => void;
passwordlessUser: boolean; passwordlessUser: boolean;
loading: boolean; loading: boolean;
authenticated: boolean; authenticated: boolean;
@@ -160,7 +155,11 @@ export const ClientProvider: FC<Props> = ({ children }) => {
initializing.current = true; initializing.current = true;
loadClient() loadClient()
.then(setInitClientState) .then((initResult) => {
setInitClientState(initResult);
if (PosthogAnalytics.instance.isEnabled())
PosthogAnalytics.instance.startListeningToSettingsChanges();
})
.catch((err) => logger.error(err)) .catch((err) => logger.error(err))
.finally(() => (initializing.current = false)); .finally(() => (initializing.current = false));
}, []); }, []);
@@ -196,24 +195,20 @@ export const ClientProvider: FC<Props> = ({ children }) => {
); );
const setClient = useCallback( const setClient = useCallback(
(clientParams?: SetClientParams) => { (client: MatrixClient, session: Session) => {
const oldClient = initClientState?.client; const oldClient = initClientState?.client;
const newClient = clientParams?.client; if (oldClient && oldClient !== client) {
if (oldClient && oldClient !== newClient) {
oldClient.stopClient(); oldClient.stopClient();
} }
if (clientParams) { saveSession(session);
saveSession(clientParams.session); setInitClientState({
setInitClientState({ widgetApi: null,
widgetApi: null, client,
client: clientParams.client, passwordlessUser: session.passwordlessUser,
passwordlessUser: clientParams.session.passwordlessUser, });
}); if (PosthogAnalytics.instance.isEnabled())
} else { PosthogAnalytics.instance.startListeningToSettingsChanges();
clearSession();
setInitClientState(null);
}
}, },
[initClientState?.client], [initClientState?.client],
); );
@@ -229,6 +224,7 @@ export const ClientProvider: FC<Props> = ({ children }) => {
clearSession(); clearSession();
setInitClientState(null); setInitClientState(null);
await navigate("/"); await navigate("/");
PosthogAnalytics.instance.logout();
PosthogAnalytics.instance.setRegistrationType(RegistrationType.Guest); PosthogAnalytics.instance.setRegistrationType(RegistrationType.Guest);
}, [navigate, initClientState?.client]); }, [navigate, initClientState?.client]);

View File

@@ -13,6 +13,7 @@ import posthog, {
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { type MatrixClient } from "matrix-js-sdk/src/matrix"; import { type MatrixClient } from "matrix-js-sdk/src/matrix";
import { Buffer } from "buffer"; import { Buffer } from "buffer";
import { type Subscription } from "rxjs";
import { widget } from "../widget"; import { widget } from "../widget";
import { import {
@@ -96,6 +97,7 @@ export class PosthogAnalytics {
private anonymity = Anonymity.Disabled; private anonymity = Anonymity.Disabled;
private platformSuperProperties = {}; private platformSuperProperties = {};
private registrationType: RegistrationType = RegistrationType.Guest; private registrationType: RegistrationType = RegistrationType.Guest;
private optInListener: Subscription | null = null;
public static hasInstance(): boolean { public static hasInstance(): boolean {
return Boolean(this.internalInstance); return Boolean(this.internalInstance);
@@ -144,7 +146,6 @@ export class PosthogAnalytics {
); );
this.enabled = false; this.enabled = false;
} }
this.startListeningToSettingsChanges(); // Triggers maybeIdentifyUser
} }
private sanitizeProperties = ( private sanitizeProperties = (
@@ -326,6 +327,8 @@ export class PosthogAnalytics {
if (this.enabled) { if (this.enabled) {
this.posthog.reset(); this.posthog.reset();
} }
this.optInListener?.unsubscribe();
this.optInListener = null;
this.setAnonymity(Anonymity.Disabled); this.setAnonymity(Anonymity.Disabled);
} }
@@ -404,7 +407,7 @@ export class PosthogAnalytics {
} }
} }
private startListeningToSettingsChanges(): void { public startListeningToSettingsChanges(): void {
// Listen to account data changes from sync so we can observe changes to relevant flags and update. // Listen to account data changes from sync so we can observe changes to relevant flags and update.
// This is called - // This is called -
// * On page load, when the account data is first received by sync // * On page load, when the account data is first received by sync
@@ -413,7 +416,7 @@ export class PosthogAnalytics {
// * When the user changes their preferences on this device // * When the user changes their preferences on this device
// Note that for new accounts, pseudonymousAnalyticsOptIn won't be set, so updateAnonymityFromSettings // Note that for new accounts, pseudonymousAnalyticsOptIn won't be set, so updateAnonymityFromSettings
// won't be called (i.e. this.anonymity will be left as the default, until the setting changes) // won't be called (i.e. this.anonymity will be left as the default, until the setting changes)
optInAnalytics.value$.subscribe((optIn) => { this.optInListener ??= optInAnalytics.value$.subscribe((optIn) => {
this.setAnonymity(optIn ? Anonymity.Pseudonymous : Anonymity.Disabled); this.setAnonymity(optIn ? Anonymity.Pseudonymous : Anonymity.Disabled);
this.maybeIdentifyUser().catch(() => this.maybeIdentifyUser().catch(() =>
logger.log("Could not identify user"), logger.log("Could not identify user"),

View File

@@ -53,7 +53,7 @@ export const LoginPage: FC = () => {
return; return;
} }
setClient({ client, session }); setClient(client, session);
const locationState = location.state; const locationState = location.state;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment

View File

@@ -95,7 +95,7 @@ export const RegisterPage: FC = () => {
} }
} }
setClient?.({ client: newClient, session }); setClient?.(newClient, session);
PosthogAnalytics.instance.eventSignup.cacheSignupEnd(new Date()); PosthogAnalytics.instance.eventSignup.cacheSignupEnd(new Date());
}; };

View File

@@ -47,7 +47,7 @@ export function useRegisterPasswordlessUser(): UseRegisterPasswordlessUserType {
recaptchaResponse, recaptchaResponse,
true, true,
); );
setClient({ client, session }); setClient(client, session);
} catch (e) { } catch (e) {
reset(); reset();
throw e; throw e;

View File

@@ -89,7 +89,7 @@ export const UnauthenticatedView: FC = () => {
// @ts-ignore // @ts-ignore
if (error.errcode === "M_ROOM_IN_USE") { if (error.errcode === "M_ROOM_IN_USE") {
setOnFinished(() => { setOnFinished(() => {
setClient({ client, session }); setClient(client, session);
const aliasLocalpart = roomAliasLocalpartFromRoomName(roomName); const aliasLocalpart = roomAliasLocalpartFromRoomName(roomName);
navigate(`/${aliasLocalpart}`)?.catch((error) => { navigate(`/${aliasLocalpart}`)?.catch((error) => {
logger.error("Failed to navigate to alias localpart", error); logger.error("Failed to navigate to alias localpart", error);
@@ -111,7 +111,7 @@ export const UnauthenticatedView: FC = () => {
if (!createRoomResult.password) if (!createRoomResult.password)
throw new Error("Failed to create room with shared secret"); throw new Error("Failed to create room with shared secret");
setClient({ client, session }); setClient(client, session);
await navigate( await navigate(
getRelativeRoomUrl( getRelativeRoomUrl(
createRoomResult.roomId, createRoomResult.roomId,

View File

@@ -166,7 +166,6 @@ const widgetPostHangupProcedure = async (
logger.error("Failed to send close action", e); logger.error("Failed to send close action", e);
} }
widget.api.transport.stop(); widget.api.transport.stop();
PosthogAnalytics.instance.logout();
} }
}; };