Skip to content

Commit

Permalink
Setup SendGrid Templates (#533)
Browse files Browse the repository at this point in the history
* refactor(dotenv): use esm import

* feat(email-service): setup email templates

* deps: bump @sendgrid/mail

* feat(environment): implement assertEnv

* feat(env): add dotenv to mocha

* ci: add test placeholders for env

* ci: update GH Actions versions
  • Loading branch information
AdrianAndersen authored Jul 9, 2024
1 parent bd29484 commit 9d97490
Show file tree
Hide file tree
Showing 18 changed files with 203 additions and 103 deletions.
24 changes: 12 additions & 12 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ jobs:
install:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "18"
node-version: "20"
cache: "yarn"
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Cache install
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ./node_modules/
key: ${{ github.sha }}-install
Expand All @@ -26,9 +26,9 @@ jobs:
runs-on: ubuntu-latest
needs: install
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Retrive install cache
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ./node_modules/
key: ${{ github.sha }}-install
Expand All @@ -39,9 +39,9 @@ jobs:
runs-on: ubuntu-latest
needs: install
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Retrive install cache
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ./node_modules/
key: ${{ github.sha }}-install
Expand All @@ -52,9 +52,9 @@ jobs:
runs-on: ubuntu-latest
needs: install
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Retrive install cache
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ./node_modules/
key: ${{ github.sha }}-install
Expand All @@ -65,9 +65,9 @@ jobs:
runs-on: ubuntu-latest
needs: install
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Retrive Install Cache
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ./node_modules/
key: ${{ github.sha }}-install
Expand Down
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
52 changes: 52 additions & 0 deletions src/config/environment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
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",
}

const testPlaceHolders: {
[key in BlEnvironment]?: string;
} = {
[BlEnvironment.SENDGRID_API_KEY]: "SG.placeholder",
[BlEnvironment.TWILIO_SMS_SID]: "AC.placeholder",
};

/**
*
*
* @param key the environment variable key
* @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): string {
const value = process.env[key];
if (process.env[BlEnvironment.NODE_ENV] === "test")
return testPlaceHolders[key] ?? "placeholder";
if (isNullish(value)) {
throw new BlError(`${key} is a required environment variable`).code(200);
}
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
Loading

0 comments on commit 9d97490

Please sign in to comment.