feature/IO-2979-DST-Handling
- Add LocalStack and Adjust local Emailing Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
@@ -7,7 +7,6 @@ _reference
|
||||
client
|
||||
redis/dockerdata
|
||||
hasura
|
||||
node_modules
|
||||
|
||||
# Files to exclude
|
||||
.ebignore
|
||||
|
||||
@@ -25,6 +25,9 @@ RUN dnf install -y \
|
||||
# Set the working directory
|
||||
WORKDIR /app
|
||||
|
||||
# This is because our test route uses a git commit hash
|
||||
RUN git config --global --add safe.directory /app
|
||||
|
||||
# Copy package.json and package-lock.json
|
||||
COPY package*.json ./
|
||||
|
||||
@@ -32,7 +35,7 @@ COPY package*.json ./
|
||||
RUN npm install -g nodemon
|
||||
|
||||
# Install dependencies
|
||||
RUN npm install --omit=dev
|
||||
RUN npm ci
|
||||
|
||||
# Copy the rest of your application code
|
||||
COPY . .
|
||||
|
||||
@@ -138,6 +138,10 @@ sudo sysctl -p
|
||||
# Install Docker and Docker Compose in WSL2
|
||||
- https://docs.docker.com/desktop/wsl/
|
||||
|
||||
# Local Stack
|
||||
- LocalStack Front end (Optional) - https://apps.microsoft.com/detail/9ntrnft9zws2?hl=en-us&gl=US
|
||||
- http://localhost:4566/_aws/ses will allow you to see emails sent
|
||||
|
||||
# Docker Commands
|
||||
|
||||
## General `docker-compose` Commands:
|
||||
@@ -150,6 +154,7 @@ sudo sysctl -p
|
||||
7. View running Containers: `docker-compose ps`
|
||||
8. View a specific containers logs: `docker-compose logs <container-name>`
|
||||
9. Scale services (multiple instances of a service): `docker-compose up --scale <container-name>=<instances number> -d`
|
||||
10. Watch a specific containers logs in realtime with timestamps: `docker-compose logs -f --timestamps <container-name>`
|
||||
|
||||
## Volume Management Commands
|
||||
1. List Docker volumes: `docker volume ls`
|
||||
|
||||
@@ -314,8 +314,8 @@ export function* SetAuthLevelFromShopDetails({ payload }) {
|
||||
try {
|
||||
const userEmail = yield select((state) => state.user.currentUser.email);
|
||||
try {
|
||||
//console.log("Setting shop timezone.");
|
||||
// dayjs.tz.setDefault(payload.timezone);
|
||||
console.log("Setting shop timezone.");
|
||||
day.tz.setDefault(payload.timezone);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
#############################
|
||||
# Ports Exposed
|
||||
# 4000 - Imex Node API
|
||||
# 3333 - SocketIO Admin-UI
|
||||
# 3334 - Redis-Insights
|
||||
# 4000 - Imex Node API
|
||||
# 4556 - LocalStack (Local AWS)
|
||||
# 3333 - SocketIO Admin-UI (Optional)
|
||||
# 3334 - Redis-Insights (Optional)
|
||||
#############################
|
||||
|
||||
services:
|
||||
|
||||
# Redis Node 1
|
||||
redis-node-1:
|
||||
build:
|
||||
context: ./redis
|
||||
@@ -22,7 +25,8 @@ services:
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
|
||||
|
||||
# Redis Node 2
|
||||
redis-node-2:
|
||||
build:
|
||||
context: ./redis
|
||||
@@ -40,6 +44,7 @@ services:
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
|
||||
# Redis Node 3
|
||||
redis-node-3:
|
||||
build:
|
||||
context: ./redis
|
||||
@@ -57,6 +62,52 @@ services:
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
|
||||
# LocalStack: Used to emulate AWS services locally, currently setup for SES
|
||||
localstack:
|
||||
image: localstack/localstack
|
||||
container_name: localstack
|
||||
hostname: localstack
|
||||
networks:
|
||||
- redis-cluster-net
|
||||
restart: always
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
environment:
|
||||
- SERVICES=ses
|
||||
- DEBUG=1
|
||||
- AWS_ACCESS_KEY_ID=test
|
||||
- AWS_SECRET_ACCESS_KEY=test
|
||||
- AWS_DEFAULT_REGION=ca-central-1
|
||||
ports:
|
||||
- "4566:4566"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:4566/_localstack/health"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 20s
|
||||
|
||||
# AWS-CLI - Used in conjunction with LocalStack to set required permission to send emails
|
||||
aws-cli:
|
||||
image: amazon/aws-cli
|
||||
container_name: aws-cli
|
||||
hostname: aws-cli
|
||||
networks:
|
||||
- redis-cluster-net
|
||||
depends_on:
|
||||
localstack:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
- AWS_ACCESS_KEY_ID=test
|
||||
- AWS_SECRET_ACCESS_KEY=test
|
||||
- AWS_DEFAULT_REGION=ca-central-1
|
||||
entrypoint: /bin/sh -c
|
||||
command: >
|
||||
"
|
||||
aws --endpoint-url=http://localstack:4566 ses verify-domain-identity --domain imex.online --region ca-central-1
|
||||
aws --endpoint-url=http://localstack:4566 ses verify-email-identity --email-address noreply@imex.online --region ca-central-1
|
||||
"
|
||||
# Node App: The Main IMEX API
|
||||
node-app:
|
||||
build:
|
||||
context: .
|
||||
@@ -73,37 +124,44 @@ services:
|
||||
condition: service_healthy
|
||||
redis-node-3:
|
||||
condition: service_healthy
|
||||
localstack:
|
||||
condition: service_healthy
|
||||
aws-cli:
|
||||
condition: service_completed_successfully
|
||||
ports:
|
||||
- "4000:4000"
|
||||
volumes:
|
||||
- .:/app
|
||||
- /app/node_modules
|
||||
- node-app-npm-cache:/app/node_modules
|
||||
|
||||
socketio-admin-ui:
|
||||
image: maitrungduc1410/socket.io-admin-ui
|
||||
container_name: socketio-admin-ui
|
||||
networks:
|
||||
- redis-cluster-net
|
||||
ports:
|
||||
- "3333:80"
|
||||
|
||||
redis-insight:
|
||||
image: redislabs/redisinsight:latest
|
||||
container_name: redis-insight
|
||||
hostname: redis-insight
|
||||
restart: always
|
||||
ports:
|
||||
- "3334:5540"
|
||||
networks:
|
||||
- redis-cluster-net
|
||||
volumes:
|
||||
- redis-insight-data:/db
|
||||
# ## Optional Container to Observe SocketIO data
|
||||
# socketio-admin-ui:
|
||||
# image: maitrungduc1410/socket.io-admin-ui
|
||||
# container_name: socketio-admin-ui
|
||||
# networks:
|
||||
# - redis-cluster-net
|
||||
# ports:
|
||||
# - "3333:80"
|
||||
|
||||
# ##Optional Container to Observe Redis Cluster Data
|
||||
# redis-insight:
|
||||
# image: redislabs/redisinsight:latest
|
||||
# container_name: redis-insight
|
||||
# hostname: redis-insight
|
||||
# restart: always
|
||||
# ports:
|
||||
# - "3334:5540"
|
||||
# networks:
|
||||
# - redis-cluster-net
|
||||
# volumes:
|
||||
# - redis-insight-data:/db
|
||||
|
||||
networks:
|
||||
redis-cluster-net:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
node-app-npm-cache:
|
||||
redis-node-1-data:
|
||||
redis-node-2-data:
|
||||
redis-node-3-data:
|
||||
|
||||
49
server/email/mailer.js
Normal file
49
server/email/mailer.js
Normal file
@@ -0,0 +1,49 @@
|
||||
const { isString, isEmpty } = require("lodash");
|
||||
const { defaultProvider } = require("@aws-sdk/credential-provider-node");
|
||||
const { default: InstanceManager } = require("../utils/instanceMgr");
|
||||
const aws = require("@aws-sdk/client-ses");
|
||||
const nodemailer = require("nodemailer");
|
||||
|
||||
const isLocal = isString(process.env?.LOCALSTACK_HOSTNAME) && !isEmpty(process.env?.LOCALSTACK_HOSTNAME);
|
||||
|
||||
const sesConfig = {
|
||||
apiVersion: "latest",
|
||||
credentials: defaultProvider(),
|
||||
region: isLocal
|
||||
? "ca-central-1"
|
||||
: InstanceManager({
|
||||
imex: "ca-central-1",
|
||||
rome: "us-east-2"
|
||||
})
|
||||
};
|
||||
|
||||
if (isLocal) {
|
||||
sesConfig.endpoint = `http://${process.env.LOCALSTACK_HOSTNAME}:4566`;
|
||||
console.log(`SES Mailer set to LocalStack end point: ${sesConfig.endpoint}`);
|
||||
}
|
||||
|
||||
const ses = new aws.SES(sesConfig);
|
||||
|
||||
let transporter = nodemailer.createTransport({
|
||||
SES: { ses, aws }
|
||||
});
|
||||
|
||||
if (isLocal) {
|
||||
// Wrap the sendMail function to log the email contents to the console in local environment
|
||||
const originalSendMail = transporter.sendMail.bind(transporter);
|
||||
transporter.sendMail = async (mailOptions) => {
|
||||
try {
|
||||
const result = await originalSendMail(mailOptions);
|
||||
console.log(
|
||||
`Email sent successfully - From: ${result?.envelope?.from} - To: ${result?.envelope?.to} - MessageID ${result.messageId} - Check LocalStack to see message`
|
||||
);
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error("Failed to send email:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = transporter;
|
||||
@@ -3,30 +3,13 @@ require("dotenv").config({
|
||||
path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`)
|
||||
});
|
||||
const axios = require("axios");
|
||||
let nodemailer = require("nodemailer");
|
||||
let aws = require("@aws-sdk/client-ses");
|
||||
let { defaultProvider } = require("@aws-sdk/credential-provider-node");
|
||||
const InstanceManager = require("../utils/instanceMgr").default;
|
||||
const logger = require("../utils/logger");
|
||||
const client = require("../graphql-client/graphql-client").client;
|
||||
const queries = require("../graphql-client/queries");
|
||||
const { isObject } = require("lodash");
|
||||
const generateEmailTemplate = require("./generateTemplate");
|
||||
const moment = require("moment");
|
||||
|
||||
const ses = new aws.SES({
|
||||
// The key apiVersion is no longer supported in v3, and can be removed.
|
||||
// @deprecated The client uses the "latest" apiVersion.
|
||||
apiVersion: "latest",
|
||||
credentials: defaultProvider(),
|
||||
region: InstanceManager({
|
||||
imex: "ca-central-1",
|
||||
rome: "us-east-2"
|
||||
})
|
||||
});
|
||||
let transporter = nodemailer.createTransport({
|
||||
SES: { ses, aws }
|
||||
});
|
||||
const mailer = require("./mailer");
|
||||
|
||||
// Get the image from the URL and return it as a base64 string
|
||||
const getImage = async (imageUrl) => {
|
||||
@@ -66,7 +49,7 @@ const logEmail = async (req, email) => {
|
||||
const sendServerEmail = async ({ subject, text }) => {
|
||||
if (process.env.NODE_ENV === undefined) return;
|
||||
try {
|
||||
transporter.sendMail(
|
||||
mailer.sendMail(
|
||||
{
|
||||
from: InstanceManager({
|
||||
imex: `ImEX Online API - ${process.env.NODE_ENV} <noreply@imex.online>`,
|
||||
@@ -98,7 +81,7 @@ const sendServerEmail = async ({ subject, text }) => {
|
||||
|
||||
const sendProManagerWelcomeEmail = async ({ to, subject, html }) => {
|
||||
try {
|
||||
await transporter.sendMail({
|
||||
await mailer.sendMail({
|
||||
from: `ProManager <noreply@promanager.web-est.com>`,
|
||||
to,
|
||||
subject,
|
||||
@@ -112,7 +95,7 @@ const sendProManagerWelcomeEmail = async ({ to, subject, html }) => {
|
||||
|
||||
const sendTaskEmail = async ({ to, subject, type = "text", html, text, attachments }) => {
|
||||
try {
|
||||
transporter.sendMail(
|
||||
mailer.sendMail(
|
||||
{
|
||||
from: InstanceManager({
|
||||
imex: `ImEX Online <noreply@imex.online>`,
|
||||
@@ -166,7 +149,7 @@ const sendEmail = async (req, res) => {
|
||||
);
|
||||
}
|
||||
|
||||
transporter.sendMail(
|
||||
mailer.sendMail(
|
||||
{
|
||||
from: `${req.body.from.name} <${req.body.from.address}>`,
|
||||
replyTo: req.body.ReplyTo.Email,
|
||||
@@ -280,7 +263,7 @@ const emailBounce = async (req, res) => {
|
||||
status: "Bounced",
|
||||
context: message.bounce?.bouncedRecipients
|
||||
});
|
||||
transporter.sendMail(
|
||||
mailer.sendMail(
|
||||
{
|
||||
from: InstanceMgr({
|
||||
imex: `ImEX Online <noreply@imex.online>`,
|
||||
|
||||
@@ -2,9 +2,6 @@ const path = require("path");
|
||||
require("dotenv").config({
|
||||
path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`)
|
||||
});
|
||||
let nodemailer = require("nodemailer");
|
||||
let aws = require("@aws-sdk/client-ses");
|
||||
let { defaultProvider } = require("@aws-sdk/credential-provider-node");
|
||||
const InstanceManager = require("../utils/instanceMgr").default;
|
||||
const logger = require("../utils/logger");
|
||||
const client = require("../graphql-client/graphql-client").client;
|
||||
@@ -12,20 +9,7 @@ const queries = require("../graphql-client/queries");
|
||||
const generateEmailTemplate = require("./generateTemplate");
|
||||
const moment = require("moment-timezone");
|
||||
const { taskEmailQueue } = require("./tasksEmailsQueue");
|
||||
|
||||
const ses = new aws.SES({
|
||||
apiVersion: "latest",
|
||||
credentials: defaultProvider(),
|
||||
region: InstanceManager({
|
||||
imex: "ca-central-1",
|
||||
rome: "us-east-2"
|
||||
})
|
||||
});
|
||||
|
||||
const transporter = nodemailer.createTransport({
|
||||
SES: { ses, aws },
|
||||
sendingRate: InstanceManager({ imex: 40, rome: 10 })
|
||||
});
|
||||
const mailer = require("./mailer");
|
||||
|
||||
// Initialize the Tasks Email Queue
|
||||
const tasksEmailQueue = taskEmailQueue();
|
||||
@@ -124,6 +108,7 @@ const generateTemplateArgs = (title, priority, description, dueDate, bodyshop, j
|
||||
* @param html
|
||||
* @param taskIds
|
||||
* @param successCallback
|
||||
* @param requestInstance
|
||||
*/
|
||||
const sendMail = (type, to, subject, html, taskIds, successCallback, requestInstance) => {
|
||||
const fromEmails = InstanceManager({
|
||||
@@ -134,7 +119,7 @@ const sendMail = (type, to, subject, html, taskIds, successCallback, requestInst
|
||||
: "Rome Online <noreply@romeonline.io>"
|
||||
});
|
||||
|
||||
transporter.sendMail(
|
||||
mailer.sendMail(
|
||||
{
|
||||
from: fromEmails,
|
||||
to,
|
||||
@@ -151,8 +136,6 @@ const sendMail = (type, to, subject, html, taskIds, successCallback, requestInst
|
||||
}
|
||||
}
|
||||
);
|
||||
// }
|
||||
// });
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user