Skip to content

Commit a11c965

Browse files
authored
feat: productivity report unsubscribed users (#9220)
1 parent 17a4099 commit a11c965

5 files changed

+39
-4
lines changed

src/lib/features/user-subscriptions/fake-user-subscriptions-read-model.ts

+4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ export class FakeUserSubscriptionsReadModel
77
return [];
88
}
99

10+
async getUnsubscribedUsers(subscription: string) {
11+
return [];
12+
}
13+
1014
async getUserSubscriptions() {
1115
return ['productivity-report'];
1216
}

src/lib/features/user-subscriptions/user-subscriptions-read-model-type.ts

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export type Subscriber = {
55

66
export interface IUserSubscriptionsReadModel {
77
getSubscribedUsers(subscription: string): Promise<Subscriber[]>;
8+
getUnsubscribedUsers(subscription: string): Promise<Subscriber[]>;
89
getUserSubscriptions(userId: number): Promise<string[]>;
910
}
1011

src/lib/features/user-subscriptions/user-subscriptions-read-model.test.ts

+14-4
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ afterAll(async () => {
3131
await db.destroy();
3232
});
3333

34-
describe('getSubscribedUsers', () => {
35-
test('returns seen users that did not unsubscribe', async () => {
34+
describe('User subscription read model', () => {
35+
test('returns subscribed and unsubscribed users', async () => {
3636
const user1 = await userStore.insert({
3737
3838
name: 'User One',
@@ -43,11 +43,13 @@ describe('getSubscribedUsers', () => {
4343
4444
name: 'User Two',
4545
});
46+
// never seen
4647
const user3 = await userStore.insert({
4748
4849
name: 'User Three',
4950
});
5051

52+
// unsubscribe
5153
await userUnsubscribeStore.insert({
5254
userId: user2.id,
5355
subscription,
@@ -62,6 +64,14 @@ describe('getSubscribedUsers', () => {
6264
{ email: '[email protected]', name: 'User One' },
6365
]),
6466
);
67+
68+
const unsubscribers =
69+
await userSubscriptionsReadModel.getUnsubscribedUsers(subscription);
70+
expect(unsubscribers).toEqual(
71+
expect.arrayContaining([
72+
{ email: '[email protected]', name: 'User Two' },
73+
]),
74+
);
6575
});
6676

6777
test('reflects changes after unsubscribe and resubscribe', async () => {
@@ -120,8 +130,8 @@ describe('getSubscribedUsers', () => {
120130
});
121131
});
122132

123-
describe('getUserSubscriptions', () => {
124-
test('returns all subscriptions if user has not unsubscribed', async () => {
133+
describe('User subscription read model', () => {
134+
test('returns all user subscriptions if user has not unsubscribed', async () => {
125135
const user = await userStore.insert({
126136
127137
name: 'User Four',

src/lib/features/user-subscriptions/user-subscriptions-read-model.ts

+15
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,21 @@ export class UserSubscriptionsReadModel implements IUserSubscriptionsReadModel {
4545
return users.map(mapRowToSubscriber);
4646
}
4747

48+
async getUnsubscribedUsers(subscription: string) {
49+
const unsubscribedUserIdsQuery = this.db(UNSUBSCRIPTION_TABLE)
50+
.select('user_id')
51+
.where('subscription', subscription);
52+
53+
const users = await this.db(USERS_TABLE)
54+
.select(USER_COLUMNS)
55+
.whereIn('id', unsubscribedUserIdsQuery)
56+
.andWhere('is_service', false)
57+
.andWhere('deleted_at', null)
58+
.andWhereNot('email', null);
59+
60+
return users.map(mapRowToSubscriber);
61+
}
62+
4863
async getUserSubscriptions(userId: number) {
4964
const unsubscriptionsList = await this.db(UNSUBSCRIPTION_TABLE)
5065
.select('subscription')

src/lib/types/experimental.ts

+5
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export type IFlagKey =
5151
| 'releasePlans'
5252
| 'releasePlanChangeRequests'
5353
| 'productivityReportEmail'
54+
| 'productivityReportUnsubscribers'
5455
| 'enterprise-payg'
5556
| 'flagOverviewRedesign'
5657
| 'showUserDeviceCount'
@@ -256,6 +257,10 @@ const flags: IFlags = {
256257
process.env.UNLEASH_EXPERIMENTAL_PRODUCTIVITY_REPORT_EMAIL,
257258
false,
258259
),
260+
productivityReportUnsubscribers: parseEnvVarBoolean(
261+
process.env.UNLEASH_EXPERIMENTAL_PRODUCTIVITY_REPORT_UNSUBSCRIBERS,
262+
false,
263+
),
259264
'enterprise-payg': parseEnvVarBoolean(
260265
process.env.UNLEASH_EXPERIMENTAL_ENTERPRISE_PAYG,
261266
false,

0 commit comments

Comments
 (0)