From 411f27e4c05f713df2e379183629972241501d78 Mon Sep 17 00:00:00 2001 From: jtm029 <43485929+jtm029@users.noreply.github.com> Date: Tue, 18 Feb 2020 14:42:53 -0600 Subject: [PATCH 01/40] Added the employee/active users models w/ some starter code --- .../activeUsers/validateActiveUserCommand.ts | 21 ++++ .../employees/helpers/employeeHelper.ts | 10 ++ .../commands/models/activeUserModel.ts | 89 ++++++++++++++ .../models/constants/databaseNames.ts | 25 +++- .../commands/models/constants/entityTypes.ts | 6 + .../commands/models/employeeModel.ts | 109 ++++++++++++++++++ src/controllers/typeDefinitions.ts | 34 ++++++ 7 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 src/controllers/commands/activeUsers/validateActiveUserCommand.ts create mode 100644 src/controllers/commands/employees/helpers/employeeHelper.ts create mode 100644 src/controllers/commands/models/activeUserModel.ts create mode 100644 src/controllers/commands/models/constants/entityTypes.ts create mode 100644 src/controllers/commands/models/employeeModel.ts diff --git a/src/controllers/commands/activeUsers/validateActiveUserCommand.ts b/src/controllers/commands/activeUsers/validateActiveUserCommand.ts new file mode 100644 index 0000000..4c9d23a --- /dev/null +++ b/src/controllers/commands/activeUsers/validateActiveUserCommand.ts @@ -0,0 +1,21 @@ +import { ActiveUserModel } from "../models/activeUserModel"; +import { Resources, ResourceKey } from "../../../resourceLookup"; +import * as ActiveUserRepository from "../models/activeUserModel"; +import { CommandResponse, ActiveUser } from "../../typeDefinitions"; + +export const execute = async (sessionKey: string): Promise> => { + return ActiveUserRepository.queryBySessionKey(sessionKey) + .then((queriedActiveUser: (ActiveUserModel | null)): Promise> => { + if (!queriedActiveUser) { + return Promise.reject(>{ + status: 404, + message: Resources.getString(ResourceKey.USER_NOT_FOUND) + }); + } + + return Promise.resolve(>{ + status: 200, + data: queriedActiveUser + }); + }); +}; \ No newline at end of file diff --git a/src/controllers/commands/employees/helpers/employeeHelper.ts b/src/controllers/commands/employees/helpers/employeeHelper.ts new file mode 100644 index 0000000..82b603b --- /dev/null +++ b/src/controllers/commands/employees/helpers/employeeHelper.ts @@ -0,0 +1,10 @@ + +import { EmployeeClassification } from "../../models/constants/entityTypes"; + +export const hashString = (toHash: string): string => { + return ""; // TODO: Look at https://nodejs.org/docs/latest-v12.x/api/crypto.html#crypto_crypto_createhash_algorithm_options as one option +}; + +export const isElevatedUser = (employeeClassification: EmployeeClassification): boolean => { + return false; // TODO: Determine if an employee is an elevated user by their classification +}; \ No newline at end of file diff --git a/src/controllers/commands/models/activeUserModel.ts b/src/controllers/commands/models/activeUserModel.ts new file mode 100644 index 0000000..8865062 --- /dev/null +++ b/src/controllers/commands/models/activeUserModel.ts @@ -0,0 +1,89 @@ +import Sequelize from "sequelize"; +import { DatabaseConnection } from "./databaseConnection"; +import { ActiveUserFieldName, DatabaseTableName } from "./constants/databaseNames"; +import { Model, DataTypes, InitOptions, ModelAttributes, ModelAttributeColumnOptions } from "sequelize"; + +export class ActiveUserModel extends Model { + public name!: string; + public employeeId!: string; + public sessionKey!: string; + public classification!: number; + + public readonly id!: string; + public readonly createdOn!: Date; +} + +ActiveUserModel.init( + { + id: { + field: ActiveUserFieldName.ID, + type: Sequelize.UUID, + autoIncrement: true, + primaryKey: true + }, + name: { + field: ActiveUserFieldName.Name, + type: new DataTypes.STRING(256), + allowNull: true + }, + createdOn: { + field: ActiveUserFieldName.CreatedOn, + type: new DataTypes.DATE(), + allowNull: true + }, + employeeId: { + field: ActiveUserFieldName.EmployeeId, + type: Sequelize.UUID, + allowNull: true + }, + sessionKey: { + field: ActiveUserFieldName.SessionKey, + type: new DataTypes.STRING(128), + allowNull: true + }, + classification: { + field: ActiveUserFieldName.Classification, + type: Sequelize.INTEGER, + allowNull: true + } + }, { + timestamps: false, + freezeTableName: true, + sequelize: DatabaseConnection, + tableName: DatabaseTableName.ACTIVE_USER + }); + + +// Database interaction +export const queryById = async ( + id: string, + queryTransaction?: Sequelize.Transaction +): Promise => { + + return ActiveUserModel.findOne({ + transaction: queryTransaction, + where: { id: id } + }); +}; + +export const queryBySessionKey = async ( + sessionKey: string, + queryTransaction?: Sequelize.Transaction +): Promise => { + + return ActiveUserModel.findOne({ + transaction: queryTransaction, + where: { sessionKey: sessionKey } + }); +}; + +export const queryByEmployeeId = async ( + employeeId: string, + queryTransaction?: Sequelize.Transaction +): Promise => { + + return ActiveUserModel.findOne({ + transaction: queryTransaction, + where: { employeeId: employeeId } + }); +}; \ No newline at end of file diff --git a/src/controllers/commands/models/constants/databaseNames.ts b/src/controllers/commands/models/constants/databaseNames.ts index 5d7afd1..559f4a9 100644 --- a/src/controllers/commands/models/constants/databaseNames.ts +++ b/src/controllers/commands/models/constants/databaseNames.ts @@ -1,5 +1,7 @@ export enum DatabaseTableName { - PRODUCT = "product" + PRODUCT = "product", + EMPLOYEE = "employee", + ACTIVE_USER = "activeuser" } /***************************************/ @@ -9,3 +11,24 @@ export enum ProductFieldName { CREATED_ON = "createdon", LOOKUP_CODE = "lookupcode" } + +export enum EmployeeFieldName { + ID = "id", + Active = "active", + Password = "password", + LastName = "lastname", + CreatedOn = "createdon", + FirstName = "firstname", + ManagerId = "managerid", + EmployeeId = "employeeid", + Classification = "classification" +} + +export enum ActiveUserFieldName { + ID = "id", + Name = "name", + CreatedOn = "createdon", + EmployeeId = "employeeid", + SessionKey = "sessionkey", + Classification = "classification" +} \ No newline at end of file diff --git a/src/controllers/commands/models/constants/entityTypes.ts b/src/controllers/commands/models/constants/entityTypes.ts new file mode 100644 index 0000000..b3265a6 --- /dev/null +++ b/src/controllers/commands/models/constants/entityTypes.ts @@ -0,0 +1,6 @@ +export enum EmployeeClassification { + NotDefined = -1, + Cashier = 101, + ShiftManager = 501, + GeneralManager = 701 +} \ No newline at end of file diff --git a/src/controllers/commands/models/employeeModel.ts b/src/controllers/commands/models/employeeModel.ts new file mode 100644 index 0000000..04671ef --- /dev/null +++ b/src/controllers/commands/models/employeeModel.ts @@ -0,0 +1,109 @@ +import Sequelize from "sequelize"; +import { DatabaseConnection } from "./databaseConnection"; +import { EmployeeFieldName, DatabaseTableName } from "./constants/databaseNames"; +import { Model, DataTypes, InitOptions, ModelAttributes, ModelAttributeColumnOptions } from "sequelize"; + +export class EmployeeModel extends Model { + public active!: boolean; + public lastName!: string; + public password!: Buffer; + public firstName!: string; + public managerId!: string; + public employeeId!: number; + public classification!: number; + + public readonly id!: string; + public readonly createdOn!: Date; +} + +EmployeeModel.init( + { + id: { + field: EmployeeFieldName.ID, + type: Sequelize.UUID, + autoIncrement: true, + primaryKey: true + }, + active: { + field: EmployeeFieldName.Active, + type: Sequelize.BOOLEAN, + allowNull: true + }, + lastName: { + field: EmployeeFieldName.LastName, + type: new DataTypes.STRING(128), + allowNull: true + }, + password: { + field: EmployeeFieldName.Password, + type: Sequelize.BLOB, + allowNull: true + }, + createdOn: { + field: EmployeeFieldName.CreatedOn, + type: new DataTypes.DATE(), + allowNull: true + }, + firstName: { + field: EmployeeFieldName.FirstName, + type: new DataTypes.STRING(128), + allowNull: true + }, + managerId: { + field: EmployeeFieldName.ManagerId, + type: Sequelize.UUID, + allowNull: true + }, + employeeId: { + field: EmployeeFieldName.EmployeeId, + type: Sequelize.INTEGER, + allowNull: true + }, + classification: { + field: EmployeeFieldName.Classification, + type: Sequelize.INTEGER, + allowNull: true + } + }, { + timestamps: false, + freezeTableName: true, + sequelize: DatabaseConnection, + tableName: DatabaseTableName.EMPLOYEE + }); + + +// Database interaction +export const queryById = async ( + id: string, + queryTransaction?: Sequelize.Transaction +): Promise => { + + return EmployeeModel.findOne({ + transaction: queryTransaction, + where: { id: id } + }); +}; + +export const queryByEmployeeId = async ( + employeeId: number, + queryTransaction?: Sequelize.Transaction +): Promise => { + + return EmployeeModel.findOne({ + transaction: queryTransaction, + where: { employeeId: employeeId } + }); +}; + +export const queryActive = async (): Promise => { + return EmployeeModel.findAll({ + order: [ [EmployeeFieldName.CreatedOn, "ASC"] ], + where: { active: true } + }); +}; + +export const queryActiveExists = async (): Promise => { + return EmployeeModel.findOne({ + where: { active: true } + }); +}; \ No newline at end of file diff --git a/src/controllers/typeDefinitions.ts b/src/controllers/typeDefinitions.ts index cb86ecb..22ee42b 100644 --- a/src/controllers/typeDefinitions.ts +++ b/src/controllers/typeDefinitions.ts @@ -4,6 +4,17 @@ export interface ProductSaveRequest { count: number; lookupCode: string; } + +export interface EmployeeSaveRequest { + id?: string; + active: boolean; + lastName: string; + password: string; + firstName: string; + managerId?: string; + classification: number; + isInitialEmployee?: boolean; +} // End request object definitions // Response object definitions @@ -14,6 +25,29 @@ export interface Product { createdOn: string; lookupCode: string; } + +export interface Employee { + id: string; + active: boolean; + lastName: string; + createdOn: Date; + firstName: string; + managerId: string; + employeeId: string; + classification: number; +} + +export interface ActiveUser { + id: string; + name: string; + employeeId: string; + classification: number; +} + +export interface EmployeeType { + value: number; + label: string; +} // End response data object definitions // Page response data From a7d1e6b009067774218f48bd6db4f485778a9eef Mon Sep 17 00:00:00 2001 From: Dalynn Hatch Date: Wed, 19 Feb 2020 18:08:03 -0600 Subject: [PATCH 02/40] fixed ts lint error --- src/controllers/commands/employees/helpers/employeeHelper.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/controllers/commands/employees/helpers/employeeHelper.ts b/src/controllers/commands/employees/helpers/employeeHelper.ts index 82b603b..e5f200a 100644 --- a/src/controllers/commands/employees/helpers/employeeHelper.ts +++ b/src/controllers/commands/employees/helpers/employeeHelper.ts @@ -1,4 +1,3 @@ - import { EmployeeClassification } from "../../models/constants/entityTypes"; export const hashString = (toHash: string): string => { From 25026c046ca5ea41478a6f9e5e1b500ec96e14e3 Mon Sep 17 00:00:00 2001 From: Dalynn Hatch Date: Thu, 20 Feb 2020 13:11:31 -0600 Subject: [PATCH 03/40] baseline for main menu view --- public/images/Sign-Out.png | Bin 0 -> 417 bytes public/scripts/mainMenu.js | 0 src/controllers/lookups/routingLookup.ts | 6 ++- src/controllers/mainMenuRouteController.ts | 27 +++++++++++ src/controllers/typeDefinitions.ts | 4 ++ src/routes/mainMenuRoutes.ts | 9 ++++ views/mainMenu.ejs | 53 +++++++++++++++++++++ 7 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 public/images/Sign-Out.png create mode 100644 public/scripts/mainMenu.js create mode 100644 src/controllers/mainMenuRouteController.ts create mode 100644 src/routes/mainMenuRoutes.ts create mode 100644 views/mainMenu.ejs diff --git a/public/images/Sign-Out.png b/public/images/Sign-Out.png new file mode 100644 index 0000000000000000000000000000000000000000..82fe8695ab00a4cdbd2b3f95f065fd7acbd108ec GIT binary patch literal 417 zcmV;S0bc%zP)7GIp>_a(3m+}_QaKE&z3o3q#8Dyh{QRup`m9ZI--K<7}2X0QOT_6(UfB~ zfFo0iTM!k^g5q{n0XmBNtqSl%ad9?U37>C(0R|XgKr-NscF2HNf}kBL;Dz{~wmv|? zI=>#2+PS61|;Y%W<1K>^~fyX^@&QOFD-2!R*p^-#O=;bI$z%Lh{J>>1jl;00000 LNkvXXu0mjf0)eri literal 0 HcmV?d00001 diff --git a/public/scripts/mainMenu.js b/public/scripts/mainMenu.js new file mode 100644 index 0000000..e69de29 diff --git a/src/controllers/lookups/routingLookup.ts b/src/controllers/lookups/routingLookup.ts index ed8001b..160f66b 100644 --- a/src/controllers/lookups/routingLookup.ts +++ b/src/controllers/lookups/routingLookup.ts @@ -8,13 +8,15 @@ export enum QueryParameterLookup { export enum ViewNameLookup { ProductDetail = "productDetail", - ProductListing = "productListing" + ProductListing = "productListing", + MainMenu = "mainMenu" } export enum RouteLookup { // Page routing - ProductListing = "/", + ProductListing = "/productListing", ProductDetail = "/productDetail", + MainMenu = "/", // Page routing - parameters ProductIdParameter = "/:productId", diff --git a/src/controllers/mainMenuRouteController.ts b/src/controllers/mainMenuRouteController.ts new file mode 100644 index 0000000..afd9284 --- /dev/null +++ b/src/controllers/mainMenuRouteController.ts @@ -0,0 +1,27 @@ +import { Request, Response } from "express"; +import { ViewNameLookup } from "./lookups/routingLookup"; +import { MainMenuPageResponse } from "./typeDefinitions"; + +const processStartMainMenuError = (error: any, res: Response): void => { +res.setHeader( +"Cache-Control", +"no-cache, max-age=0, must-revalidate, no-store"); + +return res.status((error.status || 500)) +.render( +ViewNameLookup.MainMenu, +{ +isElevatedUser: false, +errorMessage: (error.message) +}); +}; + +export const start = async (req: Request, res: Response) => { +res.setHeader("Cache-Control", "no-cache, max-age=0, must-revalidate, no-store"); + +return res.render( +ViewNameLookup.MainMenu, +{ +isElevatedUser: false +}); +}; diff --git a/src/controllers/typeDefinitions.ts b/src/controllers/typeDefinitions.ts index 22ee42b..275a78d 100644 --- a/src/controllers/typeDefinitions.ts +++ b/src/controllers/typeDefinitions.ts @@ -64,6 +64,10 @@ export interface ProductListingPageResponse extends PageResponse { products: Product[]; isElevatedUser: boolean; } + +export interface MainMenuPageResponse extends PageResponse { + isElevatedUser: boolean; +} // End page response data // API response data diff --git a/src/routes/mainMenuRoutes.ts b/src/routes/mainMenuRoutes.ts new file mode 100644 index 0000000..22aeddc --- /dev/null +++ b/src/routes/mainMenuRoutes.ts @@ -0,0 +1,9 @@ +import express from "express"; +import { RouteLookup } from "../controllers/lookups/routingLookup"; +import * as MainMenuRouteController from "../controllers/mainMenuRouteController"; + +function mainMenuRoutes(server: express.Express) { + server.get(RouteLookup.MainMenu, MainMenuRouteController.start); +} + +module.exports.routes = mainMenuRoutes; \ No newline at end of file diff --git a/views/mainMenu.ejs b/views/mainMenu.ejs new file mode 100644 index 0000000..048fad1 --- /dev/null +++ b/views/mainMenu.ejs @@ -0,0 +1,53 @@ + + + + Register - Main Menu + + + + + + + + + + +
+

Main Menu

+
+ +
+
class="hidden" <% } %>> +

