Skip to content
This repository has been archived by the owner on Dec 18, 2024. It is now read-only.

Setup SendGrid Templates #533

Merged
merged 7 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
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
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"prettier": "prettier --write . --ignore-path=.gitignore",
"prettier:check": "prettier --check . --ignore-path=.gitignore",
"lint": "eslint .",
"test": "mocha \"src/**/*.spec.ts\"",
"test": "NODE_ENV=test mocha \"src/**/*.spec.ts\"",
"load_fixtures": "mongodb-fixtures rebuild -u mongodb://127.0.0.1:27017/test"
},
"license": "ISC",
Expand All @@ -19,7 +19,7 @@
"@boklisten/bl-model": "^0.26.2",
"@boklisten/bl-post-office": "^0.5.56",
"@napi-rs/image": "^1.8.0",
"@sendgrid/mail": "^7.7.0",
"@sendgrid/mail": "^8.1.3",
"canvas": "^2.11.2",
"cookie-parser": "^1.4.5",
"cors": "^2.8.5",
Expand Down
9 changes: 5 additions & 4 deletions src/auth/facebook/facebook.auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Profile, Strategy, StrategyOptions } from "passport-facebook";

import { APP_CONFIG } from "../../application-config";
import { ApiPath } from "../../config/api-path";
import { assertEnv, BlEnvironment } from "../../config/environment";
import { SEResponseHandler } from "../../response/se.response.handler";
import { UserProvider } from "../user/user-provider/user-provider";

