diff --git a/BuildingUnits.json b/BuildingUnits.json index d6b336e7c..fed805856 100644 --- a/BuildingUnits.json +++ b/BuildingUnits.json @@ -114,9 +114,5 @@ { "unit": "Sand", "category": "Material" -}, -{ - "unit": "FakeUnitForTesting", - "category": "Material" } ] \ No newline at end of file diff --git a/src/controllers/bmdashboard/bmConsumableController.js b/src/controllers/bmdashboard/bmConsumableController.js index 23ea6e5cd..40d87fcdc 100644 --- a/src/controllers/bmdashboard/bmConsumableController.js +++ b/src/controllers/bmdashboard/bmConsumableController.js @@ -28,7 +28,7 @@ const bmConsumableController = function (BuildingConsumable) { }, ]) .exec() - .then(result => { + .then((result) => { res.status(200).send(result); }) .catch(error => res.status(500).send(error)); @@ -36,11 +36,10 @@ const bmConsumableController = function (BuildingConsumable) { res.json(err); } }; - + return { fetchBMConsumables, }; }; - + module.exports = bmConsumableController; - \ No newline at end of file diff --git a/src/controllers/bmdashboard/bmInventoryTypeController.js b/src/controllers/bmdashboard/bmInventoryTypeController.js index 66c1e0063..fc3a108bd 100644 --- a/src/controllers/bmdashboard/bmInventoryTypeController.js +++ b/src/controllers/bmdashboard/bmInventoryTypeController.js @@ -1,6 +1,9 @@ const fs = require('fs'); const path = require('path'); -const filepath = 'BuildingUnits.json'; +const filename = 'BuildingUnits.json'; +const currentFilePath = __filename; +const rootPath = path.resolve(path.dirname(currentFilePath), '../../../'); // Go up three levels to the root +const filepath = path.join(rootPath, filename); const readFile = fs.readFile; const writeFile = fs.writeFile; @@ -19,10 +22,11 @@ function bmInventoryTypeController(InvType, MatType, ConsType, ReusType, ToolTyp const fetchInvUnitsFromJson = async (req, res) => { try { + console.log(__dirname,filepath) readFile(filepath, 'utf8', (err, data) => { if (err) { console.error('Error reading file:', err); - return; + res.status(500).send(err); } try { @@ -84,7 +88,6 @@ function bmInventoryTypeController(InvType, MatType, ConsType, ReusType, ToolTyp writeFile(filepath, updatedFileContent, 'utf8', (error) => { if (error) { console.error('Error writing to file:', error); - return; } }); }); diff --git a/src/controllers/permissionChangeLogsController.js b/src/controllers/permissionChangeLogsController.js index 317b9f144..33ddb5d72 100644 --- a/src/controllers/permissionChangeLogsController.js +++ b/src/controllers/permissionChangeLogsController.js @@ -1,30 +1,28 @@ 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() + const userProfile = await UserProfile.findOne({ _id: req.params.userId }).exec(); if (userProfile) { if (userProfile.role !== 'Owner') { - res.status(204).send([]) + res.status(204).send([]); } else { - const changeLogs = await PermissionChangeLog.find({}) - res.status(200).send(changeLogs) + const changeLogs = await PermissionChangeLog.find({}); + res.status(200).send(changeLogs); } } else { - res.status(403).send(`User (${req.params.userId}) not found.`) + res.status(403).send(`User (${req.params.userId}) not found.`); } } catch (err) { - console.error(err) + console.error(err); } - } + }; return { - getPermissionChangeLogs - } -} + getPermissionChangeLogs, + }; +}; -module.exports = permissionChangeLogController \ No newline at end of file +module.exports = permissionChangeLogController; diff --git a/src/controllers/profileInitialSetupController.js b/src/controllers/profileInitialSetupController.js index 60d66424c..c8dacdeb2 100644 --- a/src/controllers/profileInitialSetupController.js +++ b/src/controllers/profileInitialSetupController.js @@ -1,10 +1,10 @@ -const mongoose = require("mongoose"); -const { v4: uuidv4 } = require("uuid"); -const moment = require("moment-timezone"); -const jwt = require("jsonwebtoken"); -const emailSender = require("../utilities/emailSender"); -const config = require("../config"); -const cache = require("../utilities/nodeCache")(); +const mongoose = require('mongoose'); +const { v4: uuidv4 } = require('uuid'); +const moment = require('moment-timezone'); +const jwt = require('jsonwebtoken'); +const emailSender = require('../utilities/emailSender'); +const config = require('../config'); +const cache = require('../utilities/nodeCache')(); // returns the email body that includes the setup link for the recipient. function sendLinkMessage(Link) { @@ -121,13 +121,13 @@ const profileInitialSetupController = function ( let { email, baseUrl, weeklyCommittedHours } = req.body; email = email.toLowerCase(); const token = uuidv4(); - const expiration = moment().tz("America/Los_Angeles").add(1, "week"); + const expiration = moment().tz('America/Los_Angeles').add(1, 'week'); try { const existingEmail = await userProfile.findOne({ email, }); if (existingEmail) { - res.status(400).send("email already in use"); + res.status(400).send('email already in use'); } else { await ProfileInitialSetupToken.findOneAndDelete({ email }); @@ -161,7 +161,7 @@ const profileInitialSetupController = function ( */ const validateSetupToken = async (req, res) => { const { token } = req.body; - const currentMoment = moment.tz("America/Los_Angeles"); + const currentMoment = moment.tz('America/Los_Angeles'); try { const foundToken = await ProfileInitialSetupToken.findOne({ token }); @@ -171,10 +171,10 @@ const profileInitialSetupController = function ( if (expirationMoment.isAfter(currentMoment)) { res.status(200).send(foundToken); } else { - res.status(400).send("Invalid token"); + res.status(400).send('Invalid token'); } } else { - res.status(404).send("Token not found"); + res.status(404).send('Token not found'); } } catch (error) { res.status(500).send(`Error finding token: ${error}`); @@ -192,30 +192,30 @@ const profileInitialSetupController = function ( */ const setUpNewUser = async (req, res) => { const { token } = req.body; - const currentMoment = moment.tz("America/Los_Angeles"); + const currentMoment = moment.tz('America/Los_Angeles'); try { const foundToken = await ProfileInitialSetupToken.findOne({ token }); const existingEmail = await userProfile.findOne({ email: foundToken.email, }); if (existingEmail) { - res.status(400).send("email already in use"); + res.status(400).send('email already in use'); } else if (foundToken) { const expirationMoment = moment(foundToken.expiration); if (expirationMoment.isAfter(currentMoment)) { const defaultProject = await Project.findOne({ - projectName: "Orientation and Initial Setup", + projectName: 'Orientation and Initial Setup', }); const newUser = new userProfile(); newUser.password = req.body.password; - newUser.role = "Volunteer"; + newUser.role = 'Volunteer'; newUser.firstName = req.body.firstName; newUser.lastName = req.body.lastName; newUser.jobTitle = req.body.jobTitle; newUser.phoneNumber = req.body.phoneNumber; - newUser.bio = ""; + newUser.bio = ''; newUser.weeklycommittedHours = foundToken.weeklyCommittedHours; newUser.weeklycommittedHoursHistory = [ { @@ -229,33 +229,32 @@ const profileInitialSetupController = function ( newUser.projects = Array.from(new Set([defaultProject])); newUser.createdDate = Date.now(); newUser.email = req.body.email; - newUser.weeklySummaries = [{ summary: "" }]; + newUser.weeklySummaries = [{ summary: '' }]; newUser.weeklySummariesCount = 0; - newUser.weeklySummaryOption = "Required"; - newUser.mediaUrl = ""; + newUser.weeklySummaryOption = 'Required'; + newUser.mediaUrl = ''; newUser.collaborationPreference = req.body.collaborationPreference; - newUser.timeZone = req.body.timeZone || "America/Los_Angeles"; + newUser.timeZone = req.body.timeZone || 'America/Los_Angeles'; newUser.location = req.body.location; newUser.profilePic = req.body.profilePicture; newUser.permissions = { frontPermissions: [], backPermissions: [], }; - newUser.bioPosted = "default"; + newUser.bioPosted = 'default'; newUser.privacySettings.email = req.body.privacySettings.email; - newUser.privacySettings.phoneNumber = - req.body.privacySettings.phoneNumber; - newUser.teamCode = ""; + newUser.privacySettings.phoneNumber = req.body.privacySettings.phoneNumber; + newUser.teamCode = ''; newUser.isFirstTimelog = true; const savedUser = await newUser.save(); emailSender( - process.env.MANAGER_EMAIL || "jae@onecommunityglobal.org", // "jae@onecommunityglobal.org" + process.env.MANAGER_EMAIL || 'jae@onecommunityglobal.org', // "jae@onecommunityglobal.org" `NEW USER REGISTERED: ${savedUser.firstName} ${savedUser.lastName}`, informManagerMessage(savedUser), null, - null + null, ); await ProfileInitialSetupToken.findByIdAndDelete(foundToken._id); @@ -265,7 +264,7 @@ const profileInitialSetupController = function ( permissions: savedUser.permissions, expiryTimestamp: moment().add( config.TOKEN.Lifetime, - config.TOKEN.Units + config.TOKEN.Units, ), }; @@ -299,14 +298,14 @@ const profileInitialSetupController = function ( email: savedUser.email, }; - const allUserCache = JSON.parse(cache.getCache("allusers")); + const allUserCache = JSON.parse(cache.getCache('allusers')); allUserCache.push(NewUserCache); - cache.setCache("allusers", JSON.stringify(allUserCache)); + cache.setCache('allusers', JSON.stringify(allUserCache)); } else { - res.status(400).send("Token is expired"); + res.status(400).send('Token is expired'); } } else { - res.status(400).send("Invalid token"); + res.status(400).send('Invalid token'); } } catch (error) { res.status(500).send(`Error: ${error}`); @@ -336,28 +335,28 @@ const profileInitialSetupController = function ( const users = []; const results = await userProfile.find( {}, - "location totalTangibleHrs hoursByCategory" + 'location totalTangibleHrs hoursByCategory', ); results.forEach((item) => { if ( - (item.location?.coords.lat && - item.location?.coords.lng && - item.totalTangibleHrs >= 10) || - (item.location?.coords.lat && - item.location?.coords.lng && - calculateTotalHours(item.hoursByCategory) >= 10) + (item.location?.coords.lat + && item.location?.coords.lng + && item.totalTangibleHrs >= 10) + || (item.location?.coords.lat + && item.location?.coords.lng + && calculateTotalHours(item.hoursByCategory) >= 10) ) { users.push(item); } }); - const modifiedUsers = users.map((item) => ({ + const modifiedUsers = users.map(item => ({ location: item.location, })); const mapUsers = await MapLocation.find({}); const combined = [...modifiedUsers, ...mapUsers]; - const countries = combined.map((user) => user.location.country); + const countries = combined.map(user => user.location.country); const totalUniqueCountries = [...new Set(countries)].length; res.status(200).send({ CountryCount: totalUniqueCountries }); } catch (error) { diff --git a/src/controllers/reasonSchedulingController.js b/src/controllers/reasonSchedulingController.js index a76dcf4a2..d8b883aa1 100644 --- a/src/controllers/reasonSchedulingController.js +++ b/src/controllers/reasonSchedulingController.js @@ -1,19 +1,19 @@ -const moment = require("moment-timezone"); -const UserModel = require("../models/userProfile"); -const ReasonModel = require("../models/reason"); -const emailSender = require("../utilities/emailSender"); +const moment = require('moment-timezone'); +const UserModel = require('../models/userProfile'); +const ReasonModel = require('../models/reason'); +const emailSender = require('../utilities/emailSender'); const postReason = async (req, res) => { try { const { userId, requestor, reasonData } = req.body; const newDate = moment - .tz(reasonData.date, "America/Los_Angeles") - .startOf("day"); - const currentDate = moment.tz("America/Los_Angeles").startOf("day"); + .tz(reasonData.date, 'America/Los_Angeles') + .startOf('day'); + const currentDate = moment.tz('America/Los_Angeles').startOf('day'); // error case 0 - if (moment.tz(reasonData.date, "America/Los_Angeles").day() !== 0) { + if (moment.tz(reasonData.date, 'America/Los_Angeles').day() !== 0) { return res.status(400).json({ message: "You must choose the Sunday YOU'LL RETURN as your date. This is so your reason ends up as a note on that blue square.", @@ -23,14 +23,14 @@ const postReason = async (req, res) => { if (newDate.isBefore(currentDate)) { return res.status(400).json({ - message: "You should select a date that is yet to come", + message: 'You should select a date that is yet to come', errorCode: 7, }); } if (!reasonData.message) { return res.status(400).json({ - message: "You must provide a reason.", + message: 'You must provide a reason.', errorCode: 6, }); } @@ -50,7 +50,7 @@ const postReason = async (req, res) => { // error case 2 if (!foundUser) { return res.status(404).json({ - message: "User not found", + message: 'User not found', errorCode: 2, }); } @@ -58,8 +58,8 @@ const postReason = async (req, res) => { // conditions added to check if timeOffFrom and timeOffTill fields existed if ( - foundUser.hasOwnProperty("timeOffFrom") && - foundUser.hasOwnProperty("timeOffTill") + foundUser.hasOwnProperty('timeOffFrom') + && foundUser.hasOwnProperty('timeOffTill') ) { // if currentDate is greater than or equal to the last timeOffTill date then both the fields will be updated if (currentDate >= foundUser.timeOffTill) { @@ -72,7 +72,7 @@ const postReason = async (req, res) => { timeOffFrom: currentDate, timeOffTill: newDate, }, - } + }, ); } else { // else only timeOffTill will be updated @@ -84,7 +84,7 @@ const postReason = async (req, res) => { $set: { timeOffTill: newDate, }, - } + }, ); } } else { @@ -98,7 +98,7 @@ const postReason = async (req, res) => { timeOffFrom: currentDate, timeOffTill: newDate, }, - } + }, ); } @@ -106,8 +106,8 @@ const postReason = async (req, res) => { const foundReason = await ReasonModel.findOne({ date: moment - .tz(reasonData.date, "America/Los_Angeles") - .startOf("day") + .tz(reasonData.date, 'America/Los_Angeles') + .startOf('day') .toISOString(), userId, }); @@ -115,14 +115,14 @@ const postReason = async (req, res) => { // error case 3 if (foundReason) { return res.status(403).json({ - message: "The reason must be unique to the date", + message: 'The reason must be unique to the date', errorCode: 3, }); } const savingDate = moment - .tz(reasonData.date, "America/Los_Angeles") - .startOf("day") + .tz(reasonData.date, 'America/Los_Angeles') + .startOf('day') .toISOString(); const newReason = new ReasonModel({ @@ -160,7 +160,7 @@ const postReason = async (req, res) => { } catch (error) { console.log(error); return res.status(400).json({ - errMessage: "Something went wrong", + errMessage: 'Something went wrong', }); } }; @@ -183,7 +183,7 @@ const getAllReasons = async (req, res) => { // error case 2 if (!foundUser) { return res.status(404).json({ - message: "User not found", + message: 'User not found', }); } @@ -197,7 +197,7 @@ const getAllReasons = async (req, res) => { } catch (error) { console.log(error); return res.status(400).json({ - errMessage: "Something went wrong while fetching the user", + errMessage: 'Something went wrong while fetching the user', }); } }; @@ -221,24 +221,24 @@ const getSingleReason = async (req, res) => { // error case 2 if (!foundUser) { return res.status(404).json({ - message: "User not found", + message: 'User not found', errorCode: 2, }); } const foundReason = await ReasonModel.findOne({ date: moment - .tz(queryDate, "America/Los_Angeles") - .startOf("day") + .tz(queryDate, 'America/Los_Angeles') + .startOf('day') .toISOString(), userId, }); if (!foundReason) { return res.status(200).json({ - reason: "", - date: "", - userId: "", + reason: '', + date: '', + userId: '', isSet: false, }); } @@ -247,7 +247,7 @@ const getSingleReason = async (req, res) => { } catch (error) { console.log(error); return res.status(400).json({ - message: "Something went wrong while fetching single reason", + message: 'Something went wrong while fetching single reason', }); } }; @@ -268,7 +268,7 @@ const patchReason = async (req, res) => { if (!reasonData.message) { return res.status(400).json({ - message: "You must provide a reason.", + message: 'You must provide a reason.', errorCode: 6, }); } @@ -278,22 +278,22 @@ const patchReason = async (req, res) => { // error case 2 if (!foundUser) { return res.status(404).json({ - message: "User not found", + message: 'User not found', errorCode: 2, }); } const foundReason = await ReasonModel.findOne({ date: moment - .tz(reasonData.date, "America/Los_Angeles") - .startOf("day") + .tz(reasonData.date, 'America/Los_Angeles') + .startOf('day') .toISOString(), userId, }); // error case 4 if (!foundReason) { return res.status(404).json({ - message: "Reason not found", + message: 'Reason not found', errorCode: 4, }); } @@ -325,12 +325,12 @@ const patchReason = async (req, res) => { } return res.status(200).json({ - message: "Reason Updated!", - message: "Reason Updated!", + message: 'Reason Updated!', + message: 'Reason Updated!', }); } catch (error) { return res.status(400).json({ - message: "something went wrong while patching the reason", + message: 'something went wrong while patching the reason', }); } }; @@ -341,10 +341,10 @@ const deleteReason = async (req, res) => { const { userId } = req.params; // error case 1 - if (requestor.role !== "Owner" && requestor.role !== "Administrator") { + if (requestor.role !== 'Owner' && requestor.role !== 'Administrator') { return res.status(403).json({ message: - "You must be an Owner or Administrator to schedule a reason for a Blue Square", + 'You must be an Owner or Administrator to schedule a reason for a Blue Square', errorCode: 1, }); @@ -355,21 +355,21 @@ const deleteReason = async (req, res) => { // error case 2 if (!foundUser) { return res.status(404).json({ - message: "User not found", + message: 'User not found', errorCode: 2, }); } const foundReason = await ReasonModel.findOne({ date: moment - .tz(reasonData.date, "America/Los_Angeles") - .startOf("day") + .tz(reasonData.date, 'America/Los_Angeles') + .startOf('day') .toISOString(), }); if (!foundReason) { return res.status(404).json({ - message: "Reason not found", + message: 'Reason not found', errorCode: 4, }); } @@ -377,13 +377,13 @@ const deleteReason = async (req, res) => { foundReason.remove((err) => { if (err) { return res.status(500).json({ - message: "Error while deleting document", + message: 'Error while deleting document', errorCode: 5, }); } return res.status(200).json({ - message: "Document deleted", + message: 'Document deleted', }); }); } catch (error) {} diff --git a/src/controllers/timeOffRequestController.js b/src/controllers/timeOffRequestController.js new file mode 100644 index 000000000..29563124a --- /dev/null +++ b/src/controllers/timeOffRequestController.js @@ -0,0 +1,162 @@ +const mongoose = require('mongoose'); +const moment = require('moment-timezone'); +const { hasPermission } = require('../utilities/permissions'); + +const timeOffRequestController = function (TimeOffRequest) { + const setTimeOffRequest = async (req, res) => { + if (!await hasPermission(req.body.requestor, 'manageTimeOffRequests')) { + res.status(403).send('You are not authorized to set time off requests.'); + return; + } + const { + duration, startingDate, reason, requestFor, +} = req.body; + if (!duration || !startingDate || !reason || !requestFor) { + res.status(400).send('bad request'); + return; + } + moment.tz.setDefault('America/Los_Angeles'); + + const startDate = moment(startingDate); + const endDate = startDate.clone().add(Number(duration), 'weeks').subtract(1, 'second'); + + + const newTimeOffRequest = new TimeOffRequest(); + + newTimeOffRequest.requestFor = mongoose.Types.ObjectId(requestFor); + newTimeOffRequest.reason = reason; + newTimeOffRequest.startingDate = startDate.toDate(); + newTimeOffRequest.endingDate = endDate.toDate(); + newTimeOffRequest.duration = Number(duration); + + try { + const savedRequest = await newTimeOffRequest.save(); + res.status(201).send(savedRequest); + } catch (error) { + res.status(500).send('Error saving the request.'); + } + }; + + const getTimeOffRequests = async (req, res) => { + try { + const allRequests = await TimeOffRequest.aggregate([ + { + $sort: { requestFor: 1 }, // Sort by requestFor in ascending order + }, + { + $group: { + _id: '$requestFor', + requests: { $push: '$$ROOT' }, // Group requests by requestFor + }, + }, + { + $project: { + _id: 0, + requestFor: '$_id', + requests: 1, + }, + }, + ]); + + const formattedRequests = {}; + allRequests.forEach((request) => { + formattedRequests[request.requestFor] = request.requests; + }); + + res.status(200).send(formattedRequests); + } catch (error) { + res.status(500).send(error); + } + }; + + const getTimeOffRequestbyId = async (req, res) => { + const requestId = req.params.id; + + try { + const request = await TimeOffRequest.findById(requestId); + + if (!request) { + res.status(404).send('Time off request not found'); + return; + } + + res.status(200).send(request); + } catch (error) { + res.status(500).send(error); + } + }; + + const updateTimeOffRequestById = async (req, res) => { + if (!await hasPermission(req.body.requestor, 'manageTimeOffRequests')) { + res.status(403).send('You are not authorized to update time off requests.'); + return; + } + const requestId = req.params.id; + const { duration, startingDate, reason } = req.body; + if (!duration || !startingDate || !reason || !requestId) { + res.status(400).send('bad request'); + return; + } + moment.tz.setDefault('America/Los_Angeles'); + + const startDate = moment(startingDate); + const endDate = startDate.clone().add(Number(duration), 'weeks').subtract(1, 'second'); + + const updateData = { + reason, + startingDate: startDate.toDate(), + endingDate: endDate.toDate(), + duration, + }; + + try { + const updatedRequest = await TimeOffRequest.findByIdAndUpdate( + requestId, + updateData, + { + new: true, + }, + ); + + if (!updatedRequest) { + res.status(404).send('Time off request not found'); + return; + } + + res.status(200).send(updatedRequest); + } catch (error) { + res.status(500).send(error); + } + }; + + const deleteTimeOffRequestById = async (req, res) => { + if (!await hasPermission(req.body.requestor, 'manageTimeOffRequests')) { + res.status(403).send('You are not authorized to delete time off requests.'); + return; + } + const requestId = req.params.id; + + try { + const deletedRequest = await TimeOffRequest.findByIdAndDelete(requestId); + + if (!deletedRequest) { + res.status(404).send('Time off request not found'); + return; + } + + res.status(200).send(deletedRequest); + } catch (error) { + res.status(500).send(error); + } + }; + + return { + setTimeOffRequest, + getTimeOffRequests, + getTimeOffRequestbyId, + updateTimeOffRequestById, + deleteTimeOffRequestById, + }; +}; + +module.exports = timeOffRequestController; diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 52da2c3c1..78b1089ea 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -483,11 +483,7 @@ const userProfileController = function (UserProfile) { return; } - if ( - !userId - || !option - || (option !== 'delete' && option !== 'archive') - ) { + if (!userId || !option || (option !== 'delete' && option !== 'archive')) { res.status(400).send({ error: 'Bad request', }); @@ -512,7 +508,9 @@ const userProfileController = function (UserProfile) { ); if (!timeArchiveUser) { - logger.logException('Time Archive user was not found. Please check the database'); + logger.logException( + 'Time Archive user was not found. Please check the database', + ); res.status(500).send({ error: 'Time Archive User not found. Please contact your developement team on why that happened', @@ -552,7 +550,10 @@ const userProfileController = function (UserProfile) { return; } - UserProfile.findById(userid, '-password -refreshTokens -lastModifiedDate -__v') + UserProfile.findById( + userid, + '-password -refreshTokens -lastModifiedDate -__v', + ) .populate([ { path: 'teams', @@ -577,7 +578,8 @@ const userProfileController = function (UserProfile) { populate: { path: 'badge', model: Badge, - select: '_id badgeName type imageUrl description ranking showReport', + select: + '_id badgeName type imageUrl description ranking showReport', }, }, ]) @@ -587,13 +589,15 @@ const userProfileController = function (UserProfile) { res.status(400).send({ error: 'This is not a valid user' }); return; } - userHelper.getTangibleHoursReportedThisWeekByUserId(userid).then((hours) => { - results.set('tangibleHoursReportedThisWeek', hours, { - strict: false, + userHelper + .getTangibleHoursReportedThisWeekByUserId(userid) + .then((hours) => { + results.set('tangibleHoursReportedThisWeek', hours, { + strict: false, + }); + cache.setCache(`user-${userid}`, JSON.stringify(results)); + res.status(200).send(results); }); - cache.setCache(`user-${userid}`, JSON.stringify(results)); - res.status(200).send(results); - }); }) .catch(error => res.status(404).send(error)); }; @@ -653,7 +657,11 @@ const userProfileController = function (UserProfile) { } // Verify correct params in body - if (!req.body.currentpassword || !req.body.newpassword || !req.body.confirmnewpassword) { + if ( + !req.body.currentpassword + || !req.body.newpassword + || !req.body.confirmnewpassword + ) { return res.status(400).send({ error: 'One of more required fields are missing', }); @@ -722,7 +730,14 @@ const userProfileController = function (UserProfile) { const userid = mongoose.Types.ObjectId(req.params.userId); - let validroles = ['Volunteer', 'Manager', 'Administrator', 'Core Team', 'Owner', 'Mentor']; + let validroles = [ + 'Volunteer', + 'Manager', + 'Administrator', + 'Core Team', + 'Owner', + 'Mentor', + ]; if (await hasPermission(req.body.requestor, 'getReporteesLimitRoles')) { validroles = ['Volunteer', 'Manager']; @@ -814,7 +829,9 @@ const userProfileController = function (UserProfile) { const isUserInCache = cache.hasCache('allusers'); if (isUserInCache) { const allUserData = JSON.parse(cache.getCache('allusers')); - const userIdx = allUserData.findIndex(users => users._id === userId); + const userIdx = allUserData.findIndex( + users => users._id === userId, + ); const userData = allUserData[userIdx]; if (!status) { userData.endDate = user.endDate.toISOString(); diff --git a/src/helpers/reporthelper.js b/src/helpers/reporthelper.js index eac0a71a1..6e5ca2bd9 100644 --- a/src/helpers/reporthelper.js +++ b/src/helpers/reporthelper.js @@ -121,13 +121,13 @@ const reporthelper = function () { }, }, teamCode: { - $ifNull: ["$teamCode", ""], + $ifNull: ['$teamCode', ''], }, timeOffFrom: { - $ifNull: ["$timeOffFrom", null], + $ifNull: ['$timeOffFrom', null], }, timeOffTill: { - $ifNull: ["$timeOffTill", null], + $ifNull: ['$timeOffTill', null], }, role: 1, weeklySummaries: { diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index b4b2acb46..fd8b8ea82 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -14,6 +14,7 @@ const logger = require('../startup/logger'); const Reason = require('../models/reason'); const token = require('../models/profileInitialSetupToken'); const cache = require('../utilities/nodeCache')(); +const timeOffRequest = require('../models/timeOffRequest'); const userHelper = function () { // Update format to "MMM-DD-YY" from "YYYY-MMM-DD" (Confirmed with Jae) @@ -72,6 +73,16 @@ const userHelper = function () { }; }; + const formatTimeOffRequestsDescription = (inputString) => { + const searchTerm = 'Notice:'; + if (inputString.includes(searchTerm)) { + const parts = inputString.split(searchTerm); + const formattedString = `${parts[0] }
${ searchTerm }` + `${ parts[1] }`; + return formattedString; + } + return inputString; + }; + const getInfringementEmailBody = function ( firstName, lastName, @@ -91,7 +102,7 @@ const userHelper = function () { const text = `Dear ${firstName} ${lastName},

