From 6bf850e5a8a76da9352ca70a3e0ec21087696745 Mon Sep 17 00:00:00 2001 From: Brennan Douglas Date: Mon, 12 Aug 2019 17:10:46 -0700 Subject: [PATCH 1/5] feat(clients): added client table and relationships --- db-init/init.sql | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/db-init/init.sql b/db-init/init.sql index 525788b..7a1693d 100644 --- a/db-init/init.sql +++ b/db-init/init.sql @@ -10,6 +10,15 @@ -- versions -- tasks +-- +-- Table structure for table `clients` +-- + +CREATE TABLE IF NOT EXISTS clients ( + id SERIAL NOT NULL PRIMARY KEY, + name VARCHAR(255) NOT NULL +) + -- -- Table structure for table `employees` -- @@ -21,7 +30,8 @@ CREATE TABLE IF NOT EXISTS employees ( username VARCHAR(255) NOT NULL UNIQUE, password VARCHAR(255) NOT NULL, phone CHAR(12) NULL, - admin BOOLEAN NOT NULL + admin BOOLEAN NOT NULL, + client_id INTEGER NOT NULL REFERENCES clients(id) ); -- @@ -32,7 +42,8 @@ CREATE TABLE IF NOT EXISTS actions ( id SERIAL NOT NULL PRIMARY KEY, name VARCHAR(255) NOT NULL, description TEXT NULL, - classname VARCHAR(20) NOT NULL + classname VARCHAR(20) NOT NULL, + client_id INTEGER NOT NULL REFERENCES clients(id) ); -- @@ -44,7 +55,8 @@ CREATE TABLE IF NOT EXISTS tanks ( name VARCHAR(255) NOT NULL, status VARCHAR(255) NOT NULL, in_use BOOLEAN NOT NULL, - update_user INTEGER NULL + update_user INTEGER NULL, + client_id INTEGER NOT NULL REFERENCES clients(id) ); CREATE TABLE IF NOT EXISTS tanks_audit ( @@ -56,7 +68,8 @@ CREATE TABLE IF NOT EXISTS tanks_audit ( name VARCHAR(255) NOT NULL, status VARCHAR(255) NOT NULL, in_use BOOLEAN NOT NULL, - update_user INTEGER NULL + update_user INTEGER NULL, + client_id INTEGER NOT NULL REFERENCES clients(id) ); -- @@ -69,7 +82,8 @@ CREATE TABLE IF NOT EXISTS recipes ( airplane_code VARCHAR(50) NOT NULL, yeast INT NULL, instructions JSONB NOT NULL, - update_user INTEGER NULL + update_user INTEGER NULL, + client_id INTEGER NOT NULL REFERENCES clients(id) ); CREATE TABLE IF NOT EXISTS recipes_audit ( @@ -82,7 +96,8 @@ CREATE TABLE IF NOT EXISTS recipes_audit ( airplane_code VARCHAR(50) NOT NULL, yeast INT NULL, instructions JSONB NOT NULL, - update_user INTEGER NULL + update_user INTEGER NULL, + client_id INTEGER NOT NULL REFERENCES clients(id) ); -- @@ -99,7 +114,8 @@ CREATE TABLE IF NOT EXISTS batches ( completed_on TIMESTAMPTZ NULL, recipe_id INTEGER NOT NULL REFERENCES recipes(id) , tank_id INTEGER NOT NULL REFERENCES tanks(id), - update_user INTEGER NULL + update_user INTEGER NULL, + client_id INTEGER NOT NULL REFERENCES clients(id) ); CREATE TABLE IF NOT EXISTS batches_audit ( @@ -116,7 +132,8 @@ CREATE TABLE IF NOT EXISTS batches_audit ( completed_on TIMESTAMPTZ NULL, recipe_id INTEGER NOT NULL, tank_id INTEGER NOT NULL, - update_user INTEGER NULL + update_user INTEGER NULL, + client_id INTEGER NOT NULL REFERENCES clients(id) ); -- From bb51b0a27fd99b4c6d0ad4a224b7f19e57ba98fb Mon Sep 17 00:00:00 2001 From: Brennan Douglas Date: Tue, 13 Aug 2019 14:47:59 -0700 Subject: [PATCH 2/5] fix(clients): remove references from audit tables --- db-init/init.sql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/db-init/init.sql b/db-init/init.sql index 7a1693d..626ca32 100644 --- a/db-init/init.sql +++ b/db-init/init.sql @@ -69,7 +69,7 @@ CREATE TABLE IF NOT EXISTS tanks_audit ( status VARCHAR(255) NOT NULL, in_use BOOLEAN NOT NULL, update_user INTEGER NULL, - client_id INTEGER NOT NULL REFERENCES clients(id) + client_id INTEGER NOT NULL ); -- @@ -97,7 +97,7 @@ CREATE TABLE IF NOT EXISTS recipes_audit ( yeast INT NULL, instructions JSONB NOT NULL, update_user INTEGER NULL, - client_id INTEGER NOT NULL REFERENCES clients(id) + client_id INTEGER NOT NULL ); -- @@ -133,7 +133,7 @@ CREATE TABLE IF NOT EXISTS batches_audit ( recipe_id INTEGER NOT NULL, tank_id INTEGER NOT NULL, update_user INTEGER NULL, - client_id INTEGER NOT NULL REFERENCES clients(id) + client_id INTEGER NOT NULL ); -- From 7190ccc9e9acec781b42a3e27202040aed1e9ae8 Mon Sep 17 00:00:00 2001 From: Brennan Douglas Date: Sat, 17 Aug 2019 14:58:40 -0700 Subject: [PATCH 3/5] feat(clients): update init data processes --- db-init/init.sql | 31 ++++++++++--------- src/components/actions/types.ts | 1 + .../batches/__tests__/controller.test.ts | 2 ++ src/components/batches/controller.ts | 1 + src/components/batches/types.ts | 1 + src/components/employees/types.ts | 1 + src/components/recipes/types.ts | 1 + src/components/tanks/types.ts | 1 + src/utils/initial_data.ts | 9 +++++- 9 files changed, 33 insertions(+), 15 deletions(-) diff --git a/db-init/init.sql b/db-init/init.sql index 626ca32..34c6b49 100644 --- a/db-init/init.sql +++ b/db-init/init.sql @@ -16,8 +16,9 @@ CREATE TABLE IF NOT EXISTS clients ( id SERIAL NOT NULL PRIMARY KEY, - name VARCHAR(255) NOT NULL -) + name VARCHAR(255) NOT NULL, + active BOOLEAN NOT NULL DEFAULT 't' +); -- -- Table structure for table `employees` @@ -373,18 +374,20 @@ $tasks_audit_trigger$ LANGUAGE plpgsql; CREATE TRIGGER tasks_audit_t AFTER INSERT OR UPDATE OR DELETE ON tasks FOR EACH ROW EXECUTE PROCEDURE tasks_audit_function(); - -INSERT INTO actions (name, description, classname) VALUES - ('Primary Fermentation', 'Primary Fermentation', 'primary-fermentation'), - ('Primary Adjuct Added', 'Primary Adjuct Added', 'primary-adjunct-add'), - ('Free Rise', 'Free Rise', 'free-rise'), - ('Cap', 'Cap', 'cap'), - ('Adjunct Added', 'Adjunct Added', 'adjunct-add'), - ('Exception', 'Exception', 'exception'), - ('Waiting for Diacetyl', 'Waiting for Diacetyl', 'wait-for-diacetyl'), - ('Crashed', 'Crashed', 'crashed'), - ('Yeast Pull', 'Yeast Pull', 'yeast-pull'), - ('No Action', 'No Action', 'no-action'); +INSERT INTO clients (name, active) VALUES + ('Ninkasi', 't'); + +INSERT INTO actions (name, description, classname, client_id) VALUES + ('Primary Fermentation', 'Primary Fermentation', 'primary-fermentation', 1), + ('Primary Adjuct Added', 'Primary Adjuct Added', 'primary-adjunct-add', 1), + ('Free Rise', 'Free Rise', 'free-rise', 1), + ('Cap', 'Cap', 'cap', 1), + ('Adjunct Added', 'Adjunct Added', 'adjunct-add', 1), + ('Exception', 'Exception', 'exception', 1), + ('Waiting for Diacetyl', 'Waiting for Diacetyl', 'wait-for-diacetyl', 1), + ('Crashed', 'Crashed', 'crashed', 1), + ('Yeast Pull', 'Yeast Pull', 'yeast-pull', 1), + ('No Action', 'No Action', 'no-action', 1); diff --git a/src/components/actions/types.ts b/src/components/actions/types.ts index 9083737..dba332e 100644 --- a/src/components/actions/types.ts +++ b/src/components/actions/types.ts @@ -2,4 +2,5 @@ export interface Action { id?: number; name: string; description: string; + client_id: number; } diff --git a/src/components/batches/__tests__/controller.test.ts b/src/components/batches/__tests__/controller.test.ts index 1cadca6..a78e250 100644 --- a/src/components/batches/__tests__/controller.test.ts +++ b/src/components/batches/__tests__/controller.test.ts @@ -111,6 +111,7 @@ describe("BatchesController ", () => { tank_id: 2, update_user: 2, volume: 2, + client_id: 2 }; request.body = batch; @@ -131,6 +132,7 @@ describe("BatchesController ", () => { tank_id: 2, update_user: 2, volume: 2, + client_id: 2 }; request.body = batch; diff --git a/src/components/batches/controller.ts b/src/components/batches/controller.ts index 62d194d..f409cda 100644 --- a/src/components/batches/controller.ts +++ b/src/components/batches/controller.ts @@ -120,6 +120,7 @@ export class BatchesController extends PostgresController implements IBatchesCon tank_id: Number(input.tank_id), update_user: Number(input.update_user), volume: Number(input.volume), + client_id: Number('client_id' in input ? input.client_id : 1) }; let { keys, values, escapes } = this.splitObjectKeyVals(batch); diff --git a/src/components/batches/types.ts b/src/components/batches/types.ts index 5956519..845dc8c 100644 --- a/src/components/batches/types.ts +++ b/src/components/batches/types.ts @@ -31,4 +31,5 @@ export interface Batch { recipe_id: number; tank_id: number; update_user?: number; + client_id: number; } diff --git a/src/components/employees/types.ts b/src/components/employees/types.ts index 8caa081..4e2bf6d 100644 --- a/src/components/employees/types.ts +++ b/src/components/employees/types.ts @@ -6,4 +6,5 @@ export interface Employee { password?: string; phone: string; admin: boolean; + client_id: number; } diff --git a/src/components/recipes/types.ts b/src/components/recipes/types.ts index 3cc85a3..33f4804 100644 --- a/src/components/recipes/types.ts +++ b/src/components/recipes/types.ts @@ -4,4 +4,5 @@ export interface Recipe { yeast: number; instructions: {}; update_user?: number; + client_id: number; } diff --git a/src/components/tanks/types.ts b/src/components/tanks/types.ts index 447b08c..77849b2 100644 --- a/src/components/tanks/types.ts +++ b/src/components/tanks/types.ts @@ -4,4 +4,5 @@ export interface Tank { status: string; in_use: boolean; update_user?: number; + client_id: number; } diff --git a/src/utils/initial_data.ts b/src/utils/initial_data.ts index f48e014..e91188b 100644 --- a/src/utils/initial_data.ts +++ b/src/utils/initial_data.ts @@ -64,6 +64,7 @@ async function insertCSVTestData() { status: "available", in_use: false, update_user: 1, + client_id: 1 }; tankIndexes[row.Tank] = Object.keys(tankIndexes).length + 1; } @@ -78,6 +79,7 @@ async function insertCSVTestData() { ratio: 3, }]), update_user: 1, + client_id: 1 }; recipeIndexes[row.Recipe] = Object.keys(recipeIndexes).length + 1; } @@ -93,6 +95,7 @@ async function insertCSVTestData() { recipe_id: recipeIndexes[row.Recipe], tank_id: tankIndexes[row.Tank], update_user: 1, + client_id: 1 }; batchIndexes[row.Batch] = Object.keys(batchIndexes).length + 1; } @@ -243,6 +246,7 @@ async function insertDevAdmin() { phone: "555-867-5309", admin: true, password: encryptPassword("password"), + client_id: 1 }; try { @@ -274,6 +278,7 @@ async function insertDevTanks() { status: "brewing", in_use: true, update_user: 1, + client_id: 1 }; if (i > 9) { tank.status = "available"; @@ -302,6 +307,7 @@ async function insertDevRecipes() { ingredient: "hops", ratio: `${i}`, }]), + client_id: 1 }; if (rows.length === 0) { const { keys, values, escapes } = recipeController.splitObjectKeyVals(recipe); @@ -333,6 +339,7 @@ async function insertDevBatches() { recipe_id: i, tank_id: i, update_user: 1, + client_id: 1 }; if (batchResult.rows.length === 0) { @@ -382,7 +389,7 @@ async function insertDevTasks() { action_id: (i % 9) + 1, employee_id: 1, added_on: new Date().toUTCString(), - update_user: 1, + update_user: 1 }; if (tasksResult.rows.length === 0) { From ecd11b7bb32206e72e8ba1f093e577c3c7e2e280 Mon Sep 17 00:00:00 2001 From: Brennan Douglas Date: Wed, 28 Aug 2019 21:47:21 -0700 Subject: [PATCH 4/5] feat(authorization): add clientId to auth token --- src/components/employees/controller.ts | 6 ++++-- src/global.d.ts | 1 + src/middleware/auth.ts | 11 +++++++---- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/components/employees/controller.ts b/src/components/employees/controller.ts index aa17102..7de18a8 100644 --- a/src/components/employees/controller.ts +++ b/src/components/employees/controller.ts @@ -77,7 +77,7 @@ export class EmployeeController extends PostgresController implements IEmployeeC } else { const { rows } = await this.create(keys, escapes, values, safeUserData); const returnedUser = rows[0]; - returnedUser.token = await generateAuthToken(returnedUser.username); + returnedUser.token = await generateAuthToken(returnedUser.username, returnedUser.client_id); res.status(201).json(rows[0]); } } catch (err) { @@ -99,11 +99,13 @@ export class EmployeeController extends PostgresController implements IEmployeeC res.status(401).send(Boom.unauthorized("Not authorized")); } else { const id = prevUser.rows[0].id; + const client_id = prevUser.rows[0].client_id; + const username = prevUser.rows[0].username; const stored = prevUser.rows[0].password; // tslint:disable-next-line:possible-timing-attack const match = password === stored; if (match) { - const token = await generateAuthToken(req.body.username); + const token = await generateAuthToken(username, client_id); res.status(200).json({ id, token, diff --git a/src/global.d.ts b/src/global.d.ts index a44165f..3518e58 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -4,6 +4,7 @@ declare global { namespace Express { interface Request { user: any; + clientId: any; } } } diff --git a/src/middleware/auth.ts b/src/middleware/auth.ts index 13d1b89..4e1379d 100644 --- a/src/middleware/auth.ts +++ b/src/middleware/auth.ts @@ -5,9 +5,12 @@ import { NextFunction, Request, Response } from "express"; import jwt, { VerifyErrors } from "jsonwebtoken"; // tslint:disable-next-line:no-any -export async function generateAuthToken(userID: any) { +export async function generateAuthToken(userId: any, clientId: any) { return new Promise((resolve, reject) => { - const payload = { sub: userID }; + const payload = { + userId, + clientId + }; jwt.sign( payload, process.env.AUTH_KEY as string, @@ -26,7 +29,6 @@ export async function generateAuthToken(userID: any) { } // tslint:disable: no-unsafe-any - export function requireAuthentication(req: Request, res: Response, next: NextFunction) { // tslint:disable-next-line:no-backbone-get-set-outside-model const authHeader = req.get("Authorization") || ""; @@ -37,7 +39,8 @@ export function requireAuthentication(req: Request, res: Response, next: NextFun jwt.verify(token, process.env.AUTH_KEY as string, (err: VerifyErrors, payload: any) => { if (!err) { // tslint:disable-next-line:no-unsafe-any - req.user = payload.sub; + req.user = payload.userId; + req.clientId = payload.clientId; next(); } else { res.status(401).send(Boom.unauthorized("Invalid authentication token")); From efacfa5d733c40f16b805093933284ebbd88be15 Mon Sep 17 00:00:00 2001 From: Dan Van Horn Date: Mon, 16 Sep 2019 19:55:26 -0700 Subject: [PATCH 5/5] chore: use object destructuring --- src/components/employees/controller.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/components/employees/controller.ts b/src/components/employees/controller.ts index 7de18a8..bbd1e7a 100644 --- a/src/components/employees/controller.ts +++ b/src/components/employees/controller.ts @@ -98,14 +98,11 @@ export class EmployeeController extends PostgresController implements IEmployeeC if (prevUser.rows.length === 0) { res.status(401).send(Boom.unauthorized("Not authorized")); } else { - const id = prevUser.rows[0].id; - const client_id = prevUser.rows[0].client_id; - const username = prevUser.rows[0].username; - const stored = prevUser.rows[0].password; + const { id, client_id, username: user, stored } = prevUser.rows[0]; // tslint:disable-next-line:possible-timing-attack const match = password === stored; if (match) { - const token = await generateAuthToken(username, client_id); + const token = await generateAuthToken(user, client_id); res.status(200).json({ id, token,