Expand All @@ -20,10 +21,10 @@ export class FacebookAuth {
this.apiPath = new ApiPath();

this.facebookPassportStrategySettings = {
clientID: process.env["FACEBOOK_CLIENT_ID"] ?? "",
clientSecret: process.env["FACEBOOK_SECRET"] ?? "",
clientID: assertEnv(BlEnvironment.FACEBOOK_CLIENT_ID),
clientSecret: assertEnv(BlEnvironment.FACEBOOK_SECRET),
callbackURL:
process.env["BL_API_URI"] +
assertEnv(BlEnvironment.BL_API_URI) +
this.apiPath.createPath("auth/facebook/callback"),
profileFields: ["id", "email", "name"],
enableProof: true,
Expand Down Expand Up @@ -98,7 +99,7 @@ export class FacebookAuth {
(err, tokens, blError: BlError) => {
if (!tokens && (err || blError)) {
return res.redirect(
process.env["CLIENT_URI"] +
assertEnv(BlEnvironment.CLIENT_URI) +
APP_CONFIG.path.client.auth.socialLoginFailure,
);
}
Expand Down
11 changes: 6 additions & 5 deletions src/auth/google/google.auth.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { BlError } from "@boklisten/bl-model";
import { Router } from "express";
import passport from "passport";
import { Strategy as GoogleStrategy, Profile } from "passport-google-oauth20";
import { Profile, Strategy as GoogleStrategy } from "passport-google-oauth20";

import { APP_CONFIG } from "../../application-config";
import { ApiPath } from "../../config/api-path";
import { assertEnv, BlEnvironment } from "../../config/environment";
import { SEResponseHandler } from "../../response/se.response.handler";
import { UserProvider } from "../user/user-provider/user-provider";

Expand All @@ -28,11 +29,11 @@ export class GoogleAuth {
passport.use(
new GoogleStrategy(
{
clientID: process.env["GOOGLE_CLIENT_ID"] ?? "",
clientSecret: process.env["GOOGLE_SECRET"] ?? "",
clientID: assertEnv(BlEnvironment.GOOGLE_CLIENT_ID),
clientSecret: assertEnv(BlEnvironment.GOOGLE_SECRET),
passReqToCallback: true,
callbackURL:
process.env["BL_API_URI"] +
assertEnv(BlEnvironment.BL_API_URI) +
this.apiPath.createPath("auth/google/callback"),
},
async (req, accessToken, refreshToken, profile, done) => {
Expand Down Expand Up @@ -95,7 +96,7 @@ export class GoogleAuth {

if (!tokens && (err || blError)) {
return res.redirect(
process.env["CLIENT_URI"] +
assertEnv(BlEnvironment.CLIENT_URI) +
APP_CONFIG.path.client.auth.socialLoginFailure,
);
}
Expand Down
4 changes: 3 additions & 1 deletion src/auth/token/access-token/access-token.secret.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { assertEnv, BlEnvironment } from "../../../config/environment";

export class AccessTokenSecret {
public get(): string {
return process.env["ACCESS_TOKEN_SECRET"] ?? "hello this is dog";
return assertEnv(BlEnvironment.ACCESS_TOKEN_SECRET);
}
}
6 changes: 3 additions & 3 deletions src/auth/token/refresh/refresh-token.secret.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { assertEnv, BlEnvironment } from "../../../config/environment";

export class RefreshTokenSecret {
get(): string {
return (
process.env["REFRESH_TOKEN_SECRET"] ?? "secretly a string is just chars"
);
return assertEnv(BlEnvironment.REFRESH_TOKEN_SECRET);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import moment from "moment";

import { BringDelivery } from "./bringDelivery";
import { APP_CONFIG } from "../../../../application-config";
import { assertEnv, BlEnvironment } from "../../../../config/environment";
import { isNullish } from "../../../../helper/typescript-helpers";
import { HttpHandler } from "../../../../http/http.handler";

Expand Down Expand Up @@ -58,8 +59,8 @@ export class BringDeliveryService {
}

const bringAuthHeaders = {
"X-MyBring-API-Key": process.env["BRING_API_KEY"],
"X-MyBring-API-Uid": process.env["BRING_API_ID"],
"X-MyBring-API-Key": assertEnv(BlEnvironment.BRING_API_KEY),
"X-MyBring-API-Uid": assertEnv(BlEnvironment.BRING_API_ID),
};

const postalInfoUrl = `https://api.bring.com/pickuppoint/api/postalCode/NO/getCityAndType/${shipmentAddress.postalCode}.json`;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { BlapiResponse, BlError } from "@boklisten/bl-model";

import { assertEnv, BlEnvironment } from "../../../config/environment";
import { isNullish } from "../../../helper/typescript-helpers";
import { HttpHandler } from "../../../http/http.handler";
import { Operation } from "../../../operation/operation";
Expand Down Expand Up @@ -47,8 +48,8 @@ export class PostalCodeLookupOperation implements Operation {
throw new BlError(`Malformed PostalCodeSpec`).code(701);
}
const bringAuthHeaders = {
"X-MyBring-API-Key": process.env["BRING_API_KEY"],
"X-MyBring-API-Uid": process.env["BRING_API_ID"],
"X-MyBring-API-Key": assertEnv(BlEnvironment.BRING_API_KEY),
"X-MyBring-API-Uid": assertEnv(BlEnvironment.BRING_API_ID),
};
try {
const response = (await this.httpHandler.getWithQuery(
Expand Down
9 changes: 3 additions & 6 deletions src/config/api-path.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
import { IncomingHttpHeaders } from "http";

import { BlEnvironment, assertEnv } from "./environment";
import { APP_CONFIG } from "../application-config";

export class ApiPath {
private readonly baseHost: string;

constructor() {
if (process.env["NODE_ENV"] == "production") {
if (assertEnv(BlEnvironment.NODE_ENV) === "production") {
this.baseHost = APP_CONFIG.path.host;
} else {
this.baseHost = APP_CONFIG.path.local.host;
}
}

private getBasePath(): string {
return process.env["SERVER_PATH"] ?? "";
}

public createPath(customPath: string): string {
return this.getBasePath() + customPath;
return assertEnv(BlEnvironment.SERVER_PATH) + customPath;
}

public retrieveRefererPath(reqHeaders: IncomingHttpHeaders) {
Expand Down
49 changes: 49 additions & 0 deletions src/config/environment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { BlError } from "@boklisten/bl-model";

import { isNullish } from "../helper/typescript-helpers";

export enum BlEnvironment {
PORT = "PORT",
SERVER_PATH = "SERVER_PATH",
NODE_ENV = "NODE_ENV",
LOG_LEVEL = "LOG_LEVEL",
URI_WHITELIST = "URI_WHITELIST",
ACCESS_TOKEN_SECRET = "ACCESS_TOKEN_SECRET",
REFRESH_TOKEN_SECRET = "REFRESH_TOKEN_SECRET",
BL_API_URI = "BL_API_URI",
CLIENT_URI = "CLIENT_URI",
MONGODB_URI = "MONGODB_URI",
DIBS_SECRET_KEY = "DIBS_SECRET_KEY",
DIBS_URI = "DIBS_URI",
FACEBOOK_CLIENT_ID = "FACEBOOK_CLIENT_ID",
FACEBOOK_SECRET = "FACEBOOK_SECRET",
GOOGLE_CLIENT_ID = "GOOGLE_CLIENT_ID",
GOOGLE_SECRET = "GOOGLE_SECRET",
SENDGRID_API_KEY = "SENDGRID_API_KEY",
TWILIO_SMS_AUTH_TOKEN = "TWILIO_SMS_AUTH_TOKEN",
TWILIO_SMS_SID = "TWILIO_SMS_SID",
BRING_API_KEY = "BRING_API_KEY",
BRING_API_ID = "BRING_API_ID",
}

/**
*
*
* @param key the environment variable key
* @param callback optional callback that runs if the environment variable is present, and we are not in a test
* @returns the value of the environment variable if the environment variable is present, and we are not in a test
*
* @throws BlError if the environment variable is not present, and we are not in a test
*/
export function assertEnv(
key: BlEnvironment,
callback?: (value: string) => unknown,
LarsSelbekk marked this conversation as resolved.
Show resolved Hide resolved
): string {
const value = process.env[key];
if (process.env[BlEnvironment.NODE_ENV] === "test") return "placeholder";
if (isNullish(value)) {
throw new BlError(`${key} is a required environment variable`).code(200);
}
callback?.(value);
return value;
}
12 changes: 6 additions & 6 deletions src/logger/logger.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import moment from "moment";
import { createLogger, format, transports } from "winston";

import { assertEnv, BlEnvironment } from "../config/environment";

function formatTimestamp(timestamp: string) {
return moment(timestamp).format("HH:mm:ss.SSS");
}
Expand All @@ -19,10 +21,8 @@ export const logger = createLogger({
format: format.combine(
format.printf((info) => {
const colorizer = format.colorize();
if (
process.env["NODE_ENV"] === "production" ||
process.env["NODE_ENV"] === "dev"
) {
const nodeEnv = assertEnv(BlEnvironment.NODE_ENV);
if (nodeEnv === "production" || nodeEnv === "dev") {
return `${info.level} ${info.message}`;
}
return colorizer.colorize(
Expand All @@ -31,12 +31,12 @@ export const logger = createLogger({
);
}),
format.colorize({
all: process.env["NODE_ENV"] !== "production",
all: assertEnv(BlEnvironment.NODE_ENV) !== "production",
}),
),
transports: [
new transports.Console({
level: process.env["LOG_LEVEL"] ?? "info",
level: assertEnv(BlEnvironment.LOG_LEVEL),
handleExceptions: true,
}),
],
Expand Down
54 changes: 40 additions & 14 deletions src/messenger/email/email-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,35 @@ import { EmailOrder } from "@boklisten/bl-email/dist/ts/template/email-order";
import { EmailSetting } from "@boklisten/bl-email/dist/ts/template/email-setting";
import { EmailUser } from "@boklisten/bl-email/dist/ts/template/email-user";
import {
BlError,
CustomerItem,
Delivery,
Item,
Message,
Order,
OrderItem,
UserDetail,
CustomerItem,
Item,
Message,
BlError,
} from "@boklisten/bl-model";
import {
Recipient,
ItemList,
MessageOptions,
PostOffice,
postOffice,
ItemList,
PostOffice,
Recipient,
} from "@boklisten/bl-post-office";
import sgMail from "@sendgrid/mail";

import { EMAIL_SETTINGS } from "./email-settings";
import { OrderEmailHandler } from "./order-email/order-email-handler";
import { dateService } from "../../blc/date.service";
import { BlCollectionName } from "../../collections/bl-collection";
import { itemSchema } from "../../collections/item/item.schema";
import { assertEnv, BlEnvironment } from "../../config/environment";
import { logger } from "../../logger/logger";
import { BlDocumentStorage } from "../../storage/blDocumentStorage";
import {
MessengerService,
CustomerDetailWithCustomerItem,
MessengerService,
} from "../messenger-service";

export class EmailService implements MessengerService {
Expand All @@ -43,11 +45,12 @@ export class EmailService implements MessengerService {
itemStorage?: BlDocumentStorage<Item>,
inputPostOffice?: PostOffice,
) {
assertEnv(BlEnvironment.SENDGRID_API_KEY, (v) => sgMail.setApiKey(v));
this._emailHandler = emailHandler
? emailHandler
: new EmailHandler({
sendgrid: {
apiKey: process.env["SENDGRID_API_KEY"] ?? "",
apiKey: assertEnv(BlEnvironment.SENDGRID_API_KEY),
},
locale: "nb",
});
Expand Down Expand Up @@ -505,13 +508,16 @@ export class EmailService implements MessengerService {
userId: customerDetail.id,
};

let emailVerificationUri = process.env["CLIENT_URI"] ?? "localhost:4200/";
let emailVerificationUri = assertEnv(BlEnvironment.CLIENT_URI);
emailVerificationUri +=
EMAIL_SETTINGS.types.emailConfirmation.path + confirmationCode;

await this._emailHandler.sendEmailVerification(
await this.sendMail(
emailSetting,
emailVerificationUri,
EMAIL_SETTINGS.types.emailConfirmation.templateId,
{
emailVerificationUri,
},
);
}

Expand All @@ -528,7 +534,7 @@ export class EmailService implements MessengerService {
userId: userId,
};

let passwordResetUri = process.env["CLIENT_URI"] ?? "localhost:4200/";
let passwordResetUri = assertEnv(BlEnvironment.CLIENT_URI);
passwordResetUri +=
EMAIL_SETTINGS.types.passwordReset.path +
pendingPasswordResetId +
Expand All @@ -553,10 +559,30 @@ export class EmailService implements MessengerService {
};
await this._emailHandler.sendGuardianSignatureRequest(
emailSetting,
(process.env["CLIENT_URI"] ?? "localhost:4200/") +
assertEnv(BlEnvironment.CLIENT_URI) +
EMAIL_SETTINGS.types.guardianSignature.path +
customerDetail.id,
branchName,
);
}

private async sendMail(
emailSetting: EmailSetting,
templateId: string,
dynamicTemplateData: Record<string, string>,
) {
try {
await sgMail.send({
LarsSelbekk marked this conversation as resolved.
Show resolved Hide resolved
from: emailSetting.fromEmail,
to: emailSetting.toEmail,
templateId,
dynamicTemplateData,
});
logger.info("Successfully sent email to " + emailSetting.toEmail);
} catch (error) {
logger.error(
`Failed to send email to ${emailSetting.toEmail}, error: ${error}`,
);
}
}
}
1 change: 1 addition & 0 deletions src/messenger/email/email-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const EMAIL_SETTINGS = {
fromEmail: "ikkesvar@boklisten.no",
subject: "Bekreft e-posten din hos Boklisten.no",
path: "auth/email/confirm/",
templateId: "d-8734d0fdf5fc4d99bf22553c3a0c724a",
},
passwordReset: {
fromEmail: "ikkesvar@boklisten.no",
Expand Down
Loading
Loading