1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-09 00:18:00 +01:00

feat: productivity report unsubscribed users (#9220)

This commit is contained in:
Mateusz Kwasniewski 2025-02-05 11:28:01 +01:00 committed by GitHub
parent 17a4099dbf
commit a11c965bec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 39 additions and 4 deletions

View File

@ -7,6 +7,10 @@ export class FakeUserSubscriptionsReadModel
return [];
}
async getUnsubscribedUsers(subscription: string) {
return [];
}
async getUserSubscriptions() {
return ['productivity-report'];
}

View File

@ -5,6 +5,7 @@ export type Subscriber = {
export interface IUserSubscriptionsReadModel {
getSubscribedUsers(subscription: string): Promise<Subscriber[]>;
getUnsubscribedUsers(subscription: string): Promise<Subscriber[]>;
getUserSubscriptions(userId: number): Promise<string[]>;
}

View File

@ -31,8 +31,8 @@ afterAll(async () => {
await db.destroy();
});
describe('getSubscribedUsers', () => {
test('returns seen users that did not unsubscribe', async () => {
describe('User subscription read model', () => {
test('returns subscribed and unsubscribed users', async () => {
const user1 = await userStore.insert({
email: 'user1@example.com',
name: 'User One',
@ -43,11 +43,13 @@ describe('getSubscribedUsers', () => {
email: 'user2@example.com',
name: 'User Two',
});
// never seen
const user3 = await userStore.insert({
email: 'user3@example.com',
name: 'User Three',
});
// unsubscribe
await userUnsubscribeStore.insert({
userId: user2.id,
subscription,
@ -62,6 +64,14 @@ describe('getSubscribedUsers', () => {
{ email: 'user1@example.com', name: 'User One' },
]),
);
const unsubscribers =
await userSubscriptionsReadModel.getUnsubscribedUsers(subscription);
expect(unsubscribers).toEqual(
expect.arrayContaining([
{ email: 'user2@example.com', name: 'User Two' },
]),
);
});
test('reflects changes after unsubscribe and resubscribe', async () => {
@ -120,8 +130,8 @@ describe('getSubscribedUsers', () => {
});
});
describe('getUserSubscriptions', () => {
test('returns all subscriptions if user has not unsubscribed', async () => {
describe('User subscription read model', () => {
test('returns all user subscriptions if user has not unsubscribed', async () => {
const user = await userStore.insert({
email: 'user4@example.com',
name: 'User Four',

View File

@ -45,6 +45,21 @@ export class UserSubscriptionsReadModel implements IUserSubscriptionsReadModel {
return users.map(mapRowToSubscriber);
}
async getUnsubscribedUsers(subscription: string) {
const unsubscribedUserIdsQuery = this.db(UNSUBSCRIPTION_TABLE)
.select('user_id')
.where('subscription', subscription);
const users = await this.db(USERS_TABLE)
.select(USER_COLUMNS)
.whereIn('id', unsubscribedUserIdsQuery)
.andWhere('is_service', false)
.andWhere('deleted_at', null)
.andWhereNot('email', null);
return users.map(mapRowToSubscriber);
}
async getUserSubscriptions(userId: number) {
const unsubscriptionsList = await this.db(UNSUBSCRIPTION_TABLE)
.select('subscription')

View File

@ -51,6 +51,7 @@ export type IFlagKey =
| 'releasePlans'
| 'releasePlanChangeRequests'
| 'productivityReportEmail'
| 'productivityReportUnsubscribers'
| 'enterprise-payg'
| 'flagOverviewRedesign'
| 'showUserDeviceCount'
@ -256,6 +257,10 @@ const flags: IFlags = {
process.env.UNLEASH_EXPERIMENTAL_PRODUCTIVITY_REPORT_EMAIL,
false,
),
productivityReportUnsubscribers: parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_PRODUCTIVITY_REPORT_UNSUBSCRIBERS,
false,
),
'enterprise-payg': parseEnvVarBoolean(
process.env.UNLEASH_EXPERIMENTAL_ENTERPRISE_PAYG,
false,