diff --git a/_reference/localEmailViewer/index.js b/_reference/localEmailViewer/index.js index 2b4c21444..1dd17f779 100644 --- a/_reference/localEmailViewer/index.js +++ b/_reference/localEmailViewer/index.js @@ -1,116 +1,96 @@ // index.js -import express from 'express'; -import fetch from 'node-fetch'; -import {simpleParser} from 'mailparser'; +import express from "express"; +import fetch from "node-fetch"; +import { simpleParser } from "mailparser"; const app = express(); const PORT = 3334; -app.get('/', async (req, res) => { - try { - const response = await fetch('http://localhost:4566/_aws/ses'); - if (!response.ok) { - throw new Error('Network response was not ok'); - } - const data = await response.json(); - const messagesHtml = await parseMessages(data.messages); - res.send(renderHtml(messagesHtml)); - } catch (error) { - console.error('Error fetching messages:', error); - res.status(500).send('Error fetching messages'); +app.get("/", async (req, res) => { + try { + const response = await fetch("http://localhost:4566/_aws/ses"); + if (!response.ok) { + throw new Error("Network response was not ok"); } + const data = await response.json(); + const messagesHtml = await parseMessages(data.messages); + res.send(renderHtml(messagesHtml)); + } catch (error) { + console.error("Error fetching messages:", error); + res.status(500).send("Error fetching messages"); + } }); async function parseMessages(messages) { - const parsedMessages = await Promise.all( - messages.map(async (message, index) => { - try { - const parsed = await simpleParser(message.RawData); - return ` -
-
-
- Message ${index + 1} -
-
- From: ${message.Source} -
-
- Region: ${message.Region} -
-
- Timestamp: ${message.Timestamp} -
-
-
- ${parsed.html || parsed.textAsHtml || 'No HTML content available'} -
-
- `; - } catch (error) { - console.error('Error parsing email:', error); - return ` -
-
- Message ${index + 1} -
-
- From: ${message.Source} -
-
- Region: ${message.Region} -
-
- Timestamp: ${message.Timestamp} -
-
- Error parsing email content -
-
- `; - } - }) - ); - return parsedMessages.join(''); + const parsedMessages = await Promise.all( + messages.map(async (message, index) => { + try { + const parsed = await simpleParser(message.RawData); + return ` +
+
+
Message ${index + 1}
+
From: ${message.Source}
+
To: ${parsed.to.text || "No To Address"}
+
Subject: ${parsed.subject || "No Subject"}
+
Region: ${message.Region}
+
Timestamp: ${message.Timestamp}
+
+
${parsed.html || parsed.textAsHtml || "No HTML content available"}
+
+ `; + } catch (error) { + console.error("Error parsing email:", error); + return ` +
+
Message ${index + 1}
+
From: ${message.Source}
+
Region: ${message.Region}
+
Timestamp: ${message.Timestamp}
+
Error parsing email content
+
+ `; + } + }) + ); + return parsedMessages.join(""); } function renderHtml(messagesHtml) { - return ` - - - - - - Email Messages Viewer - - - - -
-

Email Messages Viewer

-
- ${messagesHtml} -
-
- - - `; + return ` + + + + + + Email Messages Viewer + + + + +
+

Email Messages Viewer