+ <% if (locals.errorMessage && (locals.errorMessage !== "")) { %> + <%= locals.errorMessage %> + <% } %> +

+
+ + +
+ + + + + + + + \ No newline at end of file From ee518ba2ab0488b5a7b1f64b20f676ffe3e4c0b8 Mon Sep 17 00:00:00 2001 From: Fernando Arreola Date: Thu, 20 Feb 2020 20:47:26 -0600 Subject: [PATCH 04/40] Creating command directory and objects --- src/controllers/commands/employees/employeeCreateCommand.ts | 3 +++ src/controllers/commands/employees/employeeQuery.ts | 3 +++ src/controllers/commands/employees/employeeUpdateCommand.ts | 3 +++ 3 files changed, 9 insertions(+) create mode 100644 src/controllers/commands/employees/employeeCreateCommand.ts create mode 100644 src/controllers/commands/employees/employeeQuery.ts create mode 100644 src/controllers/commands/employees/employeeUpdateCommand.ts diff --git a/src/controllers/commands/employees/employeeCreateCommand.ts b/src/controllers/commands/employees/employeeCreateCommand.ts new file mode 100644 index 0000000..1bc01b7 --- /dev/null +++ b/src/controllers/commands/employees/employeeCreateCommand.ts @@ -0,0 +1,3 @@ +export class employeeCreateCommand { + +} \ No newline at end of file diff --git a/src/controllers/commands/employees/employeeQuery.ts b/src/controllers/commands/employees/employeeQuery.ts new file mode 100644 index 0000000..505f7dc --- /dev/null +++ b/src/controllers/commands/employees/employeeQuery.ts @@ -0,0 +1,3 @@ +export class employeeQuery { + +} \ No newline at end of file diff --git a/src/controllers/commands/employees/employeeUpdateCommand.ts b/src/controllers/commands/employees/employeeUpdateCommand.ts new file mode 100644 index 0000000..459a8db --- /dev/null +++ b/src/controllers/commands/employees/employeeUpdateCommand.ts @@ -0,0 +1,3 @@ +export class employeeUpdateCommand { + +} \ No newline at end of file From ee1efe074b162d8b0c3cc9055be9973af326c43a Mon Sep 17 00:00:00 2001 From: thebluewagon Date: Thu, 20 Feb 2020 21:43:00 -0600 Subject: [PATCH 05/40] Started employee detail view. --- views/employeeDetail.ejs | 74 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 views/employeeDetail.ejs diff --git a/views/employeeDetail.ejs b/views/employeeDetail.ejs new file mode 100644 index 0000000..79376fa --- /dev/null +++ b/views/employeeDetail.ejs @@ -0,0 +1,74 @@ + + + + Register - Employee + + + + + + + + + + +
+

