Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Superfluid emails #85

Merged
merged 22 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b925592
add badge revoke reminder events
RamRamez Feb 28, 2024
05a9322
Merge pull request #77 from Giveth/main
RamRamez Feb 28, 2024
997822e
Merge branch 'staging' into add-badge-revoke-events
RamRamez Feb 29, 2024
cb6dc6d
Merge pull request #78 from Giveth/add-badge-revoke-events
RamRamez Feb 29, 2024
deb60b8
add superfluid tokens email
CarlosQ96 Mar 6, 2024
7700be6
add isRecurringDonation and SUPER_TOKENS_CRITICAL fields and validators
RamRamez Mar 26, 2024
bb67e9f
add in-app notifications for emails of superfluid
CarlosQ96 Mar 28, 2024
440b665
Merge pull request #79 from Giveth/feature_add_super_tokens_email
RamRamez Apr 1, 2024
5bdb2bf
add SuperFluid Notification For All Users
RamRamez Apr 9, 2024
59632f5
fetch superfluid type ids from DB
RamRamez Apr 9, 2024
00985ef
Merge pull request #80 from Giveth/add-SuperFluid-Notification-For-Al…
RamRamez Apr 9, 2024
ddfae67
add SUPER_TOKENS NOTIFICATIONS_EVENT_NAMES
RamRamez Apr 9, 2024
798e7a2
Merge pull request #81 from Giveth/add-SUPER_TOKENS-NOTIFICATIONS_EVE…
RamRamez Apr 9, 2024
f210489
add logs
RamRamez Apr 9, 2024
0185d73
fix SCHEMA_VALIDATORS_NAMES for SUPERFLUID
RamRamez Apr 9, 2024
3d82be4
Merge pull request #82 from Giveth/fix-SCHEMA_VALIDATORS_NAMES-for-SU…
RamRamez Apr 9, 2024
05e777f
fix metadata SCHEMA on userSuperTokensCritical
RamRamez Apr 9, 2024
a6fd3c4
Merge pull request #83 from Giveth/fix-metadata-SCHEMA-on-userSuperTo…
RamRamez Apr 9, 2024
8cb5b9c
modify migration template
CarlosQ96 Apr 10, 2024
fcc5f9f
fix Recurring Donations network name and link
RamRamez Apr 10, 2024
2559a3e
remove content
RamRamez Apr 10, 2024
a502872
Merge pull request #84 from Giveth/hotfix_modify_superfluid_notificat…
CarlosQ96 Apr 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions migrations/1711607882826-addSuperfluidNotifications.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
import { NOTIFICATION_CATEGORY_GROUPS } from '../src/entities/notificationSetting';
import { NOTIFICATION_CATEGORY } from '../src/types/general';
import { MICRO_SERVICES } from '../src/utils/utils';
import {
NotificationType,
SCHEMA_VALIDATORS_NAMES,
} from '../src/entities/notificationType';

