mirror of https://github.com/vector-im/riot-web
Enforce anon/pseudo-anon via types
parent
3135e42586
commit
74b0e52f9a
|
@ -1,11 +1,28 @@
|
||||||
import posthog from 'posthog-js';
|
import posthog from 'posthog-js';
|
||||||
import SdkConfig from './SdkConfig';
|
import SdkConfig from './SdkConfig';
|
||||||
|
|
||||||
export interface IEvent {
|
interface IEvent {
|
||||||
key: string;
|
// The event name that will be used by PostHog.
|
||||||
|
// TODO: standard format (camel case? snake? UpperCase?)
|
||||||
|
eventName: string;
|
||||||
|
|
||||||
|
// The properties of the event that will be stored in PostHog.
|
||||||
properties: {}
|
properties: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If an event extends IPseudonymousEvent, the event contains pseudonymous data
|
||||||
|
// that won't be sent unless the user has explicitly consented to pseudonymous tracking.
|
||||||
|
// For example, hashed user IDs or room IDs.
|
||||||
|
export interface IPseudonymousEvent extends IEvent {}
|
||||||
|
|
||||||
|
// If an event extends IAnonymousEvent, the event strictly contains *only* anonymous data which
|
||||||
|
// may be sent without explicit user consent.
|
||||||
|
export interface IAnonymousEvent extends IEvent {}
|
||||||
|
|
||||||
|
export interface IRoomEvent extends IPseudonymousEvent {
|
||||||
|
hashedRoomId: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface IOnboardingLoginBegin extends IEvent {
|
export interface IOnboardingLoginBegin extends IEvent {
|
||||||
key: "onboarding_login_begin",
|
key: "onboarding_login_begin",
|
||||||
}
|
}
|
||||||
|
@ -55,27 +72,32 @@ export class PosthogAnalytics {
|
||||||
this.onlyTrackAnonymousEvents = enabled;
|
this.onlyTrackAnonymousEvents = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public track<E extends IEvent>(
|
public trackPseudonymousEvent<E extends IPseudonymousEvent>(
|
||||||
key: E["key"],
|
eventName: E["eventName"],
|
||||||
properties: E["properties"],
|
properties: E["properties"],
|
||||||
anonymous = false,
|
|
||||||
) {
|
) {
|
||||||
if (!this.initialised) return;
|
if (!this.initialised) return;
|
||||||
if (this.onlyTrackAnonymousEvents && !anonymous) return;
|
if (this.onlyTrackAnonymousEvents) return;
|
||||||
|
this.posthog.capture(eventName, properties);
|
||||||
this.posthog.capture(key, properties);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async trackRoomEvent<E extends IEvent>(
|
public trackAnonymousEvent<E extends IAnonymousEvent>(
|
||||||
key: E["key"],
|
eventName: E["eventName"],
|
||||||
roomId: string,
|
|
||||||
properties: E["properties"],
|
properties: E["properties"],
|
||||||
...args
|
) {
|
||||||
|
if (!this.initialised) return;
|
||||||
|
this.posthog.capture(eventName, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async trackRoomEvent<E extends IRoomEvent>(
|
||||||
|
eventName: E["eventName"],
|
||||||
|
roomId: string,
|
||||||
|
properties: Omit<E["properties"], "roomId">,
|
||||||
) {
|
) {
|
||||||
const updatedProperties = {
|
const updatedProperties = {
|
||||||
...properties,
|
...properties,
|
||||||
hashedRoomId: roomId ? await hashHex(roomId) : null,
|
hashedRoomId: roomId ? await hashHex(roomId) : null,
|
||||||
};
|
};
|
||||||
this.track(key, updatedProperties, ...args);
|
this.trackPseudonymousEvent(eventName, updatedProperties);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { IEvent, PosthogAnalytics } from '../src/PosthogAnalytics';
|
import { IAnonymousEvent, IRoomEvent, PosthogAnalytics } from '../src/PosthogAnalytics';
|
||||||
import SdkConfig from '../src/SdkConfig';
|
import SdkConfig from '../src/SdkConfig';
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
@ -12,13 +12,20 @@ class FakePosthog {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITestEvent extends IEvent {
|
export interface ITestEvent extends IAnonymousEvent {
|
||||||
key: "jest_test_event",
|
key: "jest_test_event",
|
||||||
properties: {
|
properties: {
|
||||||
foo: string
|
foo: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ITestRoomEvent extends IRoomEvent {
|
||||||
|
key: "jest_test_room_event",
|
||||||
|
properties: {
|
||||||
|
foo: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
describe("PosthogAnalytics", () => {
|
describe("PosthogAnalytics", () => {
|
||||||
let analytics: PosthogAnalytics;
|
let analytics: PosthogAnalytics;
|
||||||
let fakePosthog: FakePosthog;
|
let fakePosthog: FakePosthog;
|
||||||
|
@ -61,7 +68,7 @@ describe("PosthogAnalytics", () => {
|
||||||
|
|
||||||
it("Should pass track() to posthog", () => {
|
it("Should pass track() to posthog", () => {
|
||||||
analytics.init(false);
|
analytics.init(false);
|
||||||
analytics.track<ITestEvent>("jest_test_event", {
|
analytics.trackAnonymousEvent<ITestEvent>("jest_test_event", {
|
||||||
foo: "bar",
|
foo: "bar",
|
||||||
});
|
});
|
||||||
expect(fakePosthog.capture.mock.calls[0][0]).toBe("jest_test_event");
|
expect(fakePosthog.capture.mock.calls[0][0]).toBe("jest_test_event");
|
||||||
|
@ -71,7 +78,7 @@ describe("PosthogAnalytics", () => {
|
||||||
it("Should pass trackRoomEvent to posthog", () => {
|
it("Should pass trackRoomEvent to posthog", () => {
|
||||||
analytics.init(false);
|
analytics.init(false);
|
||||||
const roomId = "42";
|
const roomId = "42";
|
||||||
return analytics.trackRoomEvent<ITestEvent>("jest_test_event", roomId, {
|
return analytics.trackRoomEvent<IRoomEvent>("jest_test_event", roomId, {
|
||||||
foo: "bar",
|
foo: "bar",
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
expect(fakePosthog.capture.mock.calls[0][0]).toBe("jest_test_event");
|
expect(fakePosthog.capture.mock.calls[0][0]).toBe("jest_test_event");
|
||||||
|
@ -82,11 +89,17 @@ describe("PosthogAnalytics", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should silently not send messages if not inititalised", () => {
|
it("Should silently not track if not inititalised", () => {
|
||||||
analytics.track<ITestEvent>("jest_test_event", {
|
analytics.trackAnonymousEvent<ITestEvent>("jest_test_event", {
|
||||||
foo: "bar",
|
foo: "bar",
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(fakePosthog.capture.mock.calls.length).toBe(0);
|
expect(fakePosthog.capture.mock.calls.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Should not track non-anonymous messages if onlyTrackAnonymousEvents is true", () => {
|
||||||
|
analytics.trackAnonymousEvent<ITestEvent>("jest_test_event", {
|
||||||
|
foo: "bar",
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue