diff --git a/data/config.defaultValues.d.ts b/data/config.defaultValues.d.ts index 1a0e8dcf..e06dce52 100644 --- a/data/config.defaultValues.d.ts +++ b/data/config.defaultValues.d.ts @@ -19,6 +19,7 @@ export declare const configDefaultValues: { 'session.secret': string; 'users.canLogin': string[]; 'users.canUpdate': string[]; + 'users.canUpdateWorkOrders': string[]; 'users.isAdmin': string[]; 'users.testing': string[]; 'aliases.externalReceiptNumber': string; diff --git a/data/config.defaultValues.js b/data/config.defaultValues.js index 832d1726..aff7bc9a 100644 --- a/data/config.defaultValues.js +++ b/data/config.defaultValues.js @@ -18,6 +18,7 @@ export const configDefaultValues = { 'session.secret': 'cityssm/sunrise', 'users.canLogin': ['administrator'], 'users.canUpdate': [], + 'users.canUpdateWorkOrders': [], 'users.isAdmin': ['administrator'], 'users.testing': [], 'aliases.externalReceiptNumber': 'External Receipt Number', diff --git a/data/config.defaultValues.ts b/data/config.defaultValues.ts index a161093b..f5af12ff 100644 --- a/data/config.defaultValues.ts +++ b/data/config.defaultValues.ts @@ -32,6 +32,7 @@ export const configDefaultValues = { 'users.canLogin': ['administrator'], 'users.canUpdate': [] as string[], + 'users.canUpdateWorkOrders': [] as string[], 'users.isAdmin': ['administrator'], 'users.testing': [] as string[], diff --git a/database/initializeDatabase.js b/database/initializeDatabase.js index 3111028a..76974765 100644 --- a/database/initializeDatabase.js +++ b/database/initializeDatabase.js @@ -383,6 +383,7 @@ const initializingUser = { userProperties: { apiKey: '', canUpdate: true, + canUpdateWorkOrders: true, isAdmin: true } }; diff --git a/database/initializeDatabase.ts b/database/initializeDatabase.ts index a6f7d1cb..9ecdfa0a 100644 --- a/database/initializeDatabase.ts +++ b/database/initializeDatabase.ts @@ -440,6 +440,7 @@ const initializingUser: User = { userProperties: { apiKey: '', canUpdate: true, + canUpdateWorkOrders: true, isAdmin: true } } diff --git a/handlers/permissions.d.ts b/handlers/permissions.d.ts index bd4f8254..74495aa1 100644 --- a/handlers/permissions.d.ts +++ b/handlers/permissions.d.ts @@ -4,3 +4,5 @@ export declare function adminPostHandler(request: Request, response: Response, n export declare function apiGetHandler(request: Request, response: Response, next: NextFunction): Promise; export declare function updateGetHandler(request: Request, response: Response, next: NextFunction): void; export declare function updatePostHandler(request: Request, response: Response, next: NextFunction): void; +export declare function updateWorkOrdersGetHandler(request: Request, response: Response, next: NextFunction): void; +export declare function updateWorkOrdersPostHandler(request: Request, response: Response, next: NextFunction): void; diff --git a/handlers/permissions.js b/handlers/permissions.js index 47d50801..834b33d0 100644 --- a/handlers/permissions.js +++ b/handlers/permissions.js @@ -1,5 +1,5 @@ import { getConfigProperty } from '../helpers/config.helpers.js'; -import { apiKeyIsValid, userCanUpdate, userIsAdmin } from '../helpers/functions.user.js'; +import { apiKeyIsValid, userCanUpdate, userCanUpdateWorkOrders, userIsAdmin } from '../helpers/functions.user.js'; const urlPrefix = getConfigProperty('reverseProxy.urlPrefix'); const forbiddenStatus = 403; const forbiddenJSON = { @@ -43,3 +43,17 @@ export function updatePostHandler(request, response, next) { } response.status(forbiddenStatus).json(forbiddenJSON); } +export function updateWorkOrdersGetHandler(request, response, next) { + if (userCanUpdateWorkOrders(request)) { + next(); + return; + } + response.redirect(forbiddenRedirectURL); +} +export function updateWorkOrdersPostHandler(request, response, next) { + if (userCanUpdateWorkOrders(request)) { + next(); + return; + } + response.status(forbiddenStatus).json(forbiddenJSON); +} diff --git a/handlers/permissions.ts b/handlers/permissions.ts index 62e3695b..5f4dec6e 100644 --- a/handlers/permissions.ts +++ b/handlers/permissions.ts @@ -4,6 +4,7 @@ import { getConfigProperty } from '../helpers/config.helpers.js' import { apiKeyIsValid, userCanUpdate, + userCanUpdateWorkOrders, userIsAdmin } from '../helpers/functions.user.js' @@ -81,3 +82,29 @@ export function updatePostHandler( response.status(forbiddenStatus).json(forbiddenJSON) } + +export function updateWorkOrdersGetHandler( + request: Request, + response: Response, + next: NextFunction +): void { + if (userCanUpdateWorkOrders(request)) { + next() + return + } + + response.redirect(forbiddenRedirectURL) +} + +export function updateWorkOrdersPostHandler( + request: Request, + response: Response, + next: NextFunction +): void { + if (userCanUpdateWorkOrders(request)) { + next() + return + } + + response.status(forbiddenStatus).json(forbiddenJSON) +} \ No newline at end of file diff --git a/helpers/functions.user.d.ts b/helpers/functions.user.d.ts index 218a7ef1..a2358dd2 100644 --- a/helpers/functions.user.d.ts +++ b/helpers/functions.user.d.ts @@ -10,4 +10,5 @@ export interface UserRequest { } export declare function apiKeyIsValid(request: APIRequest): Promise; export declare function userCanUpdate(request: UserRequest): boolean; +export declare function userCanUpdateWorkOrders(request: UserRequest): boolean; export declare function userIsAdmin(request: UserRequest): boolean; diff --git a/helpers/functions.user.js b/helpers/functions.user.js index d9c98d50..66db0c2d 100644 --- a/helpers/functions.user.js +++ b/helpers/functions.user.js @@ -14,6 +14,9 @@ export async function apiKeyIsValid(request) { export function userCanUpdate(request) { return request.session?.user?.userProperties?.canUpdate ?? false; } +export function userCanUpdateWorkOrders(request) { + return request.session?.user?.userProperties?.canUpdateWorkOrders ?? false; +} export function userIsAdmin(request) { return request.session?.user?.userProperties?.isAdmin ?? false; } diff --git a/helpers/functions.user.ts b/helpers/functions.user.ts index 1149cf2b..f27b3302 100644 --- a/helpers/functions.user.ts +++ b/helpers/functions.user.ts @@ -35,6 +35,10 @@ export function userCanUpdate(request: UserRequest): boolean { return request.session?.user?.userProperties?.canUpdate ?? false } +export function userCanUpdateWorkOrders(request: UserRequest): boolean { + return request.session?.user?.userProperties?.canUpdateWorkOrders ?? false +} + export function userIsAdmin(request: UserRequest): boolean { return request.session?.user?.userProperties?.isAdmin ?? false } diff --git a/routes/login.js b/routes/login.js index 3848166b..447cf587 100644 --- a/routes/login.js +++ b/routes/login.js @@ -46,12 +46,14 @@ async function postHandler(request, response) { const canLogin = getConfigProperty('users.canLogin').some((currentUserName) => userNameLowerCase === currentUserName.toLowerCase()); if (canLogin) { const canUpdate = getConfigProperty('users.canUpdate').some((currentUserName) => userNameLowerCase === currentUserName.toLowerCase()); + const canUpdateWorkOrders = getConfigProperty('users.canUpdateWorkOrders').some((currentUserName) => userNameLowerCase === currentUserName.toLowerCase()); const isAdmin = getConfigProperty('users.isAdmin').some((currentUserName) => userNameLowerCase === currentUserName.toLowerCase()); const apiKey = await getApiKey(userNameLowerCase); userObject = { userName: userNameLowerCase, userProperties: { canUpdate, + canUpdateWorkOrders, isAdmin, apiKey } diff --git a/routes/login.ts b/routes/login.ts index af829d80..3cd8a965 100644 --- a/routes/login.ts +++ b/routes/login.ts @@ -86,6 +86,10 @@ async function postHandler( (currentUserName) => userNameLowerCase === currentUserName.toLowerCase() ) + const canUpdateWorkOrders = getConfigProperty('users.canUpdateWorkOrders').some( + (currentUserName) => userNameLowerCase === currentUserName.toLowerCase() + ) + const isAdmin = getConfigProperty('users.isAdmin').some( (currentUserName) => userNameLowerCase === currentUserName.toLowerCase() ) @@ -96,7 +100,9 @@ async function postHandler( userName: userNameLowerCase, userProperties: { canUpdate, + canUpdateWorkOrders, isAdmin, + apiKey } } diff --git a/routes/workOrders.js b/routes/workOrders.js index c8bdd9d7..5c6484a2 100644 --- a/routes/workOrders.js +++ b/routes/workOrders.js @@ -1,5 +1,5 @@ import { Router } from 'express'; -import { updateGetHandler, updatePostHandler } from '../handlers/permissions.js'; +import { updateWorkOrdersGetHandler, updateWorkOrdersPostHandler } from '../handlers/permissions.js'; import handler_edit from '../handlers/workOrders-get/edit.js'; import handler_milestoneCalendar from '../handlers/workOrders-get/milestoneCalendar.js'; import handler_new from '../handlers/workOrders-get/new.js'; @@ -36,30 +36,30 @@ router.post('/doGetWorkOrderMilestones', handler_doGetWorkOrderMilestones); // Outlook Integration router.get('/outlook', handler_outlook); // New -router.get('/new', updateGetHandler, handler_new); -router.post('/doCreateWorkOrder', updatePostHandler, handler_doCreateWorkOrder); +router.get('/new', updateWorkOrdersGetHandler, handler_new); +router.post('/doCreateWorkOrder', updateWorkOrdersPostHandler, handler_doCreateWorkOrder); // View router.get('/:workOrderId', handler_view); -router.post('/doReopenWorkOrder', updatePostHandler, handler_doReopenWorkOrder); +router.post('/doReopenWorkOrder', updateWorkOrdersPostHandler, handler_doReopenWorkOrder); // Edit -router.get('/:workOrderId/edit', updateGetHandler, handler_edit); -router.post('/doUpdateWorkOrder', updatePostHandler, handler_doUpdateWorkOrder); -router.post('/doCloseWorkOrder', updatePostHandler, handler_doCloseWorkOrder); -router.post('/doDeleteWorkOrder', updatePostHandler, handler_doDeleteWorkOrder); +router.get('/:workOrderId/edit', updateWorkOrdersGetHandler, handler_edit); +router.post('/doUpdateWorkOrder', updateWorkOrdersPostHandler, handler_doUpdateWorkOrder); +router.post('/doCloseWorkOrder', updateWorkOrdersPostHandler, handler_doCloseWorkOrder); +router.post('/doDeleteWorkOrder', updateWorkOrdersPostHandler, handler_doDeleteWorkOrder); // Burial Site Contract -router.post('/doAddWorkOrderContract', updatePostHandler, handler_doAddWorkOrderContract); -router.post('/doDeleteWorkOrderContract', updatePostHandler, handler_doDeleteWorkOrderContract); -router.post('/doAddWorkOrderBurialSite', updatePostHandler, handler_doAddWorkOrderBurialSite); -router.post('/doUpdateBurialSiteStatus', updatePostHandler, handler_doUpdateBurialSiteStatus); -router.post('/doDeleteWorkOrderBurialSite', updatePostHandler, handler_doDeleteWorkOrderBurialSite); +router.post('/doAddWorkOrderContract', updateWorkOrdersPostHandler, handler_doAddWorkOrderContract); +router.post('/doDeleteWorkOrderContract', updateWorkOrdersPostHandler, handler_doDeleteWorkOrderContract); +router.post('/doAddWorkOrderBurialSite', updateWorkOrdersPostHandler, handler_doAddWorkOrderBurialSite); +router.post('/doUpdateBurialSiteStatus', updateWorkOrdersPostHandler, handler_doUpdateBurialSiteStatus); +router.post('/doDeleteWorkOrderBurialSite', updateWorkOrdersPostHandler, handler_doDeleteWorkOrderBurialSite); // Comments -router.post('/doAddWorkOrderComment', updatePostHandler, handler_doAddWorkOrderComment); -router.post('/doUpdateWorkOrderComment', updatePostHandler, handler_doUpdateWorkOrderComment); -router.post('/doDeleteWorkOrderComment', updatePostHandler, handler_doDeleteWorkOrderComment); +router.post('/doAddWorkOrderComment', updateWorkOrdersPostHandler, handler_doAddWorkOrderComment); +router.post('/doUpdateWorkOrderComment', updateWorkOrdersPostHandler, handler_doUpdateWorkOrderComment); +router.post('/doDeleteWorkOrderComment', updateWorkOrdersPostHandler, handler_doDeleteWorkOrderComment); // Milestones -router.post('/doAddWorkOrderMilestone', updatePostHandler, handler_doAddWorkOrderMilestone); -router.post('/doUpdateWorkOrderMilestone', updatePostHandler, handler_doUpdateWorkOrderMilestone); -router.post('/doCompleteWorkOrderMilestone', updatePostHandler, handler_doCompleteWorkOrderMilestone); -router.post('/doReopenWorkOrderMilestone', updatePostHandler, handler_doReopenWorkOrderMilestone); -router.post('/doDeleteWorkOrderMilestone', updatePostHandler, handler_doDeleteWorkOrderMilestone); +router.post('/doAddWorkOrderMilestone', updateWorkOrdersPostHandler, handler_doAddWorkOrderMilestone); +router.post('/doUpdateWorkOrderMilestone', updateWorkOrdersPostHandler, handler_doUpdateWorkOrderMilestone); +router.post('/doCompleteWorkOrderMilestone', updateWorkOrdersPostHandler, handler_doCompleteWorkOrderMilestone); +router.post('/doReopenWorkOrderMilestone', updateWorkOrdersPostHandler, handler_doReopenWorkOrderMilestone); +router.post('/doDeleteWorkOrderMilestone', updateWorkOrdersPostHandler, handler_doDeleteWorkOrderMilestone); export default router; diff --git a/routes/workOrders.ts b/routes/workOrders.ts index 76e5628c..3d82ccdb 100644 --- a/routes/workOrders.ts +++ b/routes/workOrders.ts @@ -1,6 +1,9 @@ import { Router } from 'express' -import { updateGetHandler, updatePostHandler } from '../handlers/permissions.js' +import { + updateWorkOrdersGetHandler, + updateWorkOrdersPostHandler +} from '../handlers/permissions.js' import handler_edit from '../handlers/workOrders-get/edit.js' import handler_milestoneCalendar from '../handlers/workOrders-get/milestoneCalendar.js' import handler_new from '../handlers/workOrders-get/new.js' @@ -48,47 +51,75 @@ router.get('/outlook', handler_outlook) // New -router.get('/new', updateGetHandler, handler_new) +router.get('/new', updateWorkOrdersGetHandler, handler_new) -router.post('/doCreateWorkOrder', updatePostHandler, handler_doCreateWorkOrder) +router.post( + '/doCreateWorkOrder', + updateWorkOrdersPostHandler, + handler_doCreateWorkOrder +) // View router.get('/:workOrderId', handler_view) -router.post('/doReopenWorkOrder', updatePostHandler, handler_doReopenWorkOrder) +router.post( + '/doReopenWorkOrder', + updateWorkOrdersPostHandler, + handler_doReopenWorkOrder +) // Edit -router.get('/:workOrderId/edit', updateGetHandler, handler_edit) +router.get('/:workOrderId/edit', updateWorkOrdersGetHandler, handler_edit) -router.post('/doUpdateWorkOrder', updatePostHandler, handler_doUpdateWorkOrder) +router.post( + '/doUpdateWorkOrder', + updateWorkOrdersPostHandler, + handler_doUpdateWorkOrder +) -router.post('/doCloseWorkOrder', updatePostHandler, handler_doCloseWorkOrder) +router.post( + '/doCloseWorkOrder', + updateWorkOrdersPostHandler, + handler_doCloseWorkOrder +) -router.post('/doDeleteWorkOrder', updatePostHandler, handler_doDeleteWorkOrder) +router.post( + '/doDeleteWorkOrder', + updateWorkOrdersPostHandler, + handler_doDeleteWorkOrder +) // Burial Site Contract router.post( '/doAddWorkOrderContract', - updatePostHandler, + updateWorkOrdersPostHandler, handler_doAddWorkOrderContract ) router.post( '/doDeleteWorkOrderContract', - updatePostHandler, + updateWorkOrdersPostHandler, handler_doDeleteWorkOrderContract ) -router.post('/doAddWorkOrderBurialSite', updatePostHandler, handler_doAddWorkOrderBurialSite) +router.post( + '/doAddWorkOrderBurialSite', + updateWorkOrdersPostHandler, + handler_doAddWorkOrderBurialSite +) -router.post('/doUpdateBurialSiteStatus', updatePostHandler, handler_doUpdateBurialSiteStatus) +router.post( + '/doUpdateBurialSiteStatus', + updateWorkOrdersPostHandler, + handler_doUpdateBurialSiteStatus +) router.post( '/doDeleteWorkOrderBurialSite', - updatePostHandler, + updateWorkOrdersPostHandler, handler_doDeleteWorkOrderBurialSite ) @@ -96,19 +127,19 @@ router.post( router.post( '/doAddWorkOrderComment', - updatePostHandler, + updateWorkOrdersPostHandler, handler_doAddWorkOrderComment ) router.post( '/doUpdateWorkOrderComment', - updatePostHandler, + updateWorkOrdersPostHandler, handler_doUpdateWorkOrderComment ) router.post( '/doDeleteWorkOrderComment', - updatePostHandler, + updateWorkOrdersPostHandler, handler_doDeleteWorkOrderComment ) @@ -116,31 +147,31 @@ router.post( router.post( '/doAddWorkOrderMilestone', - updatePostHandler, + updateWorkOrdersPostHandler, handler_doAddWorkOrderMilestone ) router.post( '/doUpdateWorkOrderMilestone', - updatePostHandler, + updateWorkOrdersPostHandler, handler_doUpdateWorkOrderMilestone ) router.post( '/doCompleteWorkOrderMilestone', - updatePostHandler, + updateWorkOrdersPostHandler, handler_doCompleteWorkOrderMilestone ) router.post( '/doReopenWorkOrderMilestone', - updatePostHandler, + updateWorkOrdersPostHandler, handler_doReopenWorkOrderMilestone ) router.post( '/doDeleteWorkOrderMilestone', - updatePostHandler, + updateWorkOrdersPostHandler, handler_doDeleteWorkOrderMilestone ) diff --git a/temp/legacyImportFromCsv/index.js b/temp/legacyImportFromCsv/index.js index d36e28ae..4995ec1c 100644 --- a/temp/legacyImportFromCsv/index.js +++ b/temp/legacyImportFromCsv/index.js @@ -33,6 +33,7 @@ const user = { userName: 'import.unix', userProperties: { canUpdate: true, + canUpdateWorkOrders: true, isAdmin: false, apiKey: '' } diff --git a/temp/legacyImportFromCsv/index.ts b/temp/legacyImportFromCsv/index.ts index 59ba56e5..834e5ebb 100644 --- a/temp/legacyImportFromCsv/index.ts +++ b/temp/legacyImportFromCsv/index.ts @@ -56,6 +56,7 @@ const user: User = { userName: 'import.unix', userProperties: { canUpdate: true, + canUpdateWorkOrders: true, isAdmin: false, apiKey: '' diff --git a/test/functions.js b/test/functions.js index fb2bae82..24bf6dbd 100644 --- a/test/functions.js +++ b/test/functions.js @@ -204,6 +204,7 @@ await describe('functions.user', async () => { userName: '*test', userProperties: { canUpdate: false, + canUpdateWorkOrders: false, isAdmin: false, apiKey: '' } @@ -224,6 +225,7 @@ await describe('functions.user', async () => { userName: '*test', userProperties: { canUpdate: true, + canUpdateWorkOrders: true, isAdmin: false, apiKey: '' } @@ -244,6 +246,7 @@ await describe('functions.user', async () => { userName: '*test', userProperties: { canUpdate: false, + canUpdateWorkOrders: false, isAdmin: true, apiKey: '' } @@ -264,6 +267,7 @@ await describe('functions.user', async () => { userName: '*test', userProperties: { canUpdate: true, + canUpdateWorkOrders: true, isAdmin: true, apiKey: '' } diff --git a/test/functions.ts b/test/functions.ts index 13ba9f27..a30952b0 100644 --- a/test/functions.ts +++ b/test/functions.ts @@ -361,7 +361,9 @@ await describe('functions.user', async () => { userName: '*test', userProperties: { canUpdate: false, + canUpdateWorkOrders: false, isAdmin: false, + apiKey: '' } } @@ -384,7 +386,9 @@ await describe('functions.user', async () => { userName: '*test', userProperties: { canUpdate: true, + canUpdateWorkOrders: true, isAdmin: false, + apiKey: '' } } @@ -407,7 +411,9 @@ await describe('functions.user', async () => { userName: '*test', userProperties: { canUpdate: false, + canUpdateWorkOrders: false, isAdmin: true, + apiKey: '' } } @@ -430,7 +436,9 @@ await describe('functions.user', async () => { userName: '*test', userProperties: { canUpdate: true, + canUpdateWorkOrders: true, isAdmin: true, + apiKey: '' } } diff --git a/types/config.types.d.ts b/types/config.types.d.ts index a9404edc..32b29002 100644 --- a/types/config.types.d.ts +++ b/types/config.types.d.ts @@ -12,6 +12,7 @@ export interface Config { testing?: Array<`*${string}`>; canLogin?: string[]; canUpdate?: string[]; + canUpdateWorkOrders?: string[]; isAdmin?: string[]; }; aliases: { diff --git a/types/config.types.ts b/types/config.types.ts index 31fe4e9c..5d91eeab 100644 --- a/types/config.types.ts +++ b/types/config.types.ts @@ -18,6 +18,7 @@ export interface Config { canLogin?: string[] canUpdate?: string[] + canUpdateWorkOrders?: string[] isAdmin?: string[] } diff --git a/types/record.types.ts b/types/record.types.ts index a0b869ec..86fdf154 100644 --- a/types/record.types.ts +++ b/types/record.types.ts @@ -99,7 +99,7 @@ export interface Cemetery extends Record { parentCemeteryId?: number | null parentCemeteryName?: string | null - + parentCemeteryLatitude?: number | null parentCemeteryLongitude?: number | null parentCemeterySvg?: string | null @@ -461,6 +461,6 @@ export interface WorkOrderMilestoneType extends Record { export interface WorkOrderType extends Record { workOrderTypeId: number workOrderType?: string - + orderNumber?: number } diff --git a/types/user.types.d.ts b/types/user.types.d.ts index cc360606..ac13e974 100644 --- a/types/user.types.d.ts +++ b/types/user.types.d.ts @@ -7,6 +7,7 @@ declare global { export interface UserProperties { apiKey: string; canUpdate: boolean; + canUpdateWorkOrders: boolean; isAdmin: boolean; } declare module 'express-session' { diff --git a/types/user.types.ts b/types/user.types.ts index 2af0cdfa..7067bc66 100644 --- a/types/user.types.ts +++ b/types/user.types.ts @@ -8,6 +8,7 @@ declare global { export interface UserProperties { apiKey: string canUpdate: boolean + canUpdateWorkOrders: boolean isAdmin: boolean } diff --git a/views/dashboard.ejs b/views/dashboard.ejs index b023d9d2..7c3c7506 100644 --- a/views/dashboard.ejs +++ b/views/dashboard.ejs @@ -111,7 +111,7 @@