Oops, it looks like something happened and you’ve managed to get a blue square.

Date Assigned: ${infringement.date}

-

Description: ${infringement.description}

+

Description: ${formatTimeOffRequestsDescription(infringement.description)}

Total Infringements: This is your ${moment .localeData() .ordinal(totalInfringements)} blue square of 5.

@@ -355,6 +366,7 @@ const userHelper = function () { const weeklycommittedHours = user.weeklycommittedHours + (user.missedHours ?? 0); const timeNotMet = timeSpent < weeklycommittedHours; + let description; const timeRemaining = weeklycommittedHours - timeSpent; @@ -411,6 +423,33 @@ const userHelper = function () { ); } + const utcStartMoment = moment(pdtStartOfLastWeek).add(1, 'second'); + const utcEndMoment = moment(pdtStartOfLastWeek).subtract(1, 'second'); + + const requestsForTimeOff = await timeOffRequest.find({ + requestFor: personId, + startingDate: { $lte: utcStartMoment }, + endingDate: { $gte: utcEndMoment }, + }); + + const hasTimeOffRequest = requestsForTimeOff.length > 0; + let requestForTimeOff; + let requestForTimeOffStartingDate; + let requestForTimeOffEndingDate; + let requestForTimeOffreason; + + + if (hasTimeOffRequest) { + requestForTimeOff = requestsForTimeOff[0]; + requestForTimeOffStartingDate = moment( + requestForTimeOff.startingDate, + ).format('dddd YYYY-MM-DD'); + requestForTimeOffEndingDate = moment( + requestForTimeOff.endingDate, + ).format('dddd YYYY-MM-DD'); + requestForTimeOffreason = requestForTimeOff.reason; + } + if (timeNotMet || !hasWeeklySummary) { if (foundReason) { description = foundReason.reason; @@ -419,19 +458,23 @@ const userHelper = function () { 2, )} hours against committed effort of ${weeklycommittedHours} hours in the week starting ${pdtStartOfLastWeek.format( 'dddd YYYY-MM-DD', - )} and ending ${pdtEndOfLastWeek.format('dddd YYYY-MM-DD')}.`; + )} and ending ${pdtEndOfLastWeek.format('dddd YYYY-MM-DD')}. + ${hasTimeOffRequest ? `Notice: unavailable from ${requestForTimeOffStartingDate}, to ${requestForTimeOffEndingDate}, due to ${requestForTimeOffreason}` : ''}`; } else if (timeNotMet) { description = `System auto-assigned infringement for not meeting weekly volunteer time commitment. You logged ${timeSpent.toFixed( 2, )} hours against committed effort of ${weeklycommittedHours} hours in the week starting ${pdtStartOfLastWeek.format( 'dddd YYYY-MM-DD', - )} and ending ${pdtEndOfLastWeek.format('dddd YYYY-MM-DD')}.`; + )} and ending ${pdtEndOfLastWeek.format('dddd YYYY-MM-DD')}. + ${hasTimeOffRequest ? `Notice: unavailable from ${requestForTimeOffStartingDate}, to ${requestForTimeOffEndingDate}, due to ${requestForTimeOffreason}` : ''}`; } else { description = `System auto-assigned infringement for not submitting a weekly summary for the week starting ${pdtStartOfLastWeek.format( 'dddd YYYY-MM-DD', - )} and ending ${pdtEndOfLastWeek.format('dddd YYYY-MM-DD')}.`; + )} and ending ${pdtEndOfLastWeek.format('dddd YYYY-MM-DD')}. + ${hasTimeOffRequest ? `Notice: unavailable from ${requestForTimeOffStartingDate}, to ${requestForTimeOffEndingDate}, due to ${requestForTimeOffreason}` : ''}`; } + const infringement = { date: moment().utc().format('YYYY-MM-DD'), description, @@ -521,7 +564,8 @@ const userHelper = function () { } } } - } + } + await deleteOldTimeOffRequests(); } catch (err) { logger.logException(err); } @@ -843,10 +887,11 @@ const userHelper = function () { personId, { $pull: { - badgeCollection: { badge: badgeId }, - }, + badgeCollection: { _id: mongoose.Types.ObjectId(badgeId) } + } }, - (err) => { + { new: true }, + err => { if (err) { throw new Error(err); } @@ -1107,19 +1152,28 @@ const changeBadgeCount = async function (personId, badgeId, count) { // 'Personal Max', const checkPersonalMax = async function (personId, user, badgeCollection) { let badgeOfType; + let duplicateBadges = []; + for (let i = 0; i < badgeCollection.length; i += 1) { - if (badgeCollection[i].badge?.type === 'Personal Max') { - if (badgeOfType) { - removeDupBadge(personId, badgeOfType._id); + if (badgeCollection[i].badge?.type === "Personal Max") { + if (!badgeOfType) { + badgeOfType = badgeCollection[i]; + } else { + duplicateBadges.push(badgeCollection[i]); } } + for (let badge of duplicateBadges) { + await removeDupBadge(personId, badge._id); + } } await badge.findOne({ type: 'Personal Max' }).then((results) => { if ( - user.lastWeekTangibleHrs - && user.lastWeekTangibleHrs >= 1 - && user.lastWeekTangibleHrs === user.personalBestMaxHrs - ) { + + user.lastWeekTangibleHrs && + user.lastWeekTangibleHrs >= 1 && + user.lastWeekTangibleHrs === user.personalBestMaxHrs + ) + { if (badgeOfType) { changeBadgeCount( personId, @@ -1127,11 +1181,8 @@ const changeBadgeCount = async function (personId, badgeId, count) { user.personalBestMaxHrs, ); } else { - addBadge( - personId, - mongoose.Types.ObjectId(results._id), - user.personalBestMaxHrs, - ); + addBadge(personId, mongoose.Types.ObjectId(results._id), user.personalBestMaxHrs); + } } }); @@ -1489,17 +1540,13 @@ const changeBadgeCount = async function (personId, badgeId, count) { }; const awardNewBadges = async () => { - console.log('Awarding'); try { - // This will be used in production to run task on all users - const users = await userProfile - .find({ isActive: true }) - .populate('badgeCollection.badge'); - + const users = await userProfile.find({ isActive: true }).populate('badgeCollection.badge'); for (let i = 0; i < users.length; i += 1) { const user = users[i]; const { _id, badgeCollection } = user; const personId = mongoose.Types.ObjectId(_id); + await checkPersonalMax(personId, user, badgeCollection); await checkMostHrsWeek(personId, user, badgeCollection); await checkMinHoursMultiple(personId, user, badgeCollection); @@ -1519,15 +1566,10 @@ const changeBadgeCount = async function (personId, badgeId, count) { const getTangibleHoursReportedThisWeekByUserId = function (personId) { const userId = mongoose.Types.ObjectId(personId); + + const pdtstart = moment().tz('America/Los_Angeles').startOf('week').format('YYYY-MM-DD'); + const pdtend = moment().tz('America/Los_Angeles').endOf('week').format('YYYY-MM-DD'); - const pdtstart = moment() - .tz('America/Los_Angeles') - .startOf('week') - .format('YYYY-MM-DD'); - const pdtend = moment() - .tz('America/Los_Angeles') - .endOf('week') - .format('YYYY-MM-DD'); return timeEntries .find( @@ -1612,6 +1654,22 @@ const changeBadgeCount = async function (personId, badgeId, count) { } }; + const deleteOldTimeOffRequests = async () => { + const endOfLastWeek = moment() + .tz('America/Los_Angeles') + .endOf('week') + .subtract(1, 'week'); + + const utcEndMoment = moment(endOfLastWeek).add(1, 'second'); + console.log(utcEndMoment); + try { + await timeOffRequest.deleteMany({ endingDate: { $lte: utcEndMoment } }); + console.log('Deleted expired time off requests.'); + } catch (error) { + console.error('Error deleting expired time off requests:', error); + } + }; + return { changeBadgeCount, getUserName, @@ -1628,6 +1686,7 @@ const changeBadgeCount = async function (personId, badgeId, count) { awardNewBadges, getTangibleHoursReportedThisWeekByUserId, deleteExpiredTokens, + deleteOldTimeOffRequests, }; }; diff --git a/src/models/bmdashboard/buildingInventoryType.js b/src/models/bmdashboard/buildingInventoryType.js index bd125dfd3..821f3e57b 100644 --- a/src/models/bmdashboard/buildingInventoryType.js +++ b/src/models/bmdashboard/buildingInventoryType.js @@ -80,4 +80,4 @@ module.exports = { reusableType, toolType, equipmentType, -}; \ No newline at end of file +}; diff --git a/src/models/mapLocation.js b/src/models/mapLocation.js index 5f42678d0..f0689b72a 100644 --- a/src/models/mapLocation.js +++ b/src/models/mapLocation.js @@ -3,21 +3,19 @@ const mongoose = require('mongoose'); const { Schema } = mongoose; const capitalizeString = (s) => { - if (typeof s !== 'string') { return s; } const words = s.split(' '); - const capitalizedWords = words.map(word => { + const capitalizedWords = words.map((word) => { if (word.length > 0) { return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(); - } else { - return ''; } + return ''; }); const capitalizedString = capitalizedWords.join(' '); return capitalizedString; -} +}; const mapLocation = new Schema({ title: { diff --git a/src/models/permissionChangeLog.js b/src/models/permissionChangeLog.js index 3ca37e416..ee8597ee5 100644 --- a/src/models/permissionChangeLog.js +++ b/src/models/permissionChangeLog.js @@ -1,26 +1,27 @@ const mongoose = require('mongoose'); + const { Schema } = mongoose; const User = require('./userProfile'); -const rolesMergedPermissions = require('./role') +const rolesMergedPermissions = require('./role'); const PermissionChangeLog = new Schema({ logDateTime: { type: String, required: true }, - roleId: { - type: mongoose.Types.ObjectId, - ref: rolesMergedPermissions, - 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: { + requestorId: { type: mongoose.Types.ObjectId, - ref: User + ref: User, }, requestorRole: { type: String }, - requestorEmail: { type: String, required: true}, + requestorEmail: { type: String, required: true }, }); -module.exports = mongoose.model('permissionChangeLog', PermissionChangeLog, 'permissionChangeLogs'); \ No newline at end of file +module.exports = mongoose.model('permissionChangeLog', PermissionChangeLog, 'permissionChangeLogs'); diff --git a/src/models/timeOffRequest.js b/src/models/timeOffRequest.js new file mode 100644 index 000000000..d87184b36 --- /dev/null +++ b/src/models/timeOffRequest.js @@ -0,0 +1,14 @@ +const mongoose = require('mongoose'); + +const { Schema } = mongoose; + +const timeOffRequest = new Schema({ + requestFor: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + reason: { type: 'String', required: true }, + startingDate: { type: Date, required: true }, + endingDate: { type: Date }, + duration: { type: Number, required: true }, // in weeks + +}); + +module.exports = mongoose.model('timeOffRequest', timeOffRequest, 'timeOffRequests'); diff --git a/src/models/userProfile.js b/src/models/userProfile.js index 633a81026..61269a990 100644 --- a/src/models/userProfile.js +++ b/src/models/userProfile.js @@ -1,9 +1,9 @@ -const mongoose = require("mongoose"); -const moment = require("moment-timezone"); +const mongoose = require('mongoose'); +const moment = require('moment-timezone'); const { Schema } = mongoose; -const validate = require("mongoose-validator"); -const bcrypt = require("bcryptjs"); +const validate = require('mongoose-validator'); +const bcrypt = require('bcryptjs'); const SALT_ROUNDS = 10; const nextDay = new Date(); @@ -15,12 +15,11 @@ const userProfileSchema = new Schema({ required: true, validate: { validator(v) { - const passwordregex = - /(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/; + const passwordregex = /(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/; return passwordregex.test(v); }, message: - "{VALUE} is not a valid password!password should be at least 8 charcaters long with uppercase, lowercase and number/special char.", + '{VALUE} is not a valid password!password should be at least 8 charcaters long with uppercase, lowercase and number/special char.', }, }, isActive: { type: Boolean, required: true, default: true }, @@ -49,7 +48,7 @@ const userProfileSchema = new Schema({ required: true, unique: true, validate: [ - validate({ validator: "isEmail", message: "Email address is invalid" }), + validate({ validator: 'isEmail', message: 'Email address is invalid' }), ], }, weeklycommittedHours: { type: Number, default: 10 }, @@ -67,11 +66,11 @@ const userProfileSchema = new Schema({ { _id: Schema.Types.ObjectId, Name: String, Link: { type: String } }, ], adminLinks: [{ _id: Schema.Types.ObjectId, Name: String, Link: String }], - teams: [{ type: mongoose.SchemaTypes.ObjectId, ref: "team" }], - projects: [{ type: mongoose.SchemaTypes.ObjectId, ref: "project" }], + teams: [{ type: mongoose.SchemaTypes.ObjectId, ref: 'team' }], + projects: [{ type: mongoose.SchemaTypes.ObjectId, ref: 'project' }], badgeCollection: [ { - badge: { type: mongoose.SchemaTypes.ObjectId, ref: "badge" }, + badge: { type: mongoose.SchemaTypes.ObjectId, ref: 'badge' }, count: { type: Number, default: 0 }, earnedDate: { type: Array, default: [] }, lastModified: { type: Date, required: true, default: Date.now() }, @@ -90,13 +89,13 @@ const userProfileSchema = new Schema({ }, ], location: { - userProvided: { type: String, default: "" }, + userProvided: { type: String, default: '' }, coords: { - lat: { type: Number, default: "" }, - lng: { type: Number, default: "" }, + lat: { type: Number, default: '' }, + lng: { type: Number, default: '' }, }, - country: { type: String, default: "" }, - city: { type: String, default: "" }, + country: { type: String, default: '' }, + city: { type: String, default: '' }, }, oldInfringements: [ { @@ -118,7 +117,7 @@ const userProfileSchema = new Schema({ dueDate: { type: Date, required: true, - default: moment().tz("America/Los_Angeles").endOf("week"), + default: moment().tz('America/Los_Angeles').endOf('week'), }, summary: { type: String }, uploadDate: { type: Date }, @@ -148,17 +147,17 @@ const userProfileSchema = new Schema({ category: { type: String, enum: [ - "Food", - "Energy", - "Housing", - "Education", - "Society", - "Economics", - "Stewardship", - "Other", - "Unspecified", + 'Food', + 'Energy', + 'Housing', + 'Education', + 'Society', + 'Economics', + 'Stewardship', + 'Other', + 'Unspecified', ], - default: "Other", + default: 'Other', }, hrs: { type: Number, default: 0 }, }, @@ -169,27 +168,27 @@ const userProfileSchema = new Schema({ date: { type: Date, required: true, - default: moment().tz("America/Los_Angeles").toDate(), + default: moment().tz('America/Los_Angeles').toDate(), }, initialSeconds: { type: Number, required: true }, newSeconds: { type: Number, required: true }, }, ], weeklySummaryNotReq: { type: Boolean, default: false }, - timeZone: { type: String, required: true, default: "America/Los_Angeles" }, + timeZone: { type: String, required: true, default: 'America/Los_Angeles' }, isVisible: { type: Boolean, default: false }, weeklySummaryOption: { type: String }, - bioPosted: { type: String, default: "default" }, + bioPosted: { type: String, default: 'default' }, isFirstTimelog: { type: Boolean, default: true }, teamCode: { type: String, - default: "", + default: '', validate: { validator(v) { const teamCoderegex = /^([a-zA-Z]-[a-zA-Z]{3}|[a-zA-Z]{5})$|^$/; return teamCoderegex.test(v); }, - message: "Please enter a code in the format of A-AAA or AAAAA", + message: 'Please enter a code in the format of A-AAA or AAAAA', }, }, infoCollections: [ @@ -204,22 +203,22 @@ const userProfileSchema = new Schema({ timeOffTill: { type: Date, default: undefined }, }); -userProfileSchema.pre("save", function (next) { +userProfileSchema.pre('save', function (next) { const user = this; - if (!user.isModified("password")) return next(); + if (!user.isModified('password')) return next(); return bcrypt .genSalt(SALT_ROUNDS) - .then((result) => bcrypt.hash(user.password, result)) + .then(result => bcrypt.hash(user.password, result)) .then((hash) => { user.password = hash; return next(); }) - .catch((error) => next(error)); + .catch(error => next(error)); }); module.exports = mongoose.model( - "userProfile", + 'userProfile', userProfileSchema, - "userProfiles" + 'userProfiles', ); diff --git a/src/routes/permissionChangeLogsRouter.js b/src/routes/permissionChangeLogsRouter.js index 8c1f46219..50ed7696b 100644 --- a/src/routes/permissionChangeLogsRouter.js +++ b/src/routes/permissionChangeLogsRouter.js @@ -1,14 +1,14 @@ const express = require('express'); const routes = function (permissionChangeLog) { - const controller = require('../controllers/permissionChangeLogsController')(permissionChangeLog) + const controller = require('../controllers/permissionChangeLogsController')(permissionChangeLog); - const permissionChangeLogRouter = express.Router() + const permissionChangeLogRouter = express.Router(); - permissionChangeLogRouter.route("/permissionChangeLogs/:userId") - .get(controller.getPermissionChangeLogs) + permissionChangeLogRouter.route('/permissionChangeLogs/:userId') + .get(controller.getPermissionChangeLogs); - return permissionChangeLogRouter -} + return permissionChangeLogRouter; +}; -module.exports = routes \ No newline at end of file +module.exports = routes; diff --git a/src/routes/roleRouter.js b/src/routes/roleRouter.js index c9d4f963f..d2ebff196 100644 --- a/src/routes/roleRouter.js +++ b/src/routes/roleRouter.js @@ -1,5 +1,5 @@ const express = require('express'); -const changedPermissionsLogger = require('../utilities/logPermissionChangeByAccount') +const changedPermissionsLogger = require('../utilities/logPermissionChangeByAccount'); const routes = function (role) { const controller = require('../controllers/rolesController')(role); @@ -11,7 +11,7 @@ const routes = function (role) { RolesRouter.route('/roles/:roleId') .get(controller.getRoleById) - .patch(changedPermissionsLogger,controller.updateRoleById) + .patch(changedPermissionsLogger, controller.updateRoleById) .delete(controller.deleteRoleById); return RolesRouter; }; diff --git a/src/routes/timeOffRequestRouter.js b/src/routes/timeOffRequestRouter.js new file mode 100644 index 000000000..1dd27f05b --- /dev/null +++ b/src/routes/timeOffRequestRouter.js @@ -0,0 +1,26 @@ +const express = require('express'); + + +const routes = function (timeOffRequest) { + const timeOffRequestRouter = express.Router(); + const controller = require('../controllers/timeOffRequestController')(timeOffRequest); + + timeOffRequestRouter.route('/setTimeOffRequest') + .post(controller.setTimeOffRequest); + + timeOffRequestRouter.route('/getTimeOffRequests') + .get(controller.getTimeOffRequests); + + timeOffRequestRouter.route('/getTimeOffRequest/:id') + .get(controller.getTimeOffRequestbyId); + + timeOffRequestRouter.route('/updateTimeOffRequest/:id') + .post(controller.updateTimeOffRequestById); + + timeOffRequestRouter.route('/deleteTimeOffRequest/:id') + .delete(controller.deleteTimeOffRequestById); + + return timeOffRequestRouter; +}; + +module.exports = routes; diff --git a/src/startup/routes.js b/src/startup/routes.js index 1860d7060..de4dd0377 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -39,6 +39,7 @@ const { buildingTool, } = require('../models/bmdashboard/buildingInventoryItem'); // const buildingTool = require('../models/bmdashboard/buildingTool'); +const timeOffRequest = require('../models/timeOffRequest'); const userProfileRouter = require('../routes/userProfileRouter')(userProfile); const badgeRouter = require('../routes/badgeRouter')(badge); @@ -74,6 +75,7 @@ const reasonRouter = require('../routes/reasonRouter')(reason, userProfile); const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverText); const mapLocationRouter = require('../routes/mapLocationsRouter')(mapLocations); +const timeOffRequestRouter = require('../routes/timeOffRequestRouter')(timeOffRequest); // bm dashboard const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); @@ -123,4 +125,5 @@ module.exports = function (app) { app.use('/api/bm', bmInventoryTypeRouter); app.use('/api/bm', bmToolRouter); app.use('/api/bm', bmConsumablesRouter); + app.use('/api', timeOffRequestRouter); }; diff --git a/src/utilities/logPermissionChangeByAccount.js b/src/utilities/logPermissionChangeByAccount.js index dac2a4016..0d3f72f76 100644 --- a/src/utilities/logPermissionChangeByAccount.js +++ b/src/utilities/logPermissionChangeByAccount.js @@ -1,17 +1,15 @@ -const moment = require("moment-timezone"); -const PermissionChangeLog = require("../models/permissionChangeLog") +const moment = require('moment-timezone'); +const PermissionChangeLog = require('../models/permissionChangeLog'); // Middleware function const changedPermissionsLogger = async (req, res, next) => { - await logPermissionChangeByAccount(req.body) + 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 }) +const findLatestRelatedLog = roleId => new Promise((resolve, reject) => { + PermissionChangeLog.findOne({ roleId }) .sort({ logDateTime: -1 }) .exec((err, document) => { if (err) { @@ -21,48 +19,48 @@ const findLatestRelatedLog = (roleId) => { } 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(); - + const { + roleId, roleName, permissions, requestor, role, email, +} = requestBody; + const dateTime = moment().tz('America/Los_Angeles').format(); + try { - let permissionsAdded = [] - let permissionsRemoved = [] + let permissionsAdded = []; + let permissionsRemoved = []; // Find the latest log related to permission - const document = await findLatestRelatedLog(roleId) + const document = await findLatestRelatedLog(roleId); if (document) { - permissionsRemoved = document.permissions.filter(item => !(permissions.includes(item))) - permissionsAdded = permissions.filter(item => !(document.permissions.includes(item))) + 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 + permissionsAdded = permissions; } - + const logEntry = new PermissionChangeLog({ logDateTime: dateTime, - roleId: roleId, - roleName: roleName, - permissions: permissions, - permissionsAdded: permissionsAdded, - permissionsRemoved: permissionsRemoved, + roleId, + roleName, + permissions, + permissionsAdded, + permissionsRemoved, requestorId: requestor.requestorId, requestorRole: role, requestorEmail: email, - }) + }); - await logEntry.save() - - } catch (error) { + 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;