From c133c77da0aa0dac6e710928c1b693b489a8d70f Mon Sep 17 00:00:00 2001 From: Imran Issa Date: Sat, 20 Apr 2024 11:33:04 +0200 Subject: [PATCH 1/5] added route and controller for toggling user invisibility --- src/controllers/badgeController.js | 6 +- .../bmdashboard/bmConsumableController.js | 10 +- .../bmdashboard/bmInventoryTypeController.js | 7 +- .../profileInitialSetupController.js | 2 +- src/controllers/reasonSchedulingController.js | 2 +- src/controllers/timeOffRequestController.js | 31 +- src/controllers/userProfileController.js | 342 ++++++++++++------ src/helpers/userHelper.js | 2 +- src/routes/userProfileRouter.js | 4 + src/server.js | 2 +- src/utilities/createInitialPermissions.js | 19 +- 11 files changed, 284 insertions(+), 143 deletions(-) diff --git a/src/controllers/badgeController.js b/src/controllers/badgeController.js index 6f226573b..3ed522367 100644 --- a/src/controllers/badgeController.js +++ b/src/controllers/badgeController.js @@ -104,12 +104,10 @@ const badgeController = function (Badge) { const combinedEarnedDate = [...grouped[badge].earnedDate, ...item.earnedDate]; const timestampArray = combinedEarnedDate.map((date) => new Date(date).getTime()); timestampArray.sort((a, b) => a - b); - grouped[badge].earnedDate = timestampArray.map((timestamp) => - new Date(timestamp) + grouped[badge].earnedDate = timestampArray.map((timestamp) => new Date(timestamp) .toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: '2-digit' }) .replace(/ /g, '-') - .replace(',', ''), - ); + .replace(',', '')); } } diff --git a/src/controllers/bmdashboard/bmConsumableController.js b/src/controllers/bmdashboard/bmConsumableController.js index 8e766ad51..26f76bdd9 100644 --- a/src/controllers/bmdashboard/bmConsumableController.js +++ b/src/controllers/bmdashboard/bmConsumableController.js @@ -30,10 +30,10 @@ const bmConsumableController = function (BuildingConsumable) { }, ]) .exec() - .then(result => { + .then((result) => { res.status(200).send(result); }) - .catch(error => res.status(500).send(error)); + .catch((error) => res.status(500).send(error)); } catch (err) { res.json(err); } @@ -45,7 +45,7 @@ const bmConsumableController = function (BuildingConsumable) { consumableId, quantity, priority, - brand : brandPref, + brand: brandPref, requestor: { requestorId }, } = req.body; const newPurchaseRecord = { @@ -65,7 +65,7 @@ const bmConsumableController = function (BuildingConsumable) { BuildingConsumable .create(newDoc) .then(() => res.status(201).send()) - .catch(error => res.status(500).send(error)); + .catch((error) => res.status(500).send(error)); return; } BuildingConsumable @@ -75,7 +75,7 @@ const bmConsumableController = function (BuildingConsumable) { ) .exec() .then(() => res.status(201).send()) - .catch(error => res.status(500).send(error)); + .catch((error) => res.status(500).send(error)); } catch (error) { res.status(500).send(error); } diff --git a/src/controllers/bmdashboard/bmInventoryTypeController.js b/src/controllers/bmdashboard/bmInventoryTypeController.js index 160ddf1d1..dbd07c88d 100644 --- a/src/controllers/bmdashboard/bmInventoryTypeController.js +++ b/src/controllers/bmdashboard/bmInventoryTypeController.js @@ -135,7 +135,6 @@ function bmInventoryTypeController(InvType, MatType, ConsType, ReusType, ToolTyp } } - async function addConsumableType(req, res) { const { name, @@ -212,8 +211,8 @@ function bmInventoryTypeController(InvType, MatType, ConsType, ReusType, ToolTyp ConsType .find() .exec() - .then(result => res.status(200).send(result)) - .catch(error => res.status(500).send(error)); + .then((result) => res.status(200).send(result)) + .catch((error) => res.status(500).send(error)); } catch (err) { res.json(err); } @@ -252,7 +251,7 @@ function bmInventoryTypeController(InvType, MatType, ConsType, ReusType, ToolTyp }); } }) - .catch(error => res.status(500).send(error)); + .catch((error) => res.status(500).send(error)); } catch (error) { res.status(500).send(error); } diff --git a/src/controllers/profileInitialSetupController.js b/src/controllers/profileInitialSetupController.js index 7e1d5ed0a..cd40e356c 100644 --- a/src/controllers/profileInitialSetupController.js +++ b/src/controllers/profileInitialSetupController.js @@ -376,4 +376,4 @@ const profileInitialSetupController = function ( }; }; -module.exports = profileInitialSetupController; \ No newline at end of file +module.exports = profileInitialSetupController; diff --git a/src/controllers/reasonSchedulingController.js b/src/controllers/reasonSchedulingController.js index 67162abe1..a227e7f3e 100644 --- a/src/controllers/reasonSchedulingController.js +++ b/src/controllers/reasonSchedulingController.js @@ -395,4 +395,4 @@ module.exports = { getSingleReason, patchReason, deleteReason, -}; \ No newline at end of file +}; diff --git a/src/controllers/timeOffRequestController.js b/src/controllers/timeOffRequestController.js index 0f7365eae..7d676b352 100644 --- a/src/controllers/timeOffRequestController.js +++ b/src/controllers/timeOffRequestController.js @@ -4,8 +4,7 @@ const { hasPermission } = require('../utilities/permissions'); const emailSender = require('../utilities/emailSender'); const userNotificationEmail = (name, action = '') => { - const message = - action === 'delete' + const message = action === 'delete' ? `

Hello,

We wanted to inform you that your scheduled time-off request has been deleted.

No further action is needed on your part regarding this request.

@@ -20,8 +19,7 @@ const userNotificationEmail = (name, action = '') => { }; const adminsNotificationEmail = (firstName, lastName, startDate, endDate, action = '') => { - const message = - action === 'delete' + const message = action === 'delete' ? `

Hello,

${firstName} ${lastName} had initially requested time off from ${moment(startDate).format( 'MM-DD-YYYY', @@ -92,10 +90,9 @@ const timeOffRequestController = function (TimeOffRequest, Team, UserProfile) { return userProfile.email; } return null; - }).filter(email => email !== null); - - ownerAcc.forEach(user => userEmails.push(user.email)); + }).filter((email) => email !== null); + ownerAcc.forEach((user) => userEmails.push(user.email)); if (Array.isArray(userEmails) && userEmails.length > 0) { userEmails.forEach((email) => { @@ -119,14 +116,16 @@ const timeOffRequestController = function (TimeOffRequest, Team, UserProfile) { const setOwnRequested = req.body.requestor.requestorId === req.body.requestFor; if ( - !(await hasPermission(req.body.requestor, 'manageTimeOffRequests')) && - !hasRolePermission && - !setOwnRequested + !(await hasPermission(req.body.requestor, 'manageTimeOffRequests')) + && !hasRolePermission + && !setOwnRequested ) { res.status(403).send('You are not authorized to set time off requests.'); return; } - const { duration, startingDate, reason, requestFor } = req.body; + const { + duration, startingDate, reason, requestFor, +} = req.body; if (!duration || !startingDate || !reason || !requestFor) { res.status(400).send('bad request'); return; @@ -208,8 +207,8 @@ const timeOffRequestController = function (TimeOffRequest, Team, UserProfile) { try { const hasRolePermission = ['Owner', 'Administrator'].includes(req.body.requestor.role); if ( - !(await hasPermission(req.body.requestor, 'manageTimeOffRequests')) && - !hasRolePermission + !(await hasPermission(req.body.requestor, 'manageTimeOffRequests')) + && !hasRolePermission ) { res.status(403).send('You are not authorized to set time off requests.'); return; @@ -255,9 +254,9 @@ const timeOffRequestController = function (TimeOffRequest, Team, UserProfile) { const deleteOwnRequest = document?.requestFor.toString() === req.body.requestor.requestorId; if ( - !(await hasPermission(req.body.requestor, 'manageTimeOffRequests')) && - !hasRolePermission && - !deleteOwnRequest + !(await hasPermission(req.body.requestor, 'manageTimeOffRequests')) + && !hasRolePermission + && !deleteOwnRequest ) { res.status(403).send('You are not authorized to set time off requests.'); return; diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 079997afd..3e8e17533 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -15,10 +15,13 @@ const yearMonthDayDateValidator = require('../utilities/yearMonthDayDateValidato const cache = require('../utilities/nodeCache')(); // const { authorizedUserSara, authorizedUserJae } = process.env; -const authorizedUserSara = `sucheta_mu@test.com`; // To test this code please include your email here -const authorizedUserJae = `jae@onecommunityglobal.org`; +const authorizedUserSara = 'sucheta_mu@test.com'; // To test this code please include your email here +const authorizedUserJae = 'jae@onecommunityglobal.org'; -const { hasPermission, canRequestorUpdateUser } = require('../utilities/permissions'); +const { + hasPermission, + canRequestorUpdateUser, +} = require('../utilities/permissions'); const escapeRegex = require('../utilities/escapeRegex'); const emailSender = require('../utilities/emailSender'); const config = require('../config'); @@ -43,8 +46,8 @@ async function ValidatePassword(req, res) { } // Verify request is authorized by self or adminsitrator if ( - userId !== requestor.requestorId && - !(await hasPermission(req.body.requestor, 'updatePassword')) + userId !== requestor.requestorId + && !(await hasPermission(req.body.requestor, 'updatePassword')) ) { res.status(403).send({ error: "You are unauthorized to update this user's password", @@ -54,8 +57,8 @@ async function ValidatePassword(req, res) { // Verify request is authorized by self or adminsitrator if ( - userId === requestor.requestorId || - !(await hasPermission(req.body.requestor, 'updatePassword')) + userId === requestor.requestorId + || !(await hasPermission(req.body.requestor, 'updatePassword')) ) { res.status(403).send({ error: "You are unauthorized to update this user's password", @@ -146,7 +149,8 @@ const userProfileController = function (UserProfile) { if (userByEmail) { res.status(400).send({ - error: 'That email address is already in use. Please choose another email address.', + error: + 'That email address is already in use. Please choose another email address.', type: 'email', }); return; @@ -194,7 +198,8 @@ const userProfileController = function (UserProfile) { if (userByPhoneNumber) { res.status(400).send({ - error: 'That phone number is already in use. Please choose another number.', + error: + 'That phone number is already in use. Please choose another number.', type: 'phoneNumber', }); return; @@ -208,7 +213,8 @@ const userProfileController = function (UserProfile) { if (userDuplicateName && !req.body.allowsDuplicateName) { res.status(400).send({ - error: 'That name is already in use. Please confirm if you want to use this name.', + error: + 'That name is already in use. Please confirm if you want to use this name.', type: 'name', }); return; @@ -250,12 +256,17 @@ const userProfileController = function (UserProfile) { up.isVisible = !['Mentor'].includes(req.body.role); try { - - const requestor = await UserProfile.findById(req.body.requestor.requestorId).select('firstName lastName email role').exec(); + const requestor = await UserProfile.findById( + req.body.requestor.requestorId, + ) + .select('firstName lastName email role') + .exec(); await up.save().then(() => { // if connected to dev db just check for Owner roles, else it's main branch so also check admin too - const condition = process.env.dbName === 'hgnData_dev' ? (up.role === 'Owner') : (up.role === 'Owner' || up.role === 'Administrator'); + const condition = process.env.dbName === 'hgnData_dev' + ? up.role === 'Owner' + : up.role === 'Owner' || up.role === 'Administrator'; if (condition) { const subject = `${process.env.dbName !== 'hgnData_dev' ? '*Main Site* -' : ''}New ${up.role} Role Created`; @@ -283,7 +294,13 @@ const userProfileController = function (UserProfile) {

Sincerely,

The HGN A.I. (and One Community)

`; - emailSender('onecommunityglobal@gmail.com', subject, emailBody, null, null); + emailSender( + 'onecommunityglobal@gmail.com', + subject, + emailBody, + null, + null, + ); } }); @@ -308,7 +325,6 @@ const userProfileController = function (UserProfile) { res.status(200).send({ _id: up._id, }); - } catch (error) { res.status(501).send(error); } @@ -317,9 +333,9 @@ const userProfileController = function (UserProfile) { const putUserProfile = async function (req, res) { const userid = req.params.userId; const isRequestorAuthorized = !!( - canRequestorUpdateUser(req.body.requestor.requestorId, userid) && - ((await hasPermission(req.body.requestor, 'putUserProfile')) || - req.body.requestor.requestorId === userid) + canRequestorUpdateUser(req.body.requestor.requestorId, userid) + && ((await hasPermission(req.body.requestor, 'putUserProfile')) + || req.body.requestor.requestorId === userid) ); if (!isRequestorAuthorized) { @@ -328,8 +344,8 @@ const userProfileController = function (UserProfile) { } if ( - req.body.role === 'Owner' && - !(await hasPermission(req.body.requestor, 'addDeleteEditOwners')) + req.body.role === 'Owner' + && !(await hasPermission(req.body.requestor, 'addDeleteEditOwners')) ) { res.status(403).send('You are not authorized to update this user'); return; @@ -352,17 +368,20 @@ const userProfileController = function (UserProfile) { } } - const canEditTeamCode = - req.body.requestor.role === 'Owner' || - req.body.requestor.role === 'Administrator' || - req.body.requestor.permissions?.frontPermissions.includes('editTeamCode'); + const canEditTeamCode = req.body.requestor.role === 'Owner' + || req.body.requestor.role === 'Administrator' + || req.body.requestor.permissions?.frontPermissions.includes( + 'editTeamCode', + ); if (!canEditTeamCode && record.teamCode !== req.body.teamCode) { res.status(403).send('You are not authorized to edit team code.'); return; } - const originalinfringements = record.infringements ? record.infringements : []; + const originalinfringements = record.infringements + ? record.infringements + : []; const commonFields = [ 'jobTitle', @@ -410,7 +429,9 @@ const userProfileController = function (UserProfile) { userIdx = allUserData.findIndex((users) => users._id === userid); userData = allUserData[userIdx]; } - if (await hasPermission(req.body.requestor, 'putUserProfileImportantInfo')) { + if ( + await hasPermission(req.body.requestor, 'putUserProfileImportantInfo') + ) { const importantFields = [ 'role', 'isRehireable', @@ -461,14 +482,16 @@ const userProfileController = function (UserProfile) { // Logic to update weeklycommittedHours and the history of the committed hours made if ( - req.body.weeklycommittedHours !== undefined && - record.weeklycommittedHours !== req.body.weeklycommittedHours + req.body.weeklycommittedHours !== undefined + && record.weeklycommittedHours !== req.body.weeklycommittedHours ) { record.weeklycommittedHours = req.body.weeklycommittedHours; // If their last update was made today, remove that const lasti = record.weeklycommittedHoursHistory.length - 1; - const lastChangeDate = moment(record.weeklycommittedHoursHistory[lasti].dateChanged); + const lastChangeDate = moment( + record.weeklycommittedHoursHistory[lasti].dateChanged, + ); const now = moment(); if (lastChangeDate.isSame(now, 'day')) { @@ -484,7 +507,10 @@ const userProfileController = function (UserProfile) { record.weeklycommittedHoursHistory.push(newEntry); } - if (req.body.createdDate !== undefined && record.createdDate !== req.body.createdDate) { + if ( + req.body.createdDate !== undefined + && record.createdDate !== req.body.createdDate + ) { record.createdDate = moment(req.body.createdDate).toDate(); // Make sure weeklycommittedHoursHistory isn't empty if (record.weeklycommittedHoursHistory.length === 0) { @@ -499,8 +525,8 @@ const userProfileController = function (UserProfile) { } if ( - req.body.permissions !== undefined && - (await hasPermission(req.body.requestor, 'putUserProfilePermissions')) + req.body.permissions !== undefined + && (await hasPermission(req.body.requestor, 'putUserProfilePermissions')) ) { record.permissions = req.body.permissions; } @@ -525,8 +551,8 @@ const userProfileController = function (UserProfile) { } } if ( - req.body.infringements !== undefined && - (await hasPermission(req.body.requestor, 'infringementAuthorizer')) + req.body.infringements !== undefined + && (await hasPermission(req.body.requestor, 'infringementAuthorizer')) ) { record.infringements = req.body.infringements; } @@ -563,8 +589,8 @@ const userProfileController = function (UserProfile) { } if ( - req.body.role === 'Owner' && - !(await hasPermission(req.body.requestor, 'addDeleteEditOwners')) + req.body.role === 'Owner' + && !(await hasPermission(req.body.requestor, 'addDeleteEditOwners')) ) { res.status(403).send('You are not authorized to delete this user'); return; @@ -603,7 +629,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', @@ -633,11 +661,13 @@ const userProfileController = function (UserProfile) { await UserProfile.deleteOne({ _id: userId, - }).then(() => { - res.status(200).send({ message: 'Executed Successfully' }); - }).catch((err) => { - res.status(500).send(err); - }); + }) + .then(() => { + res.status(200).send({ message: 'Executed Successfully' }); + }) + .catch((err) => { + res.status(500).send(err); + }); }; const getUserById = function (req, res) { @@ -648,7 +678,10 @@ const userProfileController = function (UserProfile) { return; } - UserProfile.findById(userid, '-password -refreshTokens -lastModifiedDate -__v') + UserProfile.findById( + userid, + '-password -refreshTokens -lastModifiedDate -__v', + ) .populate([ { path: 'teams', @@ -673,7 +706,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', }, }, ]) @@ -683,13 +717,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)); }; @@ -712,10 +748,11 @@ const userProfileController = function (UserProfile) { const { key, value } = req.body; if (key === 'teamCode') { - const canEditTeamCode = - req.body.requestor.role === 'Owner' || - req.body.requestor.role === 'Administrator' || - req.body.requestor.permissions?.frontPermissions.includes('editTeamCode'); + const canEditTeamCode = req.body.requestor.role === 'Owner' + || req.body.requestor.role === 'Administrator' + || req.body.requestor.permissions?.frontPermissions.includes( + 'editTeamCode', + ); if (!canEditTeamCode) { res.status(403).send('You are not authorized to edit team code.'); @@ -755,13 +792,20 @@ 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', }); } // Check if the requestor has the permission to update passwords. - const hasUpdatePasswordPermission = await hasPermission(requestor, 'updatePassword'); + const hasUpdatePasswordPermission = await hasPermission( + requestor, + 'updatePassword', + ); // if they're updating someone else's password, they need the 'updatePassword' permission. if (!hasUpdatePasswordPermission) { @@ -819,7 +863,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']; @@ -911,7 +962,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(); @@ -933,80 +986,97 @@ const userProfileController = function (UserProfile) { }); }; - const changeUserRehireableStatus = async function (req, res) { const { userId } = req.params; const { isRehireable } = req.body; if (!mongoose.Types.ObjectId.isValid(userId)) { - return res.status(400).send({ error: 'Bad Request' }); + return res.status(400).send({ error: 'Bad Request' }); } - if (!(await hasPermission(req.body.requestor, 'changeUserRehireableStatus'))) { - return res.status(403).send('You are not authorized to change rehireable status'); + if ( + !(await hasPermission(req.body.requestor, 'changeUserRehireableStatus')) + ) { + return res + .status(403) + .send('You are not authorized to change rehireable status'); } // Invalidate the cache for this user cache.removeCache(`user-${userId}`); UserProfile.findByIdAndUpdate( - userId, - { $set: { isRehireable } }, - { new: true }, - (error, updatedUser) => { - if (error) { - return res.status(500).send(error); - } - // Check if there's a cache for all users and update it accordingly - const isUserInCache = cache.hasCache('allusers'); - if (isUserInCache) { - const allUserData = JSON.parse(cache.getCache('allusers')); - const userIdx = allUserData.findIndex((users) => users._id === userId); - const userData = allUserData[userIdx]; - userData.isRehireable = isRehireable; - allUserData.splice(userIdx, 1, userData); - cache.setCache('allusers', JSON.stringify(allUserData)); - } + userId, + { $set: { isRehireable } }, + { new: true }, + (error, updatedUser) => { + if (error) { + return res.status(500).send(error); + } + // Check if there's a cache for all users and update it accordingly + const isUserInCache = cache.hasCache('allusers'); + if (isUserInCache) { + const allUserData = JSON.parse(cache.getCache('allusers')); + const userIdx = allUserData.findIndex( + (users) => users._id === userId, + ); + const userData = allUserData[userIdx]; + userData.isRehireable = isRehireable; + allUserData.splice(userIdx, 1, userData); + cache.setCache('allusers', JSON.stringify(allUserData)); + } - // Optionally, re-fetch the user to verify the updated data - UserProfile.findById(userId, (err, verifiedUser) => { - if (err) { - return res.status(500).send('Error fetching updated user data.'); - } - res.status(200).send({ - message: 'Rehireable status updated and verified successfully', - isRehireable: verifiedUser.isRehireable, - }); - }); - }, + // Optionally, re-fetch the user to verify the updated data + UserProfile.findById(userId, (err, verifiedUser) => { + if (err) { + return res.status(500).send('Error fetching updated user data.'); + } + res.status(200).send({ + message: 'Rehireable status updated and verified successfully', + isRehireable: verifiedUser.isRehireable, + }); + }); + }, ); -}; + }; const resetPassword = async function (req, res) { try { ValidatePassword(req); - - const requestor = await UserProfile.findById(req.body.requestor.requestorId).select('firstName lastName email role').exec(); + const requestor = await UserProfile.findById( + req.body.requestor.requestorId, + ) + .select('firstName lastName email role') + .exec(); if (!requestor) { res.status(404).send({ error: 'Requestor not found' }); return; } - const user = await UserProfile.findById(req.params.userId).select('firstName lastName email role').exec(); + const user = await UserProfile.findById(req.params.userId) + .select('firstName lastName email role') + .exec(); if (!user) { res.status(404).send({ error: 'User not found' }); return; } - if (!await hasPermission(requestor, 'putUserProfileImportantInfo')) { - res.status(403).send('You are not authorized to reset this users password'); + if (!(await hasPermission(requestor, 'putUserProfileImportantInfo'))) { + res + .status(403) + .send('You are not authorized to reset this users password'); return; } - if (user.role === 'Owner' && !await hasPermission(requestor, 'addDeleteEditOwners')) { - res.status(403).send('You are not authorized to reset this user password'); + if ( + user.role === 'Owner' + && !(await hasPermission(requestor, 'addDeleteEditOwners')) + ) { + res + .status(403) + .send('You are not authorized to reset this user password'); return; } @@ -1014,7 +1084,9 @@ const userProfileController = function (UserProfile) { await user.save(); - const condition = process.env.dbName === 'hgnData_dev' ? (user.role === 'Owner') : (user.role === 'Owner' || user.role === 'Administrator'); + const condition = process.env.dbName === 'hgnData_dev' + ? user.role === 'Owner' + : user.role === 'Owner' || user.role === 'Administrator'; if (condition) { const subject = `${process.env.dbName !== 'hgnData_dev' ? '*Main Site* -' : ''}${user.role} Password Reset Notification`; const emailBody = `

Hi Admin!

@@ -1043,7 +1115,13 @@ const userProfileController = function (UserProfile) {

The HGN A.I. (and One Community)

`; - emailSender('onecommunityglobal@gmail.com', subject, emailBody, null, null); + emailSender( + 'onecommunityglobal@gmail.com', + subject, + emailBody, + null, + null, + ); } res.status(200).send({ @@ -1091,7 +1169,10 @@ const userProfileController = function (UserProfile) { // Searches for first or last name UserProfile.find({ - $or: [{ firstName: { $regex: pattern } }, { lastName: { $regex: pattern } }], + $or: [ + { firstName: { $regex: pattern } }, + { lastName: { $regex: pattern } }, + ], }) .select('firstName lastName') // eslint-disable-next-line consistent-return @@ -1112,18 +1193,25 @@ const userProfileController = function (UserProfile) { // eslint-disable-next-line consistent-return const getUserByFullName = (req, res) => { // Creates an array containing the first and last name and filters out whitespace - const fullName = req.params.fullName.split(' ').filter((name) => name !== ''); + const fullName = req.params.fullName + .split(' ') + .filter((name) => name !== ''); // Creates a partial match regex for both first and last name const firstNameRegex = new RegExp(`^${escapeRegExp(fullName[0])}`, 'i'); const lastNameRegex = new RegExp(`^${escapeRegExp(fullName[1])}`, 'i'); // Verfies both the first and last name are present if (fullName.length < 2) { - return res.status(400).send({ error: 'Both first name and last name are required.' }); + return res + .status(400) + .send({ error: 'Both first name and last name are required.' }); } UserProfile.find({ - $and: [{ firstName: { $regex: firstNameRegex } }, { lastName: { $regex: lastNameRegex } }], + $and: [ + { firstName: { $regex: firstNameRegex } }, + { lastName: { $regex: lastNameRegex } }, + ], }) .select('firstName lastName') // eslint-disable-next-line consistent-return @@ -1175,6 +1263,49 @@ const userProfileController = function (UserProfile) { res.status(500).send(err); } }; + // TODO: Implement Feature + const toggleInvisibility = async function (req, res) { + const { userId } = req.params; + const { isVisible } = req.body; + // console.log(req.body); + + if (!mongoose.Types.ObjectId.isValid(userId)) { + res.status(400).send({ + error: 'Bad Request', + }); + return; + } + if (!(await hasPermission(req.body.requestor, 'toggleInvisibility'))) { + res.status(403).send('You are not authorized to change user visibility'); + return; + } + + // console.log("Updating User Visibility ", isVisible); + cache.removeCache(`user-${userId}`); + UserProfile.findByIdAndUpdate(userId, { $set: { isVisible } }, (err, _) => { + if (err) { + console.log(err); + return res.status(500).send(error); + } + // Check if there's a cache for all users and update it accordingly + const isUserInCache = cache.hasCache('allusers'); + if (isUserInCache) { + const allUserData = JSON.parse(cache.getCache('allusers')); + const userIdx = allUserData.findIndex( + (users) => users._id === userId, + ); + const userData = allUserData[userIdx]; + userData.isVisible = isVisible; + allUserData.splice(userIdx, 1, userData); + cache.setCache('allusers', JSON.stringify(allUserData)); + } + + return res.status(200).send({ + message: 'User visibility updated successfully', + isVisible, + }); + }); + }; return { postUserProfile, @@ -1197,7 +1328,8 @@ const userProfileController = function (UserProfile) { getUserByFullName, changeUserRehireableStatus, authorizeUser, + toggleInvisibility, }; }; -module.exports = userProfileController; \ No newline at end of file +module.exports = userProfileController; diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index 1ae548c88..436988385 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -189,7 +189,7 @@ const userHelper = function () { : "Not provided!"; const googleDocLinkValue = adminLinks?.length > 0 - ? adminLinks.find(link => link.Name === 'Google Doc' && link.Link) + ? adminLinks.find((link) => link.Name === 'Google Doc' && link.Link) : null; const googleDocLink = googleDocLinkValue diff --git a/src/routes/userProfileRouter.js b/src/routes/userProfileRouter.js index 66b8976db..cecca6a5e 100644 --- a/src/routes/userProfileRouter.js +++ b/src/routes/userProfileRouter.js @@ -57,6 +57,10 @@ const routes = function (userProfile) { .route('/userProfile/:userId/rehireable') .patch(controller.changeUserRehireableStatus); + userProfileRouter + .route('/userProfile/:userId/toggleInvisibility') + .patch(controller.toggleInvisibility); + userProfileRouter .route('/userProfile/singleName/:singleName') .get(controller.getUserBySingleName); diff --git a/src/server.js b/src/server.js index 815b0fa07..ba49677c0 100644 --- a/src/server.js +++ b/src/server.js @@ -24,4 +24,4 @@ const server = app.listen(port, () => { await websockets(server); })(); -module.exports = server; \ No newline at end of file +module.exports = server; diff --git a/src/utilities/createInitialPermissions.js b/src/utilities/createInitialPermissions.js index 51f06593e..b99c68a22 100644 --- a/src/utilities/createInitialPermissions.js +++ b/src/utilities/createInitialPermissions.js @@ -50,6 +50,7 @@ const permissionsRoles = [ 'updatePassword', 'deleteUserProfile', 'infringementAuthorizer', + 'toggleInvisibility', // WBS 'postWbs', 'deleteWbs', @@ -218,6 +219,7 @@ const permissionsRoles = [ 'editTeamCode', 'totalValidWeeklySummaries', 'changeUserRehireableStatus', + 'toggleInvisibility', ], }, ]; @@ -248,8 +250,10 @@ const createInitialPermissions = async () => { role.permissions = permissions; role.save(); - // If role exists in db and does not have every permission, add the missing permissions - } else if (!permissions.every((perm) => roleDataBase.permissions.includes(perm))) { + // If role exists in db and does not have every permission, add the missing permissions + } else if ( + !permissions.every((perm) => roleDataBase.permissions.includes(perm)) + ) { const roleId = roleDataBase._id; promises.push( @@ -267,7 +271,9 @@ const createInitialPermissions = async () => { // Update Default presets - const presetDataBase = allPresets.find((preset) => preset.roleName === roleName && preset.presetName === 'default'); + const presetDataBase = allPresets.find( + (preset) => preset.roleName === roleName && preset.presetName === 'default', + ); // If role does not exist in db, create it if (!presetDataBase) { @@ -277,8 +283,11 @@ const createInitialPermissions = async () => { defaultPreset.permissions = permissions; defaultPreset.save(); - // If role exists in db and is not updated, update default - } else if (!presetDataBase.permissions.every((perm) => permissions.includes(perm)) || !permissions.every((perm) => presetDataBase.permissions.includes(perm))) { + // If role exists in db and is not updated, update default + } else if ( + !presetDataBase.permissions.every((perm) => permissions.includes(perm)) + || !permissions.every((perm) => presetDataBase.permissions.includes(perm)) + ) { const presetId = presetDataBase._id; promises.push( From 667b42e49fe44a5757d985799908d429b2ca367d Mon Sep 17 00:00:00 2001 From: Imran Issa Date: Sat, 20 Apr 2024 11:34:49 +0200 Subject: [PATCH 2/5] added route and controller for toggling user invisibility --- src/controllers/userProfileController.js | 546 ++++++++++++----------- 1 file changed, 274 insertions(+), 272 deletions(-) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 3e8e17533..ae5e81ebd 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -1,30 +1,30 @@ -const moment = require('moment-timezone'); +const moment = require("moment-timezone"); -const mongoose = require('mongoose'); -const bcrypt = require('bcryptjs'); +const mongoose = require("mongoose"); +const bcrypt = require("bcryptjs"); // eslint-disable-next-line import/no-extraneous-dependencies -const fetch = require('node-fetch'); +const fetch = require("node-fetch"); -const moment_ = require('moment'); -const jwt = require('jsonwebtoken'); -const userHelper = require('../helpers/userHelper')(); -const TimeEntry = require('../models/timeentry'); -const logger = require('../startup/logger'); -const Badge = require('../models/badge'); -const yearMonthDayDateValidator = require('../utilities/yearMonthDayDateValidator'); -const cache = require('../utilities/nodeCache')(); +const moment_ = require("moment"); +const jwt = require("jsonwebtoken"); +const userHelper = require("../helpers/userHelper")(); +const TimeEntry = require("../models/timeentry"); +const logger = require("../startup/logger"); +const Badge = require("../models/badge"); +const yearMonthDayDateValidator = require("../utilities/yearMonthDayDateValidator"); +const cache = require("../utilities/nodeCache")(); // const { authorizedUserSara, authorizedUserJae } = process.env; -const authorizedUserSara = 'sucheta_mu@test.com'; // To test this code please include your email here -const authorizedUserJae = 'jae@onecommunityglobal.org'; +const authorizedUserSara = "sucheta_mu@test.com"; // To test this code please include your email here +const authorizedUserJae = "jae@onecommunityglobal.org"; const { hasPermission, canRequestorUpdateUser, -} = require('../utilities/permissions'); -const escapeRegex = require('../utilities/escapeRegex'); -const emailSender = require('../utilities/emailSender'); -const config = require('../config'); +} = require("../utilities/permissions"); +const escapeRegex = require("../utilities/escapeRegex"); +const emailSender = require("../utilities/emailSender"); +const config = require("../config"); async function ValidatePassword(req, res) { const { userId } = req.params; @@ -32,7 +32,7 @@ async function ValidatePassword(req, res) { if (!mongoose.Types.ObjectId.isValid(userId)) { res.status(400).send({ - error: 'Bad Request', + error: "Bad Request", }); return; } @@ -40,14 +40,14 @@ async function ValidatePassword(req, res) { // Verify correct params in body if (!req.body.newpassword || !req.body.confirmnewpassword) { res.status(400).send({ - error: 'One of more required fields are missing', + error: "One of more required fields are missing", }); return; } // Verify request is authorized by self or adminsitrator if ( - userId !== requestor.requestorId - && !(await hasPermission(req.body.requestor, 'updatePassword')) + userId !== requestor.requestorId && + !(await hasPermission(req.body.requestor, "updatePassword")) ) { res.status(403).send({ error: "You are unauthorized to update this user's password", @@ -57,8 +57,8 @@ async function ValidatePassword(req, res) { // Verify request is authorized by self or adminsitrator if ( - userId === requestor.requestorId - || !(await hasPermission(req.body.requestor, 'updatePassword')) + userId === requestor.requestorId || + !(await hasPermission(req.body.requestor, "updatePassword")) ) { res.status(403).send({ error: "You are unauthorized to update this user's password", @@ -69,44 +69,44 @@ async function ValidatePassword(req, res) { // Verify new and confirm new password are correct if (req.body.newpassword !== req.body.confirmnewpassword) { res.status(400).send({ - error: 'New and confirm new passwords are not same', + error: "New and confirm new passwords are not same", }); } } const userProfileController = function (UserProfile) { const getUserProfiles = async function (req, res) { - if (!(await hasPermission(req.body.requestor, 'getUserProfiles'))) { - res.status(403).send('You are not authorized to view all users'); + if (!(await hasPermission(req.body.requestor, "getUserProfiles"))) { + res.status(403).send("You are not authorized to view all users"); return; } UserProfile.find( {}, - '_id firstName lastName role weeklycommittedHours email permissions isActive reactivationDate createdDate endDate', + "_id firstName lastName role weeklycommittedHours email permissions isActive reactivationDate createdDate endDate", ) .sort({ lastName: 1, }) .then((results) => { if (!results) { - if (cache.getCache('allusers')) { - const getData = JSON.parse(cache.getCache('allusers')); + if (cache.getCache("allusers")) { + const getData = JSON.parse(cache.getCache("allusers")); res.status(200).send(getData); return; } - res.status(500).send({ error: 'User result was invalid' }); + res.status(500).send({ error: "User result was invalid" }); return; } - cache.setCache('allusers', JSON.stringify(results)); + cache.setCache("allusers", JSON.stringify(results)); res.status(200).send(results); }) .catch((error) => res.status(404).send(error)); }; const getProjectMembers = async function (req, res) { - if (!(await hasPermission(req.body.requestor, 'getProjectMembers'))) { - res.status(403).send('You are not authorized to view all users'); + if (!(await hasPermission(req.body.requestor, "getProjectMembers"))) { + res.status(403).send("You are not authorized to view all users"); return; } UserProfile.find( @@ -115,10 +115,10 @@ const userProfileController = function (UserProfile) { $in: [req.params.projectId], }, }, - '_id firstName email', + "_id firstName email", (err, profiles) => { if (err) { - res.status(404).send('Error finding user profiles'); + res.status(404).send("Error finding user profiles"); return; } res.json(profiles); @@ -127,58 +127,58 @@ const userProfileController = function (UserProfile) { }; const postUserProfile = async function (req, res) { - if (!(await hasPermission(req.body.requestor, 'postUserProfile'))) { - res.status(403).send('You are not authorized to create new users'); + if (!(await hasPermission(req.body.requestor, "postUserProfile"))) { + res.status(403).send("You are not authorized to create new users"); return; } if ( - req.body.role === 'Owner' - && !(await hasPermission(req.body.requestor, 'addDeleteEditOwners')) + req.body.role === "Owner" && + !(await hasPermission(req.body.requestor, "addDeleteEditOwners")) ) { - res.status(403).send('You are not authorized to create new owners'); + res.status(403).send("You are not authorized to create new owners"); return; } const userByEmail = await UserProfile.findOne({ email: { $regex: escapeRegex(req.body.email), - $options: 'i', + $options: "i", }, }); if (userByEmail) { res.status(400).send({ error: - 'That email address is already in use. Please choose another email address.', - type: 'email', + "That email address is already in use. Please choose another email address.", + type: "email", }); return; } // In dev environment, if newly created user is Owner or Administrator, make fetch request to Beta login route with actualEmail and actual Password - if (process.env.dbName === 'hgnData_dev') { - if (req.body.role === 'Owner' || req.body.role === 'Administrator') { + if (process.env.dbName === "hgnData_dev") { + if (req.body.role === "Owner" || req.body.role === "Administrator") { const email = req.body.actualEmail; const password = req.body.actualPassword; - const url = 'https://hgn-rest-beta.azurewebsites.net/api/'; + const url = "https://hgn-rest-beta.azurewebsites.net/api/"; try { // Log in to Beta login route using provided credentials const response = await fetch(`${url}login`, { - method: 'POST', + method: "POST", headers: { - 'Content-Type': 'application/json', + "Content-Type": "application/json", }, body: JSON.stringify({ email, password }), }); if (!response.ok) { - throw new Error('Invalid credentials'); + throw new Error("Invalid credentials"); } } catch (error) { res.status(400).send({ error: - 'The actual email or password you provided is incorrect. Please enter the actual email and password associated with your account in the Main HGN app.', - type: 'credentials', + "The actual email or password you provided is incorrect. Please enter the actual email and password associated with your account in the Main HGN app.", + type: "credentials", }); return; } @@ -199,8 +199,8 @@ const userProfileController = function (UserProfile) { if (userByPhoneNumber) { res.status(400).send({ error: - 'That phone number is already in use. Please choose another number.', - type: 'phoneNumber', + "That phone number is already in use. Please choose another number.", + type: "phoneNumber", }); return; } @@ -214,8 +214,8 @@ const userProfileController = function (UserProfile) { if (userDuplicateName && !req.body.allowsDuplicateName) { res.status(400).send({ error: - 'That name is already in use. Please confirm if you want to use this name.', - type: 'name', + "That name is already in use. Please confirm if you want to use this name.", + type: "name", }); return; } @@ -242,33 +242,34 @@ const userProfileController = function (UserProfile) { up.projects = Array.from(new Set(req.body.projects)); up.createdDate = req.body.createdDate; up.email = req.body.email; - up.weeklySummaries = req.body.weeklySummaries || [{ summary: '' }]; + up.weeklySummaries = req.body.weeklySummaries || [{ summary: "" }]; up.weeklySummariesCount = req.body.weeklySummariesCount || 0; up.weeklySummaryOption = req.body.weeklySummaryOption; - up.mediaUrl = req.body.mediaUrl || ''; - up.collaborationPreference = req.body.collaborationPreference || ''; - up.timeZone = req.body.timeZone || 'America/Los_Angeles'; + up.mediaUrl = req.body.mediaUrl || ""; + up.collaborationPreference = req.body.collaborationPreference || ""; + up.timeZone = req.body.timeZone || "America/Los_Angeles"; up.location = req.body.location; up.permissions = req.body.permissions; - up.bioPosted = req.body.bioPosted || 'default'; + up.bioPosted = req.body.bioPosted || "default"; up.isFirstTimelog = true; up.actualEmail = req.body.actualEmail; - up.isVisible = !['Mentor'].includes(req.body.role); + up.isVisible = !["Mentor"].includes(req.body.role); try { const requestor = await UserProfile.findById( req.body.requestor.requestorId, ) - .select('firstName lastName email role') + .select("firstName lastName email role") .exec(); await up.save().then(() => { // if connected to dev db just check for Owner roles, else it's main branch so also check admin too - const condition = process.env.dbName === 'hgnData_dev' - ? up.role === 'Owner' - : up.role === 'Owner' || up.role === 'Administrator'; + const condition = + process.env.dbName === "hgnData_dev" + ? up.role === "Owner" + : up.role === "Owner" || up.role === "Administrator"; if (condition) { - const subject = `${process.env.dbName !== 'hgnData_dev' ? '*Main Site* -' : ''}New ${up.role} Role Created`; + const subject = `${process.env.dbName !== "hgnData_dev" ? "*Main Site* -" : ""}New ${up.role} Role Created`; const emailBody = `

Hi Admin!

@@ -295,7 +296,7 @@ const userProfileController = function (UserProfile) {

The HGN A.I. (and One Community)

`; emailSender( - 'onecommunityglobal@gmail.com', + "onecommunityglobal@gmail.com", subject, emailBody, null, @@ -305,7 +306,7 @@ const userProfileController = function (UserProfile) { }); // update backend cache if it exists - if (cache.getCache('allusers')) { + if (cache.getCache("allusers")) { const userCache = { permissions: up.permissions, isActive: true, @@ -317,9 +318,9 @@ const userProfileController = function (UserProfile) { lastName: up.lastName, email: up.email, }; - const allUserCache = JSON.parse(cache.getCache('allusers')); + const allUserCache = JSON.parse(cache.getCache("allusers")); allUserCache.push(userCache); - cache.setCache('allusers', JSON.stringify(allUserCache)); + cache.setCache("allusers", JSON.stringify(allUserCache)); } res.status(200).send({ @@ -333,28 +334,28 @@ const userProfileController = function (UserProfile) { const putUserProfile = async function (req, res) { const userid = req.params.userId; const isRequestorAuthorized = !!( - canRequestorUpdateUser(req.body.requestor.requestorId, userid) - && ((await hasPermission(req.body.requestor, 'putUserProfile')) - || req.body.requestor.requestorId === userid) + canRequestorUpdateUser(req.body.requestor.requestorId, userid) && + ((await hasPermission(req.body.requestor, "putUserProfile")) || + req.body.requestor.requestorId === userid) ); if (!isRequestorAuthorized) { - res.status(403).send('You are not authorized to update this user'); + res.status(403).send("You are not authorized to update this user"); return; } if ( - req.body.role === 'Owner' - && !(await hasPermission(req.body.requestor, 'addDeleteEditOwners')) + req.body.role === "Owner" && + !(await hasPermission(req.body.requestor, "addDeleteEditOwners")) ) { - res.status(403).send('You are not authorized to update this user'); + res.status(403).send("You are not authorized to update this user"); return; } cache.removeCache(`user-${userid}`); UserProfile.findById(userid, async (err, record) => { if (err || !record) { - res.status(404).send('No valid records found'); + res.status(404).send("No valid records found"); return; } // validate userprofile pic @@ -368,14 +369,15 @@ const userProfileController = function (UserProfile) { } } - const canEditTeamCode = req.body.requestor.role === 'Owner' - || req.body.requestor.role === 'Administrator' - || req.body.requestor.permissions?.frontPermissions.includes( - 'editTeamCode', + const canEditTeamCode = + req.body.requestor.role === "Owner" || + req.body.requestor.role === "Administrator" || + req.body.requestor.permissions?.frontPermissions.includes( + "editTeamCode", ); if (!canEditTeamCode && record.teamCode !== req.body.teamCode) { - res.status(403).send('You are not authorized to edit team code.'); + res.status(403).send("You are not authorized to edit team code."); return; } @@ -384,31 +386,31 @@ const userProfileController = function (UserProfile) { : []; const commonFields = [ - 'jobTitle', - 'emailPubliclyAccessible', - 'phoneNumberPubliclyAccessible', - 'profilePic', - 'firstName', - 'lastName', - 'jobTitle', - 'phoneNumber', - 'bio', - 'personalLinks', - 'location', - 'profilePic', - 'privacySettings', - 'weeklySummaries', - 'weeklySummariesCount', - 'mediaUrl', - 'timeZone', - 'hoursByCategory', - 'totalTangibleHrs', - 'totalIntangibleHrs', - 'isFirstTimelog', - 'teamCode', - 'isVisible', - 'isRehireable', - 'bioPosted', + "jobTitle", + "emailPubliclyAccessible", + "phoneNumberPubliclyAccessible", + "profilePic", + "firstName", + "lastName", + "jobTitle", + "phoneNumber", + "bio", + "personalLinks", + "location", + "profilePic", + "privacySettings", + "weeklySummaries", + "weeklySummariesCount", + "mediaUrl", + "timeZone", + "hoursByCategory", + "totalTangibleHrs", + "totalIntangibleHrs", + "isFirstTimelog", + "teamCode", + "isVisible", + "isRehireable", + "bioPosted", ]; commonFields.forEach((fieldName) => { @@ -420,38 +422,38 @@ const userProfileController = function (UserProfile) { record.lastModifiedDate = Date.now(); // find userData in cache - const isUserInCache = cache.hasCache('allusers'); + const isUserInCache = cache.hasCache("allusers"); let allUserData; let userData; let userIdx; if (isUserInCache) { - allUserData = JSON.parse(cache.getCache('allusers')); + allUserData = JSON.parse(cache.getCache("allusers")); userIdx = allUserData.findIndex((users) => users._id === userid); userData = allUserData[userIdx]; } if ( - await hasPermission(req.body.requestor, 'putUserProfileImportantInfo') + await hasPermission(req.body.requestor, "putUserProfileImportantInfo") ) { const importantFields = [ - 'role', - 'isRehireable', - 'isActive', - 'adminLinks', - 'isActive', - 'weeklySummaries', - 'weeklySummariesCount', - 'mediaUrl', - 'collaborationPreference', - 'weeklySummaryNotReq', - 'weeklySummaryOption', - 'categoryTangibleHrs', - 'totalTangibleHrs', - 'timeEntryEditHistory', + "role", + "isRehireable", + "isActive", + "adminLinks", + "isActive", + "weeklySummaries", + "weeklySummariesCount", + "mediaUrl", + "collaborationPreference", + "weeklySummaryNotReq", + "weeklySummaryOption", + "categoryTangibleHrs", + "totalTangibleHrs", + "timeEntryEditHistory", ]; if (req.body.role !== record.role) { switch (req.body.role) { - case 'Mentor': + case "Mentor": record.isVisible = false; break; default: @@ -465,7 +467,8 @@ const userProfileController = function (UserProfile) { }); if (req.body.missedHours !== undefined) { - record.missedHours = req.body.role === 'Core Team' ? req.body?.missedHours ?? 0 : 0; + record.missedHours = + req.body.role === "Core Team" ? req.body?.missedHours ?? 0 : 0; } if (req.body.teams !== undefined) { @@ -482,8 +485,8 @@ const userProfileController = function (UserProfile) { // Logic to update weeklycommittedHours and the history of the committed hours made if ( - req.body.weeklycommittedHours !== undefined - && record.weeklycommittedHours !== req.body.weeklycommittedHours + req.body.weeklycommittedHours !== undefined && + record.weeklycommittedHours !== req.body.weeklycommittedHours ) { record.weeklycommittedHours = req.body.weeklycommittedHours; @@ -494,7 +497,7 @@ const userProfileController = function (UserProfile) { ); const now = moment(); - if (lastChangeDate.isSame(now, 'day')) { + if (lastChangeDate.isSame(now, "day")) { record.weeklycommittedHoursHistory.pop(); } @@ -508,8 +511,8 @@ const userProfileController = function (UserProfile) { } if ( - req.body.createdDate !== undefined - && record.createdDate !== req.body.createdDate + req.body.createdDate !== undefined && + record.createdDate !== req.body.createdDate ) { record.createdDate = moment(req.body.createdDate).toDate(); // Make sure weeklycommittedHoursHistory isn't empty @@ -521,12 +524,13 @@ const userProfileController = function (UserProfile) { record.weeklycommittedHoursHistory.push(newEntry); } // then also change the first committed history (index 0) - record.weeklycommittedHoursHistory[0].dateChanged = record.createdDate; + record.weeklycommittedHoursHistory[0].dateChanged = + record.createdDate; } if ( - req.body.permissions !== undefined - && (await hasPermission(req.body.requestor, 'putUserProfilePermissions')) + req.body.permissions !== undefined && + (await hasPermission(req.body.requestor, "putUserProfilePermissions")) ) { record.permissions = req.body.permissions; } @@ -538,7 +542,7 @@ const userProfileController = function (UserProfile) { userData.endDate = record.endDate.toISOString(); } } else { - record.set('endDate', undefined, { strict: false }); + record.set("endDate", undefined, { strict: false }); } } @@ -551,8 +555,8 @@ const userProfileController = function (UserProfile) { } } if ( - req.body.infringements !== undefined - && (await hasPermission(req.body.requestor, 'infringementAuthorizer')) + req.body.infringements !== undefined && + (await hasPermission(req.body.requestor, "infringementAuthorizer")) ) { record.infringements = req.body.infringements; } @@ -574,7 +578,7 @@ const userProfileController = function (UserProfile) { // update alluser cache if we have cache if (isUserInCache) { allUserData.splice(userIdx, 1, userData); - cache.setCache('allusers', JSON.stringify(allUserData)); + cache.setCache("allusers", JSON.stringify(allUserData)); } }) .catch((error) => res.status(400).send(error)); @@ -583,29 +587,29 @@ const userProfileController = function (UserProfile) { const deleteUserProfile = async function (req, res) { const { option, userId } = req.body; - if (!(await hasPermission(req.body.requestor, 'deleteUserProfile'))) { - res.status(403).send('You are not authorized to delete users'); + if (!(await hasPermission(req.body.requestor, "deleteUserProfile"))) { + res.status(403).send("You are not authorized to delete users"); return; } if ( - req.body.role === 'Owner' - && !(await hasPermission(req.body.requestor, 'addDeleteEditOwners')) + req.body.role === "Owner" && + !(await hasPermission(req.body.requestor, "addDeleteEditOwners")) ) { - res.status(403).send('You are not authorized to delete this user'); + res.status(403).send("You are not authorized to delete this user"); return; } - if (!userId || !option || (option !== 'delete' && option !== 'archive')) { + if (!userId || !option || (option !== "delete" && option !== "archive")) { res.status(400).send({ - error: 'Bad request', + error: "Bad request", }); return; } if (userId === req.body.requestor) { res.status(403).send({ - error: 'You cannot delete your own account', + error: "You cannot delete your own account", }); return; } @@ -614,27 +618,27 @@ const userProfileController = function (UserProfile) { if (!user) { res.status(400).send({ - error: 'Invalid user', + error: "Invalid user", }); return; } - if (option === 'archive') { + if (option === "archive") { const timeArchiveUser = await UserProfile.findOne( { firstName: process.env.TIME_ARCHIVE_FIRST_NAME, lastName: process.env.TIME_ARCHIVE_LAST_NAME, }, - '_id', + "_id", ); if (!timeArchiveUser) { logger.logException( - 'Time Archive user was not found. Please check the database', + "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', + "Time Archive User not found. Please contact your developement team on why that happened", }); return; } @@ -652,18 +656,18 @@ const userProfileController = function (UserProfile) { } cache.removeCache(`user-${userId}`); - if (cache.getCache('allusers')) { - const allUserData = JSON.parse(cache.getCache('allusers')); + if (cache.getCache("allusers")) { + const allUserData = JSON.parse(cache.getCache("allusers")); const userIdx = allUserData.findIndex((users) => users._id === userId); allUserData.splice(userIdx, 1); - cache.setCache('allusers', JSON.stringify(allUserData)); + cache.setCache("allusers", JSON.stringify(allUserData)); } await UserProfile.deleteOne({ _id: userId, }) .then(() => { - res.status(200).send({ message: 'Executed Successfully' }); + res.status(200).send({ message: "Executed Successfully" }); }) .catch((err) => { res.status(500).send(err); @@ -680,12 +684,12 @@ const userProfileController = function (UserProfile) { UserProfile.findById( userid, - '-password -refreshTokens -lastModifiedDate -__v', + "-password -refreshTokens -lastModifiedDate -__v", ) .populate([ { - path: 'teams', - select: '_id teamName', + path: "teams", + select: "_id teamName", options: { sort: { teamName: 1, @@ -693,8 +697,8 @@ const userProfileController = function (UserProfile) { }, }, { - path: 'projects', - select: '_id projectName category', + path: "projects", + select: "_id projectName category", options: { sort: { projectName: 1, @@ -702,25 +706,25 @@ const userProfileController = function (UserProfile) { }, }, { - path: 'badgeCollection', + path: "badgeCollection", populate: { - path: 'badge', + path: "badge", model: Badge, select: - '_id badgeName type imageUrl description ranking showReport', + "_id badgeName type imageUrl description ranking showReport", }, }, ]) .exec() .then((results) => { if (!results) { - res.status(400).send({ error: 'This is not a valid user' }); + res.status(400).send({ error: "This is not a valid user" }); return; } userHelper .getTangibleHoursReportedThisWeekByUserId(userid) .then((hours) => { - results.set('tangibleHoursReportedThisWeek', hours, { + results.set("tangibleHoursReportedThisWeek", hours, { strict: false, }); cache.setCache(`user-${userid}`, JSON.stringify(results)); @@ -733,8 +737,8 @@ const userProfileController = function (UserProfile) { const getUserByName = (req, res) => { const { name } = req.params; UserProfile.find( - { firstName: name.split(' ')[0], lastName: name.split(' ')[1] }, - '_id, profilePic, badgeCollection', + { firstName: name.split(" ")[0], lastName: name.split(" ")[1] }, + "_id, profilePic, badgeCollection", ) .then((results) => { @@ -747,15 +751,16 @@ const userProfileController = function (UserProfile) { const { userId } = req.params; const { key, value } = req.body; - if (key === 'teamCode') { - const canEditTeamCode = req.body.requestor.role === 'Owner' - || req.body.requestor.role === 'Administrator' - || req.body.requestor.permissions?.frontPermissions.includes( - 'editTeamCode', + if (key === "teamCode") { + const canEditTeamCode = + req.body.requestor.role === "Owner" || + req.body.requestor.role === "Administrator" || + req.body.requestor.permissions?.frontPermissions.includes( + "editTeamCode", ); if (!canEditTeamCode) { - res.status(403).send('You are not authorized to edit team code.'); + res.status(403).send("You are not authorized to edit team code."); return; } } @@ -763,7 +768,7 @@ const userProfileController = function (UserProfile) { // remove user from cache, it should be loaded next time cache.removeCache(`user-${userId}`); if (!key || value === undefined) { - return res.status(400).send({ error: 'Missing property or value' }); + return res.status(400).send({ error: "Missing property or value" }); } return UserProfile.findById(userId) @@ -775,7 +780,7 @@ const userProfileController = function (UserProfile) { return user .save() .then(() => { - res.status(200).send({ message: 'updated property' }); + res.status(200).send({ message: "updated property" }); }) .catch((error) => res.status(500).send(error)); }) @@ -787,24 +792,24 @@ const userProfileController = function (UserProfile) { const { requestor } = req.body; if (!mongoose.Types.ObjectId.isValid(userId)) { return res.status(400).send({ - error: 'Bad Request', + error: "Bad Request", }); } // Verify correct params in body if ( - !req.body.currentpassword - || !req.body.newpassword - || !req.body.confirmnewpassword + !req.body.currentpassword || + !req.body.newpassword || + !req.body.confirmnewpassword ) { return res.status(400).send({ - error: 'One of more required fields are missing', + error: "One of more required fields are missing", }); } // Check if the requestor has the permission to update passwords. const hasUpdatePasswordPermission = await hasPermission( requestor, - 'updatePassword', + "updatePassword", ); // if they're updating someone else's password, they need the 'updatePassword' permission. @@ -817,25 +822,25 @@ const userProfileController = function (UserProfile) { // Verify new and confirm new password are correct if (req.body.newpassword !== req.body.confirmnewpassword) { return res.status(400).send({ - error: 'New and confirm new passwords are not the same', + error: "New and confirm new passwords are not the same", }); } // Verify old and new passwords are not same if (req.body.currentpassword === req.body.newpassword) { res.status(400).send({ - error: 'Old and new passwords should not be same', + error: "Old and new passwords should not be same", }); } - return UserProfile.findById(userId, 'password') + return UserProfile.findById(userId, "password") .then((user) => { bcrypt .compare(req.body.currentpassword, user.password) .then((passwordMatch) => { if (!passwordMatch) { return res.status(400).send({ - error: 'Incorrect current password', + error: "Incorrect current password", }); } @@ -845,7 +850,7 @@ const userProfileController = function (UserProfile) { }); return user .save() - .then(() => res.status(200).send({ message: 'updated password' })) + .then(() => res.status(200).send({ message: "updated password" })) .catch((error) => res.status(500).send(error)); }) .catch((error) => res.status(500).send(error)); @@ -856,7 +861,7 @@ const userProfileController = function (UserProfile) { const getreportees = async function (req, res) { if (!mongoose.Types.ObjectId.isValid(req.params.userId)) { res.status(400).send({ - error: 'Bad request', + error: "Bad request", }); return; } @@ -864,16 +869,16 @@ const userProfileController = function (UserProfile) { const userid = mongoose.Types.ObjectId(req.params.userId); let validroles = [ - 'Volunteer', - 'Manager', - 'Administrator', - 'Core Team', - 'Owner', - 'Mentor', + "Volunteer", + "Manager", + "Administrator", + "Core Team", + "Owner", + "Mentor", ]; - if (await hasPermission(req.body.requestor, 'getReporteesLimitRoles')) { - validroles = ['Volunteer', 'Manager']; + if (await hasPermission(req.body.requestor, "getReporteesLimitRoles")) { + validroles = ["Volunteer", "Manager"]; } userHelper @@ -895,7 +900,7 @@ const userProfileController = function (UserProfile) { const getTeamMembersofUser = function (req, res) { if (!mongoose.Types.ObjectId.isValid(req.params.userId)) { res.status(400).send({ - error: 'Bad request', + error: "Bad request", }); return; } @@ -913,7 +918,7 @@ const userProfileController = function (UserProfile) { const { userId } = req.params; if (mongoose.Types.ObjectId.isValid(userId)) { - UserProfile.findById(userId, 'firstName lastName') + UserProfile.findById(userId, "firstName lastName") .then((result) => { const name = `${result.firstName} ${result.lastName}`; res.status(200).send({ @@ -925,30 +930,30 @@ const userProfileController = function (UserProfile) { }); } else { res.status(400).send({ - error: 'Bad request', + error: "Bad request", }); } }; const changeUserStatus = async function (req, res) { const { userId } = req.params; - const status = req.body.status === 'Active'; + const status = req.body.status === "Active"; const activationDate = req.body.reactivationDate; const { endDate } = req.body; - const isSet = req.body.isSet === 'FinalDay'; + const isSet = req.body.isSet === "FinalDay"; if (!mongoose.Types.ObjectId.isValid(userId)) { res.status(400).send({ - error: 'Bad Request', + error: "Bad Request", }); return; } - if (!(await hasPermission(req.body.requestor, 'changeUserStatus'))) { - res.status(403).send('You are not authorized to change user status'); + if (!(await hasPermission(req.body.requestor, "changeUserStatus"))) { + res.status(403).send("You are not authorized to change user status"); return; } cache.removeCache(`user-${userId}`); - UserProfile.findById(userId, 'isActive') + UserProfile.findById(userId, "isActive") .then((user) => { user.set({ isActive: status, @@ -959,9 +964,9 @@ const userProfileController = function (UserProfile) { user .save() .then(() => { - const isUserInCache = cache.hasCache('allusers'); + const isUserInCache = cache.hasCache("allusers"); if (isUserInCache) { - const allUserData = JSON.parse(cache.getCache('allusers')); + const allUserData = JSON.parse(cache.getCache("allusers")); const userIdx = allUserData.findIndex( (users) => users._id === userId, ); @@ -971,10 +976,10 @@ const userProfileController = function (UserProfile) { } userData.isActive = user.isActive; allUserData.splice(userIdx, 1, userData); - cache.setCache('allusers', JSON.stringify(allUserData)); + cache.setCache("allusers", JSON.stringify(allUserData)); } res.status(200).send({ - message: 'status updated', + message: "status updated", }); }) .catch((error) => { @@ -991,14 +996,14 @@ const userProfileController = function (UserProfile) { const { isRehireable } = req.body; if (!mongoose.Types.ObjectId.isValid(userId)) { - return res.status(400).send({ error: 'Bad Request' }); + return res.status(400).send({ error: "Bad Request" }); } if ( - !(await hasPermission(req.body.requestor, 'changeUserRehireableStatus')) + !(await hasPermission(req.body.requestor, "changeUserRehireableStatus")) ) { return res .status(403) - .send('You are not authorized to change rehireable status'); + .send("You are not authorized to change rehireable status"); } // Invalidate the cache for this user @@ -1013,25 +1018,25 @@ const userProfileController = function (UserProfile) { return res.status(500).send(error); } // Check if there's a cache for all users and update it accordingly - const isUserInCache = cache.hasCache('allusers'); + const isUserInCache = cache.hasCache("allusers"); if (isUserInCache) { - const allUserData = JSON.parse(cache.getCache('allusers')); + const allUserData = JSON.parse(cache.getCache("allusers")); const userIdx = allUserData.findIndex( (users) => users._id === userId, ); const userData = allUserData[userIdx]; userData.isRehireable = isRehireable; allUserData.splice(userIdx, 1, userData); - cache.setCache('allusers', JSON.stringify(allUserData)); + cache.setCache("allusers", JSON.stringify(allUserData)); } // Optionally, re-fetch the user to verify the updated data UserProfile.findById(userId, (err, verifiedUser) => { if (err) { - return res.status(500).send('Error fetching updated user data.'); + return res.status(500).send("Error fetching updated user data."); } res.status(200).send({ - message: 'Rehireable status updated and verified successfully', + message: "Rehireable status updated and verified successfully", isRehireable: verifiedUser.isRehireable, }); }); @@ -1046,37 +1051,37 @@ const userProfileController = function (UserProfile) { const requestor = await UserProfile.findById( req.body.requestor.requestorId, ) - .select('firstName lastName email role') + .select("firstName lastName email role") .exec(); if (!requestor) { - res.status(404).send({ error: 'Requestor not found' }); + res.status(404).send({ error: "Requestor not found" }); return; } const user = await UserProfile.findById(req.params.userId) - .select('firstName lastName email role') + .select("firstName lastName email role") .exec(); if (!user) { - res.status(404).send({ error: 'User not found' }); + res.status(404).send({ error: "User not found" }); return; } - if (!(await hasPermission(requestor, 'putUserProfileImportantInfo'))) { + if (!(await hasPermission(requestor, "putUserProfileImportantInfo"))) { res .status(403) - .send('You are not authorized to reset this users password'); + .send("You are not authorized to reset this users password"); return; } if ( - user.role === 'Owner' - && !(await hasPermission(requestor, 'addDeleteEditOwners')) + user.role === "Owner" && + !(await hasPermission(requestor, "addDeleteEditOwners")) ) { res .status(403) - .send('You are not authorized to reset this user password'); + .send("You are not authorized to reset this user password"); return; } @@ -1084,11 +1089,12 @@ const userProfileController = function (UserProfile) { await user.save(); - const condition = process.env.dbName === 'hgnData_dev' - ? user.role === 'Owner' - : user.role === 'Owner' || user.role === 'Administrator'; + const condition = + process.env.dbName === "hgnData_dev" + ? user.role === "Owner" + : user.role === "Owner" || user.role === "Administrator"; if (condition) { - const subject = `${process.env.dbName !== 'hgnData_dev' ? '*Main Site* -' : ''}${user.role} Password Reset Notification`; + const subject = `${process.env.dbName !== "hgnData_dev" ? "*Main Site* -" : ""}${user.role} Password Reset Notification`; const emailBody = `

Hi Admin!

Account Details

@@ -1116,7 +1122,7 @@ const userProfileController = function (UserProfile) { `; emailSender( - 'onecommunityglobal@gmail.com', + "onecommunityglobal@gmail.com", subject, emailBody, null, @@ -1125,7 +1131,7 @@ const userProfileController = function (UserProfile) { } res.status(200).send({ - message: 'Password Reset', + message: "Password Reset", }); } catch (error) { res.status(500).send(error); @@ -1134,7 +1140,7 @@ const userProfileController = function (UserProfile) { const getAllUsersWithFacebookLink = function (req, res) { try { - UserProfile.find({ 'personalLinks.Name': 'Facebook' }).then((results) => { + UserProfile.find({ "personalLinks.Name": "Facebook" }).then((results) => { res.status(200).send(results); }); } catch (error) { @@ -1146,7 +1152,7 @@ const userProfileController = function (UserProfile) { const user = await UserProfile.findById(req.params.userId); if (!user) { - res.status(403).send({ message: 'User does not exist' }); + res.status(403).send({ message: "User does not exist" }); return; } @@ -1165,7 +1171,7 @@ const userProfileController = function (UserProfile) { // Search for user by first name const getUserBySingleName = (req, res) => { - const pattern = new RegExp(`^${req.params.singleName}`, 'i'); + const pattern = new RegExp(`^${req.params.singleName}`, "i"); // Searches for first or last name UserProfile.find({ @@ -1174,11 +1180,11 @@ const userProfileController = function (UserProfile) { { lastName: { $regex: pattern } }, ], }) - .select('firstName lastName') + .select("firstName lastName") // eslint-disable-next-line consistent-return .then((users) => { if (users.length === 0) { - return res.status(404).send({ error: 'Users Not Found' }); + return res.status(404).send({ error: "Users Not Found" }); } res.status(200).send(users); }) @@ -1186,7 +1192,7 @@ const userProfileController = function (UserProfile) { }; function escapeRegExp(string) { - return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } // Search for user by full name (first and last) @@ -1194,17 +1200,17 @@ const userProfileController = function (UserProfile) { const getUserByFullName = (req, res) => { // Creates an array containing the first and last name and filters out whitespace const fullName = req.params.fullName - .split(' ') - .filter((name) => name !== ''); + .split(" ") + .filter((name) => name !== ""); // Creates a partial match regex for both first and last name - const firstNameRegex = new RegExp(`^${escapeRegExp(fullName[0])}`, 'i'); - const lastNameRegex = new RegExp(`^${escapeRegExp(fullName[1])}`, 'i'); + const firstNameRegex = new RegExp(`^${escapeRegExp(fullName[0])}`, "i"); + const lastNameRegex = new RegExp(`^${escapeRegExp(fullName[1])}`, "i"); // Verfies both the first and last name are present if (fullName.length < 2) { return res .status(400) - .send({ error: 'Both first name and last name are required.' }); + .send({ error: "Both first name and last name are required." }); } UserProfile.find({ @@ -1213,11 +1219,11 @@ const userProfileController = function (UserProfile) { { lastName: { $regex: lastNameRegex } }, ], }) - .select('firstName lastName') + .select("firstName lastName") // eslint-disable-next-line consistent-return .then((users) => { if (users.length === 0) { - return res.status(404).send({ error: 'Users Not Found' }); + return res.status(404).send({ error: "Users Not Found" }); } res.status(200).send(users); }) @@ -1239,7 +1245,7 @@ const userProfileController = function (UserProfile) { await UserProfile.findOne({ email: { $regex: escapeRegex(authorizedUser), // The Authorized user's email - $options: 'i', + $options: "i", }, }).then(async (user) => { await bcrypt @@ -1247,11 +1253,11 @@ const userProfileController = function (UserProfile) { .then((passwordMatch) => { if (!passwordMatch) { return res.status(400).send({ - error: 'Incorrect current password', + error: "Incorrect current password", }); } return res.status(200).send({ - message: 'Correct Password, Password matches!', + message: "Correct Password, Password matches!", password: req.body.currentPassword, }); }) @@ -1263,20 +1269,19 @@ const userProfileController = function (UserProfile) { res.status(500).send(err); } }; - // TODO: Implement Feature + const toggleInvisibility = async function (req, res) { const { userId } = req.params; const { isVisible } = req.body; - // console.log(req.body); if (!mongoose.Types.ObjectId.isValid(userId)) { res.status(400).send({ - error: 'Bad Request', + error: "Bad Request", }); return; } - if (!(await hasPermission(req.body.requestor, 'toggleInvisibility'))) { - res.status(403).send('You are not authorized to change user visibility'); + if (!(await hasPermission(req.body.requestor, "toggleInvisibility"))) { + res.status(403).send("You are not authorized to change user visibility"); return; } @@ -1284,26 +1289,23 @@ const userProfileController = function (UserProfile) { cache.removeCache(`user-${userId}`); UserProfile.findByIdAndUpdate(userId, { $set: { isVisible } }, (err, _) => { if (err) { - console.log(err); - return res.status(500).send(error); + return res.status(500).send("Could not Find user with id " + userId); + } + // Check if there's a cache for all users and update it accordingly + const isUserInCache = cache.hasCache("allusers"); + if (isUserInCache) { + const allUserData = JSON.parse(cache.getCache("allusers")); + const userIdx = allUserData.findIndex((users) => users._id === userId); + const userData = allUserData[userIdx]; + userData.isVisible = isVisible; + allUserData.splice(userIdx, 1, userData); + cache.setCache("allusers", JSON.stringify(allUserData)); } - // Check if there's a cache for all users and update it accordingly - const isUserInCache = cache.hasCache('allusers'); - if (isUserInCache) { - const allUserData = JSON.parse(cache.getCache('allusers')); - const userIdx = allUserData.findIndex( - (users) => users._id === userId, - ); - const userData = allUserData[userIdx]; - userData.isVisible = isVisible; - allUserData.splice(userIdx, 1, userData); - cache.setCache('allusers', JSON.stringify(allUserData)); - } - return res.status(200).send({ - message: 'User visibility updated successfully', - isVisible, - }); + return res.status(200).send({ + message: "User visibility updated successfully", + isVisible, + }); }); }; From 641c7ca11c035c452859a74275d104cbd2770208 Mon Sep 17 00:00:00 2001 From: Imran Issa Date: Sat, 20 Apr 2024 12:11:23 +0200 Subject: [PATCH 3/5] added route and controller for toggling user invisibility --- src/controllers/userProfileController.js | 520 +++++++++++------------ src/utilities/permissions.js | 60 +-- 2 files changed, 290 insertions(+), 290 deletions(-) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index ae5e81ebd..7fa818937 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -1,30 +1,30 @@ -const moment = require("moment-timezone"); +const moment = require('moment-timezone'); -const mongoose = require("mongoose"); -const bcrypt = require("bcryptjs"); +const mongoose = require('mongoose'); +const bcrypt = require('bcryptjs'); // eslint-disable-next-line import/no-extraneous-dependencies -const fetch = require("node-fetch"); +const fetch = require('node-fetch'); -const moment_ = require("moment"); -const jwt = require("jsonwebtoken"); -const userHelper = require("../helpers/userHelper")(); -const TimeEntry = require("../models/timeentry"); -const logger = require("../startup/logger"); -const Badge = require("../models/badge"); -const yearMonthDayDateValidator = require("../utilities/yearMonthDayDateValidator"); -const cache = require("../utilities/nodeCache")(); +const moment_ = require('moment'); +const jwt = require('jsonwebtoken'); +const userHelper = require('../helpers/userHelper')(); +const TimeEntry = require('../models/timeentry'); +const logger = require('../startup/logger'); +const Badge = require('../models/badge'); +const yearMonthDayDateValidator = require('../utilities/yearMonthDayDateValidator'); +const cache = require('../utilities/nodeCache')(); // const { authorizedUserSara, authorizedUserJae } = process.env; -const authorizedUserSara = "sucheta_mu@test.com"; // To test this code please include your email here -const authorizedUserJae = "jae@onecommunityglobal.org"; +const authorizedUserSara = 'sucheta_mu@test.com'; // To test this code please include your email here +const authorizedUserJae = 'jae@onecommunityglobal.org'; const { hasPermission, canRequestorUpdateUser, -} = require("../utilities/permissions"); -const escapeRegex = require("../utilities/escapeRegex"); -const emailSender = require("../utilities/emailSender"); -const config = require("../config"); +} = require('../utilities/permissions'); +const escapeRegex = require('../utilities/escapeRegex'); +const emailSender = require('../utilities/emailSender'); +const config = require('../config'); async function ValidatePassword(req, res) { const { userId } = req.params; @@ -32,7 +32,7 @@ async function ValidatePassword(req, res) { if (!mongoose.Types.ObjectId.isValid(userId)) { res.status(400).send({ - error: "Bad Request", + error: 'Bad Request', }); return; } @@ -40,14 +40,14 @@ async function ValidatePassword(req, res) { // Verify correct params in body if (!req.body.newpassword || !req.body.confirmnewpassword) { res.status(400).send({ - error: "One of more required fields are missing", + error: 'One of more required fields are missing', }); return; } // Verify request is authorized by self or adminsitrator if ( - userId !== requestor.requestorId && - !(await hasPermission(req.body.requestor, "updatePassword")) + userId !== requestor.requestorId + && !(await hasPermission(req.body.requestor, 'updatePassword')) ) { res.status(403).send({ error: "You are unauthorized to update this user's password", @@ -57,8 +57,8 @@ async function ValidatePassword(req, res) { // Verify request is authorized by self or adminsitrator if ( - userId === requestor.requestorId || - !(await hasPermission(req.body.requestor, "updatePassword")) + userId === requestor.requestorId + || !(await hasPermission(req.body.requestor, 'updatePassword')) ) { res.status(403).send({ error: "You are unauthorized to update this user's password", @@ -69,44 +69,44 @@ async function ValidatePassword(req, res) { // Verify new and confirm new password are correct if (req.body.newpassword !== req.body.confirmnewpassword) { res.status(400).send({ - error: "New and confirm new passwords are not same", + error: 'New and confirm new passwords are not same', }); } } const userProfileController = function (UserProfile) { const getUserProfiles = async function (req, res) { - if (!(await hasPermission(req.body.requestor, "getUserProfiles"))) { - res.status(403).send("You are not authorized to view all users"); + if (!(await hasPermission(req.body.requestor, 'getUserProfiles'))) { + res.status(403).send('You are not authorized to view all users'); return; } UserProfile.find( {}, - "_id firstName lastName role weeklycommittedHours email permissions isActive reactivationDate createdDate endDate", + '_id firstName lastName role weeklycommittedHours email permissions isActive reactivationDate createdDate endDate', ) .sort({ lastName: 1, }) .then((results) => { if (!results) { - if (cache.getCache("allusers")) { - const getData = JSON.parse(cache.getCache("allusers")); + if (cache.getCache('allusers')) { + const getData = JSON.parse(cache.getCache('allusers')); res.status(200).send(getData); return; } - res.status(500).send({ error: "User result was invalid" }); + res.status(500).send({ error: 'User result was invalid' }); return; } - cache.setCache("allusers", JSON.stringify(results)); + cache.setCache('allusers', JSON.stringify(results)); res.status(200).send(results); }) .catch((error) => res.status(404).send(error)); }; const getProjectMembers = async function (req, res) { - if (!(await hasPermission(req.body.requestor, "getProjectMembers"))) { - res.status(403).send("You are not authorized to view all users"); + if (!(await hasPermission(req.body.requestor, 'getProjectMembers'))) { + res.status(403).send('You are not authorized to view all users'); return; } UserProfile.find( @@ -115,10 +115,10 @@ const userProfileController = function (UserProfile) { $in: [req.params.projectId], }, }, - "_id firstName email", + '_id firstName email', (err, profiles) => { if (err) { - res.status(404).send("Error finding user profiles"); + res.status(404).send('Error finding user profiles'); return; } res.json(profiles); @@ -127,58 +127,58 @@ const userProfileController = function (UserProfile) { }; const postUserProfile = async function (req, res) { - if (!(await hasPermission(req.body.requestor, "postUserProfile"))) { - res.status(403).send("You are not authorized to create new users"); + if (!(await hasPermission(req.body.requestor, 'postUserProfile'))) { + res.status(403).send('You are not authorized to create new users'); return; } if ( - req.body.role === "Owner" && - !(await hasPermission(req.body.requestor, "addDeleteEditOwners")) + req.body.role === 'Owner' + && !(await hasPermission(req.body.requestor, 'addDeleteEditOwners')) ) { - res.status(403).send("You are not authorized to create new owners"); + res.status(403).send('You are not authorized to create new owners'); return; } const userByEmail = await UserProfile.findOne({ email: { $regex: escapeRegex(req.body.email), - $options: "i", + $options: 'i', }, }); if (userByEmail) { res.status(400).send({ error: - "That email address is already in use. Please choose another email address.", - type: "email", + 'That email address is already in use. Please choose another email address.', + type: 'email', }); return; } // In dev environment, if newly created user is Owner or Administrator, make fetch request to Beta login route with actualEmail and actual Password - if (process.env.dbName === "hgnData_dev") { - if (req.body.role === "Owner" || req.body.role === "Administrator") { + if (process.env.dbName === 'hgnData_dev') { + if (req.body.role === 'Owner' || req.body.role === 'Administrator') { const email = req.body.actualEmail; const password = req.body.actualPassword; - const url = "https://hgn-rest-beta.azurewebsites.net/api/"; + const url = 'https://hgn-rest-beta.azurewebsites.net/api/'; try { // Log in to Beta login route using provided credentials const response = await fetch(`${url}login`, { - method: "POST", + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, body: JSON.stringify({ email, password }), }); if (!response.ok) { - throw new Error("Invalid credentials"); + throw new Error('Invalid credentials'); } } catch (error) { res.status(400).send({ error: - "The actual email or password you provided is incorrect. Please enter the actual email and password associated with your account in the Main HGN app.", - type: "credentials", + 'The actual email or password you provided is incorrect. Please enter the actual email and password associated with your account in the Main HGN app.', + type: 'credentials', }); return; } @@ -199,8 +199,8 @@ const userProfileController = function (UserProfile) { if (userByPhoneNumber) { res.status(400).send({ error: - "That phone number is already in use. Please choose another number.", - type: "phoneNumber", + 'That phone number is already in use. Please choose another number.', + type: 'phoneNumber', }); return; } @@ -214,8 +214,8 @@ const userProfileController = function (UserProfile) { if (userDuplicateName && !req.body.allowsDuplicateName) { res.status(400).send({ error: - "That name is already in use. Please confirm if you want to use this name.", - type: "name", + 'That name is already in use. Please confirm if you want to use this name.', + type: 'name', }); return; } @@ -242,34 +242,33 @@ const userProfileController = function (UserProfile) { up.projects = Array.from(new Set(req.body.projects)); up.createdDate = req.body.createdDate; up.email = req.body.email; - up.weeklySummaries = req.body.weeklySummaries || [{ summary: "" }]; + up.weeklySummaries = req.body.weeklySummaries || [{ summary: '' }]; up.weeklySummariesCount = req.body.weeklySummariesCount || 0; up.weeklySummaryOption = req.body.weeklySummaryOption; - up.mediaUrl = req.body.mediaUrl || ""; - up.collaborationPreference = req.body.collaborationPreference || ""; - up.timeZone = req.body.timeZone || "America/Los_Angeles"; + up.mediaUrl = req.body.mediaUrl || ''; + up.collaborationPreference = req.body.collaborationPreference || ''; + up.timeZone = req.body.timeZone || 'America/Los_Angeles'; up.location = req.body.location; up.permissions = req.body.permissions; - up.bioPosted = req.body.bioPosted || "default"; + up.bioPosted = req.body.bioPosted || 'default'; up.isFirstTimelog = true; up.actualEmail = req.body.actualEmail; - up.isVisible = !["Mentor"].includes(req.body.role); + up.isVisible = !['Mentor'].includes(req.body.role); try { const requestor = await UserProfile.findById( req.body.requestor.requestorId, ) - .select("firstName lastName email role") + .select('firstName lastName email role') .exec(); await up.save().then(() => { // if connected to dev db just check for Owner roles, else it's main branch so also check admin too - const condition = - process.env.dbName === "hgnData_dev" - ? up.role === "Owner" - : up.role === "Owner" || up.role === "Administrator"; + const condition = process.env.dbName === 'hgnData_dev' + ? up.role === 'Owner' + : up.role === 'Owner' || up.role === 'Administrator'; if (condition) { - const subject = `${process.env.dbName !== "hgnData_dev" ? "*Main Site* -" : ""}New ${up.role} Role Created`; + const subject = `${process.env.dbName !== 'hgnData_dev' ? '*Main Site* -' : ''}New ${up.role} Role Created`; const emailBody = `

Hi Admin!

@@ -296,7 +295,7 @@ const userProfileController = function (UserProfile) {

The HGN A.I. (and One Community)

`; emailSender( - "onecommunityglobal@gmail.com", + 'onecommunityglobal@gmail.com', subject, emailBody, null, @@ -306,7 +305,7 @@ const userProfileController = function (UserProfile) { }); // update backend cache if it exists - if (cache.getCache("allusers")) { + if (cache.getCache('allusers')) { const userCache = { permissions: up.permissions, isActive: true, @@ -318,9 +317,9 @@ const userProfileController = function (UserProfile) { lastName: up.lastName, email: up.email, }; - const allUserCache = JSON.parse(cache.getCache("allusers")); + const allUserCache = JSON.parse(cache.getCache('allusers')); allUserCache.push(userCache); - cache.setCache("allusers", JSON.stringify(allUserCache)); + cache.setCache('allusers', JSON.stringify(allUserCache)); } res.status(200).send({ @@ -334,28 +333,28 @@ const userProfileController = function (UserProfile) { const putUserProfile = async function (req, res) { const userid = req.params.userId; const isRequestorAuthorized = !!( - canRequestorUpdateUser(req.body.requestor.requestorId, userid) && - ((await hasPermission(req.body.requestor, "putUserProfile")) || - req.body.requestor.requestorId === userid) + canRequestorUpdateUser(req.body.requestor.requestorId, userid) + && ((await hasPermission(req.body.requestor, 'putUserProfile')) + || req.body.requestor.requestorId === userid) ); if (!isRequestorAuthorized) { - res.status(403).send("You are not authorized to update this user"); + res.status(403).send('You are not authorized to update this user'); return; } if ( - req.body.role === "Owner" && - !(await hasPermission(req.body.requestor, "addDeleteEditOwners")) + req.body.role === 'Owner' + && !(await hasPermission(req.body.requestor, 'addDeleteEditOwners')) ) { - res.status(403).send("You are not authorized to update this user"); + res.status(403).send('You are not authorized to update this user'); return; } cache.removeCache(`user-${userid}`); UserProfile.findById(userid, async (err, record) => { if (err || !record) { - res.status(404).send("No valid records found"); + res.status(404).send('No valid records found'); return; } // validate userprofile pic @@ -369,15 +368,14 @@ const userProfileController = function (UserProfile) { } } - const canEditTeamCode = - req.body.requestor.role === "Owner" || - req.body.requestor.role === "Administrator" || - req.body.requestor.permissions?.frontPermissions.includes( - "editTeamCode", + const canEditTeamCode = req.body.requestor.role === 'Owner' + || req.body.requestor.role === 'Administrator' + || req.body.requestor.permissions?.frontPermissions.includes( + 'editTeamCode', ); if (!canEditTeamCode && record.teamCode !== req.body.teamCode) { - res.status(403).send("You are not authorized to edit team code."); + res.status(403).send('You are not authorized to edit team code.'); return; } @@ -386,31 +384,31 @@ const userProfileController = function (UserProfile) { : []; const commonFields = [ - "jobTitle", - "emailPubliclyAccessible", - "phoneNumberPubliclyAccessible", - "profilePic", - "firstName", - "lastName", - "jobTitle", - "phoneNumber", - "bio", - "personalLinks", - "location", - "profilePic", - "privacySettings", - "weeklySummaries", - "weeklySummariesCount", - "mediaUrl", - "timeZone", - "hoursByCategory", - "totalTangibleHrs", - "totalIntangibleHrs", - "isFirstTimelog", - "teamCode", - "isVisible", - "isRehireable", - "bioPosted", + 'jobTitle', + 'emailPubliclyAccessible', + 'phoneNumberPubliclyAccessible', + 'profilePic', + 'firstName', + 'lastName', + 'jobTitle', + 'phoneNumber', + 'bio', + 'personalLinks', + 'location', + 'profilePic', + 'privacySettings', + 'weeklySummaries', + 'weeklySummariesCount', + 'mediaUrl', + 'timeZone', + 'hoursByCategory', + 'totalTangibleHrs', + 'totalIntangibleHrs', + 'isFirstTimelog', + 'teamCode', + 'isVisible', + 'isRehireable', + 'bioPosted', ]; commonFields.forEach((fieldName) => { @@ -422,38 +420,38 @@ const userProfileController = function (UserProfile) { record.lastModifiedDate = Date.now(); // find userData in cache - const isUserInCache = cache.hasCache("allusers"); + const isUserInCache = cache.hasCache('allusers'); let allUserData; let userData; let userIdx; if (isUserInCache) { - allUserData = JSON.parse(cache.getCache("allusers")); + allUserData = JSON.parse(cache.getCache('allusers')); userIdx = allUserData.findIndex((users) => users._id === userid); userData = allUserData[userIdx]; } if ( - await hasPermission(req.body.requestor, "putUserProfileImportantInfo") + await hasPermission(req.body.requestor, 'putUserProfileImportantInfo') ) { const importantFields = [ - "role", - "isRehireable", - "isActive", - "adminLinks", - "isActive", - "weeklySummaries", - "weeklySummariesCount", - "mediaUrl", - "collaborationPreference", - "weeklySummaryNotReq", - "weeklySummaryOption", - "categoryTangibleHrs", - "totalTangibleHrs", - "timeEntryEditHistory", + 'role', + 'isRehireable', + 'isActive', + 'adminLinks', + 'isActive', + 'weeklySummaries', + 'weeklySummariesCount', + 'mediaUrl', + 'collaborationPreference', + 'weeklySummaryNotReq', + 'weeklySummaryOption', + 'categoryTangibleHrs', + 'totalTangibleHrs', + 'timeEntryEditHistory', ]; if (req.body.role !== record.role) { switch (req.body.role) { - case "Mentor": + case 'Mentor': record.isVisible = false; break; default: @@ -467,8 +465,7 @@ const userProfileController = function (UserProfile) { }); if (req.body.missedHours !== undefined) { - record.missedHours = - req.body.role === "Core Team" ? req.body?.missedHours ?? 0 : 0; + record.missedHours = req.body.role === 'Core Team' ? req.body?.missedHours ?? 0 : 0; } if (req.body.teams !== undefined) { @@ -485,8 +482,8 @@ const userProfileController = function (UserProfile) { // Logic to update weeklycommittedHours and the history of the committed hours made if ( - req.body.weeklycommittedHours !== undefined && - record.weeklycommittedHours !== req.body.weeklycommittedHours + req.body.weeklycommittedHours !== undefined + && record.weeklycommittedHours !== req.body.weeklycommittedHours ) { record.weeklycommittedHours = req.body.weeklycommittedHours; @@ -497,7 +494,7 @@ const userProfileController = function (UserProfile) { ); const now = moment(); - if (lastChangeDate.isSame(now, "day")) { + if (lastChangeDate.isSame(now, 'day')) { record.weeklycommittedHoursHistory.pop(); } @@ -511,8 +508,8 @@ const userProfileController = function (UserProfile) { } if ( - req.body.createdDate !== undefined && - record.createdDate !== req.body.createdDate + req.body.createdDate !== undefined + && record.createdDate !== req.body.createdDate ) { record.createdDate = moment(req.body.createdDate).toDate(); // Make sure weeklycommittedHoursHistory isn't empty @@ -524,13 +521,12 @@ const userProfileController = function (UserProfile) { record.weeklycommittedHoursHistory.push(newEntry); } // then also change the first committed history (index 0) - record.weeklycommittedHoursHistory[0].dateChanged = - record.createdDate; + record.weeklycommittedHoursHistory[0].dateChanged = record.createdDate; } if ( - req.body.permissions !== undefined && - (await hasPermission(req.body.requestor, "putUserProfilePermissions")) + req.body.permissions !== undefined + && (await hasPermission(req.body.requestor, 'putUserProfilePermissions')) ) { record.permissions = req.body.permissions; } @@ -542,7 +538,7 @@ const userProfileController = function (UserProfile) { userData.endDate = record.endDate.toISOString(); } } else { - record.set("endDate", undefined, { strict: false }); + record.set('endDate', undefined, { strict: false }); } } @@ -555,8 +551,8 @@ const userProfileController = function (UserProfile) { } } if ( - req.body.infringements !== undefined && - (await hasPermission(req.body.requestor, "infringementAuthorizer")) + req.body.infringements !== undefined + && (await hasPermission(req.body.requestor, 'infringementAuthorizer')) ) { record.infringements = req.body.infringements; } @@ -578,7 +574,7 @@ const userProfileController = function (UserProfile) { // update alluser cache if we have cache if (isUserInCache) { allUserData.splice(userIdx, 1, userData); - cache.setCache("allusers", JSON.stringify(allUserData)); + cache.setCache('allusers', JSON.stringify(allUserData)); } }) .catch((error) => res.status(400).send(error)); @@ -587,29 +583,29 @@ const userProfileController = function (UserProfile) { const deleteUserProfile = async function (req, res) { const { option, userId } = req.body; - if (!(await hasPermission(req.body.requestor, "deleteUserProfile"))) { - res.status(403).send("You are not authorized to delete users"); + if (!(await hasPermission(req.body.requestor, 'deleteUserProfile'))) { + res.status(403).send('You are not authorized to delete users'); return; } if ( - req.body.role === "Owner" && - !(await hasPermission(req.body.requestor, "addDeleteEditOwners")) + req.body.role === 'Owner' + && !(await hasPermission(req.body.requestor, 'addDeleteEditOwners')) ) { - res.status(403).send("You are not authorized to delete this user"); + res.status(403).send('You are not authorized to delete this user'); return; } - if (!userId || !option || (option !== "delete" && option !== "archive")) { + if (!userId || !option || (option !== 'delete' && option !== 'archive')) { res.status(400).send({ - error: "Bad request", + error: 'Bad request', }); return; } if (userId === req.body.requestor) { res.status(403).send({ - error: "You cannot delete your own account", + error: 'You cannot delete your own account', }); return; } @@ -618,27 +614,27 @@ const userProfileController = function (UserProfile) { if (!user) { res.status(400).send({ - error: "Invalid user", + error: 'Invalid user', }); return; } - if (option === "archive") { + if (option === 'archive') { const timeArchiveUser = await UserProfile.findOne( { firstName: process.env.TIME_ARCHIVE_FIRST_NAME, lastName: process.env.TIME_ARCHIVE_LAST_NAME, }, - "_id", + '_id', ); if (!timeArchiveUser) { logger.logException( - "Time Archive user was not found. Please check the database", + '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", + 'Time Archive User not found. Please contact your developement team on why that happened', }); return; } @@ -656,18 +652,18 @@ const userProfileController = function (UserProfile) { } cache.removeCache(`user-${userId}`); - if (cache.getCache("allusers")) { - const allUserData = JSON.parse(cache.getCache("allusers")); + if (cache.getCache('allusers')) { + const allUserData = JSON.parse(cache.getCache('allusers')); const userIdx = allUserData.findIndex((users) => users._id === userId); allUserData.splice(userIdx, 1); - cache.setCache("allusers", JSON.stringify(allUserData)); + cache.setCache('allusers', JSON.stringify(allUserData)); } await UserProfile.deleteOne({ _id: userId, }) .then(() => { - res.status(200).send({ message: "Executed Successfully" }); + res.status(200).send({ message: 'Executed Successfully' }); }) .catch((err) => { res.status(500).send(err); @@ -684,12 +680,12 @@ const userProfileController = function (UserProfile) { UserProfile.findById( userid, - "-password -refreshTokens -lastModifiedDate -__v", + '-password -refreshTokens -lastModifiedDate -__v', ) .populate([ { - path: "teams", - select: "_id teamName", + path: 'teams', + select: '_id teamName', options: { sort: { teamName: 1, @@ -697,8 +693,8 @@ const userProfileController = function (UserProfile) { }, }, { - path: "projects", - select: "_id projectName category", + path: 'projects', + select: '_id projectName category', options: { sort: { projectName: 1, @@ -706,25 +702,25 @@ const userProfileController = function (UserProfile) { }, }, { - path: "badgeCollection", + path: 'badgeCollection', populate: { - path: "badge", + path: 'badge', model: Badge, select: - "_id badgeName type imageUrl description ranking showReport", + '_id badgeName type imageUrl description ranking showReport', }, }, ]) .exec() .then((results) => { if (!results) { - res.status(400).send({ error: "This is not a valid user" }); + res.status(400).send({ error: 'This is not a valid user' }); return; } userHelper .getTangibleHoursReportedThisWeekByUserId(userid) .then((hours) => { - results.set("tangibleHoursReportedThisWeek", hours, { + results.set('tangibleHoursReportedThisWeek', hours, { strict: false, }); cache.setCache(`user-${userid}`, JSON.stringify(results)); @@ -737,8 +733,8 @@ const userProfileController = function (UserProfile) { const getUserByName = (req, res) => { const { name } = req.params; UserProfile.find( - { firstName: name.split(" ")[0], lastName: name.split(" ")[1] }, - "_id, profilePic, badgeCollection", + { firstName: name.split(' ')[0], lastName: name.split(' ')[1] }, + '_id, profilePic, badgeCollection', ) .then((results) => { @@ -751,16 +747,15 @@ const userProfileController = function (UserProfile) { const { userId } = req.params; const { key, value } = req.body; - if (key === "teamCode") { - const canEditTeamCode = - req.body.requestor.role === "Owner" || - req.body.requestor.role === "Administrator" || - req.body.requestor.permissions?.frontPermissions.includes( - "editTeamCode", + if (key === 'teamCode') { + const canEditTeamCode = req.body.requestor.role === 'Owner' + || req.body.requestor.role === 'Administrator' + || req.body.requestor.permissions?.frontPermissions.includes( + 'editTeamCode', ); if (!canEditTeamCode) { - res.status(403).send("You are not authorized to edit team code."); + res.status(403).send('You are not authorized to edit team code.'); return; } } @@ -768,7 +763,7 @@ const userProfileController = function (UserProfile) { // remove user from cache, it should be loaded next time cache.removeCache(`user-${userId}`); if (!key || value === undefined) { - return res.status(400).send({ error: "Missing property or value" }); + return res.status(400).send({ error: 'Missing property or value' }); } return UserProfile.findById(userId) @@ -780,7 +775,7 @@ const userProfileController = function (UserProfile) { return user .save() .then(() => { - res.status(200).send({ message: "updated property" }); + res.status(200).send({ message: 'updated property' }); }) .catch((error) => res.status(500).send(error)); }) @@ -792,24 +787,24 @@ const userProfileController = function (UserProfile) { const { requestor } = req.body; if (!mongoose.Types.ObjectId.isValid(userId)) { return res.status(400).send({ - error: "Bad Request", + error: 'Bad Request', }); } // Verify correct params in body if ( - !req.body.currentpassword || - !req.body.newpassword || - !req.body.confirmnewpassword + !req.body.currentpassword + || !req.body.newpassword + || !req.body.confirmnewpassword ) { return res.status(400).send({ - error: "One of more required fields are missing", + error: 'One of more required fields are missing', }); } // Check if the requestor has the permission to update passwords. const hasUpdatePasswordPermission = await hasPermission( requestor, - "updatePassword", + 'updatePassword', ); // if they're updating someone else's password, they need the 'updatePassword' permission. @@ -822,25 +817,25 @@ const userProfileController = function (UserProfile) { // Verify new and confirm new password are correct if (req.body.newpassword !== req.body.confirmnewpassword) { return res.status(400).send({ - error: "New and confirm new passwords are not the same", + error: 'New and confirm new passwords are not the same', }); } // Verify old and new passwords are not same if (req.body.currentpassword === req.body.newpassword) { res.status(400).send({ - error: "Old and new passwords should not be same", + error: 'Old and new passwords should not be same', }); } - return UserProfile.findById(userId, "password") + return UserProfile.findById(userId, 'password') .then((user) => { bcrypt .compare(req.body.currentpassword, user.password) .then((passwordMatch) => { if (!passwordMatch) { return res.status(400).send({ - error: "Incorrect current password", + error: 'Incorrect current password', }); } @@ -850,7 +845,7 @@ const userProfileController = function (UserProfile) { }); return user .save() - .then(() => res.status(200).send({ message: "updated password" })) + .then(() => res.status(200).send({ message: 'updated password' })) .catch((error) => res.status(500).send(error)); }) .catch((error) => res.status(500).send(error)); @@ -861,7 +856,7 @@ const userProfileController = function (UserProfile) { const getreportees = async function (req, res) { if (!mongoose.Types.ObjectId.isValid(req.params.userId)) { res.status(400).send({ - error: "Bad request", + error: 'Bad request', }); return; } @@ -869,16 +864,16 @@ const userProfileController = function (UserProfile) { const userid = mongoose.Types.ObjectId(req.params.userId); let validroles = [ - "Volunteer", - "Manager", - "Administrator", - "Core Team", - "Owner", - "Mentor", + 'Volunteer', + 'Manager', + 'Administrator', + 'Core Team', + 'Owner', + 'Mentor', ]; - if (await hasPermission(req.body.requestor, "getReporteesLimitRoles")) { - validroles = ["Volunteer", "Manager"]; + if (await hasPermission(req.body.requestor, 'getReporteesLimitRoles')) { + validroles = ['Volunteer', 'Manager']; } userHelper @@ -900,7 +895,7 @@ const userProfileController = function (UserProfile) { const getTeamMembersofUser = function (req, res) { if (!mongoose.Types.ObjectId.isValid(req.params.userId)) { res.status(400).send({ - error: "Bad request", + error: 'Bad request', }); return; } @@ -918,7 +913,7 @@ const userProfileController = function (UserProfile) { const { userId } = req.params; if (mongoose.Types.ObjectId.isValid(userId)) { - UserProfile.findById(userId, "firstName lastName") + UserProfile.findById(userId, 'firstName lastName') .then((result) => { const name = `${result.firstName} ${result.lastName}`; res.status(200).send({ @@ -930,30 +925,30 @@ const userProfileController = function (UserProfile) { }); } else { res.status(400).send({ - error: "Bad request", + error: 'Bad request', }); } }; const changeUserStatus = async function (req, res) { const { userId } = req.params; - const status = req.body.status === "Active"; + const status = req.body.status === 'Active'; const activationDate = req.body.reactivationDate; const { endDate } = req.body; - const isSet = req.body.isSet === "FinalDay"; + const isSet = req.body.isSet === 'FinalDay'; if (!mongoose.Types.ObjectId.isValid(userId)) { res.status(400).send({ - error: "Bad Request", + error: 'Bad Request', }); return; } - if (!(await hasPermission(req.body.requestor, "changeUserStatus"))) { - res.status(403).send("You are not authorized to change user status"); + if (!(await hasPermission(req.body.requestor, 'changeUserStatus'))) { + res.status(403).send('You are not authorized to change user status'); return; } cache.removeCache(`user-${userId}`); - UserProfile.findById(userId, "isActive") + UserProfile.findById(userId, 'isActive') .then((user) => { user.set({ isActive: status, @@ -964,9 +959,9 @@ const userProfileController = function (UserProfile) { user .save() .then(() => { - const isUserInCache = cache.hasCache("allusers"); + const isUserInCache = cache.hasCache('allusers'); if (isUserInCache) { - const allUserData = JSON.parse(cache.getCache("allusers")); + const allUserData = JSON.parse(cache.getCache('allusers')); const userIdx = allUserData.findIndex( (users) => users._id === userId, ); @@ -976,10 +971,10 @@ const userProfileController = function (UserProfile) { } userData.isActive = user.isActive; allUserData.splice(userIdx, 1, userData); - cache.setCache("allusers", JSON.stringify(allUserData)); + cache.setCache('allusers', JSON.stringify(allUserData)); } res.status(200).send({ - message: "status updated", + message: 'status updated', }); }) .catch((error) => { @@ -996,14 +991,14 @@ const userProfileController = function (UserProfile) { const { isRehireable } = req.body; if (!mongoose.Types.ObjectId.isValid(userId)) { - return res.status(400).send({ error: "Bad Request" }); + return res.status(400).send({ error: 'Bad Request' }); } if ( - !(await hasPermission(req.body.requestor, "changeUserRehireableStatus")) + !(await hasPermission(req.body.requestor, 'changeUserRehireableStatus')) ) { return res .status(403) - .send("You are not authorized to change rehireable status"); + .send('You are not authorized to change rehireable status'); } // Invalidate the cache for this user @@ -1018,25 +1013,25 @@ const userProfileController = function (UserProfile) { return res.status(500).send(error); } // Check if there's a cache for all users and update it accordingly - const isUserInCache = cache.hasCache("allusers"); + const isUserInCache = cache.hasCache('allusers'); if (isUserInCache) { - const allUserData = JSON.parse(cache.getCache("allusers")); + const allUserData = JSON.parse(cache.getCache('allusers')); const userIdx = allUserData.findIndex( (users) => users._id === userId, ); const userData = allUserData[userIdx]; userData.isRehireable = isRehireable; allUserData.splice(userIdx, 1, userData); - cache.setCache("allusers", JSON.stringify(allUserData)); + cache.setCache('allusers', JSON.stringify(allUserData)); } // Optionally, re-fetch the user to verify the updated data UserProfile.findById(userId, (err, verifiedUser) => { if (err) { - return res.status(500).send("Error fetching updated user data."); + return res.status(500).send('Error fetching updated user data.'); } res.status(200).send({ - message: "Rehireable status updated and verified successfully", + message: 'Rehireable status updated and verified successfully', isRehireable: verifiedUser.isRehireable, }); }); @@ -1051,37 +1046,37 @@ const userProfileController = function (UserProfile) { const requestor = await UserProfile.findById( req.body.requestor.requestorId, ) - .select("firstName lastName email role") + .select('firstName lastName email role') .exec(); if (!requestor) { - res.status(404).send({ error: "Requestor not found" }); + res.status(404).send({ error: 'Requestor not found' }); return; } const user = await UserProfile.findById(req.params.userId) - .select("firstName lastName email role") + .select('firstName lastName email role') .exec(); if (!user) { - res.status(404).send({ error: "User not found" }); + res.status(404).send({ error: 'User not found' }); return; } - if (!(await hasPermission(requestor, "putUserProfileImportantInfo"))) { + if (!(await hasPermission(requestor, 'putUserProfileImportantInfo'))) { res .status(403) - .send("You are not authorized to reset this users password"); + .send('You are not authorized to reset this users password'); return; } if ( - user.role === "Owner" && - !(await hasPermission(requestor, "addDeleteEditOwners")) + user.role === 'Owner' + && !(await hasPermission(requestor, 'addDeleteEditOwners')) ) { res .status(403) - .send("You are not authorized to reset this user password"); + .send('You are not authorized to reset this user password'); return; } @@ -1089,12 +1084,11 @@ const userProfileController = function (UserProfile) { await user.save(); - const condition = - process.env.dbName === "hgnData_dev" - ? user.role === "Owner" - : user.role === "Owner" || user.role === "Administrator"; + const condition = process.env.dbName === 'hgnData_dev' + ? user.role === 'Owner' + : user.role === 'Owner' || user.role === 'Administrator'; if (condition) { - const subject = `${process.env.dbName !== "hgnData_dev" ? "*Main Site* -" : ""}${user.role} Password Reset Notification`; + const subject = `${process.env.dbName !== 'hgnData_dev' ? '*Main Site* -' : ''}${user.role} Password Reset Notification`; const emailBody = `

Hi Admin!

Account Details

@@ -1122,7 +1116,7 @@ const userProfileController = function (UserProfile) { `; emailSender( - "onecommunityglobal@gmail.com", + 'onecommunityglobal@gmail.com', subject, emailBody, null, @@ -1131,7 +1125,7 @@ const userProfileController = function (UserProfile) { } res.status(200).send({ - message: "Password Reset", + message: 'Password Reset', }); } catch (error) { res.status(500).send(error); @@ -1140,7 +1134,7 @@ const userProfileController = function (UserProfile) { const getAllUsersWithFacebookLink = function (req, res) { try { - UserProfile.find({ "personalLinks.Name": "Facebook" }).then((results) => { + UserProfile.find({ 'personalLinks.Name': 'Facebook' }).then((results) => { res.status(200).send(results); }); } catch (error) { @@ -1152,7 +1146,7 @@ const userProfileController = function (UserProfile) { const user = await UserProfile.findById(req.params.userId); if (!user) { - res.status(403).send({ message: "User does not exist" }); + res.status(403).send({ message: 'User does not exist' }); return; } @@ -1171,7 +1165,7 @@ const userProfileController = function (UserProfile) { // Search for user by first name const getUserBySingleName = (req, res) => { - const pattern = new RegExp(`^${req.params.singleName}`, "i"); + const pattern = new RegExp(`^${req.params.singleName}`, 'i'); // Searches for first or last name UserProfile.find({ @@ -1180,11 +1174,11 @@ const userProfileController = function (UserProfile) { { lastName: { $regex: pattern } }, ], }) - .select("firstName lastName") + .select('firstName lastName') // eslint-disable-next-line consistent-return .then((users) => { if (users.length === 0) { - return res.status(404).send({ error: "Users Not Found" }); + return res.status(404).send({ error: 'Users Not Found' }); } res.status(200).send(users); }) @@ -1192,7 +1186,7 @@ const userProfileController = function (UserProfile) { }; function escapeRegExp(string) { - return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } // Search for user by full name (first and last) @@ -1200,17 +1194,17 @@ const userProfileController = function (UserProfile) { const getUserByFullName = (req, res) => { // Creates an array containing the first and last name and filters out whitespace const fullName = req.params.fullName - .split(" ") - .filter((name) => name !== ""); + .split(' ') + .filter((name) => name !== ''); // Creates a partial match regex for both first and last name - const firstNameRegex = new RegExp(`^${escapeRegExp(fullName[0])}`, "i"); - const lastNameRegex = new RegExp(`^${escapeRegExp(fullName[1])}`, "i"); + const firstNameRegex = new RegExp(`^${escapeRegExp(fullName[0])}`, 'i'); + const lastNameRegex = new RegExp(`^${escapeRegExp(fullName[1])}`, 'i'); // Verfies both the first and last name are present if (fullName.length < 2) { return res .status(400) - .send({ error: "Both first name and last name are required." }); + .send({ error: 'Both first name and last name are required.' }); } UserProfile.find({ @@ -1219,11 +1213,11 @@ const userProfileController = function (UserProfile) { { lastName: { $regex: lastNameRegex } }, ], }) - .select("firstName lastName") + .select('firstName lastName') // eslint-disable-next-line consistent-return .then((users) => { if (users.length === 0) { - return res.status(404).send({ error: "Users Not Found" }); + return res.status(404).send({ error: 'Users Not Found' }); } res.status(200).send(users); }) @@ -1245,7 +1239,7 @@ const userProfileController = function (UserProfile) { await UserProfile.findOne({ email: { $regex: escapeRegex(authorizedUser), // The Authorized user's email - $options: "i", + $options: 'i', }, }).then(async (user) => { await bcrypt @@ -1253,11 +1247,11 @@ const userProfileController = function (UserProfile) { .then((passwordMatch) => { if (!passwordMatch) { return res.status(400).send({ - error: "Incorrect current password", + error: 'Incorrect current password', }); } return res.status(200).send({ - message: "Correct Password, Password matches!", + message: 'Correct Password, Password matches!', password: req.body.currentPassword, }); }) @@ -1276,12 +1270,12 @@ const userProfileController = function (UserProfile) { if (!mongoose.Types.ObjectId.isValid(userId)) { res.status(400).send({ - error: "Bad Request", + error: 'Bad Request', }); return; } - if (!(await hasPermission(req.body.requestor, "toggleInvisibility"))) { - res.status(403).send("You are not authorized to change user visibility"); + if (!(await hasPermission(req.body.requestor, 'toggleInvisibility'))) { + res.status(403).send('You are not authorized to change user visibility'); return; } @@ -1289,21 +1283,21 @@ const userProfileController = function (UserProfile) { cache.removeCache(`user-${userId}`); UserProfile.findByIdAndUpdate(userId, { $set: { isVisible } }, (err, _) => { if (err) { - return res.status(500).send("Could not Find user with id " + userId); + return res.status(500).send(`Could not Find user with id ${ userId}`); } // Check if there's a cache for all users and update it accordingly - const isUserInCache = cache.hasCache("allusers"); + const isUserInCache = cache.hasCache('allusers'); if (isUserInCache) { - const allUserData = JSON.parse(cache.getCache("allusers")); + const allUserData = JSON.parse(cache.getCache('allusers')); const userIdx = allUserData.findIndex((users) => users._id === userId); const userData = allUserData[userIdx]; userData.isVisible = isVisible; allUserData.splice(userIdx, 1, userData); - cache.setCache("allusers", JSON.stringify(allUserData)); + cache.setCache('allusers', JSON.stringify(allUserData)); } return res.status(200).send({ - message: "User visibility updated successfully", + message: 'User visibility updated successfully', isVisible, }); }); diff --git a/src/utilities/permissions.js b/src/utilities/permissions.js index ff522900e..96e9030fb 100644 --- a/src/utilities/permissions.js +++ b/src/utilities/permissions.js @@ -1,35 +1,41 @@ -const Role = require('../models/role'); -const UserProfile = require('../models/userProfile'); +const Role = require("../models/role"); +const UserProfile = require("../models/userProfile"); -const hasRolePermission = async (role, action) => Role.findOne({ roleName: role }) - .exec() - .then(({ permissions }) => permissions.includes(action)) - .catch(false); +const hasRolePermission = async (role, action) => + Role.findOne({ roleName: role }) + .exec() + .then(({ permissions }) => permissions.includes(action)) + .catch(false); -const hasIndividualPermission = async (userId, action) => UserProfile.findById(userId) - .select('permissions') - .exec() - .then(({ permissions }) => permissions.frontPermissions.includes(action)) - .catch(false); +const hasIndividualPermission = async (userId, action) => + UserProfile.findById(userId) + .select("permissions") + .exec() + .then(({ permissions }) => permissions.frontPermissions.includes(action)) + .catch(false); -const hasPermission = async (requestor, action) => await hasRolePermission(requestor.role, action) || hasIndividualPermission(requestor.requestorId, action); +const hasPermission = async (requestor, action) => + (await hasRolePermission(requestor.role, action)) || + hasIndividualPermission(requestor.requestorId, action); const canRequestorUpdateUser = (requestorId, userId) => { - const allowedIds = ['63feae337186de1898fa8f51', // dev jae@onecommunityglobal.org - '5baac381e16814009017678c', // dev one.community@me.com - '63fe855b7186de1898fa8ab7', // dev jsabol@me.com - '64deba9064131f13540ac23b', // main jae@onecommunityglobal.org - '610d5ae67002ae3fecdf7080', // main one.community@me.com - '63fe8e4fa79c5619d0b5a563', // main jsabol@me.com - ]; - const protectedIds = ['63feae337186de1898fa8f51', // dev jae@onecommunityglobal.org - '5baac381e16814009017678c', // dev one.community@me.com - '63fe855b7186de1898fa8ab7', // dev jsabol@me.com - '64deba9064131f13540ac23b', // main jae@onecommunityglobal.org - '610d5ae67002ae3fecdf7080', // main one.community@me.com - '63fe8e4fa79c5619d0b5a563', // main jsabol@me.com - '64c17eb8c737b05dd4ac4e28', // dev devadmin@hgn.net - ]; + const allowedIds = [ + "63feae337186de1898fa8f51", // dev jae@onecommunityglobal.org + "5baac381e16814009017678c", // dev one.community@me.com + "63fe855b7186de1898fa8ab7", // dev jsabol@me.com + "64deba9064131f13540ac23b", // main jae@onecommunityglobal.org + "610d5ae67002ae3fecdf7080", // main one.community@me.com + "63fe8e4fa79c5619d0b5a563", // main jsabol@me.com + ]; + const protectedIds = [ + "63feae337186de1898fa8f51", // dev jae@onecommunityglobal.org + "5baac381e16814009017678c", // dev one.community@me.com + "63fe855b7186de1898fa8ab7", // dev jsabol@me.com + "64deba9064131f13540ac23b", // main jae@onecommunityglobal.org + "610d5ae67002ae3fecdf7080", // main one.community@me.com + "63fe8e4fa79c5619d0b5a563", // main jsabol@me.com + "64c17eb8c737b05dd4ac4e28", // dev devadmin@hgn.net + ]; return !(protectedIds.includes(userId) && !allowedIds.includes(requestorId)); }; From 05f116b4aef8e9efc79d714239511a453dbc2f8f Mon Sep 17 00:00:00 2001 From: Jatin Agrawal Date: Tue, 5 Nov 2024 11:41:40 -0800 Subject: [PATCH 4/5] resolved errors --- src/controllers/badgeController.js | 4 ++-- src/controllers/teamController.js | 2 -- src/controllers/userProfileController.js | 6 ++---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/controllers/badgeController.js b/src/controllers/badgeController.js index bbc075e19..84d9bccaf 100644 --- a/src/controllers/badgeController.js +++ b/src/controllers/badgeController.js @@ -19,7 +19,7 @@ const badgeController = function (Badge) { // }; const getAllBadges = async function (req, res) { - console.log(req.body.requestor); // Retain logging from development branch for debugging + // console.log(req.body.requestor); // Retain logging from development branch for debugging // Check if the user has any of the following permissions if ( @@ -29,7 +29,7 @@ const badgeController = function (Badge) { !(await helper.hasPermission(req.body.requestor, 'updateBadges')) && !(await helper.hasPermission(req.body.requestor, 'deleteBadges')) ) { - console.log('in if statement'); // Retain logging from development branch for debugging + // console.log('in if statement'); // Retain logging from development branch for debugging res.status(403).send('You are not authorized to view all badge data.'); return; } diff --git a/src/controllers/teamController.js b/src/controllers/teamController.js index 54cd73e35..f8316095a 100644 --- a/src/controllers/teamController.js +++ b/src/controllers/teamController.js @@ -232,8 +232,6 @@ const teamcontroller = function (Team) { }); }; const updateTeamVisibility = async (req, res) => { - console.log('==============> 9 '); - const { visibility, teamId, userId } = req.body; try { diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 223e8d46e..d1a8e0cd1 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -483,7 +483,6 @@ const userProfileController = function (UserProfile, Project) { let originalRecord = {}; if (PROTECTED_EMAIL_ACCOUNT.includes(record.email)) { originalRecord = objectUtils.deepCopyMongooseObjectWithLodash(record); - // console.log('originalRecord', originalRecord); } // validate userprofile pic @@ -1615,7 +1614,6 @@ const userProfileController = function (UserProfile, Project) { return; } - // console.log("Updating User Visibility ", isVisible); cache.removeCache(`user-${userId}`); UserProfile.findByIdAndUpdate(userId, { $set: { isVisible } }, (err, _) => { if (err) { @@ -1636,7 +1634,8 @@ const userProfileController = function (UserProfile, Project) { message: 'User visibility updated successfully', isVisible, }); - + })} + const addInfringements = async function (req, res) { if (!(await hasPermission(req.body.requestor, 'addInfringements'))) { res.status(403).send('You are not authorized to add blue square'); @@ -1750,7 +1749,6 @@ const userProfileController = function (UserProfile, Project) { return; } const { userId, blueSquareId } = req.params; - // console.log(userId, blueSquareId); UserProfile.findById(userId, async (err, record) => { if (err || !record) { From 16b8164ae803431066410ee481db89906f3774e0 Mon Sep 17 00:00:00 2001 From: Nathan Hoffman Date: Fri, 15 Nov 2024 18:39:00 -0800 Subject: [PATCH 5/5] Update src/utilities/createInitialPermissions.js remove 'infringementAuthorizer' --- src/utilities/createInitialPermissions.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/utilities/createInitialPermissions.js b/src/utilities/createInitialPermissions.js index acbe7f7ed..a530d17c3 100644 --- a/src/utilities/createInitialPermissions.js +++ b/src/utilities/createInitialPermissions.js @@ -52,7 +52,6 @@ const permissionsRoles = [ 'changeUserRehireableStatus', 'updatePassword', 'deleteUserProfile', - 'infringementAuthorizer', 'toggleInvisibility', 'addInfringements', 'editInfringements',