export const superFluidNotificationTypes = [
{
name: 'One month left in stream balance',
description: 'Stream balance of underlying token will run out in 1 month',
microService: MICRO_SERVICES.givethio,
category: NOTIFICATION_CATEGORY.GENERAL,
icon: '',
schemaValidator: SCHEMA_VALIDATORS_NAMES.SUPERFLUID,
emailNotifierService: null,
emailNotificationId: null,
pushNotifierService: null,
categoryGroup: NOTIFICATION_CATEGORY_GROUPS.SUPERFLUID,
title: 'One Month Left in Stream Balance',
htmlTemplate: [
{
type: 'p',
content: 'Your Stream Balance of ',
},
{
type: 'p',
content: '$tokenSymbol',
},
{
type: 'p',
content: ' on ',
},
{
type: 'p',
content: '$networkName',
},
{
type: 'p',
content: ' will run out in 1 month, ',
},
{
type: 'a',
content: 'top-up here.',
href: '$recurringDonationTab', // Actual link goes here
},
],
},
{
name: 'One week left in stream balance',
description: 'Stream balance of underlying token will run out in 1 week',
microService: MICRO_SERVICES.givethio,
category: NOTIFICATION_CATEGORY.GENERAL,
icon: '',
schemaValidator: SCHEMA_VALIDATORS_NAMES.SUPERFLUID,
emailNotifierService: null,
emailNotificationId: null,
pushNotifierService: null,
categoryGroup: NOTIFICATION_CATEGORY_GROUPS.SUPERFLUID,
title: 'One Week Left in Stream Balance',
htmlTemplate: [
{
type: 'p',
content: 'Your Stream Balance of ',
},
{
type: 'p',
content: '$tokenSymbol',
},
{
type: 'p',
content: ' on ',
},
{
type: 'p',
content: '$networkName',
},
{
type: 'p',
content: ' will run out in 1 week, ',
},
{
type: 'a',
content: 'top-up here.',
href: '$recurringDonationTab', // Actual link goes here
},
],
},
{
name: 'Stream balance depleted',
description: 'Stream balance in token has run out of funds',
microService: MICRO_SERVICES.givethio,
category: NOTIFICATION_CATEGORY.GENERAL,
icon: '',
schemaValidator: SCHEMA_VALIDATORS_NAMES.SUPERFLUID,
emailNotifierService: null,
emailNotificationId: null,
pushNotifierService: null,
categoryGroup: NOTIFICATION_CATEGORY_GROUPS.SUPERFLUID,
title: 'Stream Balance Depleted',
htmlTemplate: [
{
type: 'p',
content: 'Your Stream Balance in ',
},
{
type: 'p',
content: '$tokenSymbol',
},
{
type: 'p',
content: ' on ',
},
{
type: 'p',
content: '$networkName',
},
{
type: 'p',
content:
' has run out of funds, subsequently some of your recurring donations have ended. ',
},
{
type: 'a',
content: 'Manage your Recurring Donations',
href: '$recurringDonationTab', // Actual link goes here
},
],
},
];

export class addSuperfluidNotifications1711607882826
implements MigrationInterface
{
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.manager.save(
NotificationType,
superFluidNotificationTypes,
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`DELETE FROM notification_type WHERE "categoryGroup" = 'superfluid';`,
);
}
}
45 changes: 45 additions & 0 deletions migrations/1712683625687-addSuperFluidNotificationForAllUsers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { MigrationInterface, QueryRunner } from "typeorm"

export class addSuperFluidNotificationForAllUsers1712683625687 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
// Fetch the notificationTypeIds for the "superfluid" categoryGroup
const notificationTypeIds = await queryRunner.query(`
SELECT "id" FROM "notification_type" WHERE "categoryGroup" = 'superfluid';
`);

// Fetch all unique userAddressIds
const userAddressIds = await queryRunner.query(`
SELECT DISTINCT "userAddressId" FROM "notification_setting";
`);

// For each userAddressId, insert a new row for each notificationTypeId
for (const { userAddressId } of userAddressIds) {
for (const { id: notificationTypeId } of notificationTypeIds) {
await queryRunner.query(`
INSERT INTO "notification_setting" (
"allowNotifications",
"allowEmailNotification",
"allowDappPushNotification",
"notificationTypeId",
"userAddressId"
) VALUES (true, true, true, ${notificationTypeId}, ${userAddressId});
`);
}
}
}

public async down(queryRunner: QueryRunner): Promise<void> {
// Fetch the notificationTypeIds for the "superfluid" categoryGroup
const notificationTypeIds = await queryRunner.query(`
SELECT "id" FROM "notification_type" WHERE "categoryGroup" = 'superfluid';
`);

// Convert fetched rows to a list of IDs for the IN clause
const ids = notificationTypeIds.map((nt: { id: any; }) => nt.id).join(', ');

// Delete the rows with the fetched notificationTypeIds for all userAddressIds
await queryRunner.query(`
DELETE FROM "notification_setting" WHERE "notificationTypeId" IN (${ids});
`);
}
}
1 change: 1 addition & 0 deletions src/entities/notificationSetting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { NotificationType } from './notificationType';
import { UserAddress } from './userAddress';