+
${messagesHtml}
+
+ + + `; } app.listen(PORT, () => { - console.log(`Server is running on http://localhost:${PORT}`); -}); \ No newline at end of file + console.log(`Server is running on http://localhost:${PORT}`); +}); diff --git a/_reference/localEmailViewer/package-lock.json b/_reference/localEmailViewer/package-lock.json index ae14abb19..2c7ecad93 100644 --- a/_reference/localEmailViewer/package-lock.json +++ b/_reference/localEmailViewer/package-lock.json @@ -10,7 +10,7 @@ "license": "ISC", "dependencies": { "express": "^5.1.0", - "mailparser": "^3.7.2", + "mailparser": "^3.7.4", "node-fetch": "^3.3.2" } }, @@ -634,9 +634,9 @@ "license": "MIT" }, "node_modules/libmime": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/libmime/-/libmime-5.3.6.tgz", - "integrity": "sha512-j9mBC7eiqi6fgBPAGvKCXJKJSIASanYF4EeA4iBzSG0HxQxmXnR3KbyWqTn4CwsKSebqCv2f5XZfAO6sKzgvwA==", + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/libmime/-/libmime-5.3.7.tgz", + "integrity": "sha512-FlDb3Wtha8P01kTL3P9M+ZDNDWPKPmKHWaU/cG/lg5pfuAwdflVpZE+wm9m7pKmC5ww6s+zTxBKS1p6yl3KpSw==", "license": "MIT", "dependencies": { "encoding-japanese": "2.2.0", @@ -661,31 +661,31 @@ } }, "node_modules/mailparser": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/mailparser/-/mailparser-3.7.2.tgz", - "integrity": "sha512-iI0p2TCcIodR1qGiRoDBBwboSSff50vQAWytM5JRggLfABa4hHYCf3YVujtuzV454xrOP352VsAPIzviqMTo4Q==", + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/mailparser/-/mailparser-3.7.4.tgz", + "integrity": "sha512-Beh4yyR4jLq3CZZ32asajByrXnW8dLyKCAQD3WvtTiBnMtFWhxO+wa93F6sJNjDmfjxXs4NRNjw3XAGLqZR3Vg==", "license": "MIT", "dependencies": { "encoding-japanese": "2.2.0", "he": "1.2.0", "html-to-text": "9.0.5", "iconv-lite": "0.6.3", - "libmime": "5.3.6", + "libmime": "5.3.7", "linkify-it": "5.0.0", - "mailsplit": "5.4.2", - "nodemailer": "6.9.16", + "mailsplit": "5.4.5", + "nodemailer": "7.0.4", "punycode.js": "2.3.1", - "tlds": "1.255.0" + "tlds": "1.259.0" } }, "node_modules/mailsplit": { - "version": "5.4.2", - "resolved": "https://registry.npmjs.org/mailsplit/-/mailsplit-5.4.2.tgz", - "integrity": "sha512-4cczG/3Iu3pyl8JgQ76dKkisurZTmxMrA4dj/e8d2jKYcFTZ7MxOzg1gTioTDMPuFXwTrVuN/gxhkrO7wLg7qA==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/mailsplit/-/mailsplit-5.4.5.tgz", + "integrity": "sha512-oMfhmvclR689IIaQmIcR5nODnZRRVwAKtqFT407TIvmhX2OLUBnshUTcxzQBt3+96sZVDud9NfSe1NxAkUNXEQ==", "license": "(MIT OR EUPL-1.1+)", "dependencies": { "libbase64": "1.3.0", - "libmime": "5.3.6", + "libmime": "5.3.7", "libqp": "2.1.1" } }, @@ -793,9 +793,9 @@ } }, "node_modules/nodemailer": { - "version": "6.9.16", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.16.tgz", - "integrity": "sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.4.tgz", + "integrity": "sha512-9O00Vh89/Ld2EcVCqJ/etd7u20UhME0f/NToPfArwPEe1Don1zy4mAIz6ariRr7mJ2RDxtaDzN0WJVdVXPtZaw==", "license": "MIT-0", "engines": { "node": ">=6.0.0" @@ -1114,9 +1114,9 @@ } }, "node_modules/tlds": { - "version": "1.255.0", - "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.255.0.tgz", - "integrity": "sha512-tcwMRIioTcF/FcxLev8MJWxCp+GUALRhFEqbDoZrnowmKSGqPrl5pqS+Sut2m8BgJ6S4FExCSSpGffZ0Tks6Aw==", + "version": "1.259.0", + "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.259.0.tgz", + "integrity": "sha512-AldGGlDP0PNgwppe2quAvuBl18UcjuNtOnDuUkqhd6ipPqrYYBt3aTxK1QTsBVknk97lS2JcafWMghjGWFtunw==", "license": "MIT", "bin": { "tlds": "bin.js" diff --git a/_reference/localEmailViewer/package.json b/_reference/localEmailViewer/package.json index 74cef99ff..5f553cf17 100644 --- a/_reference/localEmailViewer/package.json +++ b/_reference/localEmailViewer/package.json @@ -12,7 +12,7 @@ "description": "", "dependencies": { "express": "^5.1.0", - "mailparser": "^3.7.2", + "mailparser": "^3.7.4", "node-fetch": "^3.3.2" } } diff --git a/docker-compose.yml b/docker-compose.yml index ae8b35048..ad805e272 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -119,6 +119,7 @@ services: aws --endpoint-url=http://localstack:4566 s3api create-bucket --bucket imex-large-log --create-bucket-configuration LocationConstraint=ca-central-1 aws --endpoint-url=http://localstack:4566 s3api create-bucket --bucket imex-job-totals --create-bucket-configuration LocationConstraint=ca-central-1 aws --endpoint-url=http://localstack:4566 s3api create-bucket --bucket parts-estimates --create-bucket-configuration LocationConstraint=ca-central-1 + aws --endpoint-url=http://localstack:4566 s3api create-bucket --bucket imex-carfax-uploads --create-bucket-configuration LocationConstraint=ca-central-1 " # Node App: The Main IMEX API node-app: diff --git a/hasura/metadata/cron_triggers.yaml b/hasura/metadata/cron_triggers.yaml index 534560869..cc1baa225 100644 --- a/hasura/metadata/cron_triggers.yaml +++ b/hasura/metadata/cron_triggers.yaml @@ -6,6 +6,15 @@ headers: - name: x-imex-auth value_from_env: DATAPUMP_AUTH +- name: CARFAX Data Pump + webhook: '{{HASURA_API_URL}}/data/carfax' + schedule: 0 7 * * 6 + include_in_metadata: true + payload: {} + headers: + - name: x-imex-auth + value_from_env: DATAPUMP_AUTH + comment: Project Mexico - name: Chatter Data Pump webhook: '{{HASURA_API_URL}}/data/chatter' schedule: 45 5 * * * diff --git a/server/data/carfax.js b/server/data/carfax.js index b25e371a8..b0792813d 100644 --- a/server/data/carfax.js +++ b/server/data/carfax.js @@ -6,7 +6,7 @@ const InstanceManager = require("../utils/instanceMgr").default; const { isString, isEmpty } = require("lodash"); const fs = require("fs"); const client = require("../graphql-client/graphql-client").client; -const { sendServerEmail } = require("../email/sendemail"); +const { sendServerEmail, sendMexicoBillingEmail } = require("../email/sendemail"); const { uploadFileToS3 } = require("../utils/s3"); const crypto = require("crypto"); @@ -168,6 +168,32 @@ async function processShopData(shopsToProcess, start, end, skipUpload, ignoreDat await uploadViaSFTP(jsonObj); } + await sendMexicoBillingEmail({ + subject: `${shopid.toUpperCase()}_Mexico${InstanceManager({ + imex: "IO", + rome: "RO" + })}_${moment().format("MMDDYYYY")} ROs ${jsonObj.count} Error ${errorCode(jsonObj)}`, + text: `Errors:\n${JSON.stringify( + erroredJobs.map((ej) => ({ + ro_number: ej.job?.ro_number, + jobid: ej.job?.id, + error: ej.error + })), + null, + 2 + )}\n\nUploaded:\n${JSON.stringify( + { + bodyshopid: bodyshop.id, + imexshopid: shopid, + count: jsonObj.count, + filename: jsonObj.filename, + result: jsonObj.result + }, + null, + 2 + )}` + }); + allXMLResults.push({ bodyshopid: bodyshop.id, imexshopid: shopid, @@ -402,3 +428,14 @@ const generatePartType = (type) => { return partTypeMap[type?.toLowerCase()] || null; }; + +const errorCode = ({ count, filename, results }) => { + if (count === 0) return 1; + if (!filename) return 3; + const sftpErrorCode = results?.sftpError?.code; + if (sftpErrorCode && ["ECONNREFUSED", "ENOTFOUND", "ETIMEDOUT", "ECONNRESET"].includes(sftpErrorCode)) { + return 4; + } + if (sftpErrorCode) return 7; + return 0; +}; diff --git a/server/email/sendemail.js b/server/email/sendemail.js index 6622cb6ce..c9a72c17f 100644 --- a/server/email/sendemail.js +++ b/server/email/sendemail.js @@ -79,6 +79,41 @@ const sendServerEmail = async ({ subject, text }) => { } }; +const sendMexicoBillingEmail = async ({ subject, text }) => { + if (process.env.NODE_ENV === undefined) return; + try { + mailer.sendMail( + { + from: InstanceManager({ + imex: `ImEX Online API - ${process.env.NODE_ENV} `, + rome: `Rome Online API - ${process.env.NODE_ENV} ` + }), + to: ["mexico@rometech.zohodesk.com"], + subject: subject, + text: text, + ses: { + // optional extra arguments for SendRawEmail + Tags: [ + { + Name: "tag_name", + Value: "tag_value" + } + ] + } + }, + // eslint-disable-next-line no-unused-vars + (err, info) => { + logger.log("server-email-failure", err ? "error" : "debug", null, null, { + message: err?.message, + stack: err?.stack + }); + } + ); + } catch (error) { + logger.log("server-email-failure", "error", null, null, { message: error?.message, stack: error?.stack }); + } +}; + const sendWelcomeEmail = async ({ to, resetLink, dateLine, features, bcc }) => { try { await mailer.sendMail({ @@ -420,6 +455,7 @@ ${body.bounce?.bouncedRecipients.map( module.exports = { sendEmail, sendServerEmail, + sendMexicoBillingEmail, sendTaskEmail, emailBounce, sendWelcomeEmail