From 99818673a333cdd74b9f9b220c0ea47c8a9dcc0d Mon Sep 17 00:00:00 2001 From: ali ebrahimi Date: Tue, 6 Aug 2024 08:20:49 +0330 Subject: [PATCH 1/4] add migration for adding new notification types for project ownership changed --- ...ificationTypeForProjectOwnershipChanged.ts | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 migrations/1722907373955-seedNotificationTypeForProjectOwnershipChanged.ts diff --git a/migrations/1722907373955-seedNotificationTypeForProjectOwnershipChanged.ts b/migrations/1722907373955-seedNotificationTypeForProjectOwnershipChanged.ts new file mode 100644 index 0000000..c2cdc11 --- /dev/null +++ b/migrations/1722907373955-seedNotificationTypeForProjectOwnershipChanged.ts @@ -0,0 +1,45 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; +import { + NOTIFICATION_CATEGORY, + NOTIFICATION_TYPE_NAMES, +} from '../src/types/general'; +import { MICRO_SERVICES } from '../src/utils/utils'; +import { + NotificationType, + SCHEMA_VALIDATORS_NAMES, +} from '../src/entities/notificationType'; + +const notificationTypes = [ + { + name: NOTIFICATION_TYPE_NAMES.PROJECT_OWNERSHIP_CHANGED_TO, + description: NOTIFICATION_TYPE_NAMES.PROJECT_OWNERSHIP_CHANGED_TO, + microService: MICRO_SERVICES.givethio, + category: NOTIFICATION_CATEGORY.ORTTO, + schemaValidator: SCHEMA_VALIDATORS_NAMES.PROJECT_OWNERSHIP_CHANGED, + title: 'Notify Project Owner Changed To', + }, + { + name: NOTIFICATION_TYPE_NAMES.PROJECT_OWNERSHIP_CHANGED_FROM, + description: NOTIFICATION_TYPE_NAMES.PROJECT_OWNERSHIP_CHANGED_FROM, + microService: MICRO_SERVICES.givethio, + category: NOTIFICATION_CATEGORY.ORTTO, + schemaValidator: SCHEMA_VALIDATORS_NAMES.PROJECT_OWNERSHIP_CHANGED, + title: 'Notify Project Owner Changed From', + }, +]; + +export class SeedNotificationTypeForProjectOwnershipChanged1722907373955 + implements MigrationInterface +{ + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.manager.save(NotificationType, notificationTypes); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `DELETE FROM notification_type WHERE "name" IN + (${NOTIFICATION_TYPE_NAMES.PROJECT_OWNERSHIP_CHANGED_TO}, + ${NOTIFICATION_TYPE_NAMES.PROJECT_OWNERSHIP_CHANGED_FROM});`, + ); + } +} From ed2c3f67a7eb27403922070b2380a989a90121c1 Mon Sep 17 00:00:00 2001 From: ali ebrahimi Date: Tue, 6 Aug 2024 08:21:45 +0330 Subject: [PATCH 2/4] add project ownership changed email flow --- src/entities/notificationType.ts | 1 + src/services/notificationService.ts | 12 ++++++++++++ src/types/general.ts | 2 ++ src/types/notifications.ts | 6 ++++++ src/utils/validators/segmentAndMetadataValidators.ts | 10 ++++++++++ src/validators/schemaValidators.ts | 4 ++++ 6 files changed, 35 insertions(+) diff --git a/src/entities/notificationType.ts b/src/entities/notificationType.ts index a26fad5..55f69f9 100644 --- a/src/entities/notificationType.ts +++ b/src/entities/notificationType.ts @@ -68,6 +68,7 @@ export const SCHEMA_VALIDATORS_NAMES = { YOUR_PROJECT_GOT_A_RANK: 'yourProjectGotARank', NOTIFY_REWARD_AMOUNT: 'notifyRewardAmount', + PROJECT_OWNERSHIP_CHANGED: 'ProjectOwnershipChanged', }; export type HtmlTemplate = { type: string; content: string; href?: string }[]; diff --git a/src/services/notificationService.ts b/src/services/notificationService.ts index 1ed4a0f..0780213 100644 --- a/src/services/notificationService.ts +++ b/src/services/notificationService.ts @@ -198,6 +198,18 @@ export const activityCreator = ( 'str:cm:transactionhash': payload.transactionHash, }; break; + case NOTIFICATIONS_EVENT_NAMES.PROJECT_OWNERSHIP_CHANGED_TO: + attributes = { + 'str:cm:ownername': payload.ownerName, + 'str:cm:projectname': payload.projectName, + }; + break; + case NOTIFICATIONS_EVENT_NAMES.PROJECT_OWNERSHIP_CHANGED_FROM: + attributes = { + 'str:cm:ownername': payload.ownerName, + 'str:cm:projectname': payload.projectName, + }; + break; default: logger.debug('activityCreator() invalid event name', orttoEventName); return; diff --git a/src/types/general.ts b/src/types/general.ts index c0e3059..3d6781c 100644 --- a/src/types/general.ts +++ b/src/types/general.ts @@ -55,4 +55,6 @@ export enum NOTIFICATION_TYPE_NAMES { CREATE_ORTTO_PROFILE = 'Create Ortto profile', NOTIFY_REWARD_AMOUNT = 'Notify reward amount', + PROJECT_OWNERSHIP_CHANGED_TO = 'Project ownership changed to', + PROJECT_OWNERSHIP_CHANGED_FROM = 'Project ownership changed from', } diff --git a/src/types/notifications.ts b/src/types/notifications.ts index 68d1d35..e44c964 100644 --- a/src/types/notifications.ts +++ b/src/types/notifications.ts @@ -52,6 +52,8 @@ export enum NOTIFICATIONS_EVENT_NAMES { SEND_EMAIL_CONFIRMATION = 'Send email confirmation', SUBSCRIBE_ONBOARDING = 'Subscribe onboarding', NOTIFY_REWARD_AMOUNT = 'Notify reward amount', + PROJECT_OWNERSHIP_CHANGED_TO = 'Project ownership changed to', + PROJECT_OWNERSHIP_CHANGED_FROM = 'Project ownership changed from', } export const ORTTO_EVENT_NAMES = { @@ -81,4 +83,8 @@ export const ORTTO_EVENT_NAMES = { 'verification-form-email-verification', [NOTIFICATIONS_EVENT_NAMES.NOTIFY_REWARD_AMOUNT]: 'notify-reward', [NOTIFICATIONS_EVENT_NAMES.SUBSCRIBE_ONBOARDING]: 'onboarding-form', + [NOTIFICATIONS_EVENT_NAMES.PROJECT_OWNERSHIP_CHANGED_TO]: + 'ownership-changed-to', + [NOTIFICATIONS_EVENT_NAMES.PROJECT_OWNERSHIP_CHANGED_FROM]: + 'ownership-changed-from', }; diff --git a/src/utils/validators/segmentAndMetadataValidators.ts b/src/utils/validators/segmentAndMetadataValidators.ts index 915d5bf..988a66e 100644 --- a/src/utils/validators/segmentAndMetadataValidators.ts +++ b/src/utils/validators/segmentAndMetadataValidators.ts @@ -175,6 +175,12 @@ const notifyRewardAmountSegmentSchema = Joi.object({ email: Joi.string().required(), }); +const projectOwnershipChangedSegmentSchema = Joi.object({ + email: Joi.string().required(), + ownerName: Joi.string().required(), + projectName: Joi.string().required(), +}); + export const SEGMENT_METADATA_SCHEMA_VALIDATOR: { [key: string]: { segment: ObjectSchema | null; @@ -352,4 +358,8 @@ export const SEGMENT_METADATA_SCHEMA_VALIDATOR: { metadata: null, segment: notifyRewardAmountSegmentSchema, }, + ProjectOwnershipChanged: { + metadata: null, + segment: projectOwnershipChangedSegmentSchema, + }, }; diff --git a/src/validators/schemaValidators.ts b/src/validators/schemaValidators.ts index ccd99ff..484b818 100644 --- a/src/validators/schemaValidators.ts +++ b/src/validators/schemaValidators.ts @@ -101,6 +101,10 @@ export const sendNotificationValidator = Joi.object({ network: Joi.string(), script: Joi.string(), transactionHash: Joi.string(), + + // Project ownership change attributes + ownerName: Joi.string(), + projectName: Joi.string(), }), }), }); From 57d5d925e33503e65ba954415d855bbd110017c8 Mon Sep 17 00:00:00 2001 From: ali ebrahimi Date: Tue, 6 Aug 2024 08:22:45 +0330 Subject: [PATCH 3/4] add unit tests for project ownership changed email notification --- src/routes/v1/notificationRouter.test.ts | 120 +++++++++++++++++++++++ src/services/notificationService.test.ts | 58 +++++++++++ 2 files changed, 178 insertions(+) diff --git a/src/routes/v1/notificationRouter.test.ts b/src/routes/v1/notificationRouter.test.ts index 6f6fa7a..0bb403d 100644 --- a/src/routes/v1/notificationRouter.test.ts +++ b/src/routes/v1/notificationRouter.test.ts @@ -2167,6 +2167,126 @@ function sendNotificationTestCases() { ); } }); + + it('should create *Project Ownership Changed To* notification, success', async () => { + const data = { + eventName: 'Project ownership changed to', + sendEmail: true, + sendSegment: true, + creationTime: 1667992708000, + segment: { + payload: { + email: 'aliebrahimi2079@gmail.com', + ownerName: 'Ali', + projectName: 'Test Project', + }, + }, + }; + + const result = await axios.post(sendNotificationUrl, data, { + headers: { + authorization: getGivethIoBasicAuth(), + }, + }); + + assert.equal(result.status, 200); + assert.isOk(result.data); + assert.isTrue(result.data.success); + }); + it('should create *Project Ownership Changed To* notification, failed invalid payload', async () => { + try { + const data = { + eventName: 'Project ownership changed to', + sendEmail: true, + sendSegment: true, + creationTime: 1667992708000, + segment: { + payload: { + email: 'aliebrahimi2079@gmail.com', + ownerName: 'Ali', + projectName: 'Test Project', + invalidField: 'invalid data', + }, + }, + }; + await axios.post(sendNotificationUrl, data, { + headers: { + authorization: getGivethIoBasicAuth(), + }, + }); + // If request doesn't fail, it means this test failed + assert.isTrue(false); + } catch (e: any) { + assert.equal( + e.response.data.message, + errorMessagesEnum.IMPACT_GRAPH_VALIDATION_ERROR.message, + ); + assert.equal( + e.response.data.description, + '"segment.payload.invalidField" is not allowed', + ); + } + }); + + it('should create *Project Ownership Changed From* notification, success', async () => { + const data = { + eventName: 'Project ownership changed from', + sendEmail: true, + sendSegment: true, + creationTime: 1667992708000, + segment: { + payload: { + email: 'aliebrahimi2079@gmail.com', + ownerName: 'Ali', + projectName: 'Test Project', + }, + }, + }; + + const result = await axios.post(sendNotificationUrl, data, { + headers: { + authorization: getGivethIoBasicAuth(), + }, + }); + + assert.equal(result.status, 200); + assert.isOk(result.data); + assert.isTrue(result.data.success); + }); + it('should create *Project Ownership Changed From* notification, failed invalid payload', async () => { + try { + const data = { + eventName: 'Project ownership changed from', + sendEmail: true, + sendSegment: true, + creationTime: 1667992708000, + segment: { + payload: { + email: 'aliebrahimi2079@gmail.com', + ownerName: 'Ali', + projectName: 'Test Project', + invalidField: 'invalid data', + }, + }, + }; + await axios.post(sendNotificationUrl, data, { + headers: { + authorization: getGivethIoBasicAuth(), + }, + }); + // If request doesn't fail, it means this test failed + assert.isTrue(false); + } catch (e: any) { + assert.equal( + e.response.data.message, + errorMessagesEnum.IMPACT_GRAPH_VALIDATION_ERROR.message, + ); + assert.equal( + e.response.data.description, + '"segment.payload.invalidField" is not allowed', + ); + } + }); } function sendBulkNotificationsTestCases() { diff --git a/src/services/notificationService.test.ts b/src/services/notificationService.test.ts index 01c0f75..ec23aad 100644 --- a/src/services/notificationService.test.ts +++ b/src/services/notificationService.test.ts @@ -50,4 +50,62 @@ describe('activityCreator', () => { }), ); }); + + it('should create attributes for PROJECT_OWNER_CHANGED_TO', () => { + const payload = { + email: 'test@example.com', + ownerName: 'Test Owner', + projectName: 'Test Project', + }; + const result = activityCreator( + payload, + NOTIFICATIONS_EVENT_NAMES.PROJECT_OWNERSHIP_CHANGED_TO, + ); + expect(JSON.stringify(result)).equal( + JSON.stringify({ + activities: [ + { + activity_id: 'act:cm:ownership-changed-to', + attributes: { + 'str:cm:ownername': payload.ownerName, + 'str:cm:projectname': payload.projectName, + }, + fields: { + 'str::email': payload.email, + }, + }, + ], + merge_by: ['str::email'], + }), + ); + }); + + it('should create attributes for PROJECT_OWNER_CHANGED_FROM', () => { + const payload = { + email: 'test@example.com', + ownerName: 'Test Owner', + projectName: 'Test Project', + }; + const result = activityCreator( + payload, + NOTIFICATIONS_EVENT_NAMES.PROJECT_OWNERSHIP_CHANGED_FROM, + ); + expect(JSON.stringify(result)).equal( + JSON.stringify({ + activities: [ + { + activity_id: 'act:cm:ownership-changed-from', + attributes: { + 'str:cm:ownername': payload.ownerName, + 'str:cm:projectname': payload.projectName, + }, + fields: { + 'str::email': payload.email, + }, + }, + ], + merge_by: ['str::email'], + }), + ); + }); }); From 7b59ec690342a7f4b418545d16afa265f5125955 Mon Sep 17 00:00:00 2001 From: ali ebrahimi Date: Tue, 6 Aug 2024 08:37:15 +0330 Subject: [PATCH 4/4] add userId to project owner changed notification --- src/routes/v1/notificationRouter.test.ts | 4 ++++ src/utils/validators/segmentAndMetadataValidators.ts | 1 + 2 files changed, 5 insertions(+) diff --git a/src/routes/v1/notificationRouter.test.ts b/src/routes/v1/notificationRouter.test.ts index 0bb403d..5aab98f 100644 --- a/src/routes/v1/notificationRouter.test.ts +++ b/src/routes/v1/notificationRouter.test.ts @@ -2177,6 +2177,7 @@ function sendNotificationTestCases() { segment: { payload: { email: 'aliebrahimi2079@gmail.com', + userId: 1234, ownerName: 'Ali', projectName: 'Test Project', }, @@ -2203,6 +2204,7 @@ function sendNotificationTestCases() { segment: { payload: { email: 'aliebrahimi2079@gmail.com', + userId: 1234, ownerName: 'Ali', projectName: 'Test Project', invalidField: 'invalid data', @@ -2237,6 +2239,7 @@ function sendNotificationTestCases() { segment: { payload: { email: 'aliebrahimi2079@gmail.com', + userId: 1234, ownerName: 'Ali', projectName: 'Test Project', }, @@ -2264,6 +2267,7 @@ function sendNotificationTestCases() { payload: { email: 'aliebrahimi2079@gmail.com', ownerName: 'Ali', + userId: 1234, projectName: 'Test Project', invalidField: 'invalid data', }, diff --git a/src/utils/validators/segmentAndMetadataValidators.ts b/src/utils/validators/segmentAndMetadataValidators.ts index 988a66e..eeb7b44 100644 --- a/src/utils/validators/segmentAndMetadataValidators.ts +++ b/src/utils/validators/segmentAndMetadataValidators.ts @@ -177,6 +177,7 @@ const notifyRewardAmountSegmentSchema = Joi.object({ const projectOwnershipChangedSegmentSchema = Joi.object({ email: Joi.string().required(), + userId: Joi.number().required(), ownerName: Joi.string().required(), projectName: Joi.string().required(), });