diff --git a/migrations/1719224595366-seedNotificationTypeForSendEmailConfirmation.ts b/migrations/1719224595366-seedNotificationTypeForSendEmailConfirmation.ts new file mode 100644 index 0000000..6d956f2 --- /dev/null +++ b/migrations/1719224595366-seedNotificationTypeForSendEmailConfirmation.ts @@ -0,0 +1,27 @@ +import { MigrationInterface, QueryRunner } from "typeorm" +import { NOTIFICATION_CATEGORY } from '../src/types/general'; +import { MICRO_SERVICES } from '../src/utils/utils'; +import { NotificationType, SCHEMA_VALIDATORS_NAMES } from '../src/entities/notificationType'; +import { NOTIFICATIONS_EVENT_NAMES } from '../src/types/notifications'; + +const EmailConfirmationNotificationType = [ + { + name: NOTIFICATIONS_EVENT_NAMES.SEND_EMAIL_CONFIRMATION, + description: NOTIFICATIONS_EVENT_NAMES.SEND_EMAIL_CONFIRMATION, + microService: MICRO_SERVICES.givethio, + category: NOTIFICATION_CATEGORY.ORTTO, + schemaValidator: SCHEMA_VALIDATORS_NAMES.SEND_EMAIL_CONFIRMATION, + } +] + +export class seedNotificationTypeForSendEmailConfirmation1719224595366 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.manager.save(NotificationType, EmailConfirmationNotificationType); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `DELETE FROM notification_type WHERE "name" = 'Send email confirmation';`, + ); + } +} diff --git a/migrations/1719410008992-seedNotificationTypeForOnboardingGuide.ts b/migrations/1719410008992-seedNotificationTypeForOnboardingGuide.ts new file mode 100644 index 0000000..4e07f60 --- /dev/null +++ b/migrations/1719410008992-seedNotificationTypeForOnboardingGuide.ts @@ -0,0 +1,26 @@ +import { MigrationInterface, QueryRunner } from "typeorm" +import { NotificationType, SCHEMA_VALIDATORS_NAMES } from '../src/entities/notificationType'; +import { NOTIFICATION_CATEGORY, NOTIFICATION_TYPE_NAMES } from '../src/types/general'; +import { MICRO_SERVICES } from '../src/utils/utils'; + +const OnboardingNotificationType = [ + { + name: NOTIFICATION_TYPE_NAMES.SUBSCRIBE_ONBOARDING, + description: NOTIFICATION_TYPE_NAMES.SUBSCRIBE_ONBOARDING, + microService: MICRO_SERVICES.givethio, + category: NOTIFICATION_CATEGORY.ORTTO, + schemaValidator: SCHEMA_VALIDATORS_NAMES.SUBSCRIBE_ONBOARDING, + } +] + +export class seedNotificationTypeForOnboardingGuide1719410008992 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.manager.save(NotificationType, OnboardingNotificationType); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `DELETE FROM notification_type WHERE "name" = 'Subscribe onboarding';`, + ); + } +} diff --git a/src/entities/notificationType.ts b/src/entities/notificationType.ts index 608a102..fa12850 100644 --- a/src/entities/notificationType.ts +++ b/src/entities/notificationType.ts @@ -4,19 +4,17 @@ import { CreateDateColumn, Entity, Index, - JoinTable, - ManyToOne, OneToMany, PrimaryGeneratedColumn, - RelationId, UpdateDateColumn, } from 'typeorm'; -import { NOTIFICATION_CATEGORY } from '../types/general'; import { NotificationSetting } from './notificationSetting'; // Export Object with Schemas to N1 lookup export const SCHEMA_VALIDATORS_NAMES = { + SEND_EMAIL_CONFIRMATION: 'sendEmailConfirmation', CREATE_ORTTO_PROFILE: 'createOrttoProfile', + SUBSCRIBE_ONBOARDING: 'subscribeOnboarding', SUPERFLUID: 'userSuperTokensCritical', ADMIN_MESSAGE: 'adminMessage', RAW_HTML_BROADCAST: 'rawHtmlBroadcast', diff --git a/src/services/notificationService.ts b/src/services/notificationService.ts index 28a0472..8e64221 100644 --- a/src/services/notificationService.ts +++ b/src/services/notificationService.ts @@ -14,14 +14,14 @@ import { getEmailAdapter } from '../adapters/adapterFactory'; import { NOTIFICATION_CATEGORY } from '../types/general'; const activityCreator = (payload: any, orttoEventName: NOTIFICATIONS_EVENT_NAMES) : any=> { - const fields = { - "str::email": payload.email, - } - if (process.env.ENVIRONMENT === 'production') { - fields['str:cm:user-id'] = payload.userId?.toString() - } let attributes; switch (orttoEventName) { + case NOTIFICATIONS_EVENT_NAMES.SEND_EMAIL_CONFIRMATION: + attributes = { + "str:cm:email": payload.email, + "str:cm:verificationlink": payload.verificationLink, + } + break; case NOTIFICATIONS_EVENT_NAMES.CREATE_ORTTO_PROFILE: attributes = { "str:cm:email": payload.email, @@ -126,6 +126,7 @@ const activityCreator = (payload: any, orttoEventName: NOTIFICATIONS_EVENT_NAMES "str:cm:email": payload.email, "str:cm:projectlink": payload.projectLink, "str:cm:verified-status": 'rejected', + "txt:cm:reason": payload.verificationRejectedReason, "str:cm:userid": payload.userId?.toString(), }; break @@ -184,8 +185,12 @@ const activityCreator = (payload: any, orttoEventName: NOTIFICATIONS_EVENT_NAMES logger.debug('activityCreator() invalid ORTTO_EVENT_NAMES', orttoEventName) return; } + const fields = { + "str::email": payload.email, + } const merge_by = []; - if (process.env.ENVIRONMENT === 'production') { + if (process.env.ENVIRONMENT === 'production' && orttoEventName !== NOTIFICATIONS_EVENT_NAMES.SEND_EMAIL_CONFIRMATION) { + fields['str:cm:user-id'] = payload.userId?.toString() merge_by.push("str:cm:user-id") } else { merge_by.push("str::email") @@ -217,9 +222,7 @@ export const sendNotification = async ( message: errorMessages.DUPLICATED_TRACK_ID, }; } - const userAddress = await createNewUserAddressIfNotExists( - userWalletAddress as string, - ); + const notificationType = await getNotificationTypeByEventNameAndMicroservice({ eventName: body.eventName, microService, @@ -234,10 +237,14 @@ export const sendNotification = async ( const isOrttoSpecific = notificationType.category === NOTIFICATION_CATEGORY.ORTTO + const userAddress = isOrttoSpecific ? undefined : await createNewUserAddressIfNotExists( + userWalletAddress as string, + ); + const notificationSetting = isOrttoSpecific ? null : await findNotificationSettingByNotificationTypeAndUserAddress({ notificationTypeId: notificationType.id, - userAddressId: userAddress.id, + userAddressId: userAddress?.id as number }); const shouldSendEmail = diff --git a/src/types/general.ts b/src/types/general.ts index 34e0998..a267f31 100644 --- a/src/types/general.ts +++ b/src/types/general.ts @@ -52,6 +52,7 @@ export enum NOTIFICATION_TYPE_NAMES { PROJECT_HAS_A_NEW_RANK = 'Your project has a new rank', PROJECT_HAS_RISEN_IN_THE_RANK = 'Your Project has risen in the rank', YOUR_PROJECT_GOT_A_RANK = 'Your project got a rank', + SUBSCRIBE_ONBOARDING = 'Subscribe onboarding', CREATE_ORTTO_PROFILE = 'Create Ortto profile', NOTIFY_REWARD_AMOUNT = 'Notify reward amount', diff --git a/src/types/notifications.ts b/src/types/notifications.ts index 5eabd72..e0b0f86 100644 --- a/src/types/notifications.ts +++ b/src/types/notifications.ts @@ -48,6 +48,7 @@ export enum NOTIFICATIONS_EVENT_NAMES { SUPER_TOKENS_BALANCE_MONTH = 'One month left in stream balance', SUPER_TOKENS_BALANCE_DEPLETED = 'Stream balance depleted', CREATE_ORTTO_PROFILE = 'Create Ortto profile', + SEND_EMAIL_CONFIRMATION = 'Send email confirmation', NOTIFY_REWARD_AMOUNT = 'Notify reward amount', } @@ -69,5 +70,6 @@ export const ORTTO_EVENT_NAMES = { [NOTIFICATIONS_EVENT_NAMES.PROJECT_BADGE_REVOKE_WARNING]: 'first-update-warning', [NOTIFICATIONS_EVENT_NAMES.PROJECT_BADGE_REVOKE_LAST_WARNING]: 'second-update-warning', [NOTIFICATIONS_EVENT_NAMES.CREATE_ORTTO_PROFILE]: 'created-profile', + [NOTIFICATIONS_EVENT_NAMES.SEND_EMAIL_CONFIRMATION]: 'verification-form-email-verification', [NOTIFICATIONS_EVENT_NAMES.NOTIFY_REWARD_AMOUNT]: 'notify-reward-amount' } \ No newline at end of file diff --git a/src/utils/validators/segmentAndMetadataValidators.ts b/src/utils/validators/segmentAndMetadataValidators.ts index 901e790..a4ccd88 100644 --- a/src/utils/validators/segmentAndMetadataValidators.ts +++ b/src/utils/validators/segmentAndMetadataValidators.ts @@ -30,6 +30,7 @@ const projectRelatedTrackerSchema = Joi.object({ slug: Joi.string().required(), projectLink: Joi.string().allow(null).allow(''), + verificationRejectedReason: Joi.string().allow(null, ''), // it's for project updates update: Joi.string().allow(null, ''), }); @@ -159,6 +160,10 @@ const superFluidTokenSegmentSchema = Joi.object({ isEnded: Joi.boolean(), }); +const subscribeOnboardingSchema = Joi.object({ + email: Joi.string().required(), +}) + const createOrttoProfileSegmentSchema = Joi.object({ email: Joi.string().required(), firstName: Joi.string().required(), @@ -166,6 +171,11 @@ const createOrttoProfileSegmentSchema = Joi.object({ userId: Joi.number().required() }) +const sendEmailConfirmationSchema = Joi.object({ + email: Joi.string().required(), + verificationLink: Joi.string().required(), +}); + const notifyRewardAmountSegmentSchema = Joi.object({ round: Joi.number().required(), date: Joi.string().required(), @@ -184,10 +194,18 @@ export const SEGMENT_METADATA_SCHEMA_VALIDATOR: { metadata: ObjectSchema | null; }; } = { + sendEmailConfirmation: { + metadata: null, + segment: sendEmailConfirmationSchema, + }, createOrttoProfile: { segment: createOrttoProfileSegmentSchema, metadata: null }, + subscribeOnboarding: { + segment: subscribeOnboardingSchema, + metadata: null + }, userSuperTokensCritical: { metadata: superFluidTokenMetadataSchema, segment: superFluidTokenSegmentSchema, @@ -260,10 +278,6 @@ export const SEGMENT_METADATA_SCHEMA_VALIDATOR: { metadata: projectTitleProjectLinkSchema, segment: null, }, - sendEmailConfirmation: { - metadata: null, - segment: projectRelatedTrackerSchema, - }, madeDonation: { metadata: projectTitleProjectLinkSchema, segment: donationTrackerSchema, diff --git a/src/validators/schemaValidators.ts b/src/validators/schemaValidators.ts index 7bbb374..179f86b 100644 --- a/src/validators/schemaValidators.ts +++ b/src/validators/schemaValidators.ts @@ -60,6 +60,12 @@ export const sendNotificationValidator = Joi.object({ userId: Joi.number(), projectLink: Joi.string().allow(null).allow(''), + // Email confirmation + verificationLink: Joi.string().allow(null).allow(''), + + // Verification form + verificationRejectedReason: Joi.string().allow(null, ''), + // Donation related attributes amount: Joi.number(), token: Joi.string().allow(null, ''),