diff --git a/src/lib/features/user-subscriptions/user-subscriptions-service.e2e.test.ts b/src/lib/features/user-subscriptions/user-subscriptions-service.e2e.test.ts index 39e5744a2ccd..76db78344447 100644 --- a/src/lib/features/user-subscriptions/user-subscriptions-service.e2e.test.ts +++ b/src/lib/features/user-subscriptions/user-subscriptions-service.e2e.test.ts @@ -1,7 +1,8 @@ import { + type IEventStore, type IUnleashConfig, type IUnleashStores, - type IUser, + type IUserStore, TEST_AUDIT_USER, } from '../../types'; import type { UserSubscriptionsService } from './user-subscriptions-service'; @@ -13,25 +14,27 @@ import type { IUserSubscriptionsReadModel } from './user-subscriptions-read-mode let stores: IUnleashStores; let db: ITestDb; +let userStore: IUserStore; let userSubscriptionService: UserSubscriptionsService; let userSubscriptionsReadModel: IUserSubscriptionsReadModel; +let eventsStore: IEventStore; let config: IUnleashConfig; -let user: IUser; beforeAll(async () => { db = await dbInit('user_subscriptions', getLogger); stores = db.stores; config = createTestConfig({}); + userStore = stores.userStore; userSubscriptionService = createUserSubscriptionsService(config)( db.rawDatabase, ); userSubscriptionsReadModel = db.stores.userSubscriptionsReadModel; + eventsStore = db.stores.eventStore; +}); - user = await stores.userStore.insert({ - email: 'test@getunleash.io', - name: 'Sample Name', - }); +beforeEach(async () => { + await userStore.deleteAll(); }); afterAll(async () => { @@ -39,6 +42,11 @@ afterAll(async () => { }); test('Subscribe and unsubscribe', async () => { + const user = await userStore.insert({ + email: 'test@getunleash.io', + name: 'Sample Name', + }); + const subscribers = await userSubscriptionsReadModel.getSubscribedUsers( 'productivity-report', ); @@ -47,7 +55,7 @@ test('Subscribe and unsubscribe', async () => { ]); const userSubscriptions = - await userSubscriptionsReadModel.getUserSubscriptions(user.id); + await userSubscriptionService.getUserSubscriptions(user.id); expect(userSubscriptions).toMatchObject(['productivity-report']); await userSubscriptionService.unsubscribe( @@ -62,6 +70,49 @@ test('Subscribe and unsubscribe', async () => { expect(noSubscribers).toMatchObject([]); const noUserSubscriptions = - await userSubscriptionsReadModel.getUserSubscriptions(user.id); + await userSubscriptionService.getUserSubscriptions(user.id); expect(noUserSubscriptions).toMatchObject([]); }); + +test('Event log for subscription actions', async () => { + const user = await userStore.insert({ + email: 'test@getunleash.io', + name: 'Sample Name', + }); + + await userSubscriptionService.unsubscribe( + user.id, + 'productivity-report', + TEST_AUDIT_USER, + ); + + const unsubscribeEvent = (await eventsStore.getAll())[0]; + + expect(unsubscribeEvent).toEqual( + expect.objectContaining({ + type: 'user-preference-updated', + data: { + subscription: 'productivity-report', + action: 'unsubscribed', + }, + }), + ); + + await userSubscriptionService.subscribe( + user.id, + 'productivity-report', + TEST_AUDIT_USER, + ); + + const subscribeEvent = (await eventsStore.getAll())[0]; + + expect(subscribeEvent).toEqual( + expect.objectContaining({ + type: 'user-preference-updated', + data: { + subscription: 'productivity-report', + action: 'subscribed', + }, + }), + ); +}); diff --git a/src/lib/features/user-subscriptions/user-subscriptions-service.ts b/src/lib/features/user-subscriptions/user-subscriptions-service.ts index 9dbb8d9a535a..4ba7eb760cb4 100644 --- a/src/lib/features/user-subscriptions/user-subscriptions-service.ts +++ b/src/lib/features/user-subscriptions/user-subscriptions-service.ts @@ -1,4 +1,8 @@ -import type { IUnleashConfig, IUnleashStores } from '../../types'; +import { + UserPreferenceUpdatedEvent, + type IUnleashConfig, + type IUnleashStores, +} from '../../types'; import type { Logger } from '../../logger'; import type { IAuditUser } from '../../types/user'; import type { @@ -49,13 +53,13 @@ export class UserSubscriptionsService { }; await this.userUnsubscribeStore.delete(entry); - // TODO: log an event - // await this.eventService.storeEvent( - // new UserSubscriptionEvent({ - // data: { ...entry, action: 'subscribed' }, - // auditUser, - // }), - // ); + await this.eventService.storeEvent( + new UserPreferenceUpdatedEvent({ + userId, + data: { subscription, action: 'subscribed' }, + auditUser, + }), + ); } async unsubscribe( @@ -69,12 +73,12 @@ export class UserSubscriptionsService { }; await this.userUnsubscribeStore.insert(entry); - // TODO: log an event - // await this.eventService.storeEvent( - // new UserSubscriptionEvent({ - // data: { ...entry, action: 'unsubscribed' }, - // auditUser, - // }), - // ); + await this.eventService.storeEvent( + new UserPreferenceUpdatedEvent({ + userId, + data: { subscription, action: 'unsubscribed' }, + auditUser, + }), + ); } } diff --git a/src/lib/types/events.ts b/src/lib/types/events.ts index d71c28df5f91..865b97cf4f27 100644 --- a/src/lib/types/events.ts +++ b/src/lib/types/events.ts @@ -204,6 +204,8 @@ export const ACTIONS_CREATED = 'actions-created' as const; export const ACTIONS_UPDATED = 'actions-updated' as const; export const ACTIONS_DELETED = 'actions-deleted' as const; +export const USER_PREFERENCE_UPDATED = 'user-preference-updated' as const; + export const IEventTypes = [ APPLICATION_CREATED, FEATURE_CREATED, @@ -351,6 +353,7 @@ export const IEventTypes = [ ACTIONS_CREATED, ACTIONS_UPDATED, ACTIONS_DELETED, + USER_PREFERENCE_UPDATED, ] as const; export type IEventType = (typeof IEventTypes)[number]; @@ -2024,3 +2027,18 @@ function mapUserToData(user: IUserEventData): any { rootRole: user.rootRole, }; } + +export class UserPreferenceUpdatedEvent extends BaseEvent { + readonly userId; + readonly data: any; + + constructor(eventData: { + userId: number; + data: any; + auditUser: IAuditUser; + }) { + super(USER_PREFERENCE_UPDATED, eventData.auditUser); + this.userId = eventData.userId; + this.data = eventData.data; + } +} diff --git a/src/mailtemplates/productivity-report/productivity-report.plain.mustache b/src/mailtemplates/productivity-report/productivity-report.plain.mustache index 4c23236ce4b3..00c584100ee4 100644 --- a/src/mailtemplates/productivity-report/productivity-report.plain.mustache +++ b/src/mailtemplates/productivity-report/productivity-report.plain.mustache @@ -14,4 +14,4 @@ Production updates last month: {{productionUpdates}} Go to your Insights to learn more: {{unleashUrl}}/insights This email was sent to {{userEmail}}. You’ve received this as you are a user of Unleash. -If you wish to unsubscribe, go to you profile settings here. +If you wish to unsubscribe, go to you profile settings on {{unleashUrl}}/profile