export const NOTIFICATION_CATEGORY_GROUPS = {
SUPERFLUID: 'superfluid',
GIVPOWER_ALLOCATIONS: 'givPowerAllocations',
PROJECT_BOOSTING_STATUS: 'projectBoostStatus',
SELF_BOOSTING_STATUS: 'yourBoostStatus',
Expand Down
1 change: 1 addition & 0 deletions src/entities/notificationType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { NotificationSetting } from './notificationSetting';

// Export Object with Schemas to N1 lookup
export const SCHEMA_VALIDATORS_NAMES = {
SUPERFLUID: 'userSuperTokensCritical',
ADMIN_MESSAGE: 'adminMessage',
RAW_HTML_BROADCAST: 'rawHtmlBroadcast',
DRAFTED_PROJECT_SAVED: 'draftedProjectSavedValidator',
Expand Down
67 changes: 56 additions & 11 deletions src/services/notificationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,35 @@ const activityCreator = (payload: any, orttoEventName: NOTIFICATIONS_EVENT_NAMES
}
let attributes;
switch (orttoEventName) {
case NOTIFICATIONS_EVENT_NAMES.SUPER_TOKENS_BALANCE_DEPLETED:
attributes = {
"str:cm:tokensymbol": payload.tokenSymbol,
"str:cm:email": payload.email,
"str:cm:userId": payload.userId?.toString(),
"bol:cm:isended": payload.isEnded,
}
break;
case NOTIFICATIONS_EVENT_NAMES.SUPER_TOKENS_BALANCE_WEEK:
attributes = {
"str:cm:tokensymbol": payload.tokenSymbol,
"str:cm:email": payload.email,
"str:cm:userId": payload.userId?.toString(),
"str:cm:criticalDate": 'week',
"bol:cm:isended": payload.isEnded,
}
break;
case NOTIFICATIONS_EVENT_NAMES.SUPER_TOKENS_BALANCE_MONTH:
attributes = {
"str:cm:tokensymbol": payload.tokenSymbol,
"str:cm:email": payload.email,
"str:cm:userId": payload.userId?.toString(),
"str:cm:criticalDate": 'month',
"bol:cm:isended": payload.isEnded,
}
break;
case NOTIFICATIONS_EVENT_NAMES.DONATION_RECEIVED:
attributes = {
"bol:cm:isrecurringdonation": !!payload.isRecurringDonation,
"str:cm:projecttitle": payload.title,
"str:cm:donationamount": payload.amount.toString(),
"str:cm:donationtoken": payload.token,
Expand Down Expand Up @@ -104,6 +131,22 @@ const activityCreator = (payload: any, orttoEventName: NOTIFICATIONS_EVENT_NAMES
"str:cm:verified-status": 'revoked',
}
break
case NOTIFICATIONS_EVENT_NAMES.PROJECT_BADGE_REVOKE_WARNING:
attributes = {
"str:cm:projecttitle": payload.title,
"str:cm:email": payload.email,
"str:cm:projectupdatelink": payload.projectLink + '?tab=updates',
"str:cm:user-id": payload.userId?.toString(),
}
break
case NOTIFICATIONS_EVENT_NAMES.PROJECT_BADGE_REVOKE_LAST_WARNING:
attributes = {
"str:cm:projecttitle": payload.title,
"str:cm:email": payload.email,
"str:cm:projectupdatelink": payload.projectLink + '?tab=updates',
"str:cm:user-id": payload.userId?.toString(),
}
break
default:
logger.debug('activityCreator() invalid event name', orttoEventName)
return;
Expand Down Expand Up @@ -158,6 +201,17 @@ export const sendNotification = async (
userAddressId: userAddress.id,
});

const shouldSendEmail =
body.sendEmail && notificationSetting?.allowEmailNotification;
let emailStatus = shouldSendEmail
? EMAIL_STATUSES.WAITING_TO_BE_SEND
: EMAIL_STATUSES.NO_NEED_TO_SEND;

const segmentValidator =
SEGMENT_METADATA_SCHEMA_VALIDATOR[
notificationType?.schemaValidator as string
]?.segment;

logger.debug('notificationController.sendNotification()', {
notificationSetting,
notificationTypeId: notificationType.id,
Expand All @@ -174,19 +228,10 @@ export const sendNotification = async (
payload: body.segment?.payload,
sendEmail: body.sendEmail,
sendSegment: body.sendSegment,
segmentValidator: !!segmentValidator,
eventName: body.eventName,
});

const shouldSendEmail =
body.sendEmail && notificationSetting?.allowEmailNotification;
let emailStatus = shouldSendEmail
? EMAIL_STATUSES.WAITING_TO_BE_SEND
: EMAIL_STATUSES.NO_NEED_TO_SEND;

const segmentValidator =
SEGMENT_METADATA_SCHEMA_VALIDATOR[
notificationType?.schemaValidator as string
]?.segment;

if (shouldSendEmail && body.sendSegment && segmentValidator) {
const emailData = body.segment?.payload;
validateWithJoiSchema(emailData, segmentValidator);
Expand Down
8 changes: 8 additions & 0 deletions src/types/notifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,15 @@ export enum NOTIFICATIONS_EVENT_NAMES {
PROJECT_HAS_RISEN_IN_THE_RANK = 'Your Project has risen in the rank',
PROJECT_HAS_A_NEW_RANK = 'Your project has a new rank',
YOUR_PROJECT_GOT_A_RANK = 'Your project got a rank',
SUPER_TOKENS_BALANCE_WEEK = 'One week left in stream balance',
SUPER_TOKENS_BALANCE_MONTH = 'One month left in stream balance',
SUPER_TOKENS_BALANCE_DEPLETED = 'Stream balance depleted',
}

export const ORTTO_EVENT_NAMES = {
[NOTIFICATIONS_EVENT_NAMES.SUPER_TOKENS_BALANCE_WEEK]: 'superfluid-balance-warning',
[NOTIFICATIONS_EVENT_NAMES.SUPER_TOKENS_BALANCE_MONTH]: 'superfluid-balance-warning',
[NOTIFICATIONS_EVENT_NAMES.SUPER_TOKENS_BALANCE_DEPLETED]: 'superfluid-balance-warning',
[NOTIFICATIONS_EVENT_NAMES.DONATION_RECEIVED]: 'testing-donation-received',
[NOTIFICATIONS_EVENT_NAMES.DRAFTED_PROJECT_ACTIVATED]: 'project-created',
[NOTIFICATIONS_EVENT_NAMES.PROJECT_LISTED]: 'project-listed',
Expand All @@ -57,4 +63,6 @@ export const ORTTO_EVENT_NAMES = {
[NOTIFICATIONS_EVENT_NAMES.PROJECT_VERIFIED]: 'project-verification',
[NOTIFICATIONS_EVENT_NAMES.PROJECT_BADGE_REVOKED]: 'project-verification',
[NOTIFICATIONS_EVENT_NAMES.VERIFICATION_FORM_REJECTED]: 'project-verification',
[NOTIFICATIONS_EVENT_NAMES.PROJECT_BADGE_REVOKE_WARNING]: 'first-update-warning',
[NOTIFICATIONS_EVENT_NAMES.PROJECT_BADGE_REVOKE_LAST_WARNING]: 'second-update-warning',
}
23 changes: 23 additions & 0 deletions src/utils/validators/segmentAndMetadataValidators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ const donationTrackerSchema = Joi.object({
donationValueEth: Joi.number().greater(0).allow(null),
verified: Joi.boolean().allow(null),
transakStatus: Joi.string().allow(null),
isRecurringDonation: Joi.boolean().allow(null),
});

const projectTitleProjectLinkSchema = Joi.object({
Expand Down Expand Up @@ -141,12 +142,34 @@ const givBackReadyClaimSchema = Joi.object({
amount: Joi.string().required(),
});

const superFluidTokenMetadataSchema = Joi.object({
tokenSymbol: Joi.string().required(),
email: Joi.string().required(),
userId: Joi.number().required(),
isEnded: Joi.boolean(),
projectTitle: Joi.string(),
projectLink: Joi.string(),
networkName: Joi.string().required(),
recurringDonationTab: Joi.string().required(),
});

const superFluidTokenSegmentSchema = Joi.object({
tokenSymbol: Joi.string().required(),
email: Joi.string().required(),
userId: Joi.number().required(),
isEnded: Joi.boolean(),
});

export const SEGMENT_METADATA_SCHEMA_VALIDATOR: {
[key: string]: {
segment: ObjectSchema | null;
metadata: ObjectSchema | null;
};
} = {
userSuperTokensCritical: {
metadata: superFluidTokenMetadataSchema,
segment: superFluidTokenSegmentSchema,
},
draftedProjectSavedValidator: {
metadata: projectTitleProjectLinkSchema,
segment: projectRelatedTrackerSchema,
Expand Down
5 changes: 5 additions & 0 deletions src/validators/schemaValidators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ export const sendNotificationValidator = Joi.object({
donationValueEth: Joi.number().allow(null),
verified: Joi.boolean(),
transakStatus: Joi.string().allow(null).allow(''),
isRecurringDonation: Joi.boolean().allow(null),

//Super token critical attributes
isEnded: Joi.boolean(),
tokenSymbol: Joi.string(),

//Project related attributes
lastName: Joi.string().allow(null).allow(''),
Expand Down
Loading