Employee Detail

+
+ +
+
class="hidden" <% } %>> +

+ <% if (locals.errorMessage && (locals.errorMessage !== "")) { %> + <%= locals.errorMessage %> + <% } %> +

+
+ +
+ + + + + + + + + + + class="hidden"<% } %>> + + + + + +
Employee ID: + +
+
+ + + + +
+ + + + + + \ No newline at end of file From 4eabcd4e2357a5f3b99243da6f16518b2b260993 Mon Sep 17 00:00:00 2001 From: osanabria Date: Thu, 20 Feb 2020 22:53:28 -0600 Subject: [PATCH 06/40] adding login and signup files. --- views/login.ejs | 0 views/signup.ejs | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 views/login.ejs create mode 100644 views/signup.ejs diff --git a/views/login.ejs b/views/login.ejs new file mode 100644 index 0000000..e69de29 diff --git a/views/signup.ejs b/views/signup.ejs new file mode 100644 index 0000000..e69de29 From ad58a7923159e823150b0c9c2a87e39b0d73f6af Mon Sep 17 00:00:00 2001 From: Fernando Arreola Date: Sat, 29 Feb 2020 13:29:47 -0600 Subject: [PATCH 07/40] initial commit --- .../employees/employeeCreateCommand.ts | 36 +++++++++++++++++-- src/controllers/typeDefinitions.ts | 3 +- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/controllers/commands/employees/employeeCreateCommand.ts b/src/controllers/commands/employees/employeeCreateCommand.ts index 1bc01b7..a0162c6 100644 --- a/src/controllers/commands/employees/employeeCreateCommand.ts +++ b/src/controllers/commands/employees/employeeCreateCommand.ts @@ -1,3 +1,33 @@ -export class employeeCreateCommand { - -} \ No newline at end of file +import Sequelize from "sequelize"; +import * as Helper from "../helpers/helper"; +import { EmployeeModel } from "../models/EmployeeModel"; +import * as EmployeeRepository from "../models/employeeModel"; +import * as DatabaseConnection from "../models/databaseConnection"; +import { CommandResponse, Employee, EmployeeSaveRequest } from "../../typeDefinitions"; + +// TODO: validate this request + +export const execute = async ( + saveEmployeeRequest: EmployeeSaveRequest +): Promise> => { + + const employeeToCreate: EmployeeModel = { + active: saveEmployeeRequest.active, + lastName: saveEmployeeRequest.lastName, + password: saveEmployeeRequest.password, + firstName: saveEmployeeRequest.firstName, + managerId: saveEmployeeRequest.managerId, + employeeId: saveEmployeeRequest.employeeId, + classification: saveEmployeeRequest.classification + }; + + + return DatabaseConnection.createTransaction() + .then((createTransaction: Sequelize.Transaction): Promise => { + createTransaction = createTransaction; + + return EmployeeRepository.queryByEmployeeId( + saveEmployeeRequest.id, + createTransaction) + }) +}; diff --git a/src/controllers/typeDefinitions.ts b/src/controllers/typeDefinitions.ts index 22ee42b..bfd5aed 100644 --- a/src/controllers/typeDefinitions.ts +++ b/src/controllers/typeDefinitions.ts @@ -6,10 +6,11 @@ export interface ProductSaveRequest { } export interface EmployeeSaveRequest { + employeeId: number; id?: string; active: boolean; lastName: string; - password: string; + password: Buffer; firstName: string; managerId?: string; classification: number; From fa9a4bba8381c451c7a3adeb3707022b7886b124 Mon Sep 17 00:00:00 2001 From: Fernando Arreola Garcia Date: Sat, 29 Feb 2020 15:40:54 -0600 Subject: [PATCH 08/40] completing saveEmployeeRequest functionality --- .../employees/employeeCreateCommand.ts | 53 +++++++++++++++++-- .../commands/models/employeeModel.ts | 3 +- src/controllers/typeDefinitions.ts | 2 +- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/controllers/commands/employees/employeeCreateCommand.ts b/src/controllers/commands/employees/employeeCreateCommand.ts index a0162c6..d6b3d1a 100644 --- a/src/controllers/commands/employees/employeeCreateCommand.ts +++ b/src/controllers/commands/employees/employeeCreateCommand.ts @@ -4,6 +4,8 @@ import { EmployeeModel } from "../models/EmployeeModel"; import * as EmployeeRepository from "../models/employeeModel"; import * as DatabaseConnection from "../models/databaseConnection"; import { CommandResponse, Employee, EmployeeSaveRequest } from "../../typeDefinitions"; +import { Resources, ResourceKey } from "../../../resourceLookup"; +import sequelize from "sequelize"; // TODO: validate this request @@ -21,13 +23,54 @@ export const execute = async ( classification: saveEmployeeRequest.classification }; + let createTransaction: Sequelize.Transaction; return DatabaseConnection.createTransaction() - .then((createTransaction: Sequelize.Transaction): Promise => { - createTransaction = createTransaction; + .then((createdTransaction: Sequelize.Transaction): Promise => { + createTransaction = createdTransaction; return EmployeeRepository.queryByEmployeeId( - saveEmployeeRequest.id, - createTransaction) - }) + saveEmployeeRequest.employeeId, + createTransaction); + }).then((queriedEmployee: (EmployeeModel | null)): Promise => { + if (queriedEmployee != null) { + return Promise.reject(>{ + status: 409, + message: Resources.getString(ResourceKey.EMPLOYEE_NOT_FOUND) + }); + } + + return EmployeeModel.create( + employeeToCreate, + { + transaction: createTransaction + }); + }).then((createdEmployee: EmployeeModel): CommandResponse => { + createTransaction.commit(); + + return > { + status: 201, + data: { + id: createdEmployee.id, + active: createdEmployee.active, + lastName: createdEmployee.lastName, + createdOn: createdEmployee.createdOn, + password: createdEmployee.password, + firstName: createdEmployee.firstName, + managerId: createdEmployee.managerId, + employeeId: createdEmployee.employeeId.toString(), + classification: createdEmployee.classification + } + }; + }).catch((error: any): Promise> => { + if (createTransaction != null) { + createTransaction.rollback(); + } + + return Promise.reject(>{ + status: (error.status || 500), + message: (error.message + || Resources.getString(ResourceKey.EMPLOYEE_UNABLE_TO_SAVE)) + }); + }); }; diff --git a/src/controllers/commands/models/employeeModel.ts b/src/controllers/commands/models/employeeModel.ts index 04671ef..ff098a6 100644 --- a/src/controllers/commands/models/employeeModel.ts +++ b/src/controllers/commands/models/employeeModel.ts @@ -6,11 +6,12 @@ import { Model, DataTypes, InitOptions, ModelAttributes, ModelAttributeColumnOpt export class EmployeeModel extends Model { public active!: boolean; public lastName!: string; - public password!: Buffer; + public password!: string; public firstName!: string; public managerId!: string; public employeeId!: number; public classification!: number; + public status!: number; public readonly id!: string; public readonly createdOn!: Date; diff --git a/src/controllers/typeDefinitions.ts b/src/controllers/typeDefinitions.ts index bfd5aed..d5ac173 100644 --- a/src/controllers/typeDefinitions.ts +++ b/src/controllers/typeDefinitions.ts @@ -10,7 +10,7 @@ export interface EmployeeSaveRequest { id?: string; active: boolean; lastName: string; - password: Buffer; + password: string; firstName: string; managerId?: string; classification: number; From de09f2e1af6c447daa5c88c0b60817e28c05a86c Mon Sep 17 00:00:00 2001 From: Dalynn Hatch Date: Sat, 29 Feb 2020 15:52:44 -0600 Subject: [PATCH 09/40] fix casing --- src/controllers/commands/employees/employeeCreateCommand.ts | 2 +- src/controllers/commands/employees/employeeQuery.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/commands/employees/employeeCreateCommand.ts b/src/controllers/commands/employees/employeeCreateCommand.ts index d6b3d1a..bc22451 100644 --- a/src/controllers/commands/employees/employeeCreateCommand.ts +++ b/src/controllers/commands/employees/employeeCreateCommand.ts @@ -1,6 +1,6 @@ import Sequelize from "sequelize"; import * as Helper from "../helpers/helper"; -import { EmployeeModel } from "../models/EmployeeModel"; +import { EmployeeModel } from "../models/employeeModel"; import * as EmployeeRepository from "../models/employeeModel"; import * as DatabaseConnection from "../models/databaseConnection"; import { CommandResponse, Employee, EmployeeSaveRequest } from "../../typeDefinitions"; diff --git a/src/controllers/commands/employees/employeeQuery.ts b/src/controllers/commands/employees/employeeQuery.ts index 505f7dc..372d583 100644 --- a/src/controllers/commands/employees/employeeQuery.ts +++ b/src/controllers/commands/employees/employeeQuery.ts @@ -1,3 +1,3 @@ -export class employeeQuery { +export class EmployeeQuery { } \ No newline at end of file From a484d45eee355820271c9ae7bcda4a1a13430310 Mon Sep 17 00:00:00 2001 From: Fernando Arreola Garcia Date: Sat, 29 Feb 2020 16:21:48 -0600 Subject: [PATCH 10/40] Finishing employeeCreateCommand functionality --- .../employees/employeeCreateCommand.ts | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/controllers/commands/employees/employeeCreateCommand.ts b/src/controllers/commands/employees/employeeCreateCommand.ts index d6b3d1a..1cd3459 100644 --- a/src/controllers/commands/employees/employeeCreateCommand.ts +++ b/src/controllers/commands/employees/employeeCreateCommand.ts @@ -7,12 +7,37 @@ import { CommandResponse, Employee, EmployeeSaveRequest } from "../../typeDefini import { Resources, ResourceKey } from "../../../resourceLookup"; import sequelize from "sequelize"; -// TODO: validate this request +const validateSaveRequest = ( + saveEmployeeRequest: EmployeeSaveRequest +): CommandResponse => { + let errorMessage: string = ""; + + if (Helper.isBlankString(saveEmployeeRequest.firstName)) { + errorMessage = Resources.getString(ResourceKey.EMPLOYEE_FIRST_NAME_INVALID); + } else if ((Helper.isBlankString(saveEmployeeRequest.lastName))) { + errorMessage = Resources.getString(ResourceKey.EMPLOYEE_LAST_NAME_INVALID); + } else if ((Helper.isBlankString(saveEmployeeRequest.password))) { + errorMessage = Resources.getString(ResourceKey.EMPLOYEE_PASSWORD_INVALID); + } + + return ((errorMessage === "") + ? >{ status: 200 } + : >{ + status: 422, + message: errorMessage + }); +}; export const execute = async ( saveEmployeeRequest: EmployeeSaveRequest ): Promise> => { + const validationResponse: CommandResponse = + validateSaveRequest(saveEmployeeRequest); + if (validationResponse.status !== 200) { + return Promise.reject(validationResponse); + } + const employeeToCreate: EmployeeModel = { active: saveEmployeeRequest.active, lastName: saveEmployeeRequest.lastName, @@ -73,4 +98,4 @@ export const execute = async ( || Resources.getString(ResourceKey.EMPLOYEE_UNABLE_TO_SAVE)) }); }); -}; +}; \ No newline at end of file From db9982d7106a2d41020f06e570e493d6445ebb8c Mon Sep 17 00:00:00 2001 From: Osmin Sanabria Jr Date: Sat, 29 Feb 2020 16:25:13 -0600 Subject: [PATCH 11/40] adding routes --- src/controllers/lookups/routingLookup.ts | 4 +++- src/controllers/signInRouteController.ts | 27 ++++++++++++++++++++++++ src/controllers/typeDefinitions.ts | 4 ++++ src/routes/signin.ts | 9 ++++++++ views/login.ejs | 0 views/signin.ejs | 1 + views/signup.ejs | 0 7 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/controllers/signInRouteController.ts create mode 100644 src/routes/signin.ts delete mode 100644 views/login.ejs create mode 100644 views/signin.ejs delete mode 100644 views/signup.ejs diff --git a/src/controllers/lookups/routingLookup.ts b/src/controllers/lookups/routingLookup.ts index ed8001b..4877893 100644 --- a/src/controllers/lookups/routingLookup.ts +++ b/src/controllers/lookups/routingLookup.ts @@ -8,13 +8,15 @@ export enum QueryParameterLookup { export enum ViewNameLookup { ProductDetail = "productDetail", - ProductListing = "productListing" + ProductListing = "productListing", + Signin = "signin" } export enum RouteLookup { // Page routing ProductListing = "/", ProductDetail = "/productDetail", + Signin = "/signin", // Page routing - parameters ProductIdParameter = "/:productId", diff --git a/src/controllers/signInRouteController.ts b/src/controllers/signInRouteController.ts new file mode 100644 index 0000000..dcfdd61 --- /dev/null +++ b/src/controllers/signInRouteController.ts @@ -0,0 +1,27 @@ +import { Request, Response } from "express"; +import { ViewNameLookup } from "./lookups/routingLookup"; +import { Resources, ResourceKey } from "../resourceLookup"; +import {SignInPageResponse } from "./typeDefinitions"; + +const processStartProductListingError = (error: any, res: Response): void => { + res.setHeader( + "Cache-Control", + "no-cache, max-age=0, must-revalidate, no-store"); + + return res.status((error.status || 500)) + .render( + ViewNameLookup.Signin, + { + isElevatedUser: false, + errorMessage: (error.message + || Resources.getString(ResourceKey.PRODUCTS_UNABLE_TO_QUERY)) + }); +}; + +export const start = async (req: Request, res: Response): Promise => { + return res.render( + ViewNameLookup.Signin, + { + isElevatedUser: true + }); +}; diff --git a/src/controllers/typeDefinitions.ts b/src/controllers/typeDefinitions.ts index 22ee42b..6710db6 100644 --- a/src/controllers/typeDefinitions.ts +++ b/src/controllers/typeDefinitions.ts @@ -64,6 +64,10 @@ export interface ProductListingPageResponse extends PageResponse { products: Product[]; isElevatedUser: boolean; } + +export interface SignInPageResponse extends PageResponse { + isElevatedUser: boolean; +} // End page response data // API response data diff --git a/src/routes/signin.ts b/src/routes/signin.ts new file mode 100644 index 0000000..b7be7ca --- /dev/null +++ b/src/routes/signin.ts @@ -0,0 +1,9 @@ +import express from "express"; +import { RouteLookup } from "../controllers/lookups/routingLookup"; +import * as SignInRouteController from "../controllers/signInRouteController"; + +function SigninRoutes(server: express.Express) { + server.get(RouteLookup.Signin, SignInRouteController.start); +}; + +module.exports.routes = SigninRoutes; diff --git a/views/login.ejs b/views/login.ejs deleted file mode 100644 index e69de29..0000000 diff --git a/views/signin.ejs b/views/signin.ejs new file mode 100644 index 0000000..386919a --- /dev/null +++ b/views/signin.ejs @@ -0,0 +1 @@ +WE IN THE SIGN IN PAGE \ No newline at end of file diff --git a/views/signup.ejs b/views/signup.ejs deleted file mode 100644 index e69de29..0000000 From 60d8bfd5f2f76c77e8f9281205057d8cb87c6c89 Mon Sep 17 00:00:00 2001 From: Fernando Arreola Garcia Date: Sat, 29 Feb 2020 16:36:42 -0600 Subject: [PATCH 12/40] adding validition to employeeCreateCommand --- src/controllers/commands/employees/employeeCreateCommand.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/controllers/commands/employees/employeeCreateCommand.ts b/src/controllers/commands/employees/employeeCreateCommand.ts index 8ef7649..f23d0b0 100644 --- a/src/controllers/commands/employees/employeeCreateCommand.ts +++ b/src/controllers/commands/employees/employeeCreateCommand.ts @@ -5,7 +5,7 @@ import * as EmployeeRepository from "../models/employeeModel"; import * as DatabaseConnection from "../models/databaseConnection"; import { CommandResponse, Employee, EmployeeSaveRequest } from "../../typeDefinitions"; import { Resources, ResourceKey } from "../../../resourceLookup"; -import sequelize from "sequelize"; +import { EmployeeClassification } from "../models/constants/entityTypes"; const validateSaveRequest = ( saveEmployeeRequest: EmployeeSaveRequest @@ -48,6 +48,10 @@ export const execute = async ( classification: saveEmployeeRequest.classification }; + if (saveEmployeeRequest.isInitialEmployee) { + employeeToCreate.classification = EmployeeClassification.GeneralManager; + } + let createTransaction: Sequelize.Transaction; return DatabaseConnection.createTransaction() From aad420c61bf1e9b7dcfeff0c3b5e7df927f9ac1b Mon Sep 17 00:00:00 2001 From: Osmin Sanabria Jr Date: Sat, 29 Feb 2020 17:18:18 -0600 Subject: [PATCH 13/40] broken code 2-29 --- src/controllers/signInRouteController.ts | 5 +++++ src/routes/signin.ts | 2 ++ views/signin.ejs | 17 ++++++++++++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/controllers/signInRouteController.ts b/src/controllers/signInRouteController.ts index dcfdd61..786f5ad 100644 --- a/src/controllers/signInRouteController.ts +++ b/src/controllers/signInRouteController.ts @@ -25,3 +25,8 @@ export const start = async (req: Request, res: Response): Promise => { isElevatedUser: true }); }; +export const sigin = async (req: Request, res: Response): Promise => { + Signin.execute + + res.redirect("/signin"); +}; \ No newline at end of file diff --git a/src/routes/signin.ts b/src/routes/signin.ts index b7be7ca..4b51f87 100644 --- a/src/routes/signin.ts +++ b/src/routes/signin.ts @@ -4,6 +4,8 @@ import * as SignInRouteController from "../controllers/signInRouteController"; function SigninRoutes(server: express.Express) { server.get(RouteLookup.Signin, SignInRouteController.start); + + server.post(RouteLookup.Signin); }; module.exports.routes = SigninRoutes; diff --git a/views/signin.ejs b/views/signin.ejs index 386919a..6e23fb3 100644 --- a/views/signin.ejs +++ b/views/signin.ejs @@ -1 +1,16 @@ -WE IN THE SIGN IN PAGE \ No newline at end of file + + + + + + Signin + + +
+ + + Sign In +
+ + + \ No newline at end of file From 6fe60dc4cda801c1ca17d4cb7a103e629c55f924 Mon Sep 17 00:00:00 2001 From: Fernando Arreola Garcia Date: Sat, 29 Feb 2020 17:18:55 -0600 Subject: [PATCH 14/40] adding employeeQuery functionality --- .../commands/employees/employeeQuery.ts | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/controllers/commands/employees/employeeQuery.ts b/src/controllers/commands/employees/employeeQuery.ts index 372d583..acf8d68 100644 --- a/src/controllers/commands/employees/employeeQuery.ts +++ b/src/controllers/commands/employees/employeeQuery.ts @@ -1,3 +1,21 @@ -export class EmployeeQuery { - -} \ No newline at end of file +import { CommandResponse, Employee } from "../../typeDefinitions"; +import { EmployeeModel } from "../models/employeeModel"; +import * as Helper from "../helpers/helper"; +import * as EmployeeRepository from "../models/employeeModel"; +import { Resources, ResourceKey } from "../../../resourceLookup"; + +export const queryById = async (employeeRecordId: number): Promise> => { +if (Helper.isBlankString(employeeRecordId.toString())) { + return Promise.reject(>{ + status: 422, + message: Resources.getString(ResourceKey.EMPLOYEE_RECORD_ID_INVALID) + }); +} + +return EmployeeRepository.queryById(EmployeeId) + .then((queriedEmployee: (EmployeeModel | null)): Promise> => { + if (queriedEmployee == null) { + return Promise.reject(>) + } + } +}; \ No newline at end of file From e97090a056a301eaeeab27a164a6b0c86afabec4 Mon Sep 17 00:00:00 2001 From: Dalynn Hatch Date: Wed, 4 Mar 2020 15:14:07 -0600 Subject: [PATCH 15/40] main menu view --- public/styles/master.css | 5 ++++ src/controllers/lookups/routingLookup.ts | 2 +- src/controllers/mainMenuRouteController.ts | 32 +++++++++++----------- views/mainMenu.ejs | 22 +++++++++++++-- 4 files changed, 42 insertions(+), 19 deletions(-) diff --git a/public/styles/master.css b/public/styles/master.css index e0b1874..c28bbf4 100644 --- a/public/styles/master.css +++ b/public/styles/master.css @@ -3,6 +3,11 @@ div.header { text-align: right; } +img.footer { + margin-right: 5%; + float: right; +} + div.main { padding-top: 0px; text-align: center diff --git a/src/controllers/lookups/routingLookup.ts b/src/controllers/lookups/routingLookup.ts index 160f66b..199fd1b 100644 --- a/src/controllers/lookups/routingLookup.ts +++ b/src/controllers/lookups/routingLookup.ts @@ -16,7 +16,7 @@ export enum RouteLookup { // Page routing ProductListing = "/productListing", ProductDetail = "/productDetail", - MainMenu = "/", + MainMenu = "/mainMenu", // Page routing - parameters ProductIdParameter = "/:productId", diff --git a/src/controllers/mainMenuRouteController.ts b/src/controllers/mainMenuRouteController.ts index afd9284..668b800 100644 --- a/src/controllers/mainMenuRouteController.ts +++ b/src/controllers/mainMenuRouteController.ts @@ -3,25 +3,25 @@ import { ViewNameLookup } from "./lookups/routingLookup"; import { MainMenuPageResponse } from "./typeDefinitions"; const processStartMainMenuError = (error: any, res: Response): void => { -res.setHeader( -"Cache-Control", -"no-cache, max-age=0, must-revalidate, no-store"); + res.setHeader( + "Cache-Control", + "no-cache, max-age=0, must-revalidate, no-store"); -return res.status((error.status || 500)) -.render( -ViewNameLookup.MainMenu, -{ -isElevatedUser: false, -errorMessage: (error.message) -}); + return res.status((error.status || 500)) + .render( + ViewNameLookup.MainMenu, + { + isElevatedUser: false, + errorMessage: (error.message) + }); }; export const start = async (req: Request, res: Response) => { -res.setHeader("Cache-Control", "no-cache, max-age=0, must-revalidate, no-store"); + res.setHeader("Cache-Control", "no-cache, max-age=0, must-revalidate, no-store"); -return res.render( -ViewNameLookup.MainMenu, -{ -isElevatedUser: false -}); + return res.render( + ViewNameLookup.MainMenu, + { + isElevatedUser: true + }); }; diff --git a/views/mainMenu.ejs b/views/mainMenu.ejs index 048fad1..cc49028 100644 --- a/views/mainMenu.ejs +++ b/views/mainMenu.ejs @@ -25,7 +25,25 @@ - +
+ Start Txn +
+
+
+
+ Prod List +
+
+
+ +
class="hidden" <% } %>> + Cashier Report +


+ Emp Details +


+ Sales Report +


+
From 5f737e44818ce17eef058baedfe24c552d0cfcb3 Mon Sep 17 00:00:00 2001 From: Fernando Arreola Date: Wed, 4 Mar 2020 19:19:05 -0600 Subject: [PATCH 16/40] Adding employeeQuery functionality. Adding strange file appearing as an untracked file to .gitignore --- .gitignore | 1 + .../commands/employees/employeeQuery.ts | 34 ++++++++++++------- .../employees/helpers/employeeHelper.ts | 15 ++++++++ 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index e3b6ad5..c5615ec 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,4 @@ app/**/*.js app/**/*.map test/**/*.js test/**/*.map +.ionide/symbolCache.db diff --git a/src/controllers/commands/employees/employeeQuery.ts b/src/controllers/commands/employees/employeeQuery.ts index acf8d68..e2180ab 100644 --- a/src/controllers/commands/employees/employeeQuery.ts +++ b/src/controllers/commands/employees/employeeQuery.ts @@ -1,21 +1,31 @@ import { CommandResponse, Employee } from "../../typeDefinitions"; import { EmployeeModel } from "../models/employeeModel"; import * as Helper from "../helpers/helper"; +import * as EmployeeHelper from "./helpers/employeeHelper"; import * as EmployeeRepository from "../models/employeeModel"; import { Resources, ResourceKey } from "../../../resourceLookup"; -export const queryById = async (employeeRecordId: number): Promise> => { -if (Helper.isBlankString(employeeRecordId.toString())) { - return Promise.reject(>{ - status: 422, - message: Resources.getString(ResourceKey.EMPLOYEE_RECORD_ID_INVALID) - }); -} -return EmployeeRepository.queryById(EmployeeId) - .then((queriedEmployee: (EmployeeModel | null)): Promise> => { - if (queriedEmployee == null) { - return Promise.reject(>) - } +export const queryById = async (employeeRecordId?: string): Promise> => { + if (Helper.isBlankString(employeeRecordId)) { + return Promise.reject(>{ + status: 422, + message: Resources.getString(ResourceKey.EMPLOYEE_RECORD_ID_INVALID) + }); } + + return EmployeeRepository.queryById(employeeRecordId) + .then((queriedEmployee: (EmployeeModel | null)): Promise> => { + if (queriedEmployee == null) { + return Promise.reject(>{ + status: 404, + message: Resources.getString(ResourceKey.EMPLOYEE_NOT_FOUND) + }); + } + + return Promise.resolve(>{ + status: 200, + data: EmployeeHelper.mapEmployeeData(queriedEmployee) + }); + }); }; \ No newline at end of file diff --git a/src/controllers/commands/employees/helpers/employeeHelper.ts b/src/controllers/commands/employees/helpers/employeeHelper.ts index e5f200a..e0c71aa 100644 --- a/src/controllers/commands/employees/helpers/employeeHelper.ts +++ b/src/controllers/commands/employees/helpers/employeeHelper.ts @@ -1,4 +1,6 @@ import { EmployeeClassification } from "../../models/constants/entityTypes"; +import { EmployeeModel } from "../../models/employeeModel"; +import { Employee } from "../../..//typeDefinitions"; export const hashString = (toHash: string): string => { return ""; // TODO: Look at https://nodejs.org/docs/latest-v12.x/api/crypto.html#crypto_crypto_createhash_algorithm_options as one option @@ -6,4 +8,17 @@ export const hashString = (toHash: string): string => { export const isElevatedUser = (employeeClassification: EmployeeClassification): boolean => { return false; // TODO: Determine if an employee is an elevated user by their classification +}; + +export const mapEmployeeData = (queriedProduct: EmployeeModel): Employee => { + return { + id: queriedProduct.id, + active: queriedProduct.active, + lastName: queriedProduct.lastName, + createdOn: queriedProduct.createdOn, + firstName: queriedProduct.firstName, + managerId: queriedProduct.managerId, + employeeId: queriedProduct.employeeId.toString(), + classification: queriedProduct.classification + }; }; \ No newline at end of file From a8acba1c259416a5d75f03744614c88c9de9e967 Mon Sep 17 00:00:00 2001 From: Fernando Arreola Date: Wed, 4 Mar 2020 19:45:23 -0600 Subject: [PATCH 17/40] Adding employeeUpdate functionality --- .../employees/employeeUpdateCommand.ts | 92 ++++++++++++++++++- 1 file changed, 90 insertions(+), 2 deletions(-) diff --git a/src/controllers/commands/employees/employeeUpdateCommand.ts b/src/controllers/commands/employees/employeeUpdateCommand.ts index 459a8db..d32bbf7 100644 --- a/src/controllers/commands/employees/employeeUpdateCommand.ts +++ b/src/controllers/commands/employees/employeeUpdateCommand.ts @@ -1,3 +1,91 @@ -export class employeeUpdateCommand { - +import Sequelize from "sequelize"; +import * as Helper from "../helpers/helper"; +import { EmployeeModel } from "../models/employeeModel"; +import * as EmployeeRepository from "../models/employeeModel"; +import * as DatabaseConnection from "../models/databaseConnection"; +import { CommandResponse, Employee, EmployeeSaveRequest } from "../../typeDefinitions"; +import { Resources, ResourceKey } from "../../../resourceLookup"; +import * as EmployeeHelper from "./helpers/employeeHelper"; + + +const validateSaveRequest = ( + saveEmployeeRequest: EmployeeSaveRequest +): CommandResponse => { + let errorMessage: string = ""; + + if (Helper.isBlankString(saveEmployeeRequest.firstName)) { + errorMessage = Resources.getString(ResourceKey.EMPLOYEE_FIRST_NAME_INVALID); + } else if ((Helper.isBlankString(saveEmployeeRequest.lastName))) { + errorMessage = Resources.getString(ResourceKey.EMPLOYEE_LAST_NAME_INVALID); + } else if ((Helper.isBlankString(saveEmployeeRequest.password))) { + errorMessage = Resources.getString(ResourceKey.EMPLOYEE_PASSWORD_INVALID); + } + + return ((errorMessage === "") + ? >{ status: 200 } + : >{ + status: 422, + message: errorMessage + }); +}; + + +export const execute = async ( + saveEmployeeRequest: EmployeeSaveRequest +): Promise> => { + + const validationResponse: CommandResponse = + validateSaveRequest(saveEmployeeRequest); + if (validationResponse.status !== 200) { + return Promise.reject(validationResponse); + } + + let updateTransaction: Sequelize.Transaction; + + return DatabaseConnection.createTransaction() + .then((createdTransaction: Sequelize.Transaction): Promise => { + updateTransaction = createdTransaction; + + return EmployeeRepository.queryById( + saveEmployeeRequest.id, + updateTransaction); + }).then((queriedEmployee: (EmployeeModel | null)): Promise => { + if (queriedEmployee == null) { + return Promise.reject(>{ + status: 404, + message: Resources.getString(ResourceKey.EMPLOYEE_NOT_FOUND) + }); + } + + return queriedEmployee.update( + { + active: saveEmployeeRequest.active, + lastName: saveEmployeeRequest.lastName, + password: saveEmployeeRequest.password, + firstName: saveEmployeeRequest.firstName, + managerId: saveEmployeeRequest.managerId, + employeeId: saveEmployeeRequest.employeeId, + classification: saveEmployeeRequest.classification + }, + { + transaction: updateTransaction + }); + }).then((updatedEmployee: EmployeeModel): CommandResponse => { + updateTransaction.commit(); + + return > { + status: 200, + data: EmployeeHelper.mapEmployeeData(updatedEmployee) + }; + }).catch((error: any): Promise> => { + if (updateTransaction != null) { + updateTransaction.rollback(); + } + + return Promise.reject(>{ + status: (error.status || 500), + message: (error.message + || Resources.getString(ResourceKey.EMPLOYEE_UNABLE_TO_SAVE)) + }); + }); } \ No newline at end of file From 69eec634a7916409fdad978ec9bac34db85b0786 Mon Sep 17 00:00:00 2001 From: Fernando Arreola Date: Wed, 4 Mar 2020 19:46:01 -0600 Subject: [PATCH 18/40] Fixing formatting issues --- .../employees/employeeUpdateCommand.ts | 94 +++++++++---------- 1 file changed, 46 insertions(+), 48 deletions(-) diff --git a/src/controllers/commands/employees/employeeUpdateCommand.ts b/src/controllers/commands/employees/employeeUpdateCommand.ts index d32bbf7..4e62aad 100644 --- a/src/controllers/commands/employees/employeeUpdateCommand.ts +++ b/src/controllers/commands/employees/employeeUpdateCommand.ts @@ -7,7 +7,6 @@ import { CommandResponse, Employee, EmployeeSaveRequest } from "../../typeDefini import { Resources, ResourceKey } from "../../../resourceLookup"; import * as EmployeeHelper from "./helpers/employeeHelper"; - const validateSaveRequest = ( saveEmployeeRequest: EmployeeSaveRequest ): CommandResponse => { @@ -29,63 +28,62 @@ const validateSaveRequest = ( }); }; - export const execute = async ( - saveEmployeeRequest: EmployeeSaveRequest + saveEmployeeRequest: EmployeeSaveRequest ): Promise> => { - const validationResponse: CommandResponse = - validateSaveRequest(saveEmployeeRequest); - if (validationResponse.status !== 200) { - return Promise.reject(validationResponse); - } + const validationResponse: CommandResponse = + validateSaveRequest(saveEmployeeRequest); + if (validationResponse.status !== 200) { + return Promise.reject(validationResponse); + } let updateTransaction: Sequelize.Transaction; return DatabaseConnection.createTransaction() - .then((createdTransaction: Sequelize.Transaction): Promise => { - updateTransaction = createdTransaction; + .then((createdTransaction: Sequelize.Transaction): Promise => { + updateTransaction = createdTransaction; - return EmployeeRepository.queryById( - saveEmployeeRequest.id, - updateTransaction); - }).then((queriedEmployee: (EmployeeModel | null)): Promise => { - if (queriedEmployee == null) { - return Promise.reject(>{ - status: 404, - message: Resources.getString(ResourceKey.EMPLOYEE_NOT_FOUND) - }); - } + return EmployeeRepository.queryById( + saveEmployeeRequest.id, + updateTransaction); + }).then((queriedEmployee: (EmployeeModel | null)): Promise => { + if (queriedEmployee == null) { + return Promise.reject(>{ + status: 404, + message: Resources.getString(ResourceKey.EMPLOYEE_NOT_FOUND) + }); + } - return queriedEmployee.update( - { - active: saveEmployeeRequest.active, - lastName: saveEmployeeRequest.lastName, - password: saveEmployeeRequest.password, - firstName: saveEmployeeRequest.firstName, - managerId: saveEmployeeRequest.managerId, - employeeId: saveEmployeeRequest.employeeId, - classification: saveEmployeeRequest.classification - }, - { - transaction: updateTransaction - }); - }).then((updatedEmployee: EmployeeModel): CommandResponse => { - updateTransaction.commit(); + return queriedEmployee.update( + { + active: saveEmployeeRequest.active, + lastName: saveEmployeeRequest.lastName, + password: saveEmployeeRequest.password, + firstName: saveEmployeeRequest.firstName, + managerId: saveEmployeeRequest.managerId, + employeeId: saveEmployeeRequest.employeeId, + classification: saveEmployeeRequest.classification + }, + { + transaction: updateTransaction + }); + }).then((updatedEmployee: EmployeeModel): CommandResponse => { + updateTransaction.commit(); - return > { - status: 200, - data: EmployeeHelper.mapEmployeeData(updatedEmployee) - }; - }).catch((error: any): Promise> => { - if (updateTransaction != null) { - updateTransaction.rollback(); - } + return >{ + status: 200, + data: EmployeeHelper.mapEmployeeData(updatedEmployee) + }; + }).catch((error: any): Promise> => { + if (updateTransaction != null) { + updateTransaction.rollback(); + } - return Promise.reject(>{ - status: (error.status || 500), - message: (error.message - || Resources.getString(ResourceKey.EMPLOYEE_UNABLE_TO_SAVE)) + return Promise.reject(>{ + status: (error.status || 500), + message: (error.message + || Resources.getString(ResourceKey.EMPLOYEE_UNABLE_TO_SAVE)) + }); }); - }); } \ No newline at end of file From c2ec801ebedb0fa5e95156ba1e3a9092e1f774b2 Mon Sep 17 00:00:00 2001 From: osanabria Date: Thu, 5 Mar 2020 09:42:10 -0600 Subject: [PATCH 19/40] Revert "adding routes" This reverts commit db9982d7106a2d41020f06e570e493d6445ebb8c. --- src/controllers/lookups/routingLookup.ts | 4 +--- src/controllers/typeDefinitions.ts | 4 ---- views/login.ejs | 0 views/signup.ejs | 0 4 files changed, 1 insertion(+), 7 deletions(-) create mode 100644 views/login.ejs create mode 100644 views/signup.ejs diff --git a/src/controllers/lookups/routingLookup.ts b/src/controllers/lookups/routingLookup.ts index 4877893..ed8001b 100644 --- a/src/controllers/lookups/routingLookup.ts +++ b/src/controllers/lookups/routingLookup.ts @@ -8,15 +8,13 @@ export enum QueryParameterLookup { export enum ViewNameLookup { ProductDetail = "productDetail", - ProductListing = "productListing", - Signin = "signin" + ProductListing = "productListing" } export enum RouteLookup { // Page routing ProductListing = "/", ProductDetail = "/productDetail", - Signin = "/signin", // Page routing - parameters ProductIdParameter = "/:productId", diff --git a/src/controllers/typeDefinitions.ts b/src/controllers/typeDefinitions.ts index d516b4f..bfd5aed 100644 --- a/src/controllers/typeDefinitions.ts +++ b/src/controllers/typeDefinitions.ts @@ -65,10 +65,6 @@ export interface ProductListingPageResponse extends PageResponse { products: Product[]; isElevatedUser: boolean; } - -export interface SignInPageResponse extends PageResponse { - isElevatedUser: boolean; -} // End page response data // API response data diff --git a/views/login.ejs b/views/login.ejs new file mode 100644 index 0000000..e69de29 diff --git a/views/signup.ejs b/views/signup.ejs new file mode 100644 index 0000000..e69de29 From 9d36dc4d01a81c72138676609ce7ac43668bad46 Mon Sep 17 00:00:00 2001 From: osanabria Date: Thu, 5 Mar 2020 09:45:25 -0600 Subject: [PATCH 20/40] umm --- src/controllers/lookups/routingLookup.ts | 5 ++++- src/controllers/typeDefinitions.ts | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/controllers/lookups/routingLookup.ts b/src/controllers/lookups/routingLookup.ts index ed8001b..354b3c0 100644 --- a/src/controllers/lookups/routingLookup.ts +++ b/src/controllers/lookups/routingLookup.ts @@ -8,13 +8,16 @@ export enum QueryParameterLookup { export enum ViewNameLookup { ProductDetail = "productDetail", - ProductListing = "productListing" + ProductListing = "productListing", + Signin = "signin" } export enum RouteLookup { // Page routing ProductListing = "/", ProductDetail = "/productDetail", + Signin = "/signin", + // Page routing - parameters ProductIdParameter = "/:productId", diff --git a/src/controllers/typeDefinitions.ts b/src/controllers/typeDefinitions.ts index bfd5aed..7a71cbf 100644 --- a/src/controllers/typeDefinitions.ts +++ b/src/controllers/typeDefinitions.ts @@ -10,7 +10,7 @@ export interface EmployeeSaveRequest { id?: string; active: boolean; lastName: string; - password: Buffer; + password: string; firstName: string; managerId?: string; classification: number; @@ -84,3 +84,7 @@ export interface CommandResponse { status: number; message?: string; } + +export interface SignInPageResponse extends PageResponse { + isElevatedUser: boolean; +} From b77b73e215751d2145c442e10fbc32caa37eb37c Mon Sep 17 00:00:00 2001 From: osanabria Date: Thu, 5 Mar 2020 11:53:37 -0600 Subject: [PATCH 21/40] should be working need functionallity --- src/controllers/signInRouteController.ts | 14 +++++++------- src/routes/signin.ts | 2 +- views/signin.ejs | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/controllers/signInRouteController.ts b/src/controllers/signInRouteController.ts index 786f5ad..2557263 100644 --- a/src/controllers/signInRouteController.ts +++ b/src/controllers/signInRouteController.ts @@ -19,14 +19,14 @@ const processStartProductListingError = (error: any, res: Response): void => { }; export const start = async (req: Request, res: Response): Promise => { - return res.render( + console.log("TO") + /* return res.render( ViewNameLookup.Signin, { isElevatedUser: true - }); + }); */ }; -export const sigin = async (req: Request, res: Response): Promise => { - Signin.execute - - res.redirect("/signin"); -}; \ No newline at end of file +export const signin = async (req: Request, res: Response): Promise => { + console.log("Posyi"); + return res.redirect("/signin"); +}; \ No newline at end of file diff --git a/src/routes/signin.ts b/src/routes/signin.ts index 4b51f87..be0b7ac 100644 --- a/src/routes/signin.ts +++ b/src/routes/signin.ts @@ -5,7 +5,7 @@ import * as SignInRouteController from "../controllers/signInRouteController"; function SigninRoutes(server: express.Express) { server.get(RouteLookup.Signin, SignInRouteController.start); - server.post(RouteLookup.Signin); + server.post(RouteLookup.Signin, SignInRouteController.signin); }; module.exports.routes = SigninRoutes; diff --git a/views/signin.ejs b/views/signin.ejs index 6e23fb3..60b5dfe 100644 --- a/views/signin.ejs +++ b/views/signin.ejs @@ -9,7 +9,7 @@
- Sign In +
From 30d086a869e6db2a9ae17fdfc09f9b0b721ef834 Mon Sep 17 00:00:00 2001 From: Dalynn Hatch Date: Thu, 5 Mar 2020 14:40:04 -0600 Subject: [PATCH 22/40] mainmenu view and some logic --- src/controllers/mainMenuRouteController.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/controllers/mainMenuRouteController.ts b/src/controllers/mainMenuRouteController.ts index 668b800..3381dfc 100644 --- a/src/controllers/mainMenuRouteController.ts +++ b/src/controllers/mainMenuRouteController.ts @@ -17,11 +17,17 @@ const processStartMainMenuError = (error: any, res: Response): void => { }; export const start = async (req: Request, res: Response) => { - res.setHeader("Cache-Control", "no-cache, max-age=0, must-revalidate, no-store"); + const isAciveUser = true; + if (isAciveUser) { + res.setHeader("Cache-Control", "no-cache, max-age=0, must-revalidate, no-store"); - return res.render( - ViewNameLookup.MainMenu, - { - isElevatedUser: true - }); + return res.render( + ViewNameLookup.MainMenu, + { + isElevatedUser: true + } + ); + } else { + res.redirect("/signIn"); + } }; From c9fd952533badea7a3ac8ea7e11dea7ff9a2d483 Mon Sep 17 00:00:00 2001 From: thebluewagon Date: Thu, 5 Mar 2020 15:45:38 -0600 Subject: [PATCH 23/40] finished view amd started on client side --- public/scripts/employeeDetail.js | 74 ++++++++++++ .../employeeDetailRouteController.ts | 109 +++++++++++++++++ .../helpers/routeControllerHelper.ts | 110 ++++++++++++++++++ src/controllers/lookups/routingLookup.ts | 2 + src/routes/employeeDetailRoutes.ts | 24 ++++ views/employeeDetail.ejs | 42 ++++++- 6 files changed, 359 insertions(+), 2 deletions(-) create mode 100644 public/scripts/employeeDetail.js create mode 100644 src/controllers/employeeDetailRouteController.ts create mode 100644 src/controllers/helpers/routeControllerHelper.ts create mode 100644 src/routes/employeeDetailRoutes.ts diff --git a/public/scripts/employeeDetail.js b/public/scripts/employeeDetail.js new file mode 100644 index 0000000..cf14b73 --- /dev/null +++ b/public/scripts/employeeDetail.js @@ -0,0 +1,74 @@ +let hideEmployeeSavedAlertTimer = undefined; + +document.addEventListener("DOMContentLoaded", () => { + // TODO: Things that need doing when the view is loaded + document.getElementById("saveButton").addEventListener("click", saveActionClick); +}); + +// Save +function saveActionClick(event) {0 + // TODO: Actually save the employee via an AJAX call + const firstName = getFirstName(); + const lastName = getLastName(); + const password = getPassword(); + const confirmPassword = getConfirmPassword(); + const position = getPosition(); + const saveActionUrl = ("/api/employeeDetail/" + (employeeId)); + const saveEmployeeRequest = { + + } + + if(firstName && lastName && (password == confirmPassword) && + (position == "Cashier" || position == "Shift Manager" || position == "General Manager")) { + ajaxPost(saveActionUrl, saveEmployeeRequest, (callbackResponse) => { + + }); + } + + displayEmployeeSavedAlertModal(); +} + +function displayEmployeeSavedAlertModal() { + if (hideEmployeeSavedAlertTimer) { + clearTimeout(hideEmployeeSavedAlertTimer); + } + + const savedAlertModalElement = getSavedAlertModalElement(); + savedAlertModalElement.style.display = "none"; + savedAlertModalElement.style.display = "block"; + + hideEmployeeSavedAlertTimer = setTimeout(hideEmployeeSavedAlertModal, 1200); +} + +function hideEmployeeSavedAlertModal() { + if (hideEmployeeSavedAlertTimer) { + clearTimeout(hideEmployeeSavedAlertTimer); + } + + getSavedAlertModalElement().style.display = "none"; +} +// End save + +function getEmployeeId() { + return document.getElementById("employeeId").value; +} + +function getFirstName() { + return document.getElementById("firstName").value; +} + +function getLastName() { + return document.getElementById("lastName").value; +} + +function getPassword() { + return document.getElementById("password").value; +} + +function getConfirmPassword() { + return document.getElementById("confirmPassword").value; +} + +function getPosition() { + return document.getElementById("position").value; +} \ No newline at end of file diff --git a/src/controllers/employeeDetailRouteController.ts b/src/controllers/employeeDetailRouteController.ts new file mode 100644 index 0000000..ce42a33 --- /dev/null +++ b/src/controllers/employeeDetailRouteController.ts @@ -0,0 +1,109 @@ +import { Request, Response } from "express"; +import * as Helper from "./helpers/routeControllerHelper"; +import { Resources, ResourceKey } from "../resourceLookup"; +import * as EmployeeHelper from "./commands/employees/helpers/employeeHelper"; +import * as ValidateActiveUser from "./commands/activeUsers/validateActiveUserCommand"; +import { CommandResponse, Employee, EmployeeSaveRequest, ActiveUser } from "./typeDefinitions"; + +interface CanCreateEmployee { + employeeExists: boolean; + isElevatedUser: boolean; +} + +const determineCanCreateEmployee = async (req: Request): Promise => { + // TODO: Logic to determine if the user associated with the current session + // is able to create an employee + return { employeeExists: false, isElevatedUser: false }; +}; + +export const start = async (req: Request, res: Response): Promise => { + if (Helper.handleInvalidSession(req, res)) { + return; + } + + return determineCanCreateEmployee(req) + .then((canCreateEmployee: CanCreateEmployee): void => { + if (canCreateEmployee.employeeExists + && !canCreateEmployee.isElevatedUser) { + + return res.redirect(Helper.buildNoPermissionsRedirectUrl()); + } + + // TODO: Serve up the page + }).catch((error: any): void => { + // TODO: Handle any errors that occurred + }); +}; + +export const startWithEmployee = async (req: Request, res: Response): Promise => { + if (Helper.handleInvalidSession(req, res)) { + return; + } + + return ValidateActiveUser.execute((req.session).id) + .then((activeUserCommandResponse: CommandResponse): Promise => { + if (!EmployeeHelper.isElevatedUser((activeUserCommandResponse.data).classification)) { + return Promise.reject(>{ + status: 403, + message: Resources.getString(ResourceKey.USER_NO_PERMISSIONS) + }); + } + + // TODO: Query the employee details using the request route parameter + return Promise.resolve(); + }).then((/* TODO: Some employee details */): void => { + // TODO: Serve up the page + }).catch((error: any): void => { + // TODO: Handle any errors that occurred + }); +}; + +const saveEmployee = async ( + req: Request, + res: Response, + performSave: ( + employeeSaveRequest: EmployeeSaveRequest, + isInitialEmployee?: boolean + ) => Promise> +): Promise => { + + if (Helper.handleInvalidApiSession(req, res)) { + return; + } + + let employeeExists: boolean; + + return determineCanCreateEmployee(req) + .then((canCreateEmployee: CanCreateEmployee): Promise> => { + if (canCreateEmployee.employeeExists + && !canCreateEmployee.isElevatedUser) { + + return Promise.reject(>{ + status: 403, + message: Resources.getString(ResourceKey.USER_NO_PERMISSIONS) + }); + } + + employeeExists = canCreateEmployee.employeeExists; + + return performSave(req.body, !employeeExists); + }).then((saveEmployeeCommandResponse: CommandResponse): void => { + // TODO: Handle the save response and send a response to the HTTP request + }).catch((error: any): void => { + return Helper.processApiError( + error, + res, + { + defaultErrorMessage: Resources.getString( + ResourceKey.EMPLOYEE_UNABLE_TO_SAVE) + }); + }); +}; + +export const updateEmployee = async (req: Request, res: Response): Promise => { + return; // TODO: invoke saveEmployee() with the appropriate save functionality +}; + +export const createEmployee = async (req: Request, res: Response): Promise => { + return; // TODO: invoke saveEmployee() with the appropriate save functionality +}; \ No newline at end of file diff --git a/src/controllers/helpers/routeControllerHelper.ts b/src/controllers/helpers/routeControllerHelper.ts new file mode 100644 index 0000000..fcc81ae --- /dev/null +++ b/src/controllers/helpers/routeControllerHelper.ts @@ -0,0 +1,110 @@ +import { Request, Response } from "express"; +import { ApiResponse } from "../typeDefinitions"; +import { ResourceKey, Resources } from "../../resourceLookup"; +import { RouteLookup, QueryParameterLookup } from "../lookups/routingLookup"; + +const baseNoPermissionsRedirectUrl: string = ( + "/?" + QueryParameterLookup.ErrorCode + + "=" + ResourceKey.USER_NO_PERMISSIONS); + +const defaultNoPermissionsRedirectBaseLocation: string = RouteLookup.MainMenu; + +export interface ApiErrorHints { + defaultErrorMessage?: string; + redirectBaseLocation?: string; +} + +export const invalidSessionRedirectUrl: string = (RouteLookup.SignIn + + "/?" + QueryParameterLookup.ErrorCode + + "=" + ResourceKey.USER_SESSION_NOT_ACTIVE); + +export const buildNoPermissionsRedirectUrl = ( + redirectBaseLocation?: string +): string => { + + return ((redirectBaseLocation || defaultNoPermissionsRedirectBaseLocation) + + baseNoPermissionsRedirectUrl); +}; + +export const handleInvalidSession = (req: Request, res: Response): boolean => { + if (req.session != null) { + return false; + } + + res.redirect(invalidSessionRedirectUrl); + + return true; +}; + +export const processStartError = ( + error: any, + res: Response, + redirectBaseLocation?: string +): boolean => { + + let processedStartError: boolean = false; + + if ((error.status != null) && (error.status === 404) + && (error.message === Resources.getString(ResourceKey.USER_NOT_FOUND))) { + + res.redirect(invalidSessionRedirectUrl); + processedStartError = true; + } else if ((error.status != null) && (error.status === 403) + && (error.message === Resources.getString(ResourceKey.USER_NO_PERMISSIONS))) { + + res.redirect(buildNoPermissionsRedirectUrl(redirectBaseLocation)); + processedStartError = true; + } + + return processedStartError; +}; + +export const handleInvalidApiSession = (req: Request, res: Response): boolean => { + if (req.session != null) { + return false; + } + + res.status(404) + .send({ + redirectUrl: invalidSessionRedirectUrl, + errorMessage: Resources.getString(ResourceKey.USER_SESSION_NOT_FOUND) + }); + + return true; +}; + +export const processApiError = ( + error: any, + res: Response, + errorHints?: ApiErrorHints +): void => { + + if (errorHints == null) { + errorHints = {}; + } + + if ((error.status != null) && (error.status === 404) + && (error.message === Resources.getString(ResourceKey.USER_NOT_FOUND))) { + + res.status(error.status) + .send({ + redirectUrl: invalidSessionRedirectUrl, + errorMessage: + Resources.getString(ResourceKey.USER_SESSION_NOT_FOUND), + }); + } else if ((error.status != null) && (error.status === 403) + && (error.message === Resources.getString(ResourceKey.USER_NO_PERMISSIONS))) { + + res.status(error.status) + .send({ + errorMessage: error.message, + redirectUrl: buildNoPermissionsRedirectUrl( + errorHints.redirectBaseLocation) + }); + } else { + res.status((error.status || 500)) + .send({ + errorMessage: (error.message || errorHints.defaultErrorMessage) + }); + } +}; \ No newline at end of file diff --git a/src/controllers/lookups/routingLookup.ts b/src/controllers/lookups/routingLookup.ts index ed8001b..a3b976a 100644 --- a/src/controllers/lookups/routingLookup.ts +++ b/src/controllers/lookups/routingLookup.ts @@ -15,9 +15,11 @@ export enum RouteLookup { // Page routing ProductListing = "/", ProductDetail = "/productDetail", + EmployeeDetail = "/employeeDetail", // Page routing - parameters ProductIdParameter = "/:productId", + EmployeeIdParameter = "/:employeeId", // End page routing - parameters // End page routing diff --git a/src/routes/employeeDetailRoutes.ts b/src/routes/employeeDetailRoutes.ts new file mode 100644 index 0000000..1feef15 --- /dev/null +++ b/src/routes/employeeDetailRoutes.ts @@ -0,0 +1,24 @@ +import express from "express"; +import { RouteLookup } from "../controllers/lookups/routingLookup"; +import * as EmployeeDetailRouteController from "../controllers/employeeDetailRouteController"; + +function employeeDetailRoutes(server: express.Express) { + server.get( + RouteLookup.EmployeeDetail, + EmployeeDetailRouteController.start); + + server.get( + (RouteLookup.EmployeeDetail + RouteLookup.EmployeeIdParameter), + EmployeeDetailRouteController.start); + + server.post( + (RouteLookup.API + RouteLookup.EmployeeDetail), + EmployeeDetailRouteController.createEmployee); + + server.patch( + (RouteLookup.API + RouteLookup.EmployeeDetail + + RouteLookup.EmployeeIdParameter), + EmployeeDetailRouteController.updateEmployee); +} + +module.exports.routes = employeeDetailRoutes; \ No newline at end of file diff --git a/views/employeeDetail.ejs b/views/employeeDetail.ejs index 79376fa..9e15ebc 100644 --- a/views/employeeDetail.ejs +++ b/views/employeeDetail.ejs @@ -47,12 +47,50 @@ + + First Name: + + + + + + Last Name: + + + + + + Password: + + + + + + Confirm Password: + + + + + + Employee Position: + + + + - +
+
+ +
+