From c40fab08bfa12a6746acd469ae08596cfbebf816 Mon Sep 17 00:00:00 2001 From: Mario Sergio Date: Wed, 12 Jun 2024 13:02:29 -0300 Subject: [PATCH 01/10] feat(activists): Included context on notify options --- packages/activists-api/src/resolvers/action/next.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/activists-api/src/resolvers/action/next.ts b/packages/activists-api/src/resolvers/action/next.ts index cb34820..e1e5c82 100644 --- a/packages/activists-api/src/resolvers/action/next.ts +++ b/packages/activists-api/src/resolvers/action/next.ts @@ -16,6 +16,13 @@ export default async ({ activist, widget }: IBaseAction, done?: DoneAction } // Post-action + // Configurar contexto para categorizar mensagens no sendgrid + const context = { + widget_id:widget.id, + mobilization_id:widget.block.mobilization.id, + community_id:community.id, + autofire:true + } const { email_subject, sender_email, sender_name, email_text } = widget.settings; // TODO: Required fields to Notify "Pós-Ação" @@ -23,7 +30,8 @@ export default async ({ activist, widget }: IBaseAction, done?: DoneAction email_from: community.email_template_from, email_to: `${activist.name} <${activist.email}>`, subject: email_subject, - body: email_text + body: email_text, + context }; // TODO: Thing a better place to move this code @@ -44,7 +52,7 @@ export default async ({ activist, widget }: IBaseAction, done?: DoneAction await NotificationsAPI.send(notifyOpts); - logger.child({ activist, widget }).info('action is done'); + logger.child({ activist, widget, notifyOpts }).info('action is done'); }; // 0. trazer a função de processar pdf e inserir plip para remote schema From 3a9671d522b73006a91897b53df859859b3924a1 Mon Sep 17 00:00:00 2001 From: Igor Santos Date: Wed, 12 Jun 2024 13:05:09 -0300 Subject: [PATCH 02/10] feat(notifications): add autofire categories --- packages/notifications/src/core/mail.ts | 33 +++++++++++++++++++------ 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/packages/notifications/src/core/mail.ts b/packages/notifications/src/core/mail.ts index 2872f96..4d8fdad 100644 --- a/packages/notifications/src/core/mail.ts +++ b/packages/notifications/src/core/mail.ts @@ -1,3 +1,4 @@ +import logger, { apmAgent } from '../logger'; import nunjucks from 'nunjucks'; export interface MailSettings { @@ -73,16 +74,32 @@ class Mail { } let categories: string[] = []; - if (context?.widget_id) { - categories = [...categories, `w${context?.widget_id}`] - } - if (context?.mobilization_id) { - categories = [...categories, `m${context?.mobilization_id}`] - } - if (context?.community_id) { - categories = [...categories, `c${context?.community_id}`] + + if (!context.autofire) { + if (context?.widget_id) { + categories = [...categories, `w${context?.widget_id}`] + } + if (context?.mobilization_id) { + categories = [...categories, `m${context?.mobilization_id}`] + } + if (context?.community_id) { + categories = [...categories, `c${context?.community_id}`] + } + } else { + categories = [...categories, 'autofire'] + if (context?.widget_id) { + categories = [...categories, `autofire-w${context?.widget_id}`] + } + if (context?.mobilization_id) { + categories = [...categories, `autofire-m${context?.mobilization_id}`] + } + if (context?.community_id) { + categories = [...categories, `autofire-c${context?.community_id}`] + } } + logger.child({ categories }).info("Categorized Sendgrid Message"); + return { ...message, categories From 61c9dbe37bfeb1e4ce2d80f1d67f072ae770dda2 Mon Sep 17 00:00:00 2001 From: Igor Santos Date: Wed, 12 Jun 2024 13:07:05 -0300 Subject: [PATCH 03/10] fix(ci): update node build to 18 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index ab16bd4..cc422ce 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16-alpine +FROM node:18-alpine WORKDIR /usr/src/app From c600aa60201fc371b60a216815351b8f53cc995c Mon Sep 17 00:00:00 2001 From: Igor Santos Date: Wed, 12 Jun 2024 13:12:24 -0300 Subject: [PATCH 04/10] fix(activists): change tests next to apply context autofire --- .../src/resolvers/action/next.spec.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/activists-api/src/resolvers/action/next.spec.ts b/packages/activists-api/src/resolvers/action/next.spec.ts index b4d7a67..5abd80b 100644 --- a/packages/activists-api/src/resolvers/action/next.spec.ts +++ b/packages/activists-api/src/resolvers/action/next.spec.ts @@ -121,7 +121,13 @@ describe('next proccess on BaseAction mailchimp tests', () => { email_from: `${opts.widget.settings.sender_name} <${opts.widget.settings.sender_email}>`, email_to: `${opts.activist.name} <${opts.activist.email}>`, subject: opts.widget.settings.email_subject, - body: opts.widget.settings.email_text + body: opts.widget.settings.email_text, + context: { + autofire: true, + widget_id: opts.widget.id, + mobilization_id: opts.widget.block.mobilization.id, + community_id: opts.widget.block.mobilization.community.id + } }) }); }); @@ -139,7 +145,13 @@ describe('next proccess on BaseAction mailchimp tests', () => { email_from: opts.widget.block.mobilization.community.email_template_from, email_to: `${opts.activist.name} <${opts.activist.email}>`, subject: opts.widget.settings.email_subject, - body: opts.widget.settings.email_text + body: opts.widget.settings.email_text, + context: { + autofire: true, + widget_id: opts.widget.id, + mobilization_id: opts.widget.block.mobilization.id, + community_id: opts.widget.block.mobilization.community.id + } }) }); }); From ab1c971378f61c2da431d03ae6fec857a7ec3433 Mon Sep 17 00:00:00 2001 From: Igor Santos Date: Wed, 12 Jun 2024 17:26:33 -0300 Subject: [PATCH 05/10] feat(notifications): add example to method email_stats --- .../src/graphql-api/resolvers/email_stats.ts | 26 +++++++++++++++++++ .../src/graphql-api/resolvers/index.ts | 4 ++- .../src/graphql-api/schema/schema.graphql | 6 +++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 packages/notifications/src/graphql-api/resolvers/email_stats.ts diff --git a/packages/notifications/src/graphql-api/resolvers/email_stats.ts b/packages/notifications/src/graphql-api/resolvers/email_stats.ts new file mode 100644 index 0000000..6dffa62 --- /dev/null +++ b/packages/notifications/src/graphql-api/resolvers/email_stats.ts @@ -0,0 +1,26 @@ +import logger, { apmAgent } from "../../logger"; +import { client } from "../../core/elasticsearchdb"; + +interface EmailStatsResponse { + message: string +} + +interface EmailStatsArgs { + widget_id: number +} + + +export default async (_: void, args: EmailStatsArgs): Promise => { + const query = { + match: { + category: `autofire` + } + }; + const { statusCode, body } = await client.search({ + index: "events-sendgrid-*", + body: { query: query } + }); + + return { message: "Olá Mario e Miguel! Total de eventos filtrados por autofire: " + body.hits.total.value } + // throw new Error("Failed elasticsearch with status: " + statusCode); +} \ No newline at end of file diff --git a/packages/notifications/src/graphql-api/resolvers/index.ts b/packages/notifications/src/graphql-api/resolvers/index.ts index 7ff5025..a87c821 100644 --- a/packages/notifications/src/graphql-api/resolvers/index.ts +++ b/packages/notifications/src/graphql-api/resolvers/index.ts @@ -3,12 +3,14 @@ import notify from './notify'; import activity_feed from "./activity_feed"; import activity_feed_total from './activity_feed_total'; import activity_feed_timestamp from "./activity_feed_timestamp"; +import email_stats from './email_stats'; const resolverMap = { Query: { activity_feed, activity_feed_total, - activity_feed_timestamp + activity_feed_timestamp, + email_stats }, Mutation: { notify diff --git a/packages/notifications/src/graphql-api/schema/schema.graphql b/packages/notifications/src/graphql-api/schema/schema.graphql index 8819eb8..6bc7f49 100644 --- a/packages/notifications/src/graphql-api/schema/schema.graphql +++ b/packages/notifications/src/graphql-api/schema/schema.graphql @@ -61,10 +61,16 @@ type ActivityFeedTimestampResponse { max_timestamp: Int } +type EmailStatsResponse { + message: String +} + type Query { activity_feed(filter: ActivityFeedFilter): ActivityFeedResponse activity_feed_total(widget_id: Int!): ActivityFeedTotalResponse activity_feed_timestamp: ActivityFeedTimestampResponse + + email_stats(widget_id: Int!): EmailStatsResponse } type Mutation { From 949fd0b6c9798f3be633520167f1a0480c350609 Mon Sep 17 00:00:00 2001 From: Mario Sergio Date: Thu, 13 Jun 2024 16:53:43 -0300 Subject: [PATCH 06/10] feat(notifications): created graphql method for email stats --- .../src/graphql-api/resolvers/email_stats.ts | 57 +++++++++++++++---- .../src/graphql-api/schema/schema.graphql | 13 ++++- 2 files changed, 57 insertions(+), 13 deletions(-) diff --git a/packages/notifications/src/graphql-api/resolvers/email_stats.ts b/packages/notifications/src/graphql-api/resolvers/email_stats.ts index 6dffa62..6d5679a 100644 --- a/packages/notifications/src/graphql-api/resolvers/email_stats.ts +++ b/packages/notifications/src/graphql-api/resolvers/email_stats.ts @@ -1,26 +1,59 @@ import logger, { apmAgent } from "../../logger"; import { client } from "../../core/elasticsearchdb"; +interface EmailEvent { + email: string; + event: string; + timestamp: number; + sg_event_id: string; + sg_message_id: string; + useragent: string; + ip: string; + url: string; +} + interface EmailStatsResponse { - message: string + events: EmailEvent[]; } interface EmailStatsArgs { - widget_id: number + widget_id: number; } export default async (_: void, args: EmailStatsArgs): Promise => { const query = { - match: { - category: `autofire` + bool: { + should: [ + { match: { event: "delivered" } }, + { match: { event: "bounced" } }, + { match: { event: "processed" } }, + { match: { event: "click" } }, + { match: { event: "open" } } + ] } }; - const { statusCode, body } = await client.search({ - index: "events-sendgrid-*", - body: { query: query } - }); - - return { message: "Olá Mario e Miguel! Total de eventos filtrados por autofire: " + body.hits.total.value } - // throw new Error("Failed elasticsearch with status: " + statusCode); -} \ No newline at end of file + + try { + const { body } = await client.search({ + index: "events-sendgrid-*", + body: { query: query } + }); + + const events = body.hits.hits.map((hit: any) => ({ + email: hit._source.email, + event: hit._source.event, + timestamp: hit._source.timestamp, + sg_event_id: hit._source.sg_event_id, + sg_message_id: hit._source.sg_message_id, + useragent: hit._source.useragent, + ip: hit._source.ip, + url: hit._source.url + })); + + return { events: events }; + } catch (error) { + logger.error(`Failed to fetch email stats`); + throw new Error(`Failed to fetch email stats`); + } +}; \ No newline at end of file diff --git a/packages/notifications/src/graphql-api/schema/schema.graphql b/packages/notifications/src/graphql-api/schema/schema.graphql index 6bc7f49..967fd7d 100644 --- a/packages/notifications/src/graphql-api/schema/schema.graphql +++ b/packages/notifications/src/graphql-api/schema/schema.graphql @@ -61,8 +61,19 @@ type ActivityFeedTimestampResponse { max_timestamp: Int } +type EmailEvent { + email: String + event: String + timestamp: Int + sg_event_id: String + sg_message_id: String + useragent: String + ip: String + url: String +} + type EmailStatsResponse { - message: String + events: [EmailEvent] } type Query { From 6a8c92fbe8d1fdf6c16a715f63131fafbd486300 Mon Sep 17 00:00:00 2001 From: Mario Sergio Date: Mon, 24 Jun 2024 18:40:40 -0300 Subject: [PATCH 07/10] feat(notifications): adjusted query to filter by autofire events --- .../src/graphql-api/resolvers/email_stats.ts | 37 ++++++++++++++++--- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/packages/notifications/src/graphql-api/resolvers/email_stats.ts b/packages/notifications/src/graphql-api/resolvers/email_stats.ts index 6d5679a..5ee36cb 100644 --- a/packages/notifications/src/graphql-api/resolvers/email_stats.ts +++ b/packages/notifications/src/graphql-api/resolvers/email_stats.ts @@ -18,18 +18,43 @@ interface EmailStatsResponse { interface EmailStatsArgs { widget_id: number; + mobilization_id?: number; + community_id?: number; } export default async (_: void, args: EmailStatsArgs): Promise => { + let categories: string[] = []; + + if (args.widget_id) { + categories.push(`autofire-w${args.widget_id}`); + } + if (args.mobilization_id) { + categories.push(`autofire-m${args.mobilization_id}`); + } + if (args.community_id) { + categories.push(`autofire-c${args.community_id}`); + } + const query = { bool: { - should: [ - { match: { event: "delivered" } }, - { match: { event: "bounced" } }, - { match: { event: "processed" } }, - { match: { event: "click" } }, - { match: { event: "open" } } + must: [ + { + terms: { + category: categories + } + }, + { + bool: { + should: [ + { match: { event: "delivered" } }, + { match: { event: "bounced" } }, + { match: { event: "processed" } }, + { match: { event: "click" } }, + { match: { event: "open" } } + ] + } + } ] } }; From 0af05857aec0e171d18d11488e807124e7ad176b Mon Sep 17 00:00:00 2001 From: Mario Sergio Date: Wed, 26 Jun 2024 15:02:59 -0300 Subject: [PATCH 08/10] feat(notification): fixed autofire query filter --- .../src/graphql-api/resolvers/email_stats.ts | 35 +++++++++++-------- .../src/graphql-api/schema/schema.graphql | 9 +++++ 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/packages/notifications/src/graphql-api/resolvers/email_stats.ts b/packages/notifications/src/graphql-api/resolvers/email_stats.ts index 5ee36cb..cc43b70 100644 --- a/packages/notifications/src/graphql-api/resolvers/email_stats.ts +++ b/packages/notifications/src/graphql-api/resolvers/email_stats.ts @@ -14,34 +14,31 @@ interface EmailEvent { interface EmailStatsResponse { events: EmailEvent[]; + stats: { + open: number; + delivered: number; + bounced: number; + processed: number; + click: number; + }; } interface EmailStatsArgs { widget_id: number; - mobilization_id?: number; - community_id?: number; } export default async (_: void, args: EmailStatsArgs): Promise => { let categories: string[] = []; - if (args.widget_id) { - categories.push(`autofire-w${args.widget_id}`); - } - if (args.mobilization_id) { - categories.push(`autofire-m${args.mobilization_id}`); - } - if (args.community_id) { - categories.push(`autofire-c${args.community_id}`); - } - + categories.push(`autofire-w${args.widget_id}`); + const query = { bool: { must: [ { terms: { - category: categories + "category.keyword": categories } }, { @@ -73,10 +70,18 @@ export default async (_: void, args: EmailStatsArgs): Promise event.event === "open").length, + delivered: events.filter(event => event.event === "delivered").length, + bounced: events.filter(event => event.event === "bounced").length, + processed: events.filter(event => event.event === "processed").length, + click: events.filter(event => event.event === "click").length, + }; + + return { events, stats }; } catch (error) { logger.error(`Failed to fetch email stats`); throw new Error(`Failed to fetch email stats`); diff --git a/packages/notifications/src/graphql-api/schema/schema.graphql b/packages/notifications/src/graphql-api/schema/schema.graphql index 967fd7d..2c54ac0 100644 --- a/packages/notifications/src/graphql-api/schema/schema.graphql +++ b/packages/notifications/src/graphql-api/schema/schema.graphql @@ -72,8 +72,17 @@ type EmailEvent { url: String } +type EmailStats { + open: Int + delivered: Int + bounced: Int + processed: Int + click: Int +} + type EmailStatsResponse { events: [EmailEvent] + stats: EmailStats } type Query { From 74ada7ed4b401f1e15b0c6bfa295f4d2d1bd5cea Mon Sep 17 00:00:00 2001 From: Mario Sergio Date: Fri, 28 Jun 2024 17:49:44 -0300 Subject: [PATCH 09/10] feat(notifications): Inserted total emails fireld on autofire API graphql --- packages/notifications/src/graphql-api/resolvers/email_stats.ts | 2 ++ packages/notifications/src/graphql-api/schema/schema.graphql | 1 + 2 files changed, 3 insertions(+) diff --git a/packages/notifications/src/graphql-api/resolvers/email_stats.ts b/packages/notifications/src/graphql-api/resolvers/email_stats.ts index cc43b70..a7d4b07 100644 --- a/packages/notifications/src/graphql-api/resolvers/email_stats.ts +++ b/packages/notifications/src/graphql-api/resolvers/email_stats.ts @@ -20,6 +20,7 @@ interface EmailStatsResponse { bounced: number; processed: number; click: number; + total: number; }; } @@ -79,6 +80,7 @@ export default async (_: void, args: EmailStatsArgs): Promise event.event === "bounced").length, processed: events.filter(event => event.event === "processed").length, click: events.filter(event => event.event === "click").length, + total: events.length }; return { events, stats }; diff --git a/packages/notifications/src/graphql-api/schema/schema.graphql b/packages/notifications/src/graphql-api/schema/schema.graphql index 2c54ac0..0eddc52 100644 --- a/packages/notifications/src/graphql-api/schema/schema.graphql +++ b/packages/notifications/src/graphql-api/schema/schema.graphql @@ -78,6 +78,7 @@ type EmailStats { bounced: Int processed: Int click: Int + total: Int } type EmailStatsResponse { From c04237f68bef2b7ffb7039908107864853040959 Mon Sep 17 00:00:00 2001 From: Mario Sergio Date: Tue, 2 Jul 2024 11:31:54 -0300 Subject: [PATCH 10/10] feat(notifications): Added category filter on query graphql --- .../src/graphql-api/resolvers/email_stats.ts | 9 +++++++-- .../notifications/src/graphql-api/schema/schema.graphql | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/notifications/src/graphql-api/resolvers/email_stats.ts b/packages/notifications/src/graphql-api/resolvers/email_stats.ts index a7d4b07..8ad69c9 100644 --- a/packages/notifications/src/graphql-api/resolvers/email_stats.ts +++ b/packages/notifications/src/graphql-api/resolvers/email_stats.ts @@ -26,14 +26,19 @@ interface EmailStatsResponse { interface EmailStatsArgs { widget_id: number; + category?: string; } export default async (_: void, args: EmailStatsArgs): Promise => { + const { widget_id, category } = args; let categories: string[] = []; - categories.push(`autofire-w${args.widget_id}`); - + if (category) { + categories.push(`${category}-w${widget_id}`); + } else { + categories.push(`w${widget_id}`); + } const query = { bool: { must: [ diff --git a/packages/notifications/src/graphql-api/schema/schema.graphql b/packages/notifications/src/graphql-api/schema/schema.graphql index 0eddc52..d01ba65 100644 --- a/packages/notifications/src/graphql-api/schema/schema.graphql +++ b/packages/notifications/src/graphql-api/schema/schema.graphql @@ -91,7 +91,7 @@ type Query { activity_feed_total(widget_id: Int!): ActivityFeedTotalResponse activity_feed_timestamp: ActivityFeedTimestampResponse - email_stats(widget_id: Int!): EmailStatsResponse + email_stats(widget_id: Int!, category: String): EmailStatsResponse } type Mutation {