IO-2061 Handled Bounced Emails.

This commit is contained in:
Patrick Fic
2022-09-22 14:46:08 -07:00
parent cccd025a24
commit 7fc8cbcca4
19 changed files with 165 additions and 14 deletions

View File

@@ -1,4 +1,4 @@
<babeledit_project be_version="2.7.1" version="1.2">
<babeledit_project version="1.2" be_version="2.7.1">
<!--
BabelEdit project file
@@ -1233,6 +1233,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>status</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>subject</name>
<definition_loaded>false</definition_loaded>

View File

@@ -1,9 +1,8 @@
import React, { useState } from "react";
import { Table } from "antd";
import { alphaSort } from "../../utils/sorters";
import { DateTimeFormatter } from "../../utils/DateFormatter";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import AuditTrailValuesComponent from "../audit-trail-values/audit-trail-values.component";
import { DateTimeFormatter } from "../../utils/DateFormatter";
import { alphaSort } from "../../utils/sorters";
export default function EmailAuditTrailListComponent({ loading, data }) {
const [state, setState] = useState({
@@ -11,7 +10,7 @@ export default function EmailAuditTrailListComponent({ loading, data }) {
filteredInfo: {},
});
const { t } = useTranslation();
const columns = [
const columns = [
{
title: t("audit.fields.created"),
dataIndex: " created",

View File

@@ -85,6 +85,11 @@ export function JobAuditTrail({ currentUser, jobId }) {
dataIndex: "subject",
key: "subject",
},
{
title: t("audit.fields.status"),
dataIndex: "status",
key: "status",
},
...(currentUser?.email.includes("@imex.")
? [
{

View File

@@ -86,6 +86,7 @@
"contents": "Contents",
"created": "Time",
"operation": "Operation",
"status": "Status",
"subject": "Subject",
"to": "To",
"useremail": "User",

View File

@@ -86,6 +86,7 @@
"contents": "",
"created": "",
"operation": "",
"status": "",
"subject": "",
"to": "",
"useremail": "",

View File

@@ -86,6 +86,7 @@
"contents": "",
"created": "",
"operation": "",
"status": "",
"subject": "",
"to": "",
"useremail": "",

View File

@@ -0,0 +1,24 @@
Issue when migrating events resolved by running SQL below. User needed updating when running in prod.
CREATE TABLE IF NOT EXISTS hdb_catalog.hdb_source_catalog_version
(
version text COLLATE pg_catalog."default" NOT NULL,
upgraded_on timestamp with time zone NOT NULL
)
TABLESPACE pg_default;
ALTER TABLE hdb_catalog.hdb_source_catalog_version
OWNER to postgres;
-- Index: hdb_source_catalog_version_one_row
-- DROP INDEX hdb_catalog.hdb_source_catalog_version_one_row;
CREATE UNIQUE INDEX hdb_source_catalog_version_one_row
ON hdb_catalog.hdb_source_catalog_version USING btree
((version IS NOT NULL) ASC NULLS LAST)
TABLESPACE pg_default;
INSERT INTO hdb_catalog.hdb_source_catalog_version (version, upgraded_on) VALUES ('2', NOW());
https://devscope.io/code/hasura/graphql-engine/issues/8694

View File

@@ -1882,17 +1882,19 @@
- role: user
permission:
columns:
- cc
- to
- contents
- subject
- useremail
- created_at
- updated_at
- bodyshopid
- cc
- contents
- created_at
- id
- jobid
- noteid
- status
- status_context
- subject
- to
- updated_at
- useremail
filter:
bodyshop:
associations:
@@ -3139,6 +3141,7 @@
- po_number
- policy_no
- production_vars
- qb_multiple_payers
- queued_for_parts
- rate_ats
- rate_la1
@@ -3401,6 +3404,7 @@
- po_number
- policy_no
- production_vars
- qb_multiple_payers
- queued_for_parts
- rate_ats
- rate_la1
@@ -3673,6 +3677,7 @@
- po_number
- policy_no
- production_vars
- qb_multiple_payers
- queued_for_parts
- rate_ats
- rate_la1

View File

@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."email_audit_trail" add column "sesmessageid" text
-- null;

View File

@@ -0,0 +1,2 @@
alter table "public"."email_audit_trail" add column "sesmessageid" text
null;

View File

@@ -0,0 +1 @@
DROP INDEX IF EXISTS "public"."email_audit_trail_sesmessageid";

View File

@@ -0,0 +1,2 @@
CREATE INDEX "email_audit_trail_sesmessageid" on
"public"."email_audit_trail" using btree ("sesmessageid");

View File

@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."email_audit_trail" add column "status" text
-- null;

View File

@@ -0,0 +1,2 @@
alter table "public"."email_audit_trail" add column "status" text
null;

View File

@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."email_audit_trail" add column "status_context" jsonb
-- null default jsonb_build_array();

View File

@@ -0,0 +1,2 @@
alter table "public"."email_audit_trail" add column "status_context" jsonb
null default jsonb_build_array();

View File

@@ -64,6 +64,11 @@ app.use(
//Email Based Paths.
var sendEmail = require("./server/email/sendemail.js");
app.post("/sendemail", fb.validateFirebaseIdToken, sendEmail.sendEmail);
app.post(
"/emailbounce",
bodyParser.text(),
sendEmail.emailBounce
);
//Test route to ensure Express is responding.
app.get("/test", async function (req, res) {
@@ -238,7 +243,6 @@ app.get("/", async function (req, res) {
res.status(200).send("Access Forbidden.");
});
server.listen(port, (error) => {
if (error) throw error;
logger.log(

View File

@@ -148,6 +148,7 @@ exports.sendEmail = async (req, res) => {
to: req.body.to,
cc: req.body.cc,
subject: req.body.subject,
messageId: info.messageId,
});
res.json({
success: true, //response: info
@@ -190,6 +191,8 @@ async function logEmail(req, email) {
useremail: req.user.email,
contents: req.body.html,
jobid: req.body.jobid,
sesmessageid: email.messageId,
status: "Sent",
},
});
} catch (error) {
@@ -202,3 +205,60 @@ async function logEmail(req, email) {
});
}
}
exports.emailBounce = async function (req, res, next) {
try {
const body = JSON.parse(req.body);
if (body.type === "SubscriptionConfirmation") {
logger.log("SNS-confirmation", "DEBUG", "api", null, {
message: body.message,
url: body.SubscribeUrl,
body: body,
});
}
if (body.Type === "Notification") {
const message = JSON.parse(body.Message);
let replyTo, subject, messageId;
message.mail.headers.forEach((header) => {
if (header.name === "Reply-To") {
replyTo = header.value;
} else if (header.name === "Subject") {
subject = header.value;
} else if (header.name === "Message-ID") {
messageId = header.value;
}
});
//If it's bounced, log it as bounced in audit log. Send an email to the user.
const result = await client.request(queries.UPDATE_EMAIL_AUDIT, {
sesid: messageId,
status: "Bounced",
context: message.bounce?.bouncedRecipients,
});
transporter.sendMail(
{
from: `ImEX Online <noreply@imex.online>`,
to: "patrick@snapt.ca", // replyTo,
bcc: "patrick@snapt.ca",
subject: `ImEX Online Bounced Email - RE: ${subject}`,
text: `
ImEX Online has tried to deliver an email with the subject: ${subject} to the intended recipients but encountered an error.
${message.bounce?.bouncedRecipients.map(
(r) =>
`Recipient: ${r.emailAddress} | Status: ${r.action} | Code: ${r.diagnosticCode}
`
)}
`,
},
(err, info) => {
console.log("***", err || info);
}
);
}
} catch (error) {
logger.log("sns-error", "ERROR", "api", null, {
error: JSON.stringify(error),
});
}
res.sendStatus(200);
};

View File

@@ -1621,3 +1621,12 @@ mutation DELETE_DOCUMENTS($ids: [uuid!]!) {
}
}
`;
exports.UPDATE_EMAIL_AUDIT = `
mutation ($sesid: String!, $status: String, $context: jsonb) {
update_email_audit_trail(where: {sesmessageid: {_eq: $sesid}}, _set: {status: $status, status_context: $context}) {
returning {
contents
}
}
}`;