diff --git a/src/controllers/permissionChangeLogsController.js b/src/controllers/permissionChangeLogsController.js new file mode 100644 index 000000000..317b9f144 --- /dev/null +++ b/src/controllers/permissionChangeLogsController.js @@ -0,0 +1,30 @@ +const UserProfile = require('../models/userProfile'); + +const permissionChangeLogController = function (PermissionChangeLog) { + + const getPermissionChangeLogs = async function (req, res) { + + try { + const userProfile = await UserProfile.findOne({ _id: req.params.userId }).exec() + + if (userProfile) { + if (userProfile.role !== 'Owner') { + res.status(204).send([]) + } else { + const changeLogs = await PermissionChangeLog.find({}) + res.status(200).send(changeLogs) + } + } else { + res.status(403).send(`User (${req.params.userId}) not found.`) + } + } catch (err) { + console.error(err) + } + } + + return { + getPermissionChangeLogs + } +} + +module.exports = permissionChangeLogController \ No newline at end of file diff --git a/src/models/permissionChangeLog.js b/src/models/permissionChangeLog.js new file mode 100644 index 000000000..3ca37e416 --- /dev/null +++ b/src/models/permissionChangeLog.js @@ -0,0 +1,26 @@ +const mongoose = require('mongoose'); +const { Schema } = mongoose; + +const User = require('./userProfile'); +const rolesMergedPermissions = require('./role') + +const PermissionChangeLog = new Schema({ + logDateTime: { type: String, required: true }, + roleId: { + type: mongoose.Types.ObjectId, + ref: rolesMergedPermissions, + required: true + }, + roleName: { type: String }, + permissions: { type: [String], required: true }, + permissionsAdded: { type: [String], required: true }, + permissionsRemoved: { type: [String], required: true }, + requestorId: { + type: mongoose.Types.ObjectId, + ref: User + }, + requestorRole: { type: String }, + requestorEmail: { type: String, required: true}, +}); + +module.exports = mongoose.model('permissionChangeLog', PermissionChangeLog, 'permissionChangeLogs'); \ No newline at end of file diff --git a/src/routes/permissionChangeLogsRouter.js b/src/routes/permissionChangeLogsRouter.js new file mode 100644 index 000000000..8c1f46219 --- /dev/null +++ b/src/routes/permissionChangeLogsRouter.js @@ -0,0 +1,14 @@ +const express = require('express'); + +const routes = function (permissionChangeLog) { + const controller = require('../controllers/permissionChangeLogsController')(permissionChangeLog) + + const permissionChangeLogRouter = express.Router() + + permissionChangeLogRouter.route("/permissionChangeLogs/:userId") + .get(controller.getPermissionChangeLogs) + + return permissionChangeLogRouter +} + +module.exports = routes \ No newline at end of file diff --git a/src/routes/roleRouter.js b/src/routes/roleRouter.js index 8c5164f12..c9d4f963f 100644 --- a/src/routes/roleRouter.js +++ b/src/routes/roleRouter.js @@ -1,4 +1,5 @@ const express = require('express'); +const changedPermissionsLogger = require('../utilities/logPermissionChangeByAccount') const routes = function (role) { const controller = require('../controllers/rolesController')(role); @@ -10,7 +11,7 @@ const routes = function (role) { RolesRouter.route('/roles/:roleId') .get(controller.getRoleById) - .patch(controller.updateRoleById) + .patch(changedPermissionsLogger,controller.updateRoleById) .delete(controller.deleteRoleById); return RolesRouter; }; diff --git a/src/startup/routes.js b/src/startup/routes.js index 4701a9f61..a45598c78 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -21,6 +21,7 @@ const weeklySummaryAIPrompt = require('../models/weeklySummaryAIPrompt'); const profileInitialSetuptoken = require('../models/profileInitialSetupToken'); const reason = require('../models/reason'); const mouseoverText = require('../models/mouseoverText'); +const permissionChangeLog = require('../models/permissionChangeLog') // const inventoryItemMaterial = require('../models/inventoryItemMaterial'); const mapLocations = require('../models/mapLocation'); const buildingProject = require('../models/bmdashboard/buildingProject'); @@ -61,9 +62,9 @@ const taskNotificationRouter = require('../routes/taskNotificationRouter')(taskN const inventoryRouter = require('../routes/inventoryRouter')(inventoryItem, inventoryItemType); const timeZoneAPIRouter = require('../routes/timeZoneAPIRoutes')(); const profileInitialSetupRouter = require('../routes/profileInitialSetupRouter')(profileInitialSetuptoken, userProfile, project, mapLocations); +const permissionChangeLogRouter = require('../routes/permissionChangeLogsRouter')(permissionChangeLog) const isEmailExistsRouter = require('../routes/isEmailExistsRouter')(); - const taskEditSuggestion = require('../models/taskEditSuggestion'); const taskEditSuggestionRouter = require('../routes/taskEditSuggestionRouter')(taskEditSuggestion); const roleRouter = require('../routes/roleRouter')(role); @@ -112,6 +113,7 @@ module.exports = function (app) { app.use('/api', reasonRouter); app.use('/api', informationRouter); app.use('/api', mouseoverTextRouter); + app.use('/api', permissionChangeLogRouter); app.use('/api', isEmailExistsRouter); app.use('/api', mapLocationRouter); // bm dashboard diff --git a/src/utilities/logPermissionChangeByAccount.js b/src/utilities/logPermissionChangeByAccount.js new file mode 100644 index 000000000..dac2a4016 --- /dev/null +++ b/src/utilities/logPermissionChangeByAccount.js @@ -0,0 +1,68 @@ +const moment = require("moment-timezone"); +const PermissionChangeLog = require("../models/permissionChangeLog") + +// Middleware function +const changedPermissionsLogger = async (req, res, next) => { + await logPermissionChangeByAccount(req.body) + next(); +}; + +// Helper function finds the latest log related to the permission +const findLatestRelatedLog = (roleId) => { + + return new Promise((resolve, reject) => { + PermissionChangeLog.findOne({ roleId: roleId }) + .sort({ logDateTime: -1 }) + .exec((err, document) => { + if (err) { + console.error(err); + reject(err); + return; + } + resolve(document); + }); + }) +} + +// Function saves logs to hgnData_dev.permissionChangeLogs collection +const logPermissionChangeByAccount = async (requestBody) => { + const { roleId, roleName, permissions, requestor, role, email } = requestBody + const dateTime = moment().tz("America/Los_Angeles").format(); + + try { + let permissionsAdded = [] + let permissionsRemoved = [] + + // Find the latest log related to permission + const document = await findLatestRelatedLog(roleId) + + if (document) { + permissionsRemoved = document.permissions.filter(item => !(permissions.includes(item))) + permissionsAdded = permissions.filter(item => !(document.permissions.includes(item))) + } else { + // else this is the first permissions change log for this particular role + permissionsAdded = permissions + } + + + const logEntry = new PermissionChangeLog({ + logDateTime: dateTime, + roleId: roleId, + roleName: roleName, + permissions: permissions, + permissionsAdded: permissionsAdded, + permissionsRemoved: permissionsRemoved, + requestorId: requestor.requestorId, + requestorRole: role, + requestorEmail: email, + }) + + await logEntry.save() + + } catch (error) { + console.error('Error logging permission change:', error); + res.status(500).json({ error: 'Failed to log permission change' }); + } +} + +module.exports = changedPermissionsLogger;