From 26eaaa254bf78d2d0d3bbc634e6c7630ce82ee8d Mon Sep 17 00:00:00 2001 From: Xiao Tan Date: Thu, 15 Jun 2023 15:33:57 -0700 Subject: [PATCH 001/272] add toFixed(2) to round hour numbers to two digits --- src/controllers/timeEntryController.js | 2 +- src/helpers/userHelper.js | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/controllers/timeEntryController.js b/src/controllers/timeEntryController.js index 164206eac..f0c95a4a7 100644 --- a/src/controllers/timeEntryController.js +++ b/src/controllers/timeEntryController.js @@ -60,7 +60,7 @@ const notifyTaskOvertimeEmailBody = async (personId, taskName, estimatedHours, h

Oops, it looks like you have logged more hours than estimated for a task

Task Name : ${taskName}

Time Estimated : ${estimatedHours}

-

Hours Logged : ${hoursLogged}

+

Hours Logged : ${hoursLogged.toFixed(2)}

Please connect with your manager to explain what happened and submit a new hours estimation for completion.

Thank you,

One Community

`; diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index c39deb7da..5b783ec6e 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -34,7 +34,9 @@ const userHelper = function () { let mm = today.getMonth() + 1; let dd = today.getDate(); + // eslint-disable-next-line no-unused-expressions mm < 10 ? mm = `0${ mm}` : mm; + // eslint-disable-next-line no-unused-expressions dd < 10 ? dd = `0${ dd}` : dd; const formatedDate = `${yyyy }-${ mm }-${ dd}`; @@ -383,9 +385,9 @@ const userHelper = function () { if (timeNotMet || !hasWeeklySummary) { if (timeNotMet && !hasWeeklySummary) { - description = `System auto-assigned infringement for two reasons: not meeting weekly volunteer time commitment as well as not submitting a weekly summary. For the hours portion, you logged ${timeSpent} hours against committed effort of ${weeklycommittedHours} hours in the week starting ${pdtStartOfLastWeek.format('dddd YYYY-MM-DD')} and ending ${pdtEndOfLastWeek.format('dddd YYYY-MM-DD')}.`; + description = `System auto-assigned infringement for two reasons: not meeting weekly volunteer time commitment as well as not submitting a weekly summary. For the hours portion, you logged ${timeSpent.toFixed(2)} hours against committed effort of ${weeklycommittedHours} hours in the week starting ${pdtStartOfLastWeek.format('dddd YYYY-MM-DD')} and ending ${pdtEndOfLastWeek.format('dddd YYYY-MM-DD')}.`; } else if (timeNotMet) { - description = `System auto-assigned infringement for not meeting weekly volunteer time commitment. You logged ${timeSpent} hours against committed effort of ${weeklycommittedHours} hours in the week starting ${pdtStartOfLastWeek.format('dddd YYYY-MM-DD')} and ending ${pdtEndOfLastWeek.format('dddd YYYY-MM-DD')}.`; + description = `System auto-assigned infringement for not meeting weekly volunteer time commitment. You logged ${timeSpent.toFixed(2)} hours against committed effort of ${weeklycommittedHours} hours in the week starting ${pdtStartOfLastWeek.format('dddd YYYY-MM-DD')} and ending ${pdtEndOfLastWeek.format('dddd YYYY-MM-DD')}.`; } else { description = `System auto-assigned infringement for not submitting a weekly summary for the week starting ${pdtStartOfLastWeek.format( 'dddd YYYY-MM-DD', From 97b74203c986bfe44ed8ee4c7287ec1a3e0785fe Mon Sep 17 00:00:00 2001 From: leonzh2k Date: Thu, 6 Jul 2023 17:55:26 -0400 Subject: [PATCH 002/272] add new fields to send in UserProfileController Add jobTitle and location fields to the userProfile objects that are sent back to the client when requesting all userProfiles. These two bits of info are displayed on the interactive map. --- src/controllers/userProfileController.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 50a75258d..265346d73 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -64,10 +64,10 @@ const userProfileController = function (UserProfile) { res.status(200).send(getData); 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 location jobTitle', ) .sort({ lastName: 1, From 8000203e08ee6571c305c8df4096ca104dfb6a7f Mon Sep 17 00:00:00 2001 From: Chuehleo <122568562+Chuehleo@users.noreply.github.com> Date: Wed, 19 Jul 2023 22:35:34 -0700 Subject: [PATCH 003/272] Update teamController.js --- src/controllers/teamController.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/controllers/teamController.js b/src/controllers/teamController.js index 205ee4f0e..758b65831 100644 --- a/src/controllers/teamController.js +++ b/src/controllers/teamController.js @@ -18,14 +18,24 @@ const teamcontroller = function (Team) { }; const postTeam = function (req, res) { const team = new Team(); - team.teamName = req.body.teamName; - team.isACtive = req.body.isActive; + team.isActive = req.body.isActive; team.createdDatetime = Date.now(); team.modifiedDatetime = Date.now(); - team.save() - .then(results => res.send(results).status(200)) + // Check if a team with the same name already exists + Team.findOne({ teamName: team.teamName }) + .then((existingTeam) => { + if (existingTeam) { + // If a team with the same name exists, return an error + res.status(400).send({ error: 'A team with this name already exists' }); + } else { + // If no team with the same name exists, save the new team + team.save() + .then(results => res.send(results).status(200)) + .catch(error => res.send(error).status(404)); + } + }) .catch(error => res.send(error).status(404)); }; const deleteTeam = function (req, res) { From b6eca169302b4bc00846cb83afe8226525a22c89 Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Tue, 25 Jul 2023 19:07:39 +0800 Subject: [PATCH 004/272] send email --- src/controllers/taskController.js | 41 +++++++++++++++++++++++++++++++ src/routes/taskRouter.js | 3 +++ 2 files changed, 44 insertions(+) diff --git a/src/controllers/taskController.js b/src/controllers/taskController.js index c7d61c1bd..c6858b213 100644 --- a/src/controllers/taskController.js +++ b/src/controllers/taskController.js @@ -3,6 +3,8 @@ const wbs = require('../models/wbs'); const timeEntryHelper = require('../helpers/timeEntryHelper')(); const taskHelper = require('../helpers/taskHelper')(); const hasPermission = require('../utilities/permissions'); +const emailSender = require('../utilities/emailSender'); +const userProfile = require('../models/userProfile'); const taskController = function (Task) { const getTasks = (req, res) => { @@ -1098,6 +1100,44 @@ const taskController = function (Task) { }); }; + const getReviewReqEmailBody = function (name, taskName) { + const text = `New Task Review Request From ${name}: +

The following task is available to review:

+

${taskName}

+

Thank you,

+

One Community

`; + + return text; + }; + + const getRecipients = async function (myUserId) { + const user = await userProfile.findById(myUserId); + const membership = await userProfile.find({ teams: user.teams, role: ['Administrator', 'Manager', 'Mentor'] }); + const emails = membership.map(a => a.email); + return emails; + }; + + const sendReviewReq = async function (req, res) { + const { + myUserId, name, taskName, + } = req.body; + const emailBody = getReviewReqEmailBody(name, taskName); + const recipients = await getRecipients(myUserId); + + try { + emailSender( + recipients, + `Review Request from ${name}`, + emailBody, + 'highestgoodnetwork@gmail.com', + null, + ); + res.status(200).send('Success'); + } catch (err) { + res.status(500).send('Failed'); + } + }; + return { postTask, getTasks, @@ -1114,6 +1154,7 @@ const taskController = function (Task) { getTasksByUserList, getTasksForTeamsByUser, updateChildrenQty, + sendReviewReq, }; }; diff --git a/src/routes/taskRouter.js b/src/routes/taskRouter.js index 00db03325..e1d460d83 100644 --- a/src/routes/taskRouter.js +++ b/src/routes/taskRouter.js @@ -46,6 +46,9 @@ const routes = function (task, userProfile) { wbsRouter.route('/user/:userId/teams/tasks') .get(controller.getTasksForTeamsByUser); + wbsRouter.route('/tasks/reviewreq/:userId') + .post(controller.sendReviewReq); + return wbsRouter; }; From 24f8faa5d88692bd640d175f0d09659d6aecae6c Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Wed, 26 Jul 2023 15:15:33 +0800 Subject: [PATCH 005/272] solve the bug occurs when find users by team --- src/controllers/taskController.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/controllers/taskController.js b/src/controllers/taskController.js index c6858b213..26be8a539 100644 --- a/src/controllers/taskController.js +++ b/src/controllers/taskController.js @@ -1111,10 +1111,15 @@ const taskController = function (Task) { }; const getRecipients = async function (myUserId) { + const recipients = []; const user = await userProfile.findById(myUserId); - const membership = await userProfile.find({ teams: user.teams, role: ['Administrator', 'Manager', 'Mentor'] }); - const emails = membership.map(a => a.email); - return emails; + const membership = await userProfile.find({ role: ['Administrator', 'Manager', 'Mentor'] }); + membership.forEach((member) => { + if (member.teams.some(team => user.teams.includes(team))) { + recipients.push(member.email); + } + }); + return recipients; }; const sendReviewReq = async function (req, res) { From ab506ef557560e04a186b3a5a61af6317827cd4d Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Tue, 22 Aug 2023 19:58:52 +0800 Subject: [PATCH 006/272] create editable four-letter team code option --- src/controllers/userProfileController.js | 1 + src/helpers/reporthelper.js | 3 +++ src/models/userProfile.js | 1 + 3 files changed, 5 insertions(+) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index ef9124f01..1385a05b6 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -282,6 +282,7 @@ const userProfileController = function (UserProfile) { record.isRehireable = req.body.isRehireable || false; record.totalIntangibleHrs = req.body.totalIntangibleHrs; record.bioPosted = req.body.bioPosted || 'default'; + record.teamCode = req.body.teamCode; // find userData in cache const isUserInCache = cache.hasCache('allusers'); diff --git a/src/helpers/reporthelper.js b/src/helpers/reporthelper.js index 0ef25ff1f..191386553 100644 --- a/src/helpers/reporthelper.js +++ b/src/helpers/reporthelper.js @@ -76,6 +76,9 @@ const reporthelper = function () { weeklySummaryOption: 1, adminLinks: 1, bioPosted: 1, + teamCode: { + $ifNull: ['$teamCode', ''], + }, role: 1, weeklySummaries: { $filter: { diff --git a/src/models/userProfile.js b/src/models/userProfile.js index b62d5846a..3965a70ad 100644 --- a/src/models/userProfile.js +++ b/src/models/userProfile.js @@ -151,6 +151,7 @@ const userProfileSchema = new Schema({ isVisible: { type: Boolean, default: false }, weeklySummaryOption: { type: String }, bioPosted: { type: String, default: 'default' }, + teamCode: { type: String, default: '' }, infoCollections: [ { areaName:{type: String}, areaContent:{type:String}, From a56b80d8bd5ae4c2ca49a32ab730e26ea84e2938 Mon Sep 17 00:00:00 2001 From: Shivansh Sharma Date: Thu, 24 Aug 2023 18:20:23 -0700 Subject: [PATCH 007/272] Changes made in getInfringementEmailBody function --- src/helpers/userHelper.js | 45 +++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index f9428b3a1..e1898f334 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -85,17 +85,28 @@ const userHelper = function () { lastName, infringement, totalInfringements, + timeRemaining, ) { + let final_paragraph = ''; + + if (timeRemaining == undefined) { + final_paragraph = '

Life happens and we understand that. That’s why we allow 5 of them before taking action. This action usually includes removal from our team though, so please let your direct supervisor know what happened and do your best to avoid future blue squares if you are getting close to 5 and wish to avoid termination. Each blue square drops off after a year.

'; + } else { + final_paragraph = `

Life happens and we understand that. Please make up the missed hours this following week though to avoid getting another blue square. So you know what’s needed, the missing/incomplete hours (${timeRemaining} hours) have been added to your current week and this new weekly total can be seen at the top of your dashboard.

+

Reminder also that each blue square is removed from your profile 1 year after it was issued.

`; + } + const text = `Dear ${firstName} ${lastName},

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

Date Assigned: ${infringement.date}

Description: ${infringement.description}

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

-

Life happens and we understand that. That’s why we allow 5 of them before taking action. This action usually includes removal from our team though, so please let your direct supervisor know what happened and do your best to avoid future blue squares if you are getting close to 5 and wish to avoid termination. Each blue square drops off after a year.

+ .localeData() + .ordinal(totalInfringements)} blue square of 5.

+ ${final_paragraph}

Thank you,
One Community

`; + return text; }; @@ -299,7 +310,7 @@ const userHelper = function () { for (let i = 0; i < users.length; i += 1) { const user = users[i]; - + const person = await userProfile.findById(user._id); const personId = mongoose.Types.ObjectId(user._id); let hasWeeklySummary = false; @@ -327,6 +338,9 @@ const userHelper = function () { const timeNotMet = timeSpent < weeklycommittedHours; let description; + const timeRemaining = weeklycommittedHours - timeSpent; + + const updateResult = await userProfile.findByIdAndUpdate( personId, { @@ -409,15 +423,28 @@ const userHelper = function () { { new: true }, ); - emailSender( - status.email, - 'New Infringement Assigned', - getInfringementEmailBody( + let emailBody = ''; + if (person.role == 'Core Team' && timeRemaining > 0) { + emailBody = getInfringementEmailBody( + status.firstName, + status.lastName, + infringement, + status.infringements.length, + timeRemaining, + ); + } else { + emailBody = getInfringementEmailBody( status.firstName, status.lastName, infringement, status.infringements.length, - ), + ); + } + + emailSender( + status.email, + 'New Infringement Assigned', + emailBody, null, 'onecommunityglobal@gmail.com', ); From 95a5386820bc38e7374f2fcf68e1ee489abfa6a3 Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Tue, 29 Aug 2023 12:14:47 +0800 Subject: [PATCH 008/272] solve conflicts --- src/controllers/userProfileController.js | 1 + src/helpers/reporthelper.js | 3 +++ src/models/userProfile.js | 1 + 3 files changed, 5 insertions(+) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 9943e64d4..98c8a14ad 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -284,6 +284,7 @@ const userProfileController = function (UserProfile) { record.totalIntangibleHrs = req.body.totalIntangibleHrs; record.bioPosted = req.body.bioPosted || 'default'; record.isFirstTimelog = req.body.isFirstTimelog; + record.teamCode = req.body.teamCode; // find userData in cache const isUserInCache = cache.hasCache('allusers'); diff --git a/src/helpers/reporthelper.js b/src/helpers/reporthelper.js index 4b66c7d65..317605dd4 100644 --- a/src/helpers/reporthelper.js +++ b/src/helpers/reporthelper.js @@ -112,6 +112,9 @@ const reporthelper = function () { }, }, }, + teamCode: { + $ifNull: ['$teamCode', ''], + }, role: 1, weeklySummaries: { $filter: { diff --git a/src/models/userProfile.js b/src/models/userProfile.js index 79223fbe2..aa728f968 100644 --- a/src/models/userProfile.js +++ b/src/models/userProfile.js @@ -154,6 +154,7 @@ const userProfileSchema = new Schema({ weeklySummaryOption: { type: String }, bioPosted: { type: String, default: 'default' }, isFirstTimelog: { type: Boolean, default: true}, + teamCode: { type: String, default: '' }, infoCollections: [ { areaName:{type: String}, areaContent:{type:String}, From 3c9b355f093d1d7b6ce30951f0fb3a346866d475 Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Thu, 31 Aug 2023 15:28:57 +0800 Subject: [PATCH 009/272] add Edit Team Code permission to Owner --- src/utilities/createInitialPermissions.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utilities/createInitialPermissions.js b/src/utilities/createInitialPermissions.js index 9ac0f12b0..e42ca9a15 100644 --- a/src/utilities/createInitialPermissions.js +++ b/src/utilities/createInitialPermissions.js @@ -209,6 +209,7 @@ const permissionsRoles = [ 'getWeeklySummaries', 'getTimeZoneAPIKey', 'checkLeadTeamOfXplus', + 'editTeamCode', ], }, ]; From 346082b365e833b1439b4ce60777ee4417ca5f58 Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Tue, 29 Aug 2023 12:14:47 +0800 Subject: [PATCH 010/272] solve conflicts --- src/controllers/userProfileController.js | 1 + src/helpers/reporthelper.js | 3 +++ src/models/userProfile.js | 1 + 3 files changed, 5 insertions(+) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 9d0e7e63a..6b6cee9b1 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -284,6 +284,7 @@ const userProfileController = function (UserProfile) { record.totalIntangibleHrs = req.body.totalIntangibleHrs; record.bioPosted = req.body.bioPosted || 'default'; record.isFirstTimelog = req.body.isFirstTimelog; + record.teamCode = req.body.teamCode; // find userData in cache const isUserInCache = cache.hasCache('allusers'); diff --git a/src/helpers/reporthelper.js b/src/helpers/reporthelper.js index 4b66c7d65..317605dd4 100644 --- a/src/helpers/reporthelper.js +++ b/src/helpers/reporthelper.js @@ -112,6 +112,9 @@ const reporthelper = function () { }, }, }, + teamCode: { + $ifNull: ['$teamCode', ''], + }, role: 1, weeklySummaries: { $filter: { diff --git a/src/models/userProfile.js b/src/models/userProfile.js index 79223fbe2..aa728f968 100644 --- a/src/models/userProfile.js +++ b/src/models/userProfile.js @@ -154,6 +154,7 @@ const userProfileSchema = new Schema({ weeklySummaryOption: { type: String }, bioPosted: { type: String, default: 'default' }, isFirstTimelog: { type: Boolean, default: true}, + teamCode: { type: String, default: '' }, infoCollections: [ { areaName:{type: String}, areaContent:{type:String}, From 0b63eac581a39838425c7f698cc3758903c4236c Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Thu, 31 Aug 2023 15:28:57 +0800 Subject: [PATCH 011/272] add Edit Team Code permission to Owner --- src/utilities/createInitialPermissions.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utilities/createInitialPermissions.js b/src/utilities/createInitialPermissions.js index 9ac0f12b0..e42ca9a15 100644 --- a/src/utilities/createInitialPermissions.js +++ b/src/utilities/createInitialPermissions.js @@ -209,6 +209,7 @@ const permissionsRoles = [ 'getWeeklySummaries', 'getTimeZoneAPIKey', 'checkLeadTeamOfXplus', + 'editTeamCode', ], }, ]; From c7381ceeebd69ca13e395494a4d47ad96d11da16 Mon Sep 17 00:00:00 2001 From: xaanders Date: Sat, 2 Sep 2023 10:06:03 -0400 Subject: [PATCH 012/272] feat: adding new filters to aggrigating menthods --- src/helpers/dashboardhelper.js | 35 ++++++++++++++++++++++++++++---- src/helpers/taskHelper.js | 37 +++++++++++++++++++++++++++------- 2 files changed, 61 insertions(+), 11 deletions(-) diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index 125dfc5da..e0b4375ef 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -189,13 +189,40 @@ const dashboardhelper = function () { }, { $match: { + // leaderboard tasks hierarchy $or: [ { - role: { - $in: ['Core Team', 'Administrator', 'Owner'], - }, + role: 'Owner', + }, + { + $and: [ + { + role: 'Administrator', + }, + { 'persondata.0.role': { $nin: ['Owner'] } }, + ] + }, + { + $and: [ + { + role: 'Core Team', + }, + { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, + ], + }, + { + $and: [ + { + role: { $in: ['Manager', 'Mentor'] }, + }, + { + 'persondata.0.role': { + $nin: ['Manager', 'Mentor', 'Core Team', 'Administrator', 'Owner'], + }, + }, + ], }, - { 'persondata.0._id': userid }, + { 'persondata.0._id': userId }, { 'persondata.0.role': 'Volunteer' }, { 'persondata.0.isVisible': true }, ], diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index eb7e05af8..b1263c457 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -40,15 +40,38 @@ const taskHelper = function () { }, { $match: { + // dashboard tasks hierarchy $or: [ { - role: { - $in: [ - 'Core Team', - 'Administrator', - 'Owner', - ], - }, + role: 'Owner', + }, + { + $and: [ + { + role: 'Administrator', + }, + { 'persondata.0.role': { $nin: ['Owner'] } }, + ] + }, + { + $and: [ + { + role: 'Core Team', + }, + { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, + ], + }, + { + $and: [ + { + role: { $in: ['Manager', 'Mentor'] }, + }, + { + 'persondata.0.role': { + $nin: ['Manager', 'Mentor', 'Core Team', 'Administrator', 'Owner'], + }, + }, + ], }, { 'persondata.0._id': userId }, { 'persondata.0.role': 'Volunteer' }, From 3a6f542aae3786e12d93995e525b144f0f65b6f8 Mon Sep 17 00:00:00 2001 From: xaanders Date: Sat, 2 Sep 2023 13:53:28 -0400 Subject: [PATCH 013/272] fix: adding admin invisible for admins and core invisible for core roles --- src/helpers/dashboardhelper.js | 4 ++-- src/helpers/taskHelper.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index e0b4375ef..25b3d000e 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -199,7 +199,7 @@ const dashboardhelper = function () { { role: 'Administrator', }, - { 'persondata.0.role': { $nin: ['Owner'] } }, + { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, ] }, { @@ -207,7 +207,7 @@ const dashboardhelper = function () { { role: 'Core Team', }, - { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, + { 'persondata.0.role': { $nin: ['Owner', 'Administrator', 'Core Team'] } }, ], }, { diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index b1263c457..bc5556d0e 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -50,7 +50,7 @@ const taskHelper = function () { { role: 'Administrator', }, - { 'persondata.0.role': { $nin: ['Owner'] } }, + { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, ] }, { @@ -58,7 +58,7 @@ const taskHelper = function () { { role: 'Core Team', }, - { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, + { 'persondata.0.role': { $nin: ['Owner', 'Administrator', 'Core Team'] } }, ], }, { From 30f806868f5769532d3cd9b2e23e449fb6cf41ad Mon Sep 17 00:00:00 2001 From: xaanders Date: Sat, 2 Sep 2023 10:06:03 -0400 Subject: [PATCH 014/272] feat: adding new filters to aggrigating menthods --- src/helpers/dashboardhelper.js | 35 ++++++++++++++++++++++++++++---- src/helpers/taskHelper.js | 37 +++++++++++++++++++++++++++------- 2 files changed, 61 insertions(+), 11 deletions(-) diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index 125dfc5da..e0b4375ef 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -189,13 +189,40 @@ const dashboardhelper = function () { }, { $match: { + // leaderboard tasks hierarchy $or: [ { - role: { - $in: ['Core Team', 'Administrator', 'Owner'], - }, + role: 'Owner', + }, + { + $and: [ + { + role: 'Administrator', + }, + { 'persondata.0.role': { $nin: ['Owner'] } }, + ] + }, + { + $and: [ + { + role: 'Core Team', + }, + { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, + ], + }, + { + $and: [ + { + role: { $in: ['Manager', 'Mentor'] }, + }, + { + 'persondata.0.role': { + $nin: ['Manager', 'Mentor', 'Core Team', 'Administrator', 'Owner'], + }, + }, + ], }, - { 'persondata.0._id': userid }, + { 'persondata.0._id': userId }, { 'persondata.0.role': 'Volunteer' }, { 'persondata.0.isVisible': true }, ], diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index eb7e05af8..b1263c457 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -40,15 +40,38 @@ const taskHelper = function () { }, { $match: { + // dashboard tasks hierarchy $or: [ { - role: { - $in: [ - 'Core Team', - 'Administrator', - 'Owner', - ], - }, + role: 'Owner', + }, + { + $and: [ + { + role: 'Administrator', + }, + { 'persondata.0.role': { $nin: ['Owner'] } }, + ] + }, + { + $and: [ + { + role: 'Core Team', + }, + { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, + ], + }, + { + $and: [ + { + role: { $in: ['Manager', 'Mentor'] }, + }, + { + 'persondata.0.role': { + $nin: ['Manager', 'Mentor', 'Core Team', 'Administrator', 'Owner'], + }, + }, + ], }, { 'persondata.0._id': userId }, { 'persondata.0.role': 'Volunteer' }, From 06807570afa6c9dfce71d94cab474f7948d1606d Mon Sep 17 00:00:00 2001 From: xaanders Date: Sat, 2 Sep 2023 13:53:28 -0400 Subject: [PATCH 015/272] fix: adding admin invisible for admins and core invisible for core roles --- src/helpers/dashboardhelper.js | 4 ++-- src/helpers/taskHelper.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index e0b4375ef..25b3d000e 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -199,7 +199,7 @@ const dashboardhelper = function () { { role: 'Administrator', }, - { 'persondata.0.role': { $nin: ['Owner'] } }, + { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, ] }, { @@ -207,7 +207,7 @@ const dashboardhelper = function () { { role: 'Core Team', }, - { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, + { 'persondata.0.role': { $nin: ['Owner', 'Administrator', 'Core Team'] } }, ], }, { diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index b1263c457..bc5556d0e 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -50,7 +50,7 @@ const taskHelper = function () { { role: 'Administrator', }, - { 'persondata.0.role': { $nin: ['Owner'] } }, + { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, ] }, { @@ -58,7 +58,7 @@ const taskHelper = function () { { role: 'Core Team', }, - { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, + { 'persondata.0.role': { $nin: ['Owner', 'Administrator', 'Core Team'] } }, ], }, { From 6ab9bf08b61997c1acd837805c881c9a50a826b5 Mon Sep 17 00:00:00 2001 From: xaanders Date: Sat, 2 Sep 2023 14:19:22 -0400 Subject: [PATCH 016/272] fix: comments to the changes --- src/helpers/dashboardhelper.js | 2 +- src/helpers/taskHelper.js | 56 +++++++++++++++++----------------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index 25b3d000e..2b61b8131 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -189,7 +189,7 @@ const dashboardhelper = function () { }, { $match: { - // leaderboard tasks hierarchy + // leaderboard user roles hierarchy $or: [ { role: 'Owner', diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index bc5556d0e..7b9303b0b 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -40,7 +40,7 @@ const taskHelper = function () { }, { $match: { - // dashboard tasks hierarchy + // dashboard tasks user roles hierarchy $or: [ { role: 'Owner', @@ -86,10 +86,10 @@ const taskHelper = function () { weeklycommittedHours: { $sum: [ { - $arrayElemAt: ['$persondata.weeklycommittedHours', 0], + $arrayElemAt: ['$persondata.weeklycommittedHours', 0], }, { - $ifNull: [{ $arrayElemAt: ['$persondata.missedHours', 0] }, 0], + $ifNull: [{ $arrayElemAt: ['$persondata.missedHours', 0] }, 0], }, ], }, @@ -142,7 +142,7 @@ const taskHelper = function () { totalSeconds: { $cond: [ { - $gte: ['$timeEntryData.totalSeconds', 0], + $gte: ['$timeEntryData.totalSeconds', 0], }, '$timeEntryData.totalSeconds', 0, @@ -151,7 +151,7 @@ const taskHelper = function () { isTangible: { $cond: [ { - $gte: ['$timeEntryData.totalSeconds', 0], + $gte: ['$timeEntryData.totalSeconds', 0], }, '$timeEntryData.isTangible', false, @@ -165,7 +165,7 @@ const taskHelper = function () { tangibletime: { $cond: [ { - $eq: ['$isTangible', true], + $eq: ['$isTangible', true], }, '$totalSeconds', 0, @@ -324,9 +324,9 @@ const taskHelper = function () { role: '$role', name: { $concat: [ - '$firstName', - ' ', - '$lastName', + '$firstName', + ' ', + '$lastName', ], }, weeklycommittedHours: { @@ -359,12 +359,12 @@ const taskHelper = function () { as: 'timeentry', cond: { $and: [ - { - $gte: ['$$timeentry.dateOfWork', pdtstart], - }, - { - $lte: ['$$timeentry.dateOfWork', pdtend], - }, + { + $gte: ['$$timeentry.dateOfWork', pdtstart], + }, + { + $lte: ['$$timeentry.dateOfWork', pdtend], + }, ], }, }, @@ -459,7 +459,7 @@ const taskHelper = function () { $project: { tasks: { resources: { - profilePic: 0, + profilePic: 0, }, }, }, @@ -482,9 +482,9 @@ const taskHelper = function () { $addFields: { 'tasks.projectId': { $cond: [ - { $ne: ['$projectId', []] }, - { $arrayElemAt: ['$projectId', 0] }, - '$tasks.projectId', + { $ne: ['$projectId', []] }, + { $arrayElemAt: ['$projectId', 0] }, + '$tasks.projectId', ], }, }, @@ -494,12 +494,12 @@ const taskHelper = function () { projectId: 0, tasks: { projectId: { - _id: 0, - isActive: 0, - modifiedDatetime: 0, - wbsName: 0, - createdDatetime: 0, - __v: 0, + _id: 0, + isActive: 0, + modifiedDatetime: 0, + wbsName: 0, + createdDatetime: 0, + __v: 0, }, }, }, @@ -530,9 +530,9 @@ const taskHelper = function () { $addFields: { 'data.tasks': { $filter: { - input: '$tasks', - as: 'task', - cond: { $ne: ['$$task', {}] }, + input: '$tasks', + as: 'task', + cond: { $ne: ['$$task', {}] }, }, }, }, From c3731c0ad66cc5236a30fb7cd3f6aad55f1cd6ad Mon Sep 17 00:00:00 2001 From: xaanders Date: Sat, 2 Sep 2023 16:18:39 -0400 Subject: [PATCH 017/272] fix: giving Core Team role ability to see everyone --- src/helpers/dashboardhelper.js | 10 +--------- src/helpers/taskHelper.js | 10 +--------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index 2b61b8131..34d464583 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -192,7 +192,7 @@ const dashboardhelper = function () { // leaderboard user roles hierarchy $or: [ { - role: 'Owner', + role: { $in: ['Owner', 'Core Team'] }, }, { $and: [ @@ -202,14 +202,6 @@ const dashboardhelper = function () { { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, ] }, - { - $and: [ - { - role: 'Core Team', - }, - { 'persondata.0.role': { $nin: ['Owner', 'Administrator', 'Core Team'] } }, - ], - }, { $and: [ { diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index 7b9303b0b..a94aaee94 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -43,7 +43,7 @@ const taskHelper = function () { // dashboard tasks user roles hierarchy $or: [ { - role: 'Owner', + role: { $in: ['Owner', 'Core Team'] }, }, { $and: [ @@ -53,14 +53,6 @@ const taskHelper = function () { { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, ] }, - { - $and: [ - { - role: 'Core Team', - }, - { 'persondata.0.role': { $nin: ['Owner', 'Administrator', 'Core Team'] } }, - ], - }, { $and: [ { From e40e91cf40e9a7b944f32db310a8c0ee9f676e97 Mon Sep 17 00:00:00 2001 From: Nathan Hoffman Date: Sun, 3 Sep 2023 13:51:44 -0700 Subject: [PATCH 018/272] Revert "Revert "new perms and no removing PMP perms on startup"" This reverts commit 97f97b6639348dabb6993c8226cf4bfee669b8a1. --- src/utilities/createInitialPermissions.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/utilities/createInitialPermissions.js b/src/utilities/createInitialPermissions.js index 9ac0f12b0..ffc655b60 100644 --- a/src/utilities/createInitialPermissions.js +++ b/src/utilities/createInitialPermissions.js @@ -72,7 +72,10 @@ const permissionsRoles = [ }, { roleName: 'Volunteer', - permissions: ['getReporteesLimitRoles'], + permissions: [ + 'getReporteesLimitRoles', + 'suggestTask', + ], }, { roleName: 'Core Team', @@ -105,7 +108,8 @@ const permissionsRoles = [ 'putUserProfile', 'infringementAuthorizer', 'getReporteesLimitRoles', - 'suggestTask', + 'updateTask', + 'putTeam', 'getAllInvInProjectWBS', 'postInvInProjectWBS', 'getAllInvInProject', @@ -239,12 +243,16 @@ const createInitialPermissions = async () => { role.permissions = permissions; role.save(); - // If role exists in db and is not updated, update it - } else if (!roleDataBase.permissions.every(perm => permissions.includes(perm)) || !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(Role.findById(roleId, (_, record) => { - record.permissions = permissions; + permissions.forEach((perm) => { + if (!record.permissions.includes(perm)) { + record.permissions.push(perm); + } + }); record.save(); })); } From 84b3baf05c234f43ba2099f080d855e729490854 Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Wed, 6 Sep 2023 09:15:41 +0800 Subject: [PATCH 019/272] add teamCode Property to team object --- src/controllers/teamController.js | 1 + src/models/team.js | 1 + 2 files changed, 2 insertions(+) diff --git a/src/controllers/teamController.js b/src/controllers/teamController.js index 1072f1fb4..0ff777870 100644 --- a/src/controllers/teamController.js +++ b/src/controllers/teamController.js @@ -71,6 +71,7 @@ const teamcontroller = function (Team) { } record.teamName = req.body.teamName; record.isActive = req.body.isActive; + record.teamCode = req.body.teamCode; record.createdDatetime = Date.now(); record.modifiedDatetime = Date.now(); diff --git a/src/models/team.js b/src/models/team.js index 8d46db283..a57d7bb27 100644 --- a/src/models/team.js +++ b/src/models/team.js @@ -13,6 +13,7 @@ const team = new Schema({ addDateTime: { type: Date, default: Date.now(), ref: 'userProfile' }, }, ], + teamCode: { type: 'String', default: '' }, }); module.exports = mongoose.model('team', team, 'teams'); From 36b17749febb5e77f4dda02d4c35b5802c55354e Mon Sep 17 00:00:00 2001 From: Lin1404 <78375725+Lin1404@users.noreply.github.com> Date: Fri, 8 Sep 2023 10:21:26 -0400 Subject: [PATCH 020/272] get users information, able to update permission --- src/controllers/userProfileController.js | 86 ++++++++++++++++-------- 1 file changed, 57 insertions(+), 29 deletions(-) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 86c62b4b8..2106b807d 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -52,8 +52,11 @@ async function ValidatePassword(req, res) { const userProfileController = function (UserProfile) { const getUserProfiles = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'getUserProfiles')) { - res.status(403).send('You are not authorized to view all users'); + if ( + !(await hasPermission(req.body.requestor.role, "getUserProfiles")) && + !req.body.requestor.permissions?.frontPermissions.includes("manageUser") + ) { + res.status(403).send("You are not authorized to view all users"); return; } @@ -224,26 +227,29 @@ 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.role, 'putUserProfile') - || req.body.requestor.requestorId === userid - ) + canRequestorUpdateUser(req.body.requestor.requestorId, userid) && + ((await hasPermission(req.body.requestor.role, "putUserProfile")) || + req.body.requestor.requestorId === userid || + req.body.requestor.permissions?.frontPermissions.includes("manageUser")) ); 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.role, 'addDeleteEditOwners')) { - res.status(403).send('You are not authorized to update this user'); + if ( + req.body.role === "Owner" && + !(await hasPermission(req.body.requestor.role, "addDeleteEditOwners")) + ) { + 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 @@ -257,10 +263,13 @@ const userProfileController = function (UserProfile) { } } - const originalinfringements = record.infringements ? record.infringements : []; + const originalinfringements = record.infringements + ? record.infringements + : []; record.jobTitle = req.body.jobTitle; record.emailPubliclyAccessible = req.body.emailPubliclyAccessible; - record.phoneNumberPubliclyAccessible = req.body.phoneNumberPubliclyAccessible; + record.phoneNumberPubliclyAccessible = + req.body.phoneNumberPubliclyAccessible; record.profilePic = req.body.profilePic; record.firstName = req.body.firstName; @@ -282,20 +291,26 @@ const userProfileController = function (UserProfile) { record.isVisible = req.body.isVisible || false; record.isRehireable = req.body.isRehireable || false; record.totalIntangibleHrs = req.body.totalIntangibleHrs; - record.bioPosted = req.body.bioPosted || 'default'; + record.bioPosted = req.body.bioPosted || "default"; record.isFirstTimelog = req.body.isFirstTimelog; // 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')); - userIdx = allUserData.findIndex(users => users._id === userid); + allUserData = JSON.parse(cache.getCache("allusers")); + userIdx = allUserData.findIndex((users) => users._id === userid); userData = allUserData[userIdx]; } - if (await hasPermission(req.body.requestor.role, 'putUserProfileImportantInfo')) { + if ( + (await hasPermission( + req.body.requestor.role, + "putUserProfileImportantInfo" + )) || + req.body.requestor.permissions?.frontPermissions.includes("manageUser") + ) { record.role = req.body.role; record.isRehireable = req.body.isRehireable; record.isActive = req.body.isActive; @@ -306,10 +321,12 @@ const userProfileController = function (UserProfile) { // 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')) { + if (lastChangeDate.isSame(now, "day")) { record.weeklycommittedHoursHistory.pop(); } @@ -322,7 +339,8 @@ const userProfileController = function (UserProfile) { record.weeklycommittedHoursHistory.push(newEntry); } - record.missedHours = req.body.role === 'Core Team' ? req.body?.missedHours ?? 0 : 0; + record.missedHours = + req.body.role === "Core Team" ? req.body?.missedHours ?? 0 : 0; record.adminLinks = req.body.adminLinks; record.teams = Array.from(new Set(req.body.teams)); record.projects = Array.from(new Set(req.body.projects)); @@ -354,12 +372,20 @@ 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; } - record.bioPosted = req.body.bioPosted || 'default'; - - if (await hasPermission(req.body.requestor.role, 'putUserProfilePermissions')) { + record.bioPosted = req.body.bioPosted || "default"; + if ( + (await hasPermission( + req.body.requestor.role, + "putUserProfilePermissions" + )) || + req.body.requestor.permissions?.frontPermissions.includes( + "manageUser" + ) + ) { record.permissions = req.body.permissions; } @@ -369,7 +395,7 @@ const userProfileController = function (UserProfile) { userData.endDate = record.endDate.toISOString(); } } else { - record.set('endDate', undefined, { strict: false }); + record.set("endDate", undefined, { strict: false }); } if (isUserInCache) { userData.role = record.role; @@ -379,7 +405,9 @@ const userProfileController = function (UserProfile) { userData.createdDate = record.createdDate.toISOString(); } } - if (await hasPermission(req.body.requestor.role, 'infringementAuthorizer')) { + if ( + await hasPermission(req.body.requestor.role, "infringementAuthorizer") + ) { record.infringements = req.body.infringements; } @@ -391,7 +419,7 @@ const userProfileController = function (UserProfile) { results.infringements, results.firstName, results.lastName, - results.email, + results.email ); res.status(200).json({ _id: record._id, @@ -400,10 +428,10 @@ 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)); + .catch((error) => res.status(400).send(error)); }); }; From 54fbe3674e25437c1dca552808f81d69c0e18af4 Mon Sep 17 00:00:00 2001 From: Lin1404 <78375725+Lin1404@users.noreply.github.com> Date: Fri, 8 Sep 2023 21:06:01 -0400 Subject: [PATCH 021/272] fix permission name manageUser -> putUserProfilePermissions --- src/controllers/userProfileController.js | 80 ++++++++++++++---------- 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 2106b807d..8f0086d65 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -54,39 +54,41 @@ const userProfileController = function (UserProfile) { const getUserProfiles = async function (req, res) { if ( !(await hasPermission(req.body.requestor.role, "getUserProfiles")) && - !req.body.requestor.permissions?.frontPermissions.includes("manageUser") + !req.body.requestor.permissions?.frontPermissions.includes( + "putUserProfilePermissions" + ) ) { res.status(403).send("You are not authorized to view all users"); return; } - 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; } 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) { - 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)); + .catch((error) => res.status(404).send(error)); }; const getProjectMembers = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'getProjectMembers')) { - res.status(403).send('You are not authorized to view all users'); + if (!(await hasPermission(req.body.requestor.role, "getProjectMembers"))) { + res.status(403).send("You are not authorized to view all users"); return; } UserProfile.find( @@ -95,39 +97,43 @@ 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); - }, + } ); }; const postUserProfile = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'postUserProfile')) { - res.status(403).send('You are not authorized to create new users'); + if (!(await hasPermission(req.body.requestor.role, "postUserProfile"))) { + res.status(403).send("You are not authorized to create new users"); return; } - if (req.body.role === 'Owner' && !await hasPermission(req.body.requestor.role, 'addDeleteEditOwners')) { - res.status(403).send('You are not authorized to create new owners'); + if ( + req.body.role === "Owner" && + !(await hasPermission(req.body.requestor.role, "addDeleteEditOwners")) + ) { + 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', + error: + "That email address is already in use. Please choose another email address.", + type: "email", }); return; } @@ -145,8 +151,9 @@ const userProfileController = function (UserProfile) { if (userByPhoneNumber) { res.status(400).send({ - error: 'That phone number is already in use. Please choose another number.', - type: 'phoneNumber', + error: + "That phone number is already in use. Please choose another number.", + type: "phoneNumber", }); return; } @@ -159,8 +166,9 @@ 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', + error: + "That name is already in use. Please confirm if you want to use this name.", + type: "name", }); return; } @@ -187,15 +195,15 @@ 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.save() @@ -217,11 +225,11 @@ 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)); }) - .catch(error => res.status(501).send(error)); + .catch((error) => res.status(501).send(error)); }; const putUserProfile = async function (req, res) { @@ -230,7 +238,9 @@ const userProfileController = function (UserProfile) { canRequestorUpdateUser(req.body.requestor.requestorId, userid) && ((await hasPermission(req.body.requestor.role, "putUserProfile")) || req.body.requestor.requestorId === userid || - req.body.requestor.permissions?.frontPermissions.includes("manageUser")) + req.body.requestor.permissions?.frontPermissions.includes( + "putUserProfilePermissions" + )) ); if (!isRequestorAuthorized) { @@ -309,7 +319,9 @@ const userProfileController = function (UserProfile) { req.body.requestor.role, "putUserProfileImportantInfo" )) || - req.body.requestor.permissions?.frontPermissions.includes("manageUser") + req.body.requestor.permissions?.frontPermissions.includes( + "putUserProfilePermissions" + ) ) { record.role = req.body.role; record.isRehireable = req.body.isRehireable; @@ -383,7 +395,7 @@ const userProfileController = function (UserProfile) { "putUserProfilePermissions" )) || req.body.requestor.permissions?.frontPermissions.includes( - "manageUser" + "putUserProfilePermissions" ) ) { record.permissions = req.body.permissions; From 85c82de7f4efb81ca85a70bc5ceda59588470d71 Mon Sep 17 00:00:00 2001 From: Carl Bebli Date: Thu, 14 Sep 2023 18:25:18 +0000 Subject: [PATCH 022/272] added error handling to easily deduce errors in production --- package-lock.json | 2743 +++++++++++++++++++----- package.json | 7 +- src/controllers/dashBoardController.js | 248 ++- 3 files changed, 2379 insertions(+), 619 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5c6bd6db5..cdfa61193 100644 --- a/package-lock.json +++ b/package-lock.json @@ -115,12 +115,28 @@ } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", - "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", "requires": { - "@babel/helper-explode-assignable-expression": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.15" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", + "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" + }, + "@babel/types": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", + "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.15", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-compilation-targets": { @@ -142,47 +158,229 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz", - "integrity": "sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7" + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz", + "integrity": "sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "requires": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" + }, + "@babel/helper-function-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "requires": { + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", + "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" + }, + "@babel/highlight": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", + "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", + "requires": { + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.22.16", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", + "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==" + }, + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + }, + "@babel/types": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", + "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.15", + "to-fast-properties": "^2.0.0" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", - "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "regexpu-core": "^5.0.1" + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "dependencies": { + "@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", + "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" + }, + "@babel/types": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", + "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.15", + "to-fast-properties": "^2.0.0" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } } }, "@babel/helper-define-polyfill-provider": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", - "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz", + "integrity": "sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw==", "requires": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" + "resolve": "^1.14.2" }, "dependencies": { + "@babel/compat-data": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", + "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==" + }, + "@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "requires": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + }, + "@babel/helper-validator-option": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==" + }, + "browserslist": { + "version": "4.21.10", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", + "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", + "requires": { + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.11" + } + }, + "caniuse-lite": { + "version": "1.0.30001532", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001532.tgz", + "integrity": "sha512-FbDFnNat3nMnrROzqrsg314zhqN5LGQ1kyyMk2opcrwGbVGpHRhgCWtAgD5YJUqNAiQ+dklreil/c3Qf1dfCTw==" + }, + "electron-to-chromium": { + "version": "1.4.513", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.513.tgz", + "integrity": "sha512-cOB0xcInjm+E5qIssHeXJ29BaUyWpMyFKT5RB3bsLENDheCja0wMkHJyiPl0NBE/VzDI7JDuNEQWhe6RitEUcw==" + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" + }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" } } }, @@ -194,14 +392,6 @@ "@babel/types": "^7.16.7" } }, - "@babel/helper-explode-assignable-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", - "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", - "requires": { - "@babel/types": "^7.16.7" - } - }, "@babel/helper-function-name": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", @@ -229,11 +419,28 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", - "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.15.tgz", + "integrity": "sha512-qLNsZbgrNh0fDQBCPocSL8guki1hcPvltGDv/NxvUoABwFq7GkKSu1nRXeJkVZc+wJvne2E0RKQz+2SQrz6eAA==", "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.15" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", + "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" + }, + "@babel/types": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", + "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.15", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-module-imports": { @@ -260,11 +467,28 @@ } }, "@babel/helper-optimise-call-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", - "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", + "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" + }, + "@babel/types": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", + "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.15", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-plugin-utils": { @@ -283,15 +507,20 @@ } }, "@babel/helper-replace-supers": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", - "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz", + "integrity": "sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg==", "requires": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5" + }, + "dependencies": { + "@babel/helper-environment-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" + } } }, "@babel/helper-simple-access": { @@ -303,11 +532,28 @@ } }, "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", - "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", "requires": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.22.5" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", + "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" + }, + "@babel/types": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", + "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.15", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-split-export-declaration": { @@ -318,6 +564,11 @@ "@babel/types": "^7.16.7" } }, + "@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==" + }, "@babel/helper-validator-identifier": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", @@ -378,165 +629,41 @@ "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==" }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", - "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.15.tgz", + "integrity": "sha512-FB9iYlz7rURmRJyXRKEnalYPPdn87H5no108cyuQQyMwlpJ2SJtpIUBI27kdTin956pz+LPypkPVPUTlxOmrsg==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", - "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.7" - } - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", - "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8", - "@babel/plugin-syntax-async-generators": "^7.8.4" - } - }, - "@babel/plugin-proposal-class-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", - "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-proposal-class-static-block": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.6.tgz", - "integrity": "sha512-X/tididvL2zbs7jZCeeRJ8167U/+Ac135AM6jCAx6gYXDUviZV5Ku9UDvWS2NCuWlFjIRXklYhwo6HhAC7ETnA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.15.tgz", + "integrity": "sha512-Hyph9LseGvAeeXzikV88bczhsrLrIZqDPxO+sSmAunMPaGrBGhfMWzCPYTtiW9t+HzSE2wtV8e5cc5P6r1xMDQ==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.17.6", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - } - }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", - "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - } - }, - "@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", - "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - } - }, - "@babel/plugin-proposal-json-strings": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", - "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" - } - }, - "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", - "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - } - }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", - "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - } - }, - "@babel/plugin-proposal-numeric-separator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", - "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz", - "integrity": "sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw==", - "requires": { - "@babel/compat-data": "^7.17.0", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.7" - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", - "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - } - }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", - "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - } - }, - "@babel/plugin-proposal-private-methods": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", - "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.10", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.22.15" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, "@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", - "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - } - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", - "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==" }, "@babel/plugin-syntax-async-generators": { "version": "7.8.4", @@ -578,6 +705,44 @@ "@babel/helper-plugin-utils": "^7.8.3" } }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz", + "integrity": "sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } + } + }, + "@babel/plugin-syntax-import-attributes": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.5.tgz", + "integrity": "sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, "@babel/plugin-syntax-json-strings": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", @@ -650,339 +815,1585 @@ "@babel/helper-plugin-utils": "^7.14.5" } }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", - "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", - "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", - "requires": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8" - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", - "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", + "@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, - "@babel/plugin-transform-block-scoping": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", - "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", + "@babel/plugin-transform-arrow-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz", + "integrity": "sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, - "@babel/plugin-transform-classes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", - "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", + "@babel/plugin-transform-async-generator-functions": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.15.tgz", + "integrity": "sha512-jBm1Es25Y+tVoTi5rfd5t1KLmL8ogLKpXszboWOTTtGFGz2RKnQe2yn7HbZ+kb/B8N0FVSGQo874NSlOU1T4+w==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "globals": "^11.1.0" - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", - "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "requires": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" + }, + "@babel/helper-function-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "requires": { + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.17.tgz", + "integrity": "sha512-bxH77R5gjH3Nkde6/LuncQoLaP16THYPscurp1S8z7S9ZgezCyV3G8Hc+TZiCmY8pz4fp8CvKSgtJMW0FkLAxA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-wrap-function": "^7.22.17" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", + "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" + }, + "@babel/helper-wrap-function": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.17.tgz", + "integrity": "sha512-nAhoheCMlrqU41tAojw9GpVEKDlTS8r3lzFmF0lP52LwblCPbuFSO7nGIZoIcoU5NIm1ABrna0cJExE4Ay6l2Q==", + "requires": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.17" + } + }, + "@babel/highlight": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", + "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", + "requires": { + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.22.16", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", + "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==" + }, + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + }, + "@babel/types": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", + "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.15", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", + "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", + "requires": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.8" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz", + "integrity": "sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.15.tgz", + "integrity": "sha512-G1czpdJBZCtngoK1sJgloLiOHUnkb/bLZwqVZD8kXmq0ZnVfTTWUcs9OWtp0mBtYJ+4LQY1fllqBkOIPhXmFmw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } + } + }, + "@babel/plugin-transform-class-properties": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.22.5.tgz", + "integrity": "sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } + } + }, + "@babel/plugin-transform-class-static-block": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.11.tgz", + "integrity": "sha512-GMM8gGmqI7guS/llMFk1bJDkKfn3v3C4KHK9Yg1ey5qcHcOlKb0QvcMrgzvxo+T03/4szNh5lghY+fEC98Kq9g==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.22.11", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } + } + }, + "@babel/plugin-transform-classes": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.15.tgz", + "integrity": "sha512-VbbC3PGjBdE0wAWDdHM9G8Gm977pnYI0XpqMd6LrKISj8/DJXEsWqgRuTYaNE9Bv0JGhTZUzHDlMk18IpOuoqw==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.9", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "requires": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + } + }, + "@babel/compat-data": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", + "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==" + }, + "@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "requires": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" + }, + "@babel/helper-function-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "requires": { + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", + "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" + }, + "@babel/helper-validator-option": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==" + }, + "@babel/highlight": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", + "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", + "requires": { + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.22.16", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", + "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==" + }, + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + }, + "@babel/types": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", + "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.15", + "to-fast-properties": "^2.0.0" + } + }, + "browserslist": { + "version": "4.21.10", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", + "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", + "requires": { + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.11" + } + }, + "caniuse-lite": { + "version": "1.0.30001532", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001532.tgz", + "integrity": "sha512-FbDFnNat3nMnrROzqrsg314zhqN5LGQ1kyyMk2opcrwGbVGpHRhgCWtAgD5YJUqNAiQ+dklreil/c3Qf1dfCTw==" + }, + "electron-to-chromium": { + "version": "1.4.513", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.513.tgz", + "integrity": "sha512-cOB0xcInjm+E5qIssHeXJ29BaUyWpMyFKT5RB3bsLENDheCja0wMkHJyiPl0NBE/VzDI7JDuNEQWhe6RitEUcw==" + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz", + "integrity": "sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.5" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "requires": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + }, + "@babel/helper-validator-identifier": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", + "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" + }, + "@babel/highlight": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", + "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", + "requires": { + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.22.16", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", + "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==" + }, + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + }, + "@babel/types": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", + "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.15", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/plugin-transform-destructuring": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.3.tgz", - "integrity": "sha512-dDFzegDYKlPqa72xIlbmSkly5MluLoaC1JswABGktyt6NTXSBcUuse/kWE/wvKFWJHPETpi158qJZFS3JmykJg==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.15.tgz", + "integrity": "sha512-HzG8sFl1ZVGTme74Nw+X01XsUTqERVQ6/RLHo3XjGRzm7XD6QTtfS3NJotVgCGy8BzkDqRjRBD8dAyJn5TuvSQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", - "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz", + "integrity": "sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", - "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz", + "integrity": "sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } + } + }, + "@babel/plugin-transform-dynamic-import": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.11.tgz", + "integrity": "sha512-g/21plo58sfteWjaO0ZNVb+uEOkJNjAaHhbejrnBmu011l/eNDScmkbjCC3l4FKb10ViaGU4aOkFznSu2zRHgA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", - "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz", + "integrity": "sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g==", + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } + } + }, + "@babel/plugin-transform-export-namespace-from": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.11.tgz", + "integrity": "sha512-xa7aad7q7OiT8oNZ1mU7NrISjlSkVdMbNxn9IuLZyL9AJEhs1Apba3I+u5riX1dIkdptP5EKDG5XDPByWxtehw==", "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, "@babel/plugin-transform-for-of": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", - "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.15.tgz", + "integrity": "sha512-me6VGeHsx30+xh9fbDLLPi0J1HzmeIIyenoOQHuw2D4m2SAU3NrspX5XxJLBpqn5yrLzrlw2Iy3RA//Bx27iOA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, "@babel/plugin-transform-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", - "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz", + "integrity": "sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg==", "requires": { - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "requires": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + } + }, + "@babel/compat-data": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", + "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==" + }, + "@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "requires": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + } + }, + "@babel/helper-function-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "requires": { + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + }, + "@babel/helper-validator-identifier": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", + "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" + }, + "@babel/helper-validator-option": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==" + }, + "@babel/highlight": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", + "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", + "requires": { + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.22.16", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", + "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==" + }, + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + }, + "@babel/types": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", + "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.15", + "to-fast-properties": "^2.0.0" + } + }, + "browserslist": { + "version": "4.21.10", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", + "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", + "requires": { + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.11" + } + }, + "caniuse-lite": { + "version": "1.0.30001532", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001532.tgz", + "integrity": "sha512-FbDFnNat3nMnrROzqrsg314zhqN5LGQ1kyyMk2opcrwGbVGpHRhgCWtAgD5YJUqNAiQ+dklreil/c3Qf1dfCTw==" + }, + "electron-to-chromium": { + "version": "1.4.513", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.513.tgz", + "integrity": "sha512-cOB0xcInjm+E5qIssHeXJ29BaUyWpMyFKT5RB3bsLENDheCja0wMkHJyiPl0NBE/VzDI7JDuNEQWhe6RitEUcw==" + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + } + }, + "@babel/plugin-transform-json-strings": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.11.tgz", + "integrity": "sha512-CxT5tCqpA9/jXFlme9xIBCc5RPtdDq3JpkkhgHQqtDdiTnTI0jtZ0QzXhr5DILeYifDPp2wvY2ad+7+hLMW5Pw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, "@babel/plugin-transform-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", - "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz", + "integrity": "sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } + } + }, + "@babel/plugin-transform-logical-assignment-operators": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.11.tgz", + "integrity": "sha512-qQwRTP4+6xFCDV5k7gZBF3C31K34ut0tbEcTKxlX/0KXxm9GLcO14p570aWxFvVzx6QAfPgq7gaeIHXJC8LswQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, "@babel/plugin-transform-member-expression-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", - "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz", + "integrity": "sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz", + "integrity": "sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ==", + "requires": { + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-environment-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" + }, + "@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@babel/helper-module-transforms": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.17.tgz", + "integrity": "sha512-XouDDhQESrLHTpnBtCKExJdyY4gJCdrvH2Pyv8r8kovX2U8G0dRUOT45T9XlbLtuu9CLXP15eusnkprhoPV5iQ==", + "requires": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.15" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + }, + "@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", + "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" + }, + "@babel/types": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", + "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.15", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.15.tgz", + "integrity": "sha512-jWL4eh90w0HQOTKP2MoXXUpVxilxsB2Vl4ji69rSjS3EcZ/v4sBmn+A3NpepuJzBhOaEBbR7udonlHHn5DWidg==", + "requires": { + "@babel/helper-module-transforms": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + }, + "dependencies": { + "@babel/helper-environment-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" + }, + "@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@babel/helper-module-transforms": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.17.tgz", + "integrity": "sha512-XouDDhQESrLHTpnBtCKExJdyY4gJCdrvH2Pyv8r8kovX2U8G0dRUOT45T9XlbLtuu9CLXP15eusnkprhoPV5iQ==", + "requires": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.15" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + }, + "@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", + "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" + }, + "@babel/types": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", + "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.15", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.11.tgz", + "integrity": "sha512-rIqHmHoMEOhI3VkVf5jQ15l539KrwhzqcBO6wdCNWPWc/JWt9ILNYNUssbRpeq0qWns8svuw8LnMNCvWBIJ8wA==", + "requires": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.22.9", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5" + }, + "dependencies": { + "@babel/helper-environment-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" + }, + "@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@babel/helper-module-transforms": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.17.tgz", + "integrity": "sha512-XouDDhQESrLHTpnBtCKExJdyY4gJCdrvH2Pyv8r8kovX2U8G0dRUOT45T9XlbLtuu9CLXP15eusnkprhoPV5iQ==", + "requires": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.15" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + }, + "@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", + "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" + }, + "@babel/types": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", + "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.15", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz", + "integrity": "sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ==", + "requires": { + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-environment-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" + }, + "@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@babel/helper-module-transforms": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.17.tgz", + "integrity": "sha512-XouDDhQESrLHTpnBtCKExJdyY4gJCdrvH2Pyv8r8kovX2U8G0dRUOT45T9XlbLtuu9CLXP15eusnkprhoPV5iQ==", + "requires": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.15" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + }, + "@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", + "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" + }, + "@babel/types": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", + "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.15", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz", + "integrity": "sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } + } + }, + "@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.11.tgz", + "integrity": "sha512-YZWOw4HxXrotb5xsjMJUDlLgcDXSfO9eCmdl1bgW4+/lAGdkjaEvOnQ4p5WKKdUgSzO39dgPl0pTnfxm0OAXcg==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, - "@babel/plugin-transform-modules-amd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", - "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", + "@babel/plugin-transform-numeric-separator": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.11.tgz", + "integrity": "sha512-3dzU4QGPsILdJbASKhF/V2TVP+gJya1PsueQCxIPCEcerqF21oEcrob4mzjsp2Py/1nLfF5m+xYNMDpmA8vffg==", "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", - "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", + "@babel/plugin-transform-object-rest-spread": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.15.tgz", + "integrity": "sha512-fEB+I1+gAmfAyxZcX1+ZUwLeAuuf8VIg67CTznZE0MqVFumWkh8xWtn58I4dxdVf080wn7gzWoF8vndOViJe9Q==", "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/compat-data": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.22.15" + }, + "dependencies": { + "@babel/compat-data": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", + "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==" + }, + "@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "requires": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + }, + "@babel/helper-validator-option": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==" + }, + "browserslist": { + "version": "4.21.10", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", + "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", + "requires": { + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.11" + } + }, + "caniuse-lite": { + "version": "1.0.30001532", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001532.tgz", + "integrity": "sha512-FbDFnNat3nMnrROzqrsg314zhqN5LGQ1kyyMk2opcrwGbVGpHRhgCWtAgD5YJUqNAiQ+dklreil/c3Qf1dfCTw==" + }, + "electron-to-chromium": { + "version": "1.4.513", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.513.tgz", + "integrity": "sha512-cOB0xcInjm+E5qIssHeXJ29BaUyWpMyFKT5RB3bsLENDheCja0wMkHJyiPl0NBE/VzDI7JDuNEQWhe6RitEUcw==" + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } } }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", - "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", + "@babel/plugin-transform-object-super": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz", + "integrity": "sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw==", "requires": { - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, - "@babel/plugin-transform-modules-umd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", - "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", + "@babel/plugin-transform-optional-catch-binding": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.11.tgz", + "integrity": "sha512-rli0WxesXUeCJnMYhzAglEjLWVDF6ahb45HuprcmQuLidBJFWjNnOzssk2kuc6e33FlLaiZhG/kUIzUMWdBKaQ==", "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", - "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", + "@babel/plugin-transform-optional-chaining": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.15.tgz", + "integrity": "sha512-ngQ2tBhq5vvSJw2Q2Z9i7ealNkpDMU0rGWnHPKqRZO0tzZ5tlaoz4hDvhXioOoaE0X2vfNss1djwg0DXlfu30A==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, - "@babel/plugin-transform-new-target": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", - "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", + "@babel/plugin-transform-parameters": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.15.tgz", + "integrity": "sha512-hjk7qKIqhyzhhUvRT683TYQOFa/4cQKwQy7ALvTpODswN40MljzNDa0YldevS6tGbxwaEKVn502JmY0dP7qEtQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, - "@babel/plugin-transform-object-super": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", - "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", + "@babel/plugin-transform-private-methods": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.22.5.tgz", + "integrity": "sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7" + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, - "@babel/plugin-transform-parameters": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", - "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", + "@babel/plugin-transform-private-property-in-object": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.11.tgz", + "integrity": "sha512-sSCbqZDBKHetvjSwpyWzhuHkmW5RummxJBVbYLkGkaiTOWGxml7SXt0iWa03bzxFIx7wOj3g/ILRd0RcJKBeSQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.11", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "dependencies": { + "@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + }, + "@babel/helper-validator-identifier": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", + "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" + }, + "@babel/types": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", + "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.15", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/plugin-transform-property-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", - "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz", + "integrity": "sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, "@babel/plugin-transform-regenerator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", - "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.10.tgz", + "integrity": "sha512-F28b1mDt8KcT5bUyJc/U9nwzw6cV+UmTeRlXYIl2TNqMMJif0Jeey9/RQ3C4NOd2zp0/TRsDns9ttj2L523rsw==", "requires": { - "regenerator-transform": "^0.14.2" + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, "@babel/plugin-transform-reserved-words": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", - "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz", + "integrity": "sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, "@babel/plugin-transform-runtime": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.17.0.tgz", - "integrity": "sha512-fr7zPWnKXNc1xoHfrIU9mN/4XKX4VLZ45Q+oMhfsYIaHvg7mHgmhfOy/ckRWqDK7XF3QDigRpkh5DKq6+clE8A==", - "requires": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "semver": "^6.3.0" + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.15.tgz", + "integrity": "sha512-tEVLhk8NRZSmwQ0DJtxxhTrCht1HVo8VaMzYT4w6lwyKBuHsgoioAUA7/6eT2fRfc5/23fuGdlwIxXhRVgWr4g==", + "requires": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "babel-plugin-polyfill-corejs2": "^0.4.5", + "babel-plugin-polyfill-corejs3": "^0.8.3", + "babel-plugin-polyfill-regenerator": "^0.5.2", + "semver": "^6.3.1" }, "dependencies": { + "@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + }, + "@babel/helper-validator-identifier": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", + "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" + }, + "@babel/types": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", + "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.15", + "to-fast-properties": "^2.0.0" + } + }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", - "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz", + "integrity": "sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, "@babel/plugin-transform-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", - "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz", + "integrity": "sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", - "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz", + "integrity": "sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, "@babel/plugin-transform-template-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", - "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz", + "integrity": "sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", - "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz", + "integrity": "sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, "@babel/plugin-transform-unicode-escapes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", - "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.10.tgz", + "integrity": "sha512-lRfaRKGZCBqDlRU3UIFovdp9c9mEvlylmpod0/OatICsSfuQ9YFthRo1tpTkGsklEefZdqlEFdY4A2dwTb6ohg==", + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } + } + }, + "@babel/plugin-transform-unicode-property-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.5.tgz", + "integrity": "sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A==", "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", - "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz", + "integrity": "sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } } }, - "@babel/preset-env": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", - "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", + "@babel/plugin-transform-unicode-sets-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.5.tgz", + "integrity": "sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg==", "requires": { - "@babel/compat-data": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-async-generator-functions": "^7.16.8", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.16.7", - "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.16.7", - "@babel/plugin-proposal-json-strings": "^7.16.7", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", - "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.16.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.11", - "@babel/plugin-proposal-private-property-in-object": "^7.16.7", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + } + } + }, + "@babel/preset-env": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.15.tgz", + "integrity": "sha512-tZFHr54GBkHk6hQuVA8w4Fmq+MSPsfvMG0vPnOYyTnJpyfMqybL8/MbNCPRT9zc2KBO2pe4tq15g6Uno4Jpoag==", + "requires": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.15", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.15", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.22.5", + "@babel/plugin-syntax-import-attributes": "^7.22.5", + "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", @@ -992,62 +2403,252 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.7", - "@babel/plugin-transform-async-to-generator": "^7.16.8", - "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.16.7", - "@babel/plugin-transform-classes": "^7.16.7", - "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.16.7", - "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.16.7", - "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.16.7", - "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.16.7", - "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.16.8", - "@babel/plugin-transform-modules-systemjs": "^7.16.7", - "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", - "@babel/plugin-transform-new-target": "^7.16.7", - "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.16.7", - "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.16.7", - "@babel/plugin-transform-reserved-words": "^7.16.7", - "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.16.7", - "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.16.7", - "@babel/plugin-transform-typeof-symbol": "^7.16.7", - "@babel/plugin-transform-unicode-escapes": "^7.16.7", - "@babel/plugin-transform-unicode-regex": "^7.16.7", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.8", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.20.2", - "semver": "^6.3.0" + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.22.5", + "@babel/plugin-transform-async-generator-functions": "^7.22.15", + "@babel/plugin-transform-async-to-generator": "^7.22.5", + "@babel/plugin-transform-block-scoped-functions": "^7.22.5", + "@babel/plugin-transform-block-scoping": "^7.22.15", + "@babel/plugin-transform-class-properties": "^7.22.5", + "@babel/plugin-transform-class-static-block": "^7.22.11", + "@babel/plugin-transform-classes": "^7.22.15", + "@babel/plugin-transform-computed-properties": "^7.22.5", + "@babel/plugin-transform-destructuring": "^7.22.15", + "@babel/plugin-transform-dotall-regex": "^7.22.5", + "@babel/plugin-transform-duplicate-keys": "^7.22.5", + "@babel/plugin-transform-dynamic-import": "^7.22.11", + "@babel/plugin-transform-exponentiation-operator": "^7.22.5", + "@babel/plugin-transform-export-namespace-from": "^7.22.11", + "@babel/plugin-transform-for-of": "^7.22.15", + "@babel/plugin-transform-function-name": "^7.22.5", + "@babel/plugin-transform-json-strings": "^7.22.11", + "@babel/plugin-transform-literals": "^7.22.5", + "@babel/plugin-transform-logical-assignment-operators": "^7.22.11", + "@babel/plugin-transform-member-expression-literals": "^7.22.5", + "@babel/plugin-transform-modules-amd": "^7.22.5", + "@babel/plugin-transform-modules-commonjs": "^7.22.15", + "@babel/plugin-transform-modules-systemjs": "^7.22.11", + "@babel/plugin-transform-modules-umd": "^7.22.5", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.22.5", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.11", + "@babel/plugin-transform-numeric-separator": "^7.22.11", + "@babel/plugin-transform-object-rest-spread": "^7.22.15", + "@babel/plugin-transform-object-super": "^7.22.5", + "@babel/plugin-transform-optional-catch-binding": "^7.22.11", + "@babel/plugin-transform-optional-chaining": "^7.22.15", + "@babel/plugin-transform-parameters": "^7.22.15", + "@babel/plugin-transform-private-methods": "^7.22.5", + "@babel/plugin-transform-private-property-in-object": "^7.22.11", + "@babel/plugin-transform-property-literals": "^7.22.5", + "@babel/plugin-transform-regenerator": "^7.22.10", + "@babel/plugin-transform-reserved-words": "^7.22.5", + "@babel/plugin-transform-shorthand-properties": "^7.22.5", + "@babel/plugin-transform-spread": "^7.22.5", + "@babel/plugin-transform-sticky-regex": "^7.22.5", + "@babel/plugin-transform-template-literals": "^7.22.5", + "@babel/plugin-transform-typeof-symbol": "^7.22.5", + "@babel/plugin-transform-unicode-escapes": "^7.22.10", + "@babel/plugin-transform-unicode-property-regex": "^7.22.5", + "@babel/plugin-transform-unicode-regex": "^7.22.5", + "@babel/plugin-transform-unicode-sets-regex": "^7.22.5", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "@babel/types": "^7.22.15", + "babel-plugin-polyfill-corejs2": "^0.4.5", + "babel-plugin-polyfill-corejs3": "^0.8.3", + "babel-plugin-polyfill-regenerator": "^0.5.2", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" }, "dependencies": { + "@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "requires": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + } + }, + "@babel/compat-data": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", + "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==" + }, + "@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "requires": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" + }, + "@babel/helper-function-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "requires": { + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.17.tgz", + "integrity": "sha512-bxH77R5gjH3Nkde6/LuncQoLaP16THYPscurp1S8z7S9ZgezCyV3G8Hc+TZiCmY8pz4fp8CvKSgtJMW0FkLAxA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-wrap-function": "^7.22.17" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", + "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" + }, + "@babel/helper-validator-option": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==" + }, + "@babel/helper-wrap-function": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.17.tgz", + "integrity": "sha512-nAhoheCMlrqU41tAojw9GpVEKDlTS8r3lzFmF0lP52LwblCPbuFSO7nGIZoIcoU5NIm1ABrna0cJExE4Ay6l2Q==", + "requires": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.17" + } + }, + "@babel/highlight": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", + "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", + "requires": { + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.22.16", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", + "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==" + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz", + "integrity": "sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ==", + "requires": { + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.5" + } + }, + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + }, + "@babel/types": { + "version": "7.22.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", + "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.15", + "to-fast-properties": "^2.0.0" + } + }, + "browserslist": { + "version": "4.21.10", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", + "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", + "requires": { + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.11" + } + }, + "caniuse-lite": { + "version": "1.0.30001532", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001532.tgz", + "integrity": "sha512-FbDFnNat3nMnrROzqrsg314zhqN5LGQ1kyyMk2opcrwGbVGpHRhgCWtAgD5YJUqNAiQ+dklreil/c3Qf1dfCTw==" + }, + "electron-to-chromium": { + "version": "1.4.513", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.513.tgz", + "integrity": "sha512-cOB0xcInjm+E5qIssHeXJ29BaUyWpMyFKT5RB3bsLENDheCja0wMkHJyiPl0NBE/VzDI7JDuNEQWhe6RitEUcw==" + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" + }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" } } }, "@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", "requires": { "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", "@babel/types": "^7.4.4", "esutils": "^2.0.2" } @@ -1064,6 +2665,11 @@ "source-map-support": "^0.5.16" } }, + "@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" + }, "@babel/runtime": { "version": "7.17.2", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", @@ -2516,14 +4122,6 @@ } } }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "requires": { - "object.assign": "^4.1.0" - } - }, "babel-plugin-module-resolver": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-5.0.0.tgz", @@ -2585,37 +4183,42 @@ } }, "babel-plugin-polyfill-corejs2": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", - "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz", + "integrity": "sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg==", "requires": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.3.1", - "semver": "^6.1.1" + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.4.2", + "semver": "^6.3.1" }, "dependencies": { + "@babel/compat-data": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", + "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==" + }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, "babel-plugin-polyfill-corejs3": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", - "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.3.tgz", + "integrity": "sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA==", "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.21.0" + "@babel/helper-define-polyfill-provider": "^0.4.2", + "core-js-compat": "^3.31.0" } }, "babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz", + "integrity": "sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA==", "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1" + "@babel/helper-define-polyfill-provider": "^0.4.2" } }, "balanced-match": { @@ -2973,18 +4576,38 @@ "integrity": "sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==" }, "core-js-compat": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.1.tgz", - "integrity": "sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g==", + "version": "3.32.2", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.32.2.tgz", + "integrity": "sha512-+GjlguTDINOijtVRUxrQOv3kfu9rl+qPNdX2LTbJ/ZyVTuxK+ksVSAGX1nHstu4hrv1En/uPTtWgq2gI5wt4AQ==", "requires": { - "browserslist": "^4.19.1", - "semver": "7.0.0" + "browserslist": "^4.21.10" }, "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" + "browserslist": { + "version": "4.21.10", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", + "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", + "requires": { + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.11" + } + }, + "caniuse-lite": { + "version": "1.0.30001532", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001532.tgz", + "integrity": "sha512-FbDFnNat3nMnrROzqrsg314zhqN5LGQ1kyyMk2opcrwGbVGpHRhgCWtAgD5YJUqNAiQ+dklreil/c3Qf1dfCTw==" + }, + "electron-to-chromium": { + "version": "1.4.513", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.513.tgz", + "integrity": "sha512-cOB0xcInjm+E5qIssHeXJ29BaUyWpMyFKT5RB3bsLENDheCja0wMkHJyiPl0NBE/VzDI7JDuNEQWhe6RitEUcw==" + }, + "node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" } } }, @@ -5104,9 +6727,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" } @@ -5397,7 +7020,7 @@ "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, "lodash.merge": { "version": "4.6.2", @@ -5681,15 +7304,15 @@ } }, "mongoose": { - "version": "5.13.15", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.15.tgz", - "integrity": "sha512-cxp1Gbb8yUWkaEbajdhspSaKzAvsIvOtRlYD87GN/P2QEUhpd6bIvebi36T6M0tIVAMauNaK9SPA055N3PwF8Q==", + "version": "5.13.20", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.20.tgz", + "integrity": "sha512-TjGFa/XnJYt+wLmn8y9ssjyO2OhBMeEBtOHb9iJM16EWu2Du6L1Q6zSiEK2ziyYQM8agb4tumNIQFzqbxId7MA==", "requires": { "@types/bson": "1.x || 4.0.x", "@types/mongodb": "^3.5.27", "bson": "^1.1.4", "kareem": "2.3.2", - "mongodb": "3.7.3", + "mongodb": "3.7.4", "mongoose-legacy-pluralize": "1.0.2", "mpath": "0.8.4", "mquery": "3.2.5", @@ -5701,6 +7324,29 @@ "sliced": "1.0.1" }, "dependencies": { + "mongodb": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.4.tgz", + "integrity": "sha512-K5q8aBqEXMwWdVNh94UQTwZ6BejVbFhh1uB6c5FKtPE9eUMZPUO3sRZdgIEcHSrAWmxzpG/FeODDKL388sqRmw==", + "requires": { + "bl": "^2.2.1", + "bson": "^1.1.4", + "denque": "^1.4.1", + "optional-require": "^1.1.8", + "safe-buffer": "^5.1.2", + "saslprep": "^1.0.0" + }, + "dependencies": { + "optional-require": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.1.8.tgz", + "integrity": "sha512-jq83qaUb0wNg9Krv1c5OQ+58EK+vHde6aBPzLvPPqJm89UQWsvSuFy9X/OSNJnFeSOKo7btE0n8Nl2+nE+z5nA==", + "requires": { + "require-at": "^1.0.6" + } + } + } + }, "optional-require": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz", @@ -6753,6 +8399,11 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, + "prettier": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==" + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -6865,9 +8516,9 @@ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" }, "regenerate-unicode-properties": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", - "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", "requires": { "regenerate": "^1.4.2" } @@ -6878,9 +8529,9 @@ "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" }, "regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", "requires": { "@babel/runtime": "^7.8.4" } @@ -6914,27 +8565,22 @@ } }, "regexpu-core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", - "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", "requires": { + "@babel/regjsgen": "^0.8.0", "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.0.1", - "regjsgen": "^0.6.0", - "regjsparser": "^0.8.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" + "unicode-match-property-value-ecmascript": "^2.1.0" } }, - "regjsgen": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", - "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==" - }, "regjsparser": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", - "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", "requires": { "jsesc": "~0.5.0" }, @@ -6942,7 +8588,7 @@ "jsesc": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==" } } }, @@ -7831,20 +9477,29 @@ } }, "unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==" }, "unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==" }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, + "update-browserslist-db": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", diff --git a/package.json b/package.json index f9387e933..509755c88 100644 --- a/package.json +++ b/package.json @@ -40,8 +40,8 @@ "@babel/core": "^7.10.2", "@babel/node": "^7.14.9", "@babel/plugin-transform-async-to-generator": "^7.10.1", - "@babel/plugin-transform-runtime": "^7.10.1", - "@babel/preset-env": "^7.10.2", + "@babel/plugin-transform-runtime": "^7.22.15", + "@babel/preset-env": "^7.22.15", "@babel/runtime": "^7.10.2", "@sentry/node": "^5.17.0", "async-exit-hook": "^2.0.1", @@ -58,11 +58,12 @@ "moment": "^2.29.4", "moment-timezone": "^0.5.35", "mongodb": "^3.7.3", - "mongoose": "^5.13.15", + "mongoose": "^5.13.20", "mongoose-validator": "^2.1.0", "node-cache": "^5.1.2", "node-datetime": "^2.0.3", "nodemailer": "^6.4.16", + "prettier": "^3.0.3", "redis": "^4.2.0", "uuid": "^3.4.0", "ws": "^8.8.1" diff --git a/src/controllers/dashBoardController.js b/src/controllers/dashBoardController.js index 4bd05b91e..742bfe4d8 100644 --- a/src/controllers/dashBoardController.js +++ b/src/controllers/dashBoardController.js @@ -1,8 +1,8 @@ -const mongoose = require('mongoose'); -const path = require('path'); -const fs = require('fs/promises'); -const dashboardhelper = require('../helpers/dashboardhelper')(); -const emailSender = require('../utilities/emailSender'); +const mongoose = require("mongoose"); +const path = require("path"); +const fs = require("fs/promises"); +const dashboardhelper = require("../helpers/dashboardhelper")(); +const emailSender = require("../utilities/emailSender"); const dashboardcontroller = function () { const dashboarddata = function (req, res) { @@ -10,18 +10,26 @@ const dashboardcontroller = function () { const snapshot = dashboardhelper.personaldetails(userId); - snapshot.then((results) => { res.send(results).status(200); }); + snapshot.then((results) => { + res.send(results).status(200); + }); }; const monthlydata = function (req, res) { const userId = mongoose.Types.ObjectId(req.params.userId); - const laborthismonth = dashboardhelper.laborthismonth(userId, req.params.fromDate, req.params.toDate); + const laborthismonth = dashboardhelper.laborthismonth( + userId, + req.params.fromDate, + req.params.toDate + ); laborthismonth.then((results) => { if (!results || results.length === 0) { - const emptyresult = [{ - projectName: '', - timeSpent_hrs: 0, - }]; + const emptyresult = [ + { + projectName: "", + timeSpent_hrs: 0, + }, + ]; res.status(200).send(emptyresult); return; } @@ -31,35 +39,54 @@ const dashboardcontroller = function () { const weeklydata = function (req, res) { const userId = mongoose.Types.ObjectId(req.params.userId); - const laborthisweek = dashboardhelper.laborthisweek(userId, req.params.fromDate, req.params.toDate); - laborthisweek.then((results) => { res.send(results).status(200); }); + const laborthisweek = dashboardhelper.laborthisweek( + userId, + req.params.fromDate, + req.params.toDate + ); + laborthisweek.then((results) => { + res.send(results).status(200); + }); }; - const leaderboarddata = function (req, res) { const userId = mongoose.Types.ObjectId(req.params.userId); const leaderboard = dashboardhelper.getLeaderboard(userId); - leaderboard.then((results) => { - if (results.length > 0) { - res.status(200).send(results); - } else { - const { getUserLaborData } = dashboardhelper; - getUserLaborData(userId).then((r) => { - res.status(200).send(r); - }); - } - }) - .catch(error => res.status(400).send(error)); + leaderboard + .then((results) => { + if (results.length > 0) { + res.status(200).send(results); + } else { + const { getUserLaborData } = dashboardhelper; + getUserLaborData(userId).then((r) => { + res.status(200).send(r); + }); + } + }) + .catch((error) => res.status(400).send(error)); }; const orgData = function (req, res) { const fullOrgData = dashboardhelper.getOrgData(); - fullOrgData.then((results) => { res.status(200).send(results[0]); }) - .catch(error => res.status(400).send(error)); + fullOrgData + .then((results) => { + res.status(200).send(results[0]); + }) + .catch((error) => res.status(400).send(error)); }; - const getBugReportEmailBody = function (firstName, lastName, title, environment, reproduction, expected, actual, visual, severity) { + const getBugReportEmailBody = function ( + firstName, + lastName, + title, + environment, + reproduction, + expected, + actual, + visual, + severity + ) { const text = `New Bug Report From ${firstName} ${lastName}:

[Feature Name] Bug Title:

${title}

@@ -83,43 +110,90 @@ const dashboardcontroller = function () { const sendBugReport = function (req, res) { const { - firstName, lastName, title, environment, reproduction, expected, actual, visual, severity, email, + firstName, + lastName, + title, + environment, + reproduction, + expected, + actual, + visual, + severity, + email, } = req.body; - const emailBody = getBugReportEmailBody(firstName, lastName, title, environment, reproduction, expected, actual, visual, severity); + const emailBody = getBugReportEmailBody( + firstName, + lastName, + title, + environment, + reproduction, + expected, + actual, + visual, + severity + ); try { emailSender( - 'onecommunityglobal@gmail.com', + "onecommunityglobal@gmail.com", `Bug Rport from ${firstName} ${lastName}`, emailBody, - email, + email ); - res.status(200).send('Success'); + res.status(200).send("Success"); } catch { - res.status(500).send('Failed'); + res.status(500).send("Failed"); } }; - // read suggestion data from file + + const getSuggestionFilePath = async () => { + // Define a base path based on the process.cwd() + const basePath = process.cwd(); + console.log(basePath, "basePath"); + + // Define the relative path to the JSON file (adjust as needed) + const relativePath = "src/constants/suggestionModalData.json"; + + // Combine the base path and relative path to create the full path + const fullPath = path.join(basePath, relativePath); + + return fullPath; + }; + const readSuggestionFile = async () => { - const filepath = path.join(process.cwd(), 'src', 'constants', 'suggestionModalData.json'); - let readfile = await fs.readFile(filepath).catch(err => console.log(err)); - readfile = JSON.parse(readfile); - return readfile; + // Specify the absolute path to the JSON file + const filepath = await getSuggestionFilePath(); + + try { + // Check if the file exists + await fs.access(filepath); + + // Read and parse the file + const readfile = await fs.readFile(filepath, "utf8"); + const parsedData = JSON.parse(readfile); + return parsedData; + } catch (err) { + console.error("Error reading suggestionModalData.json:", err); + return null; // Handle the error appropriately + } }; + // create suggestion emailbody const getsuggestionEmailBody = async (...args) => { const readfile = await readSuggestionFile(); let fieldaaray = []; if (readfile.field.length) { - fieldaaray = readfile.field.map(item => `

${item}

-

${args[3][item]}

`); + fieldaaray = readfile.field.map( + (item) => `

${item}

+

${args[3][item]}

` + ); } const text = `New Suggestion:

Suggestion Category:

${args[0]}

Suggestion:

${args[1]}

- ${fieldaaray.length > 0 ? fieldaaray : ''} + ${fieldaaray.length > 0 ? fieldaaray : ""}

Wants Feedback:

${args[2]}

Thank you,
@@ -130,50 +204,80 @@ const dashboardcontroller = function () { // send suggestion email const sendMakeSuggestion = async (req, res) => { - const { - suggestioncate, suggestion, confirm, ...rest - } = req.body; - const emailBody = await getsuggestionEmailBody(suggestioncate, suggestion, confirm, rest); + const { suggestioncate, suggestion, confirm, ...rest } = req.body; + const emailBody = await getsuggestionEmailBody( + suggestioncate, + suggestion, + confirm, + rest + ); try { emailSender( - 'onecommunityglobal@gmail.com', - 'A new suggestion', - emailBody, + "onecommunityglobal@gmail.com", + "A new suggestion", + emailBody ); - res.status(200).send('Success'); + res.status(200).send("Success"); } catch { - res.status(500).send('Failed'); + res.status(500).send("Failed"); } }; - const getSuggestionOption = async (req, res) => { - const readfile = await readSuggestionFile(); - res.status(200).send(readfile); + try { + const readfile = await readSuggestionFile(); + if (readfile) { + res.status(200).send(readfile); + } else { + res.status(404).send("Suggestion file not found."); + } + } catch (error) { + console.error("Error reading suggestion file:", error); + res.status(500).send("Internal Server Error"); + } }; + // add new suggestion category or field const editSuggestionOption = async (req, res) => { - let readfile = await readSuggestionFile(); - if (req.body.suggestion) { - if (req.body.action === 'add') readfile.suggestion.unshift(req.body.newField); - if (req.body.action === 'delete') { - readfile = { - ...readfile, - suggestion: readfile.suggestion.filter((item, index) => index + 1 !== +req.body.newField), - }; + try { + // Read the current suggestion data + let readfile = await readSuggestionFile(); + + if (req.body.suggestion) { + if (req.body.action === "add") { + readfile.suggestion.unshift(req.body.newField); + } + if (req.body.action === "delete") { + readfile = { + ...readfile, + suggestion: readfile.suggestion.filter( + (item, index) => index + 1 !== +req.body.newField + ), + }; + } + } else { + if (req.body.action === "add") { + readfile.field.unshift(req.body.newField); } - } else { - if (req.body.action === 'add') readfile.field.unshift(req.body.newField); - if (req.body.action === 'delete') { - readfile = { - ...readfile, - field: readfile.field.filter(item => item !== req.body.newField), - }; + if (req.body.action === "delete") { + readfile = { + ...readfile, + field: readfile.field.filter((item) => item !== req.body.newField), + }; } + } + + // Get the file path + const filepath = await getSuggestionFilePath(); + + // Write the updated data back to the file + await fs.writeFile(filepath, JSON.stringify(readfile, null, 2)); + + res.status(200).send("success"); + } catch (error) { + console.error("Error editing suggestion option:", error); + res.status(500).send("Internal Server Error"); } - const filepath = path.join(process.cwd(), 'src', 'constants', 'suggestionModalData.json'); - await fs.writeFile(filepath, JSON.stringify(readfile)).catch(err => console.log(err)); - res.status(200).send('success'); }; return { From 95015c4ebb613ed81f152a2c67d171f9713eac8d Mon Sep 17 00:00:00 2001 From: leonzh2k Date: Thu, 6 Jul 2023 17:55:26 -0400 Subject: [PATCH 023/272] add new fields to send in UserProfileController Add jobTitle and location fields to the userProfile objects that are sent back to the client when requesting all userProfiles. These two bits of info are displayed on the interactive map. --- src/controllers/userProfileController.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 5f36e91a2..8a866401a 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -62,10 +62,10 @@ const userProfileController = function (UserProfile) { res.status(200).send(getData); 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 location jobTitle', ) .sort({ lastName: 1, From 9600e9dee200bf32bcc52c5757adc53a231a94f2 Mon Sep 17 00:00:00 2001 From: xaanders Date: Thu, 14 Sep 2023 16:40:41 -0400 Subject: [PATCH 024/272] feat: adding location object to user profile schema --- src/models/userProfile.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/models/userProfile.js b/src/models/userProfile.js index fbb59e6e3..faeef3a86 100644 --- a/src/models/userProfile.js +++ b/src/models/userProfile.js @@ -7,7 +7,7 @@ const bcrypt = require('bcryptjs'); const SALT_ROUNDS = 10; const nextDay = new Date(); -nextDay.setDate(nextDay.getDate()+1); +nextDay.setDate(nextDay.getDate() + 1); const userProfileSchema = new Schema({ password: { @@ -81,7 +81,16 @@ const userProfileSchema = new Schema({ infringements: [ { date: { type: String, required: true }, description: { type: String, required: true } }, ], - location: { type: String, default: '' }, + location: { + userProvided: { type: String, default: '' }, + coords: { + lat: { type: Number, default: '' }, + lng: { type: Number, default: '' }, + }, + country: { type: String, default: '' }, + city: { type: String, default: '' } + + }, oldInfringements: [ { date: { type: String, required: true }, description: { type: String, required: true } }, ], @@ -153,12 +162,12 @@ const userProfileSchema = new Schema({ isVisible: { type: Boolean, default: false }, weeklySummaryOption: { type: String }, bioPosted: { type: String, default: 'default' }, - isFirstTimelog: { type: Boolean, default: true}, + isFirstTimelog: { type: Boolean, default: true }, infoCollections: [ { - areaName: { type: String }, + areaName: { type: String }, areaContent: { type: String }, - }], + }], }); userProfileSchema.pre('save', function (next) { From 2d1e82c56bce45d24d31eafab3eca2297b03dd2c Mon Sep 17 00:00:00 2001 From: xaanders Date: Sat, 16 Sep 2023 12:02:02 -0400 Subject: [PATCH 025/272] fix: editing email message after new user creating --- src/controllers/profileInitialSetupController.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/profileInitialSetupController.js b/src/controllers/profileInitialSetupController.js index d5c955d88..c35230dbe 100644 --- a/src/controllers/profileInitialSetupController.js +++ b/src/controllers/profileInitialSetupController.js @@ -59,7 +59,7 @@ function informManagerMessage(user) { Location: - ${user.location} + ${user.location.userProvided}, ${user.location.country}

Please check the details provided by the user. If any errors were made, kindly ask them to correct the information accordingly.

@@ -184,8 +184,8 @@ const profileInitialSetupController = function (ProfileInitialSetupToken, userPr newUser.bioPosted = 'default'; newUser.privacySettings.email = req.body.privacySettings.email newUser.privacySettings.phoneNumber = req.body.privacySettings.phoneNumber - const savedUser = await newUser.save(); + const savedUser = await newUser.save(); emailSender( process.env.MANAGER_EMAIL, 'New User Profile Created', From 15ec92739130b6d5743fd3f55e41489a0d04bf93 Mon Sep 17 00:00:00 2001 From: wang9hu Date: Tue, 19 Sep 2023 18:15:29 -0700 Subject: [PATCH 026/272] add hasIndividualPermission to badgeController, which checks seeBadge permission from userProfile db --- src/controllers/badgeController.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/badgeController.js b/src/controllers/badgeController.js index 4777297dd..6238c381e 100644 --- a/src/controllers/badgeController.js +++ b/src/controllers/badgeController.js @@ -1,11 +1,11 @@ const mongoose = require('mongoose'); const UserProfile = require('../models/userProfile'); -const { hasPermission } = require('../utilities/permissions'); +const { hasPermission, hasIndividualPermission } = require('../utilities/permissions'); const escapeRegex = require('../utilities/escapeRegex'); const badgeController = function (Badge) { const getAllBadges = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'seeBadges')) { + if (!await hasPermission(req.body.requestor.role, 'seeBadges') && !await hasIndividualPermission(req.body.requestor.requestorId, 'seeBadges')) { res.status(403).send('You are not authorized to view all badge data.'); return; } From 464a4eef488e01c3a368580082651dc40e710702 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Wed, 20 Sep 2023 12:30:58 -0700 Subject: [PATCH 027/272] add bm login route, router, controller --- .../bmdashboard/bmLoginController.js | 44 +++++++++++++++++++ src/controllers/logincontroller.js | 3 ++ src/controllers/userProfileController.js | 3 ++ src/routes/bmdashboard/bmLoginRouter.js | 13 ++++++ src/startup/routes.js | 7 ++- 5 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 src/controllers/bmdashboard/bmLoginController.js create mode 100644 src/routes/bmdashboard/bmLoginRouter.js diff --git a/src/controllers/bmdashboard/bmLoginController.js b/src/controllers/bmdashboard/bmLoginController.js new file mode 100644 index 000000000..b8db7286c --- /dev/null +++ b/src/controllers/bmdashboard/bmLoginController.js @@ -0,0 +1,44 @@ +const jwt = require('jsonwebtoken'); +const bcrypt = require('bcryptjs'); + +const config = require('../../config'); + +const userprofile = require('../../models/userProfile'); + +const bmLoginController = function () { + const { JWT_SECRET } = config; + const bmLogin = async function _login(req, res) { + const { email: _email, password: _password } = req.body; + const currentToken = req.headers.authorization; + try { + const decode = jwt.verify(currentToken, JWT_SECRET); + const user = await userprofile.findOne({ _id: decode.userid }); + + // check email + if (user.email !== _email) { + res.status(422); + return res.json({ label: 'email', message: 'Email must match current login. Please try again.' }); + } + // check password + const check = await bcrypt.compare(_password, user.password); + if (!check) { + res.status(422); + return res.json({ label: 'password', message: 'Password must match current login. Please try again.' }); + } + // create new token + const jwtPayload = { + ...decode, + access: { + canAccessBMPortal: true, + }, + }; + const newToken = jwt.sign(jwtPayload, JWT_SECRET); + return res.json({ token: newToken }); + } catch (err) { + res.json(err); + } + }; + return { bmLogin }; +}; + +module.exports = bmLoginController; diff --git a/src/controllers/logincontroller.js b/src/controllers/logincontroller.js index 27a09edee..cdeae9b37 100644 --- a/src/controllers/logincontroller.js +++ b/src/controllers/logincontroller.js @@ -49,6 +49,9 @@ const logincontroller = function () { userid: user._id, role: user.role, permissions: user.permissions, + access: { + canAccessBMPortal: false, + }, expiryTimestamp: moment().add(config.TOKEN.Lifetime, config.TOKEN.Units), }; diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 5f36e91a2..5000e36ad 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -808,6 +808,9 @@ const userProfileController = function (UserProfile) { userid: user._id, role: user.role, permissions: user.permissions, + access: { + canAccessBMPortal: false, + }, expiryTimestamp: moment_().add(config.TOKEN.Lifetime, config.TOKEN.Units), }; const currentRefreshToken = jwt.sign(jwtPayload, JWT_SECRET); diff --git a/src/routes/bmdashboard/bmLoginRouter.js b/src/routes/bmdashboard/bmLoginRouter.js new file mode 100644 index 000000000..c87e46c41 --- /dev/null +++ b/src/routes/bmdashboard/bmLoginRouter.js @@ -0,0 +1,13 @@ +const express = require('express'); + +const routes = function () { + const loginrouter = express.Router(); + const controller = require('../../controllers/bmdashboard/bmLoginController')(); + + loginrouter.route('/login') + .post(controller.bmLogin); + + return loginrouter; +}; + +module.exports = routes; diff --git a/src/startup/routes.js b/src/startup/routes.js index 6e000002e..43cd226bd 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -53,6 +53,9 @@ const ownerStandardMessageRouter = require('../routes/ownerStandardMessageRouter const reasonRouter = require('../routes/reasonRouter')(reason, userProfile); const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverText); +// bm dashboard +const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); + module.exports = function (app) { app.use('/api', forgotPwdRouter); @@ -79,8 +82,10 @@ module.exports = function (app) { app.use('/api', roleRouter); app.use('/api', ownerMessageRouter); app.use('/api', ownerStandardMessageRouter); - app.use('/api', profileInitialSetupRouter) + app.use('/api', profileInitialSetupRouter); app.use('/api', reasonRouter); app.use('/api', informationRouter); app.use('/api', mouseoverTextRouter); + // bm dashboard + app.use('/api/bm', bmLoginRouter); }; From ea1d82eba3d326d5e40d422778f6458d72ee9551 Mon Sep 17 00:00:00 2001 From: Carl Bebli Date: Wed, 20 Sep 2023 21:53:16 +0000 Subject: [PATCH 028/272] packages --- package-lock.json | 2721 +++++++++------------------------------------ package.json | 7 +- 2 files changed, 536 insertions(+), 2192 deletions(-) diff --git a/package-lock.json b/package-lock.json index cdfa61193..5c6bd6db5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -115,28 +115,12 @@ } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", - "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", + "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", "requires": { - "@babel/types": "^7.22.15" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", - "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" - }, - "@babel/types": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", - "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.15", - "to-fast-properties": "^2.0.0" - } - } + "@babel/helper-explode-assignable-expression": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-compilation-targets": { @@ -158,229 +142,47 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz", - "integrity": "sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", - "@babel/helper-member-expression-to-functions": "^7.22.15", - "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "semver": "^6.3.1" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "requires": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" - }, - "@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", - "requires": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", - "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" - }, - "@babel/highlight": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", - "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", - "requires": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.22.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", - "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==" - }, - "@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - } - }, - "@babel/types": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", - "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.15", - "to-fast-properties": "^2.0.0" - } - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - } + "version": "7.17.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz", + "integrity": "sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7" } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", - "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", + "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", "requires": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "regexpu-core": "^5.3.1", - "semver": "^6.3.1" - }, - "dependencies": { - "@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", - "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" - }, - "@babel/types": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", - "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.15", - "to-fast-properties": "^2.0.0" - } - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - } + "@babel/helper-annotate-as-pure": "^7.16.7", + "regexpu-core": "^5.0.1" } }, "@babel/helper-define-polyfill-provider": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz", - "integrity": "sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", + "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", "requires": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-compilation-targets": "^7.13.0", + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/traverse": "^7.13.0", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" + "resolve": "^1.14.2", + "semver": "^6.1.2" }, "dependencies": { - "@babel/compat-data": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", - "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==" - }, - "@babel/helper-compilation-targets": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", - "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", - "requires": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - }, - "@babel/helper-validator-option": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", - "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==" - }, - "browserslist": { - "version": "4.21.10", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", - "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", - "requires": { - "caniuse-lite": "^1.0.30001517", - "electron-to-chromium": "^1.4.477", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.11" - } - }, - "caniuse-lite": { - "version": "1.0.30001532", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001532.tgz", - "integrity": "sha512-FbDFnNat3nMnrROzqrsg314zhqN5LGQ1kyyMk2opcrwGbVGpHRhgCWtAgD5YJUqNAiQ+dklreil/c3Qf1dfCTw==" - }, - "electron-to-chromium": { - "version": "1.4.513", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.513.tgz", - "integrity": "sha512-cOB0xcInjm+E5qIssHeXJ29BaUyWpMyFKT5RB3bsLENDheCja0wMkHJyiPl0NBE/VzDI7JDuNEQWhe6RitEUcw==" - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "requires": { - "yallist": "^3.0.2" - } - }, - "node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" - }, "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, @@ -392,6 +194,14 @@ "@babel/types": "^7.16.7" } }, + "@babel/helper-explode-assignable-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", + "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", + "requires": { + "@babel/types": "^7.16.7" + } + }, "@babel/helper-function-name": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", @@ -419,28 +229,11 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.15.tgz", - "integrity": "sha512-qLNsZbgrNh0fDQBCPocSL8guki1hcPvltGDv/NxvUoABwFq7GkKSu1nRXeJkVZc+wJvne2E0RKQz+2SQrz6eAA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", + "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", "requires": { - "@babel/types": "^7.22.15" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", - "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" - }, - "@babel/types": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", - "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.15", - "to-fast-properties": "^2.0.0" - } - } + "@babel/types": "^7.16.7" } }, "@babel/helper-module-imports": { @@ -467,28 +260,11 @@ } }, "@babel/helper-optimise-call-expression": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", - "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", + "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", "requires": { - "@babel/types": "^7.22.5" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", - "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" - }, - "@babel/types": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", - "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.15", - "to-fast-properties": "^2.0.0" - } - } + "@babel/types": "^7.16.7" } }, "@babel/helper-plugin-utils": { @@ -507,20 +283,15 @@ } }, "@babel/helper-replace-supers": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz", - "integrity": "sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", + "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", "requires": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-member-expression-to-functions": "^7.22.5", - "@babel/helper-optimise-call-expression": "^7.22.5" - }, - "dependencies": { - "@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" - } + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-simple-access": { @@ -532,28 +303,11 @@ } }, "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", - "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", + "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", "requires": { - "@babel/types": "^7.22.5" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", - "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" - }, - "@babel/types": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", - "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.15", - "to-fast-properties": "^2.0.0" - } - } + "@babel/types": "^7.16.0" } }, "@babel/helper-split-export-declaration": { @@ -564,11 +318,6 @@ "@babel/types": "^7.16.7" } }, - "@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==" - }, "@babel/helper-validator-identifier": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", @@ -629,41 +378,165 @@ "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==" }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.15.tgz", - "integrity": "sha512-FB9iYlz7rURmRJyXRKEnalYPPdn87H5no108cyuQQyMwlpJ2SJtpIUBI27kdTin956pz+LPypkPVPUTlxOmrsg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", + "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.15.tgz", - "integrity": "sha512-Hyph9LseGvAeeXzikV88bczhsrLrIZqDPxO+sSmAunMPaGrBGhfMWzCPYTtiW9t+HzSE2wtV8e5cc5P6r1xMDQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", + "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/plugin-transform-optional-chaining": "^7.22.15" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/plugin-proposal-optional-chaining": "^7.16.7" + } + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", + "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.8", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", + "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-proposal-class-static-block": { + "version": "7.17.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.6.tgz", + "integrity": "sha512-X/tididvL2zbs7jZCeeRJ8167U/+Ac135AM6jCAx6gYXDUviZV5Ku9UDvWS2NCuWlFjIRXklYhwo6HhAC7ETnA==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.17.6", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", + "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", + "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", + "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", + "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", + "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", + "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz", + "integrity": "sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw==", + "requires": { + "@babel/compat-data": "^7.17.0", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.16.7" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", + "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", + "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.16.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", + "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.16.10", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==" + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", + "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", + "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" + } }, "@babel/plugin-syntax-async-generators": { "version": "7.8.4", @@ -705,44 +578,6 @@ "@babel/helper-plugin-utils": "^7.8.3" } }, - "@babel/plugin-syntax-import-assertions": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz", - "integrity": "sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg==", - "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } - } - }, - "@babel/plugin-syntax-import-attributes": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.5.tgz", - "integrity": "sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg==", - "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } - } - }, - "@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, "@babel/plugin-syntax-json-strings": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", @@ -815,1585 +650,339 @@ "@babel/helper-plugin-utils": "^7.14.5" } }, - "@babel/plugin-syntax-unicode-sets-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", - "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "@babel/plugin-transform-arrow-functions": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", + "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-plugin-utils": "^7.16.7" } }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz", - "integrity": "sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw==", + "@babel/plugin-transform-async-to-generator": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", + "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.8" } }, - "@babel/plugin-transform-async-generator-functions": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.15.tgz", - "integrity": "sha512-jBm1Es25Y+tVoTi5rfd5t1KLmL8ogLKpXszboWOTTtGFGz2RKnQe2yn7HbZ+kb/B8N0FVSGQo874NSlOU1T4+w==", + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", + "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", "requires": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-remap-async-to-generator": "^7.22.9", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "requires": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" - }, - "@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", - "requires": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.17.tgz", - "integrity": "sha512-bxH77R5gjH3Nkde6/LuncQoLaP16THYPscurp1S8z7S9ZgezCyV3G8Hc+TZiCmY8pz4fp8CvKSgtJMW0FkLAxA==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-wrap-function": "^7.22.17" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", - "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" - }, - "@babel/helper-wrap-function": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.17.tgz", - "integrity": "sha512-nAhoheCMlrqU41tAojw9GpVEKDlTS8r3lzFmF0lP52LwblCPbuFSO7nGIZoIcoU5NIm1ABrna0cJExE4Ay6l2Q==", - "requires": { - "@babel/helper-function-name": "^7.22.5", - "@babel/template": "^7.22.15", - "@babel/types": "^7.22.17" - } - }, - "@babel/highlight": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", - "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", - "requires": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.22.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", - "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==" - }, - "@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - } - }, - "@babel/types": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", - "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.15", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", - "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", - "requires": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8" - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz", - "integrity": "sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA==", - "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-block-scoping": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.15.tgz", - "integrity": "sha512-G1czpdJBZCtngoK1sJgloLiOHUnkb/bLZwqVZD8kXmq0ZnVfTTWUcs9OWtp0mBtYJ+4LQY1fllqBkOIPhXmFmw==", - "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } - } - }, - "@babel/plugin-transform-class-properties": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.22.5.tgz", - "integrity": "sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } - } - }, - "@babel/plugin-transform-class-static-block": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.11.tgz", - "integrity": "sha512-GMM8gGmqI7guS/llMFk1bJDkKfn3v3C4KHK9Yg1ey5qcHcOlKb0QvcMrgzvxo+T03/4szNh5lghY+fEC98Kq9g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", + "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.22.11", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-classes": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.15.tgz", - "integrity": "sha512-VbbC3PGjBdE0wAWDdHM9G8Gm977pnYI0XpqMd6LrKISj8/DJXEsWqgRuTYaNE9Bv0JGhTZUzHDlMk18IpOuoqw==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", - "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.9", - "@babel/helper-split-export-declaration": "^7.22.6", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", + "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", "globals": "^11.1.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "requires": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" - } - }, - "@babel/compat-data": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", - "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==" - }, - "@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", - "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", - "requires": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - } - }, - "@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" - }, - "@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", - "requires": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - }, - "@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", - "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" - }, - "@babel/helper-validator-option": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", - "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==" - }, - "@babel/highlight": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", - "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", - "requires": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.22.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", - "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==" - }, - "@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - } - }, - "@babel/types": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", - "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.15", - "to-fast-properties": "^2.0.0" - } - }, - "browserslist": { - "version": "4.21.10", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", - "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", - "requires": { - "caniuse-lite": "^1.0.30001517", - "electron-to-chromium": "^1.4.477", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.11" - } - }, - "caniuse-lite": { - "version": "1.0.30001532", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001532.tgz", - "integrity": "sha512-FbDFnNat3nMnrROzqrsg314zhqN5LGQ1kyyMk2opcrwGbVGpHRhgCWtAgD5YJUqNAiQ+dklreil/c3Qf1dfCTw==" - }, - "electron-to-chromium": { - "version": "1.4.513", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.513.tgz", - "integrity": "sha512-cOB0xcInjm+E5qIssHeXJ29BaUyWpMyFKT5RB3bsLENDheCja0wMkHJyiPl0NBE/VzDI7JDuNEQWhe6RitEUcw==" - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "requires": { - "yallist": "^3.0.2" - } - }, - "node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - } } }, "@babel/plugin-transform-computed-properties": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz", - "integrity": "sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", + "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/template": "^7.22.5" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "requires": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - }, - "@babel/helper-validator-identifier": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", - "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" - }, - "@babel/highlight": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", - "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", - "requires": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.22.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", - "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==" - }, - "@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - } - }, - "@babel/types": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", - "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.15", - "to-fast-properties": "^2.0.0" - } - } + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-destructuring": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.15.tgz", - "integrity": "sha512-HzG8sFl1ZVGTme74Nw+X01XsUTqERVQ6/RLHo3XjGRzm7XD6QTtfS3NJotVgCGy8BzkDqRjRBD8dAyJn5TuvSQ==", + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.3.tgz", + "integrity": "sha512-dDFzegDYKlPqa72xIlbmSkly5MluLoaC1JswABGktyt6NTXSBcUuse/kWE/wvKFWJHPETpi158qJZFS3JmykJg==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz", - "integrity": "sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", + "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz", - "integrity": "sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", + "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } - } - }, - "@babel/plugin-transform-dynamic-import": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.11.tgz", - "integrity": "sha512-g/21plo58sfteWjaO0ZNVb+uEOkJNjAaHhbejrnBmu011l/eNDScmkbjCC3l4FKb10ViaGU4aOkFznSu2zRHgA==", - "requires": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz", - "integrity": "sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", + "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } - } - }, - "@babel/plugin-transform-export-namespace-from": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.11.tgz", - "integrity": "sha512-xa7aad7q7OiT8oNZ1mU7NrISjlSkVdMbNxn9IuLZyL9AJEhs1Apba3I+u5riX1dIkdptP5EKDG5XDPByWxtehw==", - "requires": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-for-of": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.15.tgz", - "integrity": "sha512-me6VGeHsx30+xh9fbDLLPi0J1HzmeIIyenoOQHuw2D4m2SAU3NrspX5XxJLBpqn5yrLzrlw2Iy3RA//Bx27iOA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", + "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz", - "integrity": "sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg==", - "requires": { - "@babel/helper-compilation-targets": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "requires": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" - } - }, - "@babel/compat-data": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", - "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==" - }, - "@babel/helper-compilation-targets": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", - "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", - "requires": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - } - }, - "@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", - "requires": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - }, - "@babel/helper-validator-identifier": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", - "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" - }, - "@babel/helper-validator-option": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", - "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==" - }, - "@babel/highlight": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", - "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", - "requires": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.22.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", - "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==" - }, - "@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - } - }, - "@babel/types": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", - "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.15", - "to-fast-properties": "^2.0.0" - } - }, - "browserslist": { - "version": "4.21.10", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", - "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", - "requires": { - "caniuse-lite": "^1.0.30001517", - "electron-to-chromium": "^1.4.477", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.11" - } - }, - "caniuse-lite": { - "version": "1.0.30001532", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001532.tgz", - "integrity": "sha512-FbDFnNat3nMnrROzqrsg314zhqN5LGQ1kyyMk2opcrwGbVGpHRhgCWtAgD5YJUqNAiQ+dklreil/c3Qf1dfCTw==" - }, - "electron-to-chromium": { - "version": "1.4.513", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.513.tgz", - "integrity": "sha512-cOB0xcInjm+E5qIssHeXJ29BaUyWpMyFKT5RB3bsLENDheCja0wMkHJyiPl0NBE/VzDI7JDuNEQWhe6RitEUcw==" - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "requires": { - "yallist": "^3.0.2" - } - }, - "node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - } - } - }, - "@babel/plugin-transform-json-strings": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.11.tgz", - "integrity": "sha512-CxT5tCqpA9/jXFlme9xIBCc5RPtdDq3JpkkhgHQqtDdiTnTI0jtZ0QzXhr5DILeYifDPp2wvY2ad+7+hLMW5Pw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", + "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-literals": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz", - "integrity": "sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g==", - "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } - } - }, - "@babel/plugin-transform-logical-assignment-operators": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.11.tgz", - "integrity": "sha512-qQwRTP4+6xFCDV5k7gZBF3C31K34ut0tbEcTKxlX/0KXxm9GLcO14p570aWxFvVzx6QAfPgq7gaeIHXJC8LswQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", + "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-member-expression-literals": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz", - "integrity": "sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew==", - "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz", - "integrity": "sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ==", - "requires": { - "@babel/helper-module-transforms": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" - }, - "@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", - "requires": { - "@babel/types": "^7.22.15" - } - }, - "@babel/helper-module-transforms": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.17.tgz", - "integrity": "sha512-XouDDhQESrLHTpnBtCKExJdyY4gJCdrvH2Pyv8r8kovX2U8G0dRUOT45T9XlbLtuu9CLXP15eusnkprhoPV5iQ==", - "requires": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.15" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - }, - "@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", - "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" - }, - "@babel/types": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", - "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.15", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.15.tgz", - "integrity": "sha512-jWL4eh90w0HQOTKP2MoXXUpVxilxsB2Vl4ji69rSjS3EcZ/v4sBmn+A3NpepuJzBhOaEBbR7udonlHHn5DWidg==", - "requires": { - "@babel/helper-module-transforms": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-simple-access": "^7.22.5" - }, - "dependencies": { - "@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" - }, - "@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", - "requires": { - "@babel/types": "^7.22.15" - } - }, - "@babel/helper-module-transforms": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.17.tgz", - "integrity": "sha512-XouDDhQESrLHTpnBtCKExJdyY4gJCdrvH2Pyv8r8kovX2U8G0dRUOT45T9XlbLtuu9CLXP15eusnkprhoPV5iQ==", - "requires": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.15" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - }, - "@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", - "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" - }, - "@babel/types": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", - "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.15", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.11.tgz", - "integrity": "sha512-rIqHmHoMEOhI3VkVf5jQ15l539KrwhzqcBO6wdCNWPWc/JWt9ILNYNUssbRpeq0qWns8svuw8LnMNCvWBIJ8wA==", - "requires": { - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-module-transforms": "^7.22.9", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5" - }, - "dependencies": { - "@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" - }, - "@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", - "requires": { - "@babel/types": "^7.22.15" - } - }, - "@babel/helper-module-transforms": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.17.tgz", - "integrity": "sha512-XouDDhQESrLHTpnBtCKExJdyY4gJCdrvH2Pyv8r8kovX2U8G0dRUOT45T9XlbLtuu9CLXP15eusnkprhoPV5iQ==", - "requires": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.15" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - }, - "@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", - "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" - }, - "@babel/types": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", - "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.15", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz", - "integrity": "sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ==", - "requires": { - "@babel/helper-module-transforms": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" - }, - "@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", - "requires": { - "@babel/types": "^7.22.15" - } - }, - "@babel/helper-module-transforms": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.17.tgz", - "integrity": "sha512-XouDDhQESrLHTpnBtCKExJdyY4gJCdrvH2Pyv8r8kovX2U8G0dRUOT45T9XlbLtuu9CLXP15eusnkprhoPV5iQ==", - "requires": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.15" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - }, - "@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", - "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" - }, - "@babel/types": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", - "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.15", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", - "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz", - "integrity": "sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw==", - "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } - } - }, - "@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.11.tgz", - "integrity": "sha512-YZWOw4HxXrotb5xsjMJUDlLgcDXSfO9eCmdl1bgW4+/lAGdkjaEvOnQ4p5WKKdUgSzO39dgPl0pTnfxm0OAXcg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", + "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-plugin-utils": "^7.16.7" } }, - "@babel/plugin-transform-numeric-separator": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.11.tgz", - "integrity": "sha512-3dzU4QGPsILdJbASKhF/V2TVP+gJya1PsueQCxIPCEcerqF21oEcrob4mzjsp2Py/1nLfF5m+xYNMDpmA8vffg==", + "@babel/plugin-transform-modules-amd": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", + "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "babel-plugin-dynamic-import-node": "^2.3.3" } }, - "@babel/plugin-transform-object-rest-spread": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.15.tgz", - "integrity": "sha512-fEB+I1+gAmfAyxZcX1+ZUwLeAuuf8VIg67CTznZE0MqVFumWkh8xWtn58I4dxdVf080wn7gzWoF8vndOViJe9Q==", + "@babel/plugin-transform-modules-commonjs": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", + "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", "requires": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.22.15" - }, - "dependencies": { - "@babel/compat-data": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", - "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==" - }, - "@babel/helper-compilation-targets": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", - "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", - "requires": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - }, - "@babel/helper-validator-option": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", - "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==" - }, - "browserslist": { - "version": "4.21.10", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", - "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", - "requires": { - "caniuse-lite": "^1.0.30001517", - "electron-to-chromium": "^1.4.477", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.11" - } - }, - "caniuse-lite": { - "version": "1.0.30001532", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001532.tgz", - "integrity": "sha512-FbDFnNat3nMnrROzqrsg314zhqN5LGQ1kyyMk2opcrwGbVGpHRhgCWtAgD5YJUqNAiQ+dklreil/c3Qf1dfCTw==" - }, - "electron-to-chromium": { - "version": "1.4.513", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.513.tgz", - "integrity": "sha512-cOB0xcInjm+E5qIssHeXJ29BaUyWpMyFKT5RB3bsLENDheCja0wMkHJyiPl0NBE/VzDI7JDuNEQWhe6RitEUcw==" - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "requires": { - "yallist": "^3.0.2" - } - }, - "node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - } + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", + "babel-plugin-dynamic-import-node": "^2.3.3" } }, - "@babel/plugin-transform-object-super": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz", - "integrity": "sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw==", + "@babel/plugin-transform-modules-systemjs": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", + "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "babel-plugin-dynamic-import-node": "^2.3.3" } }, - "@babel/plugin-transform-optional-catch-binding": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.11.tgz", - "integrity": "sha512-rli0WxesXUeCJnMYhzAglEjLWVDF6ahb45HuprcmQuLidBJFWjNnOzssk2kuc6e33FlLaiZhG/kUIzUMWdBKaQ==", + "@babel/plugin-transform-modules-umd": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", + "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, - "@babel/plugin-transform-optional-chaining": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.15.tgz", - "integrity": "sha512-ngQ2tBhq5vvSJw2Q2Z9i7ealNkpDMU0rGWnHPKqRZO0tzZ5tlaoz4hDvhXioOoaE0X2vfNss1djwg0DXlfu30A==", + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", + "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-create-regexp-features-plugin": "^7.16.7" } }, - "@babel/plugin-transform-parameters": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.15.tgz", - "integrity": "sha512-hjk7qKIqhyzhhUvRT683TYQOFa/4cQKwQy7ALvTpODswN40MljzNDa0YldevS6tGbxwaEKVn502JmY0dP7qEtQ==", + "@babel/plugin-transform-new-target": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", + "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-plugin-utils": "^7.16.7" } }, - "@babel/plugin-transform-private-methods": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.22.5.tgz", - "integrity": "sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA==", + "@babel/plugin-transform-object-super": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", + "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7" } }, - "@babel/plugin-transform-private-property-in-object": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.11.tgz", - "integrity": "sha512-sSCbqZDBKHetvjSwpyWzhuHkmW5RummxJBVbYLkGkaiTOWGxml7SXt0iWa03bzxFIx7wOj3g/ILRd0RcJKBeSQ==", + "@babel/plugin-transform-parameters": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", + "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", "requires": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.22.11", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, - "dependencies": { - "@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - }, - "@babel/helper-validator-identifier": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", - "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" - }, - "@babel/types": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", - "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.15", - "to-fast-properties": "^2.0.0" - } - } + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-property-literals": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz", - "integrity": "sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", + "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-regenerator": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.10.tgz", - "integrity": "sha512-F28b1mDt8KcT5bUyJc/U9nwzw6cV+UmTeRlXYIl2TNqMMJif0Jeey9/RQ3C4NOd2zp0/TRsDns9ttj2L523rsw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", + "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5", - "regenerator-transform": "^0.15.2" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "regenerator-transform": "^0.14.2" } }, "@babel/plugin-transform-reserved-words": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz", - "integrity": "sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", + "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-runtime": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.15.tgz", - "integrity": "sha512-tEVLhk8NRZSmwQ0DJtxxhTrCht1HVo8VaMzYT4w6lwyKBuHsgoioAUA7/6eT2fRfc5/23fuGdlwIxXhRVgWr4g==", - "requires": { - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", - "babel-plugin-polyfill-corejs2": "^0.4.5", - "babel-plugin-polyfill-corejs3": "^0.8.3", - "babel-plugin-polyfill-regenerator": "^0.5.2", - "semver": "^6.3.1" + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.17.0.tgz", + "integrity": "sha512-fr7zPWnKXNc1xoHfrIU9mN/4XKX4VLZ45Q+oMhfsYIaHvg7mHgmhfOy/ckRWqDK7XF3QDigRpkh5DKq6+clE8A==", + "requires": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "babel-plugin-polyfill-corejs2": "^0.3.0", + "babel-plugin-polyfill-corejs3": "^0.5.0", + "babel-plugin-polyfill-regenerator": "^0.3.0", + "semver": "^6.3.0" }, "dependencies": { - "@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", - "requires": { - "@babel/types": "^7.22.15" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - }, - "@babel/helper-validator-identifier": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", - "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" - }, - "@babel/types": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", - "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.15", - "to-fast-properties": "^2.0.0" - } - }, "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz", - "integrity": "sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", + "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-spread": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz", - "integrity": "sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", + "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz", - "integrity": "sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", + "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-template-literals": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz", - "integrity": "sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", + "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz", - "integrity": "sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", + "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-unicode-escapes": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.10.tgz", - "integrity": "sha512-lRfaRKGZCBqDlRU3UIFovdp9c9mEvlylmpod0/OatICsSfuQ9YFthRo1tpTkGsklEefZdqlEFdY4A2dwTb6ohg==", - "requires": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } - } - }, - "@babel/plugin-transform-unicode-property-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.5.tgz", - "integrity": "sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", + "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz", - "integrity": "sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } - } - }, - "@babel/plugin-transform-unicode-sets-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.5.tgz", - "integrity": "sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", + "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - } + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/preset-env": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.15.tgz", - "integrity": "sha512-tZFHr54GBkHk6hQuVA8w4Fmq+MSPsfvMG0vPnOYyTnJpyfMqybL8/MbNCPRT9zc2KBO2pe4tq15g6Uno4Jpoag==", - "requires": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-option": "^7.22.15", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.15", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.15", - "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "version": "7.16.11", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", + "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", + "requires": { + "@babel/compat-data": "^7.16.8", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-option": "^7.16.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", + "@babel/plugin-proposal-async-generator-functions": "^7.16.8", + "@babel/plugin-proposal-class-properties": "^7.16.7", + "@babel/plugin-proposal-class-static-block": "^7.16.7", + "@babel/plugin-proposal-dynamic-import": "^7.16.7", + "@babel/plugin-proposal-export-namespace-from": "^7.16.7", + "@babel/plugin-proposal-json-strings": "^7.16.7", + "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", + "@babel/plugin-proposal-numeric-separator": "^7.16.7", + "@babel/plugin-proposal-object-rest-spread": "^7.16.7", + "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", + "@babel/plugin-proposal-optional-chaining": "^7.16.7", + "@babel/plugin-proposal-private-methods": "^7.16.11", + "@babel/plugin-proposal-private-property-in-object": "^7.16.7", + "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.22.5", - "@babel/plugin-syntax-import-attributes": "^7.22.5", - "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", @@ -2403,252 +992,62 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.22.5", - "@babel/plugin-transform-async-generator-functions": "^7.22.15", - "@babel/plugin-transform-async-to-generator": "^7.22.5", - "@babel/plugin-transform-block-scoped-functions": "^7.22.5", - "@babel/plugin-transform-block-scoping": "^7.22.15", - "@babel/plugin-transform-class-properties": "^7.22.5", - "@babel/plugin-transform-class-static-block": "^7.22.11", - "@babel/plugin-transform-classes": "^7.22.15", - "@babel/plugin-transform-computed-properties": "^7.22.5", - "@babel/plugin-transform-destructuring": "^7.22.15", - "@babel/plugin-transform-dotall-regex": "^7.22.5", - "@babel/plugin-transform-duplicate-keys": "^7.22.5", - "@babel/plugin-transform-dynamic-import": "^7.22.11", - "@babel/plugin-transform-exponentiation-operator": "^7.22.5", - "@babel/plugin-transform-export-namespace-from": "^7.22.11", - "@babel/plugin-transform-for-of": "^7.22.15", - "@babel/plugin-transform-function-name": "^7.22.5", - "@babel/plugin-transform-json-strings": "^7.22.11", - "@babel/plugin-transform-literals": "^7.22.5", - "@babel/plugin-transform-logical-assignment-operators": "^7.22.11", - "@babel/plugin-transform-member-expression-literals": "^7.22.5", - "@babel/plugin-transform-modules-amd": "^7.22.5", - "@babel/plugin-transform-modules-commonjs": "^7.22.15", - "@babel/plugin-transform-modules-systemjs": "^7.22.11", - "@babel/plugin-transform-modules-umd": "^7.22.5", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", - "@babel/plugin-transform-new-target": "^7.22.5", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.11", - "@babel/plugin-transform-numeric-separator": "^7.22.11", - "@babel/plugin-transform-object-rest-spread": "^7.22.15", - "@babel/plugin-transform-object-super": "^7.22.5", - "@babel/plugin-transform-optional-catch-binding": "^7.22.11", - "@babel/plugin-transform-optional-chaining": "^7.22.15", - "@babel/plugin-transform-parameters": "^7.22.15", - "@babel/plugin-transform-private-methods": "^7.22.5", - "@babel/plugin-transform-private-property-in-object": "^7.22.11", - "@babel/plugin-transform-property-literals": "^7.22.5", - "@babel/plugin-transform-regenerator": "^7.22.10", - "@babel/plugin-transform-reserved-words": "^7.22.5", - "@babel/plugin-transform-shorthand-properties": "^7.22.5", - "@babel/plugin-transform-spread": "^7.22.5", - "@babel/plugin-transform-sticky-regex": "^7.22.5", - "@babel/plugin-transform-template-literals": "^7.22.5", - "@babel/plugin-transform-typeof-symbol": "^7.22.5", - "@babel/plugin-transform-unicode-escapes": "^7.22.10", - "@babel/plugin-transform-unicode-property-regex": "^7.22.5", - "@babel/plugin-transform-unicode-regex": "^7.22.5", - "@babel/plugin-transform-unicode-sets-regex": "^7.22.5", - "@babel/preset-modules": "0.1.6-no-external-plugins", - "@babel/types": "^7.22.15", - "babel-plugin-polyfill-corejs2": "^0.4.5", - "babel-plugin-polyfill-corejs3": "^0.8.3", - "babel-plugin-polyfill-regenerator": "^0.5.2", - "core-js-compat": "^3.31.0", - "semver": "^6.3.1" + "@babel/plugin-transform-arrow-functions": "^7.16.7", + "@babel/plugin-transform-async-to-generator": "^7.16.8", + "@babel/plugin-transform-block-scoped-functions": "^7.16.7", + "@babel/plugin-transform-block-scoping": "^7.16.7", + "@babel/plugin-transform-classes": "^7.16.7", + "@babel/plugin-transform-computed-properties": "^7.16.7", + "@babel/plugin-transform-destructuring": "^7.16.7", + "@babel/plugin-transform-dotall-regex": "^7.16.7", + "@babel/plugin-transform-duplicate-keys": "^7.16.7", + "@babel/plugin-transform-exponentiation-operator": "^7.16.7", + "@babel/plugin-transform-for-of": "^7.16.7", + "@babel/plugin-transform-function-name": "^7.16.7", + "@babel/plugin-transform-literals": "^7.16.7", + "@babel/plugin-transform-member-expression-literals": "^7.16.7", + "@babel/plugin-transform-modules-amd": "^7.16.7", + "@babel/plugin-transform-modules-commonjs": "^7.16.8", + "@babel/plugin-transform-modules-systemjs": "^7.16.7", + "@babel/plugin-transform-modules-umd": "^7.16.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", + "@babel/plugin-transform-new-target": "^7.16.7", + "@babel/plugin-transform-object-super": "^7.16.7", + "@babel/plugin-transform-parameters": "^7.16.7", + "@babel/plugin-transform-property-literals": "^7.16.7", + "@babel/plugin-transform-regenerator": "^7.16.7", + "@babel/plugin-transform-reserved-words": "^7.16.7", + "@babel/plugin-transform-shorthand-properties": "^7.16.7", + "@babel/plugin-transform-spread": "^7.16.7", + "@babel/plugin-transform-sticky-regex": "^7.16.7", + "@babel/plugin-transform-template-literals": "^7.16.7", + "@babel/plugin-transform-typeof-symbol": "^7.16.7", + "@babel/plugin-transform-unicode-escapes": "^7.16.7", + "@babel/plugin-transform-unicode-regex": "^7.16.7", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.16.8", + "babel-plugin-polyfill-corejs2": "^0.3.0", + "babel-plugin-polyfill-corejs3": "^0.5.0", + "babel-plugin-polyfill-regenerator": "^0.3.0", + "core-js-compat": "^3.20.2", + "semver": "^6.3.0" }, "dependencies": { - "@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "requires": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" - } - }, - "@babel/compat-data": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", - "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==" - }, - "@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", - "requires": { - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", - "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", - "requires": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - } - }, - "@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" - }, - "@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", - "requires": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" - } - }, - "@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", - "requires": { - "@babel/types": "^7.22.15" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.17.tgz", - "integrity": "sha512-bxH77R5gjH3Nkde6/LuncQoLaP16THYPscurp1S8z7S9ZgezCyV3G8Hc+TZiCmY8pz4fp8CvKSgtJMW0FkLAxA==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-wrap-function": "^7.22.17" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", - "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==" - }, - "@babel/helper-validator-option": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", - "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==" - }, - "@babel/helper-wrap-function": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.17.tgz", - "integrity": "sha512-nAhoheCMlrqU41tAojw9GpVEKDlTS8r3lzFmF0lP52LwblCPbuFSO7nGIZoIcoU5NIm1ABrna0cJExE4Ay6l2Q==", - "requires": { - "@babel/helper-function-name": "^7.22.5", - "@babel/template": "^7.22.15", - "@babel/types": "^7.22.17" - } - }, - "@babel/highlight": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", - "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", - "requires": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.22.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", - "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==" - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz", - "integrity": "sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ==", - "requires": { - "@babel/helper-module-imports": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-remap-async-to-generator": "^7.22.5" - } - }, - "@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - } - }, - "@babel/types": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", - "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.15", - "to-fast-properties": "^2.0.0" - } - }, - "browserslist": { - "version": "4.21.10", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", - "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", - "requires": { - "caniuse-lite": "^1.0.30001517", - "electron-to-chromium": "^1.4.477", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.11" - } - }, - "caniuse-lite": { - "version": "1.0.30001532", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001532.tgz", - "integrity": "sha512-FbDFnNat3nMnrROzqrsg314zhqN5LGQ1kyyMk2opcrwGbVGpHRhgCWtAgD5YJUqNAiQ+dklreil/c3Qf1dfCTw==" - }, - "electron-to-chromium": { - "version": "1.4.513", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.513.tgz", - "integrity": "sha512-cOB0xcInjm+E5qIssHeXJ29BaUyWpMyFKT5RB3bsLENDheCja0wMkHJyiPl0NBE/VzDI7JDuNEQWhe6RitEUcw==" - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "requires": { - "yallist": "^3.0.2" - } - }, - "node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" - }, "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, "@babel/preset-modules": { - "version": "0.1.6-no-external-plugins", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", - "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", "requires": { "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", "@babel/types": "^7.4.4", "esutils": "^2.0.2" } @@ -2665,11 +1064,6 @@ "source-map-support": "^0.5.16" } }, - "@babel/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" - }, "@babel/runtime": { "version": "7.17.2", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", @@ -4122,6 +2516,14 @@ } } }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "requires": { + "object.assign": "^4.1.0" + } + }, "babel-plugin-module-resolver": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-5.0.0.tgz", @@ -4183,42 +2585,37 @@ } }, "babel-plugin-polyfill-corejs2": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz", - "integrity": "sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", + "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", "requires": { - "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.4.2", - "semver": "^6.3.1" + "@babel/compat-data": "^7.13.11", + "@babel/helper-define-polyfill-provider": "^0.3.1", + "semver": "^6.1.1" }, "dependencies": { - "@babel/compat-data": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", - "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==" - }, "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, "babel-plugin-polyfill-corejs3": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.3.tgz", - "integrity": "sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", + "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", "requires": { - "@babel/helper-define-polyfill-provider": "^0.4.2", - "core-js-compat": "^3.31.0" + "@babel/helper-define-polyfill-provider": "^0.3.1", + "core-js-compat": "^3.21.0" } }, "babel-plugin-polyfill-regenerator": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz", - "integrity": "sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", + "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", "requires": { - "@babel/helper-define-polyfill-provider": "^0.4.2" + "@babel/helper-define-polyfill-provider": "^0.3.1" } }, "balanced-match": { @@ -4576,38 +2973,18 @@ "integrity": "sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==" }, "core-js-compat": { - "version": "3.32.2", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.32.2.tgz", - "integrity": "sha512-+GjlguTDINOijtVRUxrQOv3kfu9rl+qPNdX2LTbJ/ZyVTuxK+ksVSAGX1nHstu4hrv1En/uPTtWgq2gI5wt4AQ==", + "version": "3.21.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.1.tgz", + "integrity": "sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g==", "requires": { - "browserslist": "^4.21.10" + "browserslist": "^4.19.1", + "semver": "7.0.0" }, "dependencies": { - "browserslist": { - "version": "4.21.10", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", - "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", - "requires": { - "caniuse-lite": "^1.0.30001517", - "electron-to-chromium": "^1.4.477", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.11" - } - }, - "caniuse-lite": { - "version": "1.0.30001532", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001532.tgz", - "integrity": "sha512-FbDFnNat3nMnrROzqrsg314zhqN5LGQ1kyyMk2opcrwGbVGpHRhgCWtAgD5YJUqNAiQ+dklreil/c3Qf1dfCTw==" - }, - "electron-to-chromium": { - "version": "1.4.513", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.513.tgz", - "integrity": "sha512-cOB0xcInjm+E5qIssHeXJ29BaUyWpMyFKT5RB3bsLENDheCja0wMkHJyiPl0NBE/VzDI7JDuNEQWhe6RitEUcw==" - }, - "node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" } } }, @@ -6727,9 +5104,9 @@ } }, "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "requires": { "lru-cache": "^6.0.0" } @@ -7020,7 +5397,7 @@ "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" }, "lodash.merge": { "version": "4.6.2", @@ -7304,15 +5681,15 @@ } }, "mongoose": { - "version": "5.13.20", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.20.tgz", - "integrity": "sha512-TjGFa/XnJYt+wLmn8y9ssjyO2OhBMeEBtOHb9iJM16EWu2Du6L1Q6zSiEK2ziyYQM8agb4tumNIQFzqbxId7MA==", + "version": "5.13.15", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.15.tgz", + "integrity": "sha512-cxp1Gbb8yUWkaEbajdhspSaKzAvsIvOtRlYD87GN/P2QEUhpd6bIvebi36T6M0tIVAMauNaK9SPA055N3PwF8Q==", "requires": { "@types/bson": "1.x || 4.0.x", "@types/mongodb": "^3.5.27", "bson": "^1.1.4", "kareem": "2.3.2", - "mongodb": "3.7.4", + "mongodb": "3.7.3", "mongoose-legacy-pluralize": "1.0.2", "mpath": "0.8.4", "mquery": "3.2.5", @@ -7324,29 +5701,6 @@ "sliced": "1.0.1" }, "dependencies": { - "mongodb": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.4.tgz", - "integrity": "sha512-K5q8aBqEXMwWdVNh94UQTwZ6BejVbFhh1uB6c5FKtPE9eUMZPUO3sRZdgIEcHSrAWmxzpG/FeODDKL388sqRmw==", - "requires": { - "bl": "^2.2.1", - "bson": "^1.1.4", - "denque": "^1.4.1", - "optional-require": "^1.1.8", - "safe-buffer": "^5.1.2", - "saslprep": "^1.0.0" - }, - "dependencies": { - "optional-require": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.1.8.tgz", - "integrity": "sha512-jq83qaUb0wNg9Krv1c5OQ+58EK+vHde6aBPzLvPPqJm89UQWsvSuFy9X/OSNJnFeSOKo7btE0n8Nl2+nE+z5nA==", - "requires": { - "require-at": "^1.0.6" - } - } - } - }, "optional-require": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz", @@ -8399,11 +6753,6 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, - "prettier": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", - "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==" - }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -8516,9 +6865,9 @@ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" }, "regenerate-unicode-properties": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", - "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", + "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", "requires": { "regenerate": "^1.4.2" } @@ -8529,9 +6878,9 @@ "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" }, "regenerator-transform": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", - "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", + "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", "requires": { "@babel/runtime": "^7.8.4" } @@ -8565,22 +6914,27 @@ } }, "regexpu-core": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", + "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", "requires": { - "@babel/regjsgen": "^0.8.0", "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", + "regenerate-unicode-properties": "^10.0.1", + "regjsgen": "^0.6.0", + "regjsparser": "^0.8.2", "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" + "unicode-match-property-value-ecmascript": "^2.0.0" } }, + "regjsgen": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", + "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==" + }, "regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", + "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", "requires": { "jsesc": "~0.5.0" }, @@ -8588,7 +6942,7 @@ "jsesc": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==" + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" } } }, @@ -9477,29 +7831,20 @@ } }, "unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==" }, "unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", + "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==" }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, - "update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", diff --git a/package.json b/package.json index 509755c88..f9387e933 100644 --- a/package.json +++ b/package.json @@ -40,8 +40,8 @@ "@babel/core": "^7.10.2", "@babel/node": "^7.14.9", "@babel/plugin-transform-async-to-generator": "^7.10.1", - "@babel/plugin-transform-runtime": "^7.22.15", - "@babel/preset-env": "^7.22.15", + "@babel/plugin-transform-runtime": "^7.10.1", + "@babel/preset-env": "^7.10.2", "@babel/runtime": "^7.10.2", "@sentry/node": "^5.17.0", "async-exit-hook": "^2.0.1", @@ -58,12 +58,11 @@ "moment": "^2.29.4", "moment-timezone": "^0.5.35", "mongodb": "^3.7.3", - "mongoose": "^5.13.20", + "mongoose": "^5.13.15", "mongoose-validator": "^2.1.0", "node-cache": "^5.1.2", "node-datetime": "^2.0.3", "nodemailer": "^6.4.16", - "prettier": "^3.0.3", "redis": "^4.2.0", "uuid": "^3.4.0", "ws": "^8.8.1" From 9e74615fde0dcc10c98f419361bb69755f917a51 Mon Sep 17 00:00:00 2001 From: xaanders Date: Fri, 22 Sep 2023 19:58:43 -0400 Subject: [PATCH 029/272] feat: adding a initial functionality for adding new people to the map(maplocation controller, maplocation router, maplocation model) --- src/controllers/mapLocationsController.js | 69 +++++++++++++++++++++++ src/models/mapLocation.js | 42 ++++++++++++++ src/routes/mapLocationsRouter.js | 18 ++++++ src/startup/routes.js | 4 ++ 4 files changed, 133 insertions(+) create mode 100644 src/controllers/mapLocationsController.js create mode 100644 src/models/mapLocation.js create mode 100644 src/routes/mapLocationsRouter.js diff --git a/src/controllers/mapLocationsController.js b/src/controllers/mapLocationsController.js new file mode 100644 index 000000000..83526998d --- /dev/null +++ b/src/controllers/mapLocationsController.js @@ -0,0 +1,69 @@ +const mongoose = require('mongoose'); +const mapLocation = require('../models/mapLocation'); +const { hasPermission } = require('../utilities/permissions'); + +const mapLocationsController = function () { + const getAllLocations = function (req, res) { + console.log('controller:') + console.log(req.body) + + mapLocation.find({}) + .then(results => res.send(results).status(200)) + .catch(error => res.send(error).status(404)); + }; + const deleteLocation = async function (req, res) { + if (!await hasPermission(req.body.requestor.role, 'deleteTeam')) { + res.status(403).send({ error: 'You are not authorized to delete teams.' }); + return; + } + const { teamId } = req.params; + Team.findById(teamId, (error, record) => { + if (error || record === null) { + res.status(400).send({ error: 'No valid records found' }); + return; + } + const removeteamfromprofile = userProfile.updateMany({}, { $pull: { teams: record._id } }).exec(); + const deleteteam = record.remove(); + + Promise.all([removeteamfromprofile, deleteteam]) + .then(res.status(200).send({ message: ' Team successfully deleted and user profiles updated' })) + .catch((errors) => { + res.status(400).send(errors); + }); + }).catch((error) => { + res.status(400).send(error); + }); + }; + const putUserLocation = async function (req, res) { + if (!await hasPermission(req.body.requestor.role, 'putTeam')) { + res.status(403).send('You are not authorized to make changes in the teams.'); + return; + } + + const { teamId } = req.params; + + Team.findById(teamId, (error, record) => { + if (error || record === null) { + res.status(400).send('No valid records found'); + return; + } + record.teamName = req.body.teamName; + record.isActive = req.body.isActive; + record.createdDatetime = Date.now(); + record.modifiedDatetime = Date.now(); + + record + .save() + .then(results => res.status(201).send(results._id)) + .catch(errors => res.status(400).send(errors)); + }); + }; + + return { + getAllLocations, + deleteLocation, + putUserLocation + }; +}; + +module.exports = mapLocationsController; diff --git a/src/models/mapLocation.js b/src/models/mapLocation.js new file mode 100644 index 000000000..d7b9d82b5 --- /dev/null +++ b/src/models/mapLocation.js @@ -0,0 +1,42 @@ +const mongoose = require('mongoose'); + +const { Schema } = mongoose; + +const mapLocation = new Schema({ + firstName: { + type: String, + default: 'Prior to HGN Data Collection', + }, + lastName: { + type: String, + default: 'Prior to HGN Data Collection', + }, + title: { + type: String, + default: 'Prior to HGN Data Collection', + }, + userProvided: { + type: String, + required: true, + }, + coords: { + lat: { + type: String, + required: true, + }, + lng: { + type: String, + required: true, + } + }, + country: { + type: String, + required: true, + }, + city: { + type: String, + default: '', + } +}); + +module.exports = mongoose.model('MapLocation', mapLocation, 'maplocations'); diff --git a/src/routes/mapLocationsRouter.js b/src/routes/mapLocationsRouter.js new file mode 100644 index 000000000..e2e780dac --- /dev/null +++ b/src/routes/mapLocationsRouter.js @@ -0,0 +1,18 @@ +const express = require('express'); + +const router = function (mapLocations) { + const controller = require('../controllers/mapLocationsController')(mapLocations); + + const mapRouter = express.Router(); + + mapRouter.route('/mapLocations') + .get(controller.getAllLocations) + .put(controller.putUserLocation); + + mapRouter.route('/mapLocations/:locationId') + .delete(controller.deleteLocation) + + return mapRouter; +}; + +module.exports = router; diff --git a/src/startup/routes.js b/src/startup/routes.js index 6e000002e..ffe02ccc5 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -20,6 +20,7 @@ const ownerStandardMessage = require('../models/ownerStandardMessage'); const profileInitialSetuptoken = require('../models/profileInitialSetupToken'); const reason = require('../models/reason'); const mouseoverText = require('../models/mouseoverText'); +const mapLocations = require('../models/mapLocation'); const userProfileRouter = require('../routes/userProfileRouter')(userProfile); const badgeRouter = require('../routes/badgeRouter')(badge); @@ -53,6 +54,8 @@ const ownerStandardMessageRouter = require('../routes/ownerStandardMessageRouter const reasonRouter = require('../routes/reasonRouter')(reason, userProfile); const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverText); +const mapLocationRouter = require('../routes/mapLocationsRouter')(mapLocations); + module.exports = function (app) { app.use('/api', forgotPwdRouter); @@ -83,4 +86,5 @@ module.exports = function (app) { app.use('/api', reasonRouter); app.use('/api', informationRouter); app.use('/api', mouseoverTextRouter); + app.use('/api', mapLocationRouter); }; From 65f675eb60fc6de9f35274f9c4a67477596456ad Mon Sep 17 00:00:00 2001 From: navneeeth Date: Fri, 22 Sep 2023 19:25:14 -0700 Subject: [PATCH 030/272] updated controllers to check permissions for project management tab --- src/controllers/projectController.js | 14 ++++++++++---- src/controllers/userProfileController.js | 5 ++++- src/controllers/wbsController.js | 9 ++++++--- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/controllers/projectController.js b/src/controllers/projectController.js index 6bac2124c..d3e849498 100644 --- a/src/controllers/projectController.js +++ b/src/controllers/projectController.js @@ -2,7 +2,7 @@ const mongoose = require('mongoose'); const timeentry = require('../models/timeentry'); const userProfile = require('../models/userProfile'); const userProject = require('../helpers/helperModels/userProjects'); -const { hasPermission } = require('../utilities/permissions'); +const { hasPermission, hasIndividualPermission } = require('../utilities/permissions'); const escapeRegex = require('../utilities/escapeRegex'); @@ -15,7 +15,8 @@ const projectController = function (Project) { }; const deleteProject = function (req, res) { - if (!hasPermission(req.body.requestor.role, 'deleteProject')) { + if (!hasPermission(req.body.requestor.role, 'deleteProject') + && !hasIndividualPermission(req.body.requestor.requestorId, 'seeProjectManagement')) { res.status(403).send({ error: 'You are not authorized to delete projects.' }); return; } @@ -46,7 +47,8 @@ const projectController = function (Project) { }; const postProject = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'postProject')) { + if (!await hasPermission(req.body.requestor.role, 'postProject') + && !await hasIndividualPermission(req.body.requestor.requestorId, 'seeProjectManagement')) { res.status(403).send({ error: 'You are not authorized to create new projects.' }); return; } @@ -77,7 +79,8 @@ const projectController = function (Project) { const putProject = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'putProject')) { + if (!await hasPermission(req.body.requestor.role, 'putProject') + && !await hasIndividualPermission(req.body.requestor.requestorId, 'seeProjectManagement')) { res.status(403).send('You are not authorized to make changes in the projects.'); return; } @@ -125,8 +128,11 @@ const projectController = function (Project) { // verify requestor is administrator, projectId is passed in request params and is valid mongoose objectid, and request body contains an array of users if (!await hasPermission(req.body.requestor.role, 'assignProjectToUsers')) { + if (!await hasIndividualPermission(req.body.requestor.requestorId, 'seeProjectManagement') + && !await hasIndividualPermission(req.body.requestor.requestorId, 'seeProjectManagementTab')) { res.status(403).send({ error: 'You are not authorized to perform this operation' }); return; + } } if (!req.params.projectId || !mongoose.Types.ObjectId.isValid(req.params.projectId) || !req.body.users || (req.body.users.length === 0)) { diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 5f36e91a2..35f3ff395 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -12,7 +12,7 @@ const Badge = require('../models/badge'); const userProfile = require('../models/userProfile'); const yearMonthDayDateValidator = require('../utilities/yearMonthDayDateValidator'); const cache = require('../utilities/nodeCache')(); -const { hasPermission, canRequestorUpdateUser } = require('../utilities/permissions'); +const { hasPermission, hasIndividualPermission, canRequestorUpdateUser } = require('../utilities/permissions'); const escapeRegex = require('../utilities/escapeRegex'); const config = require('../config'); @@ -53,8 +53,11 @@ async function ValidatePassword(req, res) { const userProfileController = function (UserProfile) { const getUserProfiles = async function (req, res) { if (!await hasPermission(req.body.requestor.role, 'getUserProfiles')) { + if (!await hasIndividualPermission(req.body.requestor.requestorId, 'seeProjectManagement') + && !await hasIndividualPermission(req.body.requestor.requestorId, 'seeProjectManagementTab')) { res.status(403).send('You are not authorized to view all users'); return; + } } if (cache.getCache('allusers')) { diff --git a/src/controllers/wbsController.js b/src/controllers/wbsController.js index 48b640061..815fc59d0 100644 --- a/src/controllers/wbsController.js +++ b/src/controllers/wbsController.js @@ -1,4 +1,4 @@ -const { hasPermission } = require('../utilities/permissions'); +const { hasPermission, hasIndividualPermission } = require('../utilities/permissions'); const wbsController = function (WBS) { const getAllWBS = function (req, res) { @@ -11,7 +11,9 @@ const wbsController = function (WBS) { }; const postWBS = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'postWbs')) { + if (!await hasPermission(req.body.requestor.role, 'postWbs') + && !await hasIndividualPermission(req.body.requestor.requestorId, 'seeProjectManagement') + && !await hasIndividualPermission(req.body.requestor.requestorId, 'seeProjectManagementTab')) { res.status(403).send({ error: 'You are not authorized to create new projects.' }); return; } @@ -34,7 +36,8 @@ const wbsController = function (WBS) { }; const deleteWBS = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'deleteWbs')) { + if (!await hasPermission(req.body.requestor.role, 'deleteWbs') + && !await hasIndividualPermission(req.body.requestor.requestorId, 'seeProjectManagement')) { res.status(403).send({ error: 'You are not authorized to delete projects.' }); return; } From d4f4ae237dd163dd4d839ec74618058c692aeef1 Mon Sep 17 00:00:00 2001 From: tsunami776 <43768723+tsunami776@users.noreply.github.com> Date: Sat, 23 Sep 2023 13:00:23 -0500 Subject: [PATCH 031/272] A possible fix for late update of user profiles --- src/controllers/userProfileController.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 5f36e91a2..292ee17ed 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -57,12 +57,6 @@ const userProfileController = function (UserProfile) { return; } - if (cache.getCache('allusers')) { - const getData = JSON.parse(cache.getCache('allusers')); - res.status(200).send(getData); - return; - } - UserProfile.find( {}, '_id firstName lastName role weeklycommittedHours email permissions isActive reactivationDate createdDate endDate', @@ -79,6 +73,12 @@ const userProfileController = function (UserProfile) { res.status(200).send(results); }) .catch(error => res.status(404).send(error)); + + if (cache.getCache('allusers')) { + const getData = JSON.parse(cache.getCache('allusers')); + res.status(200).send(getData); + return; + } }; const getProjectMembers = async function (req, res) { From 2987b20350f29e5324d13f8b65170cd70e7fef67 Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Mon, 25 Sep 2023 10:22:18 +0800 Subject: [PATCH 032/272] fix create new user issue --- src/controllers/profileInitialSetupController.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/controllers/profileInitialSetupController.js b/src/controllers/profileInitialSetupController.js index d5c955d88..01d497865 100644 --- a/src/controllers/profileInitialSetupController.js +++ b/src/controllers/profileInitialSetupController.js @@ -184,6 +184,7 @@ const profileInitialSetupController = function (ProfileInitialSetupToken, userPr newUser.bioPosted = 'default'; newUser.privacySettings.email = req.body.privacySettings.email newUser.privacySettings.phoneNumber = req.body.privacySettings.phoneNumber + newUser.teamCode = ''; const savedUser = await newUser.save(); emailSender( From 0b50204c4971a6688be51cb76b9d39b63530979d Mon Sep 17 00:00:00 2001 From: Nathan Hoffman Date: Mon, 25 Sep 2023 17:06:27 -0700 Subject: [PATCH 033/272] Create role preset model/API --- src/controllers/rolePresetsController.js | 79 +++++++++++++++++++++++ src/models/rolePreset.js | 14 ++++ src/routes/rolePresetRouter.js | 20 ++++++ src/startup/routes.js | 5 +- src/utilities/createInitialPermissions.js | 23 +++++++ 5 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 src/controllers/rolePresetsController.js create mode 100644 src/models/rolePreset.js create mode 100644 src/routes/rolePresetRouter.js diff --git a/src/controllers/rolePresetsController.js b/src/controllers/rolePresetsController.js new file mode 100644 index 000000000..63c182577 --- /dev/null +++ b/src/controllers/rolePresetsController.js @@ -0,0 +1,79 @@ +const { hasPermission } = require('../utilities/permissions'); + +const rolePresetsController = function (Preset) { + const getPresetsByRole = async function (req, res) { + if (!await hasPermission(req.body.requestor.role, 'putRole')) { + res.status(403).send('You are not authorized to make changes to roles.'); + return; + } + + const { roleName } = req.params; + Preset.find({ roleName }) + .then((results) => { res.status(200).send(results); }) + .catch((error) => { res.status(400).send(error); }); + }; + + const createNewPreset = async function (req, res) { + if (!await hasPermission(req.body.requestor.role, 'putRole')) { + res.status(403).send('You are not authorized to make changes to roles.'); + return; + } + + if (!req.body.roleName || !req.body.presetName || !req.body.permissions) { + res.status(400).send({ error: 'roleName, presetName, and permissions are mandatory fields.' }); + return; + } + + const preset = new Preset(); + preset.roleName = req.body.roleName; + preset.presetName = req.body.presetName; + preset.permissions = req.body.permissions; + preset.save() + .then(res.status(200).send({ message: 'New preset created' })) + .catch(error => res.status(400).send({ error })); + }; + + const updatePresetById = async function (req, res) { + if (!await hasPermission(req.body.requestor.role, 'putRole')) { + res.status(403).send('You are not authorized to make changes to roles.'); + return; + } + + const { presetId } = req.params; + Preset.findById(presetId) + .then((record) => { + record.roleName = req.body.roleName; + record.presetName = req.body.presetName; + record.permissions = req.body.permissions; + record.save() + .then(results => res.status(201).send(results)) + .catch(errors => res.status(400).send(errors)); + }) + .catch(error => res.status(400).send({ error })); + }; + + const deletePresetById = async function (req, res) { + if (!await hasPermission(req.body.requestor.role, 'putRole')) { + res.status(403).send('You are not authorized to make changes to roles.'); + return; + } + + const { presetId } = req.params; + Preset.findById(presetId) + .then((result) => { + result.remove() + .then(res.status(200).send({ message: 'Deleted preset' })) + .catch(error => res.status(400).send({ error })); + }) + .catch(error => res.status(400).send({ error })); + }; + + return { + getPresetsByRole, + createNewPreset, + updatePresetById, + deletePresetById, + }; +}; + +module.exports = rolePresetsController; diff --git a/src/models/rolePreset.js b/src/models/rolePreset.js new file mode 100644 index 000000000..1bf785e2d --- /dev/null +++ b/src/models/rolePreset.js @@ -0,0 +1,14 @@ +const mongoose = require('mongoose'); + +const { Schema } = mongoose; + + +const RolePermissionPresets = new Schema({ + roleName: { type: String, required: true }, + presetName: { type: String, required: true }, + permissions: [String], +}); + +// RolePermissionPresets.createIndex({ roleName: 1, presetName: 1 }, { unique: true }); + +module.exports = mongoose.model('rolePermissionPresets', RolePermissionPresets, 'rolePermissionPresets'); diff --git a/src/routes/rolePresetRouter.js b/src/routes/rolePresetRouter.js new file mode 100644 index 000000000..8b522c7ee --- /dev/null +++ b/src/routes/rolePresetRouter.js @@ -0,0 +1,20 @@ +const express = require('express'); + +const routes = function (rolePreset) { + const controller = require('../controllers/rolePresetsController')(rolePreset); + const PresetsRouter = express.Router(); + + PresetsRouter.route('/rolePreset') + .post(controller.createNewPreset); + + PresetsRouter.route('/rolePreset/:roleName') + .get(controller.getPresetsByRole); + + PresetsRouter.route('/rolePreset/:presetId') + .put(controller.updatePresetById) + .delete(controller.deletePresetById); + +return PresetsRouter; +}; + +module.exports = routes; diff --git a/src/startup/routes.js b/src/startup/routes.js index 6e000002e..665792ba6 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -15,6 +15,7 @@ const badge = require('../models/badge'); const inventoryItem = require('../models/inventoryItem'); const inventoryItemType = require('../models/inventoryItemType'); const role = require('../models/role'); +const rolePreset = require('../models/rolePreset'); const ownerMessage = require('../models/ownerMessage'); const ownerStandardMessage = require('../models/ownerStandardMessage'); const profileInitialSetuptoken = require('../models/profileInitialSetupToken'); @@ -47,6 +48,7 @@ const profileInitialSetupRouter = require('../routes/profileInitialSetupRouter') const taskEditSuggestion = require('../models/taskEditSuggestion'); const taskEditSuggestionRouter = require('../routes/taskEditSuggestionRouter')(taskEditSuggestion); const roleRouter = require('../routes/roleRouter')(role); +const rolePresetRouter = require('../routes/rolePresetRouter')(rolePreset); const ownerMessageRouter = require('../routes/ownerMessageRouter')(ownerMessage); const ownerStandardMessageRouter = require('../routes/ownerStandardMessageRouter')(ownerStandardMessage); @@ -77,9 +79,10 @@ module.exports = function (app) { app.use('/api', timeZoneAPIRouter); app.use('/api', taskEditSuggestionRouter); app.use('/api', roleRouter); + app.use('/api', rolePresetRouter); app.use('/api', ownerMessageRouter); app.use('/api', ownerStandardMessageRouter); - app.use('/api', profileInitialSetupRouter) + app.use('/api', profileInitialSetupRouter); app.use('/api', reasonRouter); app.use('/api', informationRouter); app.use('/api', mouseoverTextRouter); diff --git a/src/utilities/createInitialPermissions.js b/src/utilities/createInitialPermissions.js index 9ac0f12b0..a5c69d87f 100644 --- a/src/utilities/createInitialPermissions.js +++ b/src/utilities/createInitialPermissions.js @@ -1,4 +1,5 @@ const Role = require('../models/role'); +const RolePreset = require('../models/rolePreset'); const User = require('../models/userProfile'); const permissionsRoles = [ @@ -222,6 +223,7 @@ const createInitialPermissions = async () => { // Get Roles From DB const allRoles = await Role.find(); + const allPresets = await RolePreset.find(); const onlyUpdateOwner = false; const promises = []; @@ -249,6 +251,27 @@ const createInitialPermissions = async () => { })); } } + + // Update Default presets + const presetDataBase = allPresets.find(preset => preset.roleName === roleName && preset.presetName === 'default'); + + // If role does not exist in db, create it + if (!presetDataBase) { + const defaultPreset = new RolePreset(); + defaultPreset.roleName = roleName; + defaultPreset.presetName = 'default'; + 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))) { + const roleId = presetDataBase._id; + + promises.push(Role.findById(roleId, (_, record) => { + record.permissions = permissions; + record.save(); + })); + } } await Promise.all(promises); }; From 5d732a8a224579bb44af576e9f26a86bfb1d134a Mon Sep 17 00:00:00 2001 From: Nathan Hoffman Date: Mon, 25 Sep 2023 17:29:36 -0700 Subject: [PATCH 034/272] Fix hasPermission() to include individual perms --- src/utilities/permissions.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/utilities/permissions.js b/src/utilities/permissions.js index e00d864f2..2e2ac4194 100644 --- a/src/utilities/permissions.js +++ b/src/utilities/permissions.js @@ -1,15 +1,19 @@ const Role = require('../models/role'); -const UserProfile = require('../models/userProfile'); +const UserProfile = require('../models/userProfile'); -const hasPermission = async (role, action) => Role.findOne({ roleName: role }) - .exec() - .then(({ permissions }) => permissions.includes(action)); + +const hasRolePermission = async (role, action) => Role.findOne({ roleName: role }) + .exec() + .then(({ permissions }) => permissions.includes(action)); const hasIndividualPermission = async (userId, action) => UserProfile.findById(userId) .select('permissions') .exec() .then(({ permissions }) => permissions.frontPermissions.includes(action)); + +const hasPermission = async (requestor, action) => 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 @@ -29,4 +33,4 @@ const canRequestorUpdateUser = (requestorId, userId) => { return !(protectedIds.includes(userId) && !allowedIds.includes(requestorId)); }; -module.exports = { hasPermission, hasIndividualPermission, canRequestorUpdateUser }; +module.exports = { hasPermission, canRequestorUpdateUser }; From 7c70e5de5a3655c8c98f19e5b080266793b66c3f Mon Sep 17 00:00:00 2001 From: Nathan Hoffman Date: Mon, 25 Sep 2023 17:30:20 -0700 Subject: [PATCH 035/272] updated hasPermission() calls for updated params --- src/controllers/badgeController.js | 12 +++---- src/controllers/inventoryController.js | 26 ++++++++-------- .../popupEditorBackupController.js | 4 +-- src/controllers/popupEditorController.js | 4 +-- src/controllers/projectController.js | 12 +++---- src/controllers/reportsController.js | 4 +-- src/controllers/rolesController.js | 6 ++-- src/controllers/taskController.js | 14 ++++----- src/controllers/teamController.js | 8 ++--- src/controllers/timeEntryController.js | 6 ++-- src/controllers/timeZoneAPIController.js | 3 +- src/controllers/userProfileController.js | 31 +++++++++---------- src/controllers/wbsController.js | 4 +-- 13 files changed, 66 insertions(+), 68 deletions(-) diff --git a/src/controllers/badgeController.js b/src/controllers/badgeController.js index 6238c381e..62bad6399 100644 --- a/src/controllers/badgeController.js +++ b/src/controllers/badgeController.js @@ -1,11 +1,11 @@ const mongoose = require('mongoose'); const UserProfile = require('../models/userProfile'); -const { hasPermission, hasIndividualPermission } = require('../utilities/permissions'); +const { hasPermission } = require('../utilities/permissions'); const escapeRegex = require('../utilities/escapeRegex'); const badgeController = function (Badge) { const getAllBadges = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'seeBadges') && !await hasIndividualPermission(req.body.requestor.requestorId, 'seeBadges')) { + if (!await hasPermission(req.body.requestor, 'seeBadges')) { res.status(403).send('You are not authorized to view all badge data.'); return; } @@ -26,7 +26,7 @@ const badgeController = function (Badge) { }; const assignBadges = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'assignBadges')) { + if (!await hasPermission(req.body.requestor, 'assignBadges')) { res.status(403).send('You are not authorized to assign badges.'); return; } @@ -57,7 +57,7 @@ const badgeController = function (Badge) { }; const postBadge = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'createBadges')) { + if (!await hasPermission(req.body.requestor, 'createBadges')) { res.status(403).send({ error: 'You are not authorized to create new badges.' }); return; } @@ -91,7 +91,7 @@ const badgeController = function (Badge) { }; const deleteBadge = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'deleteBadges')) { + if (!await hasPermission(req.body.requestor, 'deleteBadges')) { res.status(403).send({ error: 'You are not authorized to delete badges.' }); return; } @@ -112,7 +112,7 @@ const badgeController = function (Badge) { }; const putBadge = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'updateBadges')) { + if (!await hasPermission(req.body.requestor, 'updateBadges')) { res.status(403).send({ error: 'You are not authorized to update badges.' }); return; } diff --git a/src/controllers/inventoryController.js b/src/controllers/inventoryController.js index bc0902aeb..f1e00402d 100644 --- a/src/controllers/inventoryController.js +++ b/src/controllers/inventoryController.js @@ -7,7 +7,7 @@ const escapeRegex = require('../utilities/escapeRegex'); const inventoryController = function (Item, ItemType) { const getAllInvInProjectWBS = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'getAllInvInProjectWBS')) { + if (!await hasPermission(req.body.requestor, 'getAllInvInProjectWBS')) { return res.status(403).send('You are not authorized to view inventory data.'); } // use req.params.projectId and wbsId @@ -40,7 +40,7 @@ const inventoryController = function (Item, ItemType) { }; const postInvInProjectWBS = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'postInvInProjectWBS')) { + if (!await hasPermission(req.body.requestor, 'postInvInProjectWBS')) { return res.status(403).send('You are not authorized to view inventory data.'); } // use req.body.projectId and req.body.wbsId req.body.quantity, @@ -108,7 +108,7 @@ const inventoryController = function (Item, ItemType) { const getAllInvInProject = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'getAllInvInProject')) { + if (!await hasPermission(req.body.requestor, 'getAllInvInProject')) { return res.status(403).send('You are not authorized to view inventory data.'); } // same as getAllInvInProjectWBS but just using only the project to find the items of inventory @@ -140,7 +140,7 @@ const inventoryController = function (Item, ItemType) { }; const postInvInProject = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'postInvInProject')) { + if (!await hasPermission(req.body.requestor, 'postInvInProject')) { return res.status(403).send('You are not authorized to post new inventory data.'); } // same as posting an item inProjectWBS but the WBS is uanassigned(i.e. null) @@ -194,7 +194,7 @@ const inventoryController = function (Item, ItemType) { }; const transferInvById = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'transferInvById')) { + if (!await hasPermission(req.body.requestor, 'transferInvById')) { return res.status(403).send('You are not authorized to transfer inventory data.'); } // This function transfer inventory by id @@ -283,7 +283,7 @@ const inventoryController = function (Item, ItemType) { const delInvById = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'delInvById')) { + if (!await hasPermission(req.body.requestor, 'delInvById')) { return res.status(403).send('You are not authorized to waste inventory.'); } // send result just sending something now to have it work and not break anything @@ -372,7 +372,7 @@ const inventoryController = function (Item, ItemType) { }; const unWasteInvById = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'unWasteInvById')) { + if (!await hasPermission(req.body.requestor, 'unWasteInvById')) { return res.status(403).send('You are not authorized to unwaste inventory.'); } const properUnWaste = await Item.findOne({ _id: req.params.invId, quantity: { $gte: req.body.quantity }, wasted: true }).select('_id').lean(); @@ -453,7 +453,7 @@ const inventoryController = function (Item, ItemType) { }; const getInvIdInfo = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'getInvIdInfo')) { + if (!await hasPermission(req.body.requestor, 'getInvIdInfo')) { return res.status(403).send('You are not authorized to get inventory by id.'); } // req.params.invId @@ -465,7 +465,7 @@ const inventoryController = function (Item, ItemType) { }; const putInvById = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'putInvById')) { + if (!await hasPermission(req.body.requestor, 'putInvById')) { return res.status(403).send('You are not authorized to edit inventory by id.'); } // update the inv by id. @@ -493,7 +493,7 @@ const inventoryController = function (Item, ItemType) { }; const getInvTypeById = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'getInvTypeById')) { + if (!await hasPermission(req.body.requestor, 'getInvTypeById')) { return res.status(403).send('You are not authorized to get inv type by id.'); } // send result just sending something now to have it work and not break anything @@ -504,7 +504,7 @@ const inventoryController = function (Item, ItemType) { }; const putInvType = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'putInvType')) { + if (!await hasPermission(req.body.requestor, 'putInvType')) { return res.status(403).send('You are not authorized to edit an inventory type.'); } const { typeId } = req.params; @@ -527,7 +527,7 @@ const inventoryController = function (Item, ItemType) { }; const getAllInvType = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'getAllInvType')) { + if (!await hasPermission(req.body.requestor, 'getAllInvType')) { return res.status(403).send('You are not authorized to get all inventory.'); } // send result just sending something now to have it work and not break anything @@ -537,7 +537,7 @@ const inventoryController = function (Item, ItemType) { }; const postInvType = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'postInvType')) { + if (!await hasPermission(req.body.requestor, 'postInvType')) { return res.status(403).send('You are not authorized to save an inventory type.'); } return ItemType.find({ name: { $regex: escapeRegex(req.body.name), $options: 'i' } }) diff --git a/src/controllers/popupEditorBackupController.js b/src/controllers/popupEditorBackupController.js index 7b2493909..21eccaf8f 100644 --- a/src/controllers/popupEditorBackupController.js +++ b/src/controllers/popupEditorBackupController.js @@ -20,7 +20,7 @@ const popupEditorBackupController = function (PopupEditorBackups) { const createPopupEditorBackup = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'createPopup')) { + if (!await hasPermission(req.body.requestor, 'createPopup')) { res .status(403) .send({ error: 'You are not authorized to create new popup' }); @@ -46,7 +46,7 @@ const popupEditorBackupController = function (PopupEditorBackups) { }; const updatePopupEditorBackup = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'updatePopup')) { + if (!await hasPermission(req.body.requestor, 'updatePopup')) { res .status(403) .send({ error: 'You are not authorized to create new popup' }); diff --git a/src/controllers/popupEditorController.js b/src/controllers/popupEditorController.js index 25eed80dd..71dcb7b69 100644 --- a/src/controllers/popupEditorController.js +++ b/src/controllers/popupEditorController.js @@ -15,7 +15,7 @@ const popupEditorController = function (PopupEditors) { const createPopupEditor = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'createPopup')) { + if (!await hasPermission(req.body.requestor, 'createPopup')) { res .status(403) .send({ error: 'You are not authorized to create new popup' }); @@ -38,7 +38,7 @@ const popupEditorController = function (PopupEditors) { }; const updatePopupEditor = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'updatePopup')) { + if (!await hasPermission(req.body.requestor, 'updatePopup')) { res .status(403) .send({ error: 'You are not authorized to create new popup' }); diff --git a/src/controllers/projectController.js b/src/controllers/projectController.js index 6bac2124c..a88378985 100644 --- a/src/controllers/projectController.js +++ b/src/controllers/projectController.js @@ -14,9 +14,9 @@ const projectController = function (Project) { .catch(error => res.status(404).send(error)); }; - const deleteProject = function (req, res) { - if (!hasPermission(req.body.requestor.role, 'deleteProject')) { - res.status(403).send({ error: 'You are not authorized to delete projects.' }); + const deleteProject = async function (req, res) { + if (!await hasPermission(req.body.requestor, 'deleteProject')) { + res.status(403).send({ error: 'You are not authorized to delete projects.' }); return; } const { projectId } = req.params; @@ -46,7 +46,7 @@ const projectController = function (Project) { }; const postProject = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'postProject')) { + if (!await hasPermission(req.body.requestor, 'postProject')) { res.status(403).send({ error: 'You are not authorized to create new projects.' }); return; } @@ -77,7 +77,7 @@ const projectController = function (Project) { const putProject = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'putProject')) { + if (!await hasPermission(req.body.requestor, 'putProject')) { res.status(403).send('You are not authorized to make changes in the projects.'); return; } @@ -124,7 +124,7 @@ const projectController = function (Project) { const assignProjectToUsers = async function (req, res) { // verify requestor is administrator, projectId is passed in request params and is valid mongoose objectid, and request body contains an array of users - if (!await hasPermission(req.body.requestor.role, 'assignProjectToUsers')) { + if (!await hasPermission(req.body.requestor, 'assignProjectToUsers')) { res.status(403).send({ error: 'You are not authorized to perform this operation' }); return; } diff --git a/src/controllers/reportsController.js b/src/controllers/reportsController.js index e139924fa..8f4aba87b 100644 --- a/src/controllers/reportsController.js +++ b/src/controllers/reportsController.js @@ -1,9 +1,9 @@ const reporthelper = require('../helpers/reporthelper')(); -const { hasPermission, hasIndividualPermission } = require('../utilities/permissions'); +const { hasPermission } = require('../utilities/permissions'); const reportsController = function () { const getWeeklySummaries = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'getWeeklySummaries') && !await hasIndividualPermission(req.body.requestor.requestorId, 'getWeeklySummaries')) { + if (!await hasPermission(req.body.requestor, 'getWeeklySummaries')) { res.status(403).send('You are not authorized to view all users'); return; } diff --git a/src/controllers/rolesController.js b/src/controllers/rolesController.js index a97e9408f..d3d9f8310 100644 --- a/src/controllers/rolesController.js +++ b/src/controllers/rolesController.js @@ -10,7 +10,7 @@ const rolesController = function (Role) { }; const createNewRole = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'postRole')) { + if (!await hasPermission(req.body.requestor, 'postRole')) { res.status(403).send('You are not authorized to create new roles.'); return; } @@ -39,7 +39,7 @@ const rolesController = function (Role) { const updateRoleById = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'putRole')) { + if (!await hasPermission(req.body.requestor, 'putRole')) { res.status(403).send('You are not authorized to make changes to roles.'); return; } @@ -67,7 +67,7 @@ const rolesController = function (Role) { }; const deleteRoleById = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'deleteRole')) { + if (!await hasPermission(req.body.requestor, 'deleteRole')) { res.status(403).send('You are not authorized to delete roles.'); return; } diff --git a/src/controllers/taskController.js b/src/controllers/taskController.js index 79222ed4b..d5e048537 100644 --- a/src/controllers/taskController.js +++ b/src/controllers/taskController.js @@ -390,7 +390,7 @@ const taskController = function (Task) { }; const importTask = async (req, res) => { - if (!await hasPermission(req.body.requestor.role, 'importTask')) { + if (!await hasPermission(req.body.requestor, 'importTask')) { res .status(403) .send({ error: 'You are not authorized to create new Task.' }); @@ -420,7 +420,7 @@ const taskController = function (Task) { }; const postTask = async (req, res) => { - if (!await hasPermission(req.body.requestor.role, 'postTask')) { + if (!await hasPermission(req.body.requestor, 'postTask')) { res .status(403) .send({ error: 'You are not authorized to create new Task.' }); @@ -456,7 +456,7 @@ const taskController = function (Task) { }; const updateNum = async (req, res) => { - if (!await hasPermission(req.body.requestor.role, 'updateNum')) { + if (!await hasPermission(req.body.requestor, 'updateNum')) { res .status(403) .send({ error: 'You are not authorized to create new projects.' }); @@ -593,7 +593,7 @@ const taskController = function (Task) { }; const deleteTask = async (req, res) => { - if (!await hasPermission(req.body.requestor.role, 'deleteTask')) { + if (!await hasPermission(req.body.requestor, 'deleteTask')) { res .status(403) .send({ error: 'You are not authorized to deleteTasks.' }); @@ -642,7 +642,7 @@ const taskController = function (Task) { }; const deleteTaskByWBS = async (req, res) => { - if (!await hasPermission(req.body.requestor.role, 'deleteTask')) { + if (!await hasPermission(req.body.requestor, 'deleteTask')) { res .status(403) .send({ error: 'You are not authorized to deleteTasks.' }); @@ -673,7 +673,7 @@ const taskController = function (Task) { }; const updateTask = async (req, res) => { - if (!await hasPermission(req.body.requestor.role, 'updateTask')) { + if (!await hasPermission(req.body.requestor, 'updateTask')) { res.status(403).send({ error: 'You are not authorized to update Task.' }); return; } @@ -689,7 +689,7 @@ const taskController = function (Task) { }; const swap = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'swapTask')) { + if (!await hasPermission(req.body.requestor, 'swapTask')) { res .status(403) .send({ error: 'You are not authorized to create new projects.' }); diff --git a/src/controllers/teamController.js b/src/controllers/teamController.js index 1072f1fb4..0486a5df7 100644 --- a/src/controllers/teamController.js +++ b/src/controllers/teamController.js @@ -17,7 +17,7 @@ const teamcontroller = function (Team) { .catch(error => res.send(error).status(404)); }; const postTeam = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'postTeam')) { + if (!await hasPermission(req.body.requestor, 'postTeam')) { res.status(403).send({ error: 'You are not authorized to create teams.' }); return; } @@ -34,7 +34,7 @@ const teamcontroller = function (Team) { .catch(error => res.send(error).status(404)); }; const deleteTeam = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'deleteTeam')) { + if (!await hasPermission(req.body.requestor, 'deleteTeam')) { res.status(403).send({ error: 'You are not authorized to delete teams.' }); return; } @@ -57,7 +57,7 @@ const teamcontroller = function (Team) { }); }; const putTeam = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'putTeam')) { + if (!await hasPermission(req.body.requestor, 'putTeam')) { res.status(403).send('You are not authorized to make changes in the teams.'); return; } @@ -84,7 +84,7 @@ const teamcontroller = function (Team) { const assignTeamToUsers = async function (req, res) { // verify requestor is administrator, teamId is passed in request params and is valid mongoose objectid, and request body contains an array of users - if (!await hasPermission(req.body.requestor.role, 'assignTeamToUsers')) { + if (!await hasPermission(req.body.requestor, 'assignTeamToUsers')) { res.status(403).send({ error: 'You are not authorized to perform this operation' }); return; } diff --git a/src/controllers/timeEntryController.js b/src/controllers/timeEntryController.js index e83a7e31b..6b13d9331 100644 --- a/src/controllers/timeEntryController.js +++ b/src/controllers/timeEntryController.js @@ -106,7 +106,7 @@ const timeEntrycontroller = function (TimeEntry) { return res.status(400).send({ error: `No valid records found for ${req.params.timeEntryId}` }); } - if (!(await hasPermission(req.body.requestor.role, 'editTimeEntry') || timeEntry.personId.toString() === req.body.requestor.requestorId.toString())) { + if (!(await hasPermission(req.body.requestor, 'editTimeEntry') || timeEntry.personId.toString() === req.body.requestor.requestorId.toString())) { return res.status(403).send({ error: 'Unauthorized request' }); } @@ -153,7 +153,7 @@ const timeEntrycontroller = function (TimeEntry) { if (initialSeconds !== totalSeconds && timeEntry.isTangible && req.body.requestor.requestorId === timeEntry.personId.toString() - && !await hasPermission(req.body.requestor.role, 'editTimeEntry') + && !await hasPermission(req.body.requestor, 'editTimeEntry') ) { const requestor = await userProfile.findById(req.body.requestor.requestorId); requestor.timeEntryEditHistory.push({ @@ -463,7 +463,7 @@ const timeEntrycontroller = function (TimeEntry) { if ( record.personId.toString() === req.body.requestor.requestorId.toString() - || await hasPermission(req.body.requestor.role, 'deleteTimeEntry') + || await hasPermission(req.body.requestor, 'deleteTimeEntry') ) { // Revert this tangible timeEntry of related task's hoursLogged if (record.isTangible === true) { diff --git a/src/controllers/timeZoneAPIController.js b/src/controllers/timeZoneAPIController.js index 2ed0792c9..3c4df0a22 100644 --- a/src/controllers/timeZoneAPIController.js +++ b/src/controllers/timeZoneAPIController.js @@ -2,14 +2,13 @@ const { hasPermission } = require('../utilities/permissions'); const timeZoneAPIController = function () { const getTimeZoneAPIKey = async (req, res) => { - const requestorRole = req.body.requestor.role; const premiumKey = process.env.TIMEZONE_PREMIUM_KEY; const commonKey = process.env.TIMEZONE_COMMON_KEY; if (!req.body.requestor.role) { res.status(403).send('Unauthorized Request'); return; } - if (await hasPermission(requestorRole, 'getTimeZoneAPIKey')) { + if (await hasPermission(req.body.requestor, 'getTimeZoneAPIKey')) { res.status(200).send({ userAPIKey: premiumKey }); return; } diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 244e7cf45..b42bf705b 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -35,7 +35,7 @@ async function ValidatePassword(req, res) { return; } // Verify request is authorized by self or adminsitrator - if (!userId === requestor.requestorId && !await hasPermission(requestor.role, 'updatePassword')) { + if (!userId === requestor.requestorId && !await hasPermission(req.body.requestor, 'updatePassword')) { res.status(403).send({ error: "You are unauthorized to update this user's password", }); @@ -52,7 +52,7 @@ async function ValidatePassword(req, res) { const userProfileController = function (UserProfile) { const getUserProfiles = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'getUserProfiles')) { + if (!await hasPermission(req.body.requestor, 'getUserProfiles')) { res.status(403).send('You are not authorized to view all users'); return; } @@ -82,7 +82,7 @@ const userProfileController = function (UserProfile) { }; const getProjectMembers = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'getProjectMembers')) { + if (!await hasPermission(req.body.requestor, 'getProjectMembers')) { res.status(403).send('You are not authorized to view all users'); return; } @@ -104,12 +104,12 @@ const userProfileController = function (UserProfile) { }; const postUserProfile = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'postUserProfile')) { + 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.role, 'addDeleteEditOwners')) { + if (req.body.role === 'Owner' && !await hasPermission(req.body.requestor, 'addDeleteEditOwners')) { res.status(403).send('You are not authorized to create new owners'); return; } @@ -225,7 +225,7 @@ const userProfileController = function (UserProfile) { const userid = req.params.userId; const isRequestorAuthorized = !!( canRequestorUpdateUser(req.body.requestor.requestorId, userid) && ( - await hasPermission(req.body.requestor.role, 'putUserProfile') + await hasPermission(req.body.requestor, 'putUserProfile') || req.body.requestor.requestorId === userid ) ); @@ -235,7 +235,7 @@ const userProfileController = function (UserProfile) { return; } - if (req.body.role === 'Owner' && !await hasPermission(req.body.requestor.role, 'addDeleteEditOwners')) { + if (req.body.role === 'Owner' && !await hasPermission(req.body.requestor, 'addDeleteEditOwners')) { res.status(403).send('You are not authorized to update this user'); return; } @@ -296,7 +296,7 @@ const userProfileController = function (UserProfile) { userIdx = allUserData.findIndex(users => users._id === userid); userData = allUserData[userIdx]; } - if (await hasPermission(req.body.requestor.role, 'putUserProfileImportantInfo')) { + if (await hasPermission(req.body.requestor, 'putUserProfileImportantInfo')) { record.role = req.body.role; record.isRehireable = req.body.isRehireable; record.isActive = req.body.isActive; @@ -360,7 +360,7 @@ const userProfileController = function (UserProfile) { record.bioPosted = req.body.bioPosted || 'default'; - if (await hasPermission(req.body.requestor.role, 'putUserProfilePermissions')) { + if (await hasPermission(req.body.requestor, 'putUserProfilePermissions')) { record.permissions = req.body.permissions; } @@ -380,7 +380,7 @@ const userProfileController = function (UserProfile) { userData.createdDate = record.createdDate.toISOString(); } } - if (await hasPermission(req.body.requestor.role, 'infringementAuthorizer')) { + if (await hasPermission(req.body.requestor, 'infringementAuthorizer')) { record.infringements = req.body.infringements; } @@ -410,12 +410,12 @@ const userProfileController = function (UserProfile) { const deleteUserProfile = async function (req, res) { const { option, userId } = req.body; - if (!await hasPermission(req.body.requestor.role, 'deleteUserProfile')) { + 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.role, 'addDeleteEditOwners')) { + if (req.body.role === 'Owner' && !await hasPermission(req.body.requestor, 'addDeleteEditOwners')) { res.status(403).send('You are not authorized to delete this user'); return; } @@ -586,7 +586,7 @@ const userProfileController = function (UserProfile) { }); } // Verify request is authorized by self or adminsitrator - if (!userId === requestor.requestorId && !await hasPermission(requestor.role, 'updatePassword')) { + if (!userId === requestor.requestorId && !await hasPermission(req.body.requestor, 'updatePassword')) { return res.status(403).send({ error: "You are unauthorized to update this user's password", }); @@ -647,11 +647,10 @@ const userProfileController = function (UserProfile) { } const userid = mongoose.Types.ObjectId(req.params.userId); - const { role } = req.body.requestor; let validroles = ['Volunteer', 'Manager', 'Administrator', 'Core Team', 'Owner', 'Mentor']; - if (await hasPermission(role, 'getReporteesLimitRoles')) { + if (await hasPermission(req.body.requestor, 'getReporteesLimitRoles')) { validroles = ['Volunteer', 'Manager']; } @@ -722,7 +721,7 @@ const userProfileController = function (UserProfile) { }); return; } - if (!await hasPermission(req.body.requestor.role, 'changeUserStatus')) { + if (!await hasPermission(req.body.requestor, 'changeUserStatus')) { res.status(403).send('You are not authorized to change user status'); return; } diff --git a/src/controllers/wbsController.js b/src/controllers/wbsController.js index 48b640061..fa7f4427f 100644 --- a/src/controllers/wbsController.js +++ b/src/controllers/wbsController.js @@ -11,7 +11,7 @@ const wbsController = function (WBS) { }; const postWBS = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'postWbs')) { + if (!await hasPermission(req.body.requestor, 'postWbs')) { res.status(403).send({ error: 'You are not authorized to create new projects.' }); return; } @@ -34,7 +34,7 @@ const wbsController = function (WBS) { }; const deleteWBS = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'deleteWbs')) { + if (!await hasPermission(req.body.requestor, 'deleteWbs')) { res.status(403).send({ error: 'You are not authorized to delete projects.' }); return; } From bcf9fd94771bc143d3213fbe86ffa576fcfe308d Mon Sep 17 00:00:00 2001 From: Nathan Hoffman Date: Mon, 25 Sep 2023 17:56:24 -0700 Subject: [PATCH 036/272] Fix await --- src/utilities/permissions.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/utilities/permissions.js b/src/utilities/permissions.js index 2e2ac4194..7b5d4a245 100644 --- a/src/utilities/permissions.js +++ b/src/utilities/permissions.js @@ -11,8 +11,7 @@ const hasIndividualPermission = async (userId, action) => UserProfile.findById(u .exec() .then(({ permissions }) => permissions.frontPermissions.includes(action)); - -const hasPermission = async (requestor, action) => 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 From dd55a3223ed8d27c2f56cd5b0094e127bee04df8 Mon Sep 17 00:00:00 2001 From: Carl Bebli Date: Wed, 27 Sep 2023 14:38:05 +0000 Subject: [PATCH 037/272] removed suggestionModalData.json file --- src/constants/suggestionModalData.json | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/constants/suggestionModalData.json diff --git a/src/constants/suggestionModalData.json b/src/constants/suggestionModalData.json deleted file mode 100644 index e5b735091..000000000 --- a/src/constants/suggestionModalData.json +++ /dev/null @@ -1 +0,0 @@ -{"suggestion":["Identify and remedy poor client and/or user service experiences","Identify bright spots and enhance positive service experiences","Make fundamental changes to our programs and/or operations","Inform the development of new programs/projects","Identify where we are less inclusive or equitable across demographic groups","Strengthen relationships with the people we serve","Understand people's needs and how we can help them achieve their goals","Other"],"field":[]} \ No newline at end of file From a075a3697bbf3aa6862ab599ce628fdc2180e290 Mon Sep 17 00:00:00 2001 From: Carl Bebli Date: Wed, 27 Sep 2023 14:40:08 +0000 Subject: [PATCH 038/272] changed all functions to use localized suggestion data --- src/controllers/dashBoardController.js | 109 +++++++++---------------- 1 file changed, 37 insertions(+), 72 deletions(-) diff --git a/src/controllers/dashBoardController.js b/src/controllers/dashBoardController.js index 742bfe4d8..c9cdbd588 100644 --- a/src/controllers/dashBoardController.js +++ b/src/controllers/dashBoardController.js @@ -100,7 +100,7 @@ const dashboardcontroller = function () {

${actual}

Visual Proof (screenshots, videos, text)

${visual}

-

Severity/Priority (How Bad is the Bug?

+

Severity/Priority (How Bad is the Bug?)

${severity}

Thank you,
One Community

`; @@ -146,58 +146,38 @@ const dashboardcontroller = function () { } }; - const getSuggestionFilePath = async () => { - // Define a base path based on the process.cwd() - const basePath = process.cwd(); - console.log(basePath, "basePath"); - - // Define the relative path to the JSON file (adjust as needed) - const relativePath = "src/constants/suggestionModalData.json"; - - // Combine the base path and relative path to create the full path - const fullPath = path.join(basePath, relativePath); - - return fullPath; - }; - - const readSuggestionFile = async () => { - // Specify the absolute path to the JSON file - const filepath = await getSuggestionFilePath(); - - try { - // Check if the file exists - await fs.access(filepath); - - // Read and parse the file - const readfile = await fs.readFile(filepath, "utf8"); - const parsedData = JSON.parse(readfile); - return parsedData; - } catch (err) { - console.error("Error reading suggestionModalData.json:", err); - return null; // Handle the error appropriately - } + const suggestionData = { + suggestion: [ + "Identify and remedy poor client and/or user service experiences", + "Identify bright spots and enhance positive service experiences", + "Make fundamental changes to our programs and/or operations", + "Inform the development of new programs/projects", + "Identify where we are less inclusive or equitable across demographic groups", + "Strengthen relationships with the people we serve", + "Understand people's needs and how we can help them achieve their goals", + "Other", + ], + field: [], }; - // create suggestion emailbody const getsuggestionEmailBody = async (...args) => { - const readfile = await readSuggestionFile(); let fieldaaray = []; - if (readfile.field.length) { - fieldaaray = readfile.field.map( + if (suggestionData.field.length) { + fieldaaray = suggestionData.field.map( (item) => `

${item}

-

${args[3][item]}

` +

${args[3][item]}

` ); } const text = `New Suggestion: -

Suggestion Category:

-

${args[0]}

-

Suggestion:

-

${args[1]}

- ${fieldaaray.length > 0 ? fieldaaray : ""} -

Wants Feedback:

-

${args[2]}

-

Thank you,
- One Community

`; +

Suggestion Category:

+

${args[0]}

+

Suggestion:

+

${args[1]}

+ ${fieldaaray.length > 0 ? fieldaaray : ""} +

Wants Feedback:

+

${args[2]}

+

Thank you,
+ One Community

`; return text; }; @@ -225,54 +205,39 @@ const dashboardcontroller = function () { const getSuggestionOption = async (req, res) => { try { - const readfile = await readSuggestionFile(); - if (readfile) { - res.status(200).send(readfile); + if (suggestionData) { + res.status(200).send(suggestionData); } else { - res.status(404).send("Suggestion file not found."); + res.status(404).send("Suggestion data not found."); } } catch (error) { - console.error("Error reading suggestion file:", error); + console.error("Error getting suggestion data:", error); res.status(500).send("Internal Server Error"); } }; - // add new suggestion category or field const editSuggestionOption = async (req, res) => { try { - // Read the current suggestion data - let readfile = await readSuggestionFile(); - if (req.body.suggestion) { if (req.body.action === "add") { - readfile.suggestion.unshift(req.body.newField); + suggestionData.suggestion.unshift(req.body.newField); } if (req.body.action === "delete") { - readfile = { - ...readfile, - suggestion: readfile.suggestion.filter( - (item, index) => index + 1 !== +req.body.newField - ), - }; + suggestionData.suggestion = suggestionData.suggestion.filter( + (item, index) => index + 1 !== +req.body.newField + ); } } else { if (req.body.action === "add") { - readfile.field.unshift(req.body.newField); + suggestionData.field.unshift(req.body.newField); } if (req.body.action === "delete") { - readfile = { - ...readfile, - field: readfile.field.filter((item) => item !== req.body.newField), - }; + suggestionData.field = suggestionData.field.filter( + (item) => item !== req.body.newField + ); } } - // Get the file path - const filepath = await getSuggestionFilePath(); - - // Write the updated data back to the file - await fs.writeFile(filepath, JSON.stringify(readfile, null, 2)); - res.status(200).send("success"); } catch (error) { console.error("Error editing suggestion option:", error); From 1b9f75a788ab4290efc310d14283246ee118d549 Mon Sep 17 00:00:00 2001 From: Nathan Hoffman Date: Thu, 28 Sep 2023 13:02:47 -0700 Subject: [PATCH 039/272] Change HTTP status codes --- src/controllers/rolePresetsController.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/rolePresetsController.js b/src/controllers/rolePresetsController.js index 63c182577..3642627f7 100644 --- a/src/controllers/rolePresetsController.js +++ b/src/controllers/rolePresetsController.js @@ -29,7 +29,7 @@ const rolePresetsController = function (Preset) { preset.presetName = req.body.presetName; preset.permissions = req.body.permissions; preset.save() - .then(res.status(200).send({ message: 'New preset created' })) + .then(result => res.status(201).send({ newPreset: result, message: 'New preset created' })) .catch(error => res.status(400).send({ error })); }; @@ -46,7 +46,7 @@ const rolePresetsController = function (Preset) { record.presetName = req.body.presetName; record.permissions = req.body.permissions; record.save() - .then(results => res.status(201).send(results)) + .then(results => res.status(200).send(results)) .catch(errors => res.status(400).send(errors)); }) .catch(error => res.status(400).send({ error })); From 0c0373bf3f03c1a73370673df00f36a6ee2e6ff3 Mon Sep 17 00:00:00 2001 From: robertoooc Date: Thu, 28 Sep 2023 16:21:55 -0700 Subject: [PATCH 040/272] added statement to clear user cache if needed so profile page is updated immediately --- src/controllers/teamController.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/controllers/teamController.js b/src/controllers/teamController.js index 1072f1fb4..9fa20ab2b 100644 --- a/src/controllers/teamController.js +++ b/src/controllers/teamController.js @@ -1,6 +1,7 @@ const mongoose = require('mongoose'); const userProfile = require('../models/userProfile'); const { hasPermission } = require('../utilities/permissions'); +const cache = require('../utilities/nodeCache')(); const teamcontroller = function (Team) { const getAllTeams = function (req, res) { @@ -113,6 +114,8 @@ const teamcontroller = function (Team) { users.forEach((element) => { const { userId, operation } = element; + // if user's profile is stored in cache, clear it so when you visit their profile page it will be up to date + if(cache.hasCache(`user-${userId}`)) cache.removeCache(`user-${userId}`); if (operation === 'Assign') { assignlist.push(userId); From b69dd8beb4916b15ac9eb7756bf499a18426782b Mon Sep 17 00:00:00 2001 From: abdelmounaim lallouache Date: Thu, 28 Sep 2023 19:13:38 -0500 Subject: [PATCH 041/272] update profileInitialSetupController --- .../profileInitialSetupController.js | 334 +++++++++--------- 1 file changed, 174 insertions(+), 160 deletions(-) diff --git a/src/controllers/profileInitialSetupController.js b/src/controllers/profileInitialSetupController.js index 01d497865..052915994 100644 --- a/src/controllers/profileInitialSetupController.js +++ b/src/controllers/profileInitialSetupController.js @@ -1,29 +1,28 @@ -const mongoose = require('mongoose'); -const { v4: uuidv4 } = require('uuid'); -const moment = require('moment-timezone'); -const jwt = require('jsonwebtoken'); -const emailSender = require('../utilities/emailSender'); -const config = require('../config'); - +const mongoose = require("mongoose"); +const { v4: uuidv4 } = require("uuid"); +const moment = require("moment-timezone"); +const jwt = require("jsonwebtoken"); +const emailSender = require("../utilities/emailSender"); +const config = require("../config"); // returns the email body that includes the setup link for the recipient. function sendLinkMessage(Link) { - const message = `

Hello,

+ const message = `

Hello,

Welcome to the One Community Highest Good Network! We’re excited to have you as a new member of our team.
To work as a member of our volunteer team, you need to complete the following profile setup:

Click to Complete Profile

Please complete all fields and be accurate. If you have any questions or need assistance during the profile setup process, please contact your manager.

Thank you and welcome!

-

With Gratitude,
- One Community.

`; - return message; +

With Gratitude,

+

One Community.

`; + return message; } // returns the email body containing the details of the newly created user. function informManagerMessage(user) { - const message = ` + const message = `

Hello,

-

A new user has created their profile on our platform. Below is the information provided by the user:

+

New User ${user.firstName} ${user.lastName} has completed their part of setup.
These areas need to now be completed by an Admin: Weekly Committed Hours, Admin Document, Link to Media Files, Assign Projects, and (if applicable) Assign Team.

@@ -39,11 +38,7 @@ function informManagerMessage(user) { - - - - - + @@ -62,83 +57,92 @@ function informManagerMessage(user) {
First Name:
Phone Number:${user.phoneNumber}
Weekly Committed Hours:${user.weeklycommittedHours}+${user.phoneNumber}
Collaboration Preference:${user.location}
-

Please check the details provided by the user. If any errors were made, kindly ask them to correct the information accordingly.

+

Thank you,

One Community.

`; - return message; + return message; } -const profileInitialSetupController = function (ProfileInitialSetupToken, userProfile, Project) { - const { JWT_SECRET } = config; +const profileInitialSetupController = function ( + ProfileInitialSetupToken, + userProfile, + Project +) { + const { JWT_SECRET } = config; - /* + /* Function to handle token generation and email process: - Generates a new token and saves it to the database. - If the email already has a token, the old one is deleted. - Sets the token expiration to one week. - Generates a link using the token and emails it to the recipient. */ - const getSetupToken = async (req, res) => { - let { email, baseUrl } = req.body - email = email.toLowerCase() - const token = uuidv4(); - const expiration = moment().tz('America/Los_Angeles').add(1, 'week') - try { - await ProfileInitialSetupToken.findOneAndDelete({ email }); - - const newToken = new ProfileInitialSetupToken({ - token, - email, - expiration: expiration.toDate(), - }); - - const savedToken = await newToken.save(); - const link = `${baseUrl}/ProfileInitialSetup/${savedToken.token}` + const getSetupToken = async (req, res) => { + let { email, baseUrl } = req.body; + email = email.toLowerCase(); + const token = uuidv4(); + const expiration = moment().tz("America/Los_Angeles").add(1, "week"); + try { + const existingEmail = await userProfile.findOne({ + email: email, + }); + if (existingEmail) { + res.status(400).send("email already in use"); + } else { + await ProfileInitialSetupToken.findOneAndDelete({ email }); - emailSender( - email, - 'NEEDED: Complete your One Community profile setup', - sendLinkMessage(link), - null, - null, - ); + const newToken = new ProfileInitialSetupToken({ + token, + email, + expiration: expiration.toDate(), + }); - res.status(200).send(link); + const savedToken = await newToken.save(); + const link = `${baseUrl}/ProfileInitialSetup/${savedToken.token}`; - } catch (error) { - res.status(400).send(`Error: ${error}`); - } + emailSender( + email, + "NEEDED: Complete your One Community profile setup", + sendLinkMessage(link), + null, + null + ); + res.status(200).send(link); + } + } catch (error) { + res.status(400).send(`Error: ${error}`); } + }; - /* + /* Function to validate a token: - Checks if the token exists in the database. - Verifies that the token's expiration date has not passed yet. */ - const validateSetupToken = async (req, res) => { - const { token } = req.body - const currentMoment = moment.tz('America/Los_Angeles'); - try { - const foundToken = await ProfileInitialSetupToken.findOne({ token }); - if (foundToken) { - const expirationMoment = moment(foundToken.expiration); - - if (expirationMoment.isAfter(currentMoment)) { - res.status(200).send("Valid token"); - } else { - res.status(400).send("Invalid token"); - } - } else { - res.status(404).send("Token not found") - } - } catch (error) { - res.status(500).send(`Error finding token: ${error}`); - } + const validateSetupToken = async (req, res) => { + const { token } = req.body; + const currentMoment = moment.tz("America/Los_Angeles"); + try { + const foundToken = await ProfileInitialSetupToken.findOne({ token }); + if (foundToken) { + const expirationMoment = moment(foundToken.expiration); + + if (expirationMoment.isAfter(currentMoment)) { + res.status(200).send(foundToken); + } else { + res.status(400).send("Invalid token"); + } + } else { + res.status(404).send("Token not found"); + } + } catch (error) { + res.status(500).send(`Error finding token: ${error}`); } + }; - /* + /* Function for creating and authenticating a new user: - Validates the token used to submit the form. - Creates a new user using the information received through req.body. @@ -147,104 +151,114 @@ const profileInitialSetupController = function (ProfileInitialSetupToken, userPr - Generates a JWT token using the newly created user information. - Sends the JWT as a response. */ - const setUpNewUser = async (req, res) => { - const { token } = req.body; - const currentMoment = moment.tz('America/Los_Angeles'); - try { - const foundToken = await ProfileInitialSetupToken.findOne({ token }); - if (foundToken) { - const expirationMoment = moment(foundToken.expiration); - - if (expirationMoment.isAfter(currentMoment)) { - - const defaultProject = await Project.findOne({ projectName: "Orientation and Initial Setup" }) - - const newUser = new userProfile(); - newUser.password = req.body.password - newUser.role = "Volunteer"; - newUser.firstName = req.body.firstName; - newUser.lastName = req.body.lastName; - newUser.jobTitle = req.body.jobTitle; - newUser.phoneNumber = req.body.phoneNumber; - newUser.bio = ""; - newUser.weeklycommittedHours = req.body.weeklycommittedHours; - newUser.personalLinks = []; - newUser.adminLinks = []; - newUser.teams = Array.from(new Set([])); - newUser.projects = Array.from(new Set([defaultProject])); - newUser.createdDate = Date.now(); - newUser.email = req.body.email; - newUser.weeklySummaries = [{ summary: '' }]; - newUser.weeklySummariesCount = 0; - newUser.weeklySummaryOption = 'Required'; - newUser.mediaUrl = ''; - newUser.collaborationPreference = req.body.collaborationPreference; - newUser.timeZone = req.body.timeZone || 'America/Los_Angeles'; - newUser.location = req.body.location; - newUser.bioPosted = 'default'; - newUser.privacySettings.email = req.body.privacySettings.email - newUser.privacySettings.phoneNumber = req.body.privacySettings.phoneNumber - newUser.teamCode = ''; - const savedUser = await newUser.save(); - - emailSender( - process.env.MANAGER_EMAIL, - 'New User Profile Created', - informManagerMessage(savedUser), - null, - null, - ); - await ProfileInitialSetupToken.findByIdAndDelete(foundToken._id); - - const jwtPayload = { - userid: savedUser._id, - role: savedUser.role, - permissions: savedUser.permissions, - expiryTimestamp: moment().add(config.TOKEN.Lifetime, config.TOKEN.Units), - }; - - const token = jwt.sign(jwtPayload, JWT_SECRET); - - res.send({ token }).status(200); - } else { - res.status(400).send("Token is expired"); - } - } else { - res.status(400).send("Invalid token"); - } - } catch (error) { - res.status(500).send(`Error: ${error}`); - } + const setUpNewUser = async (req, res) => { + const { token } = req.body; + const currentMoment = moment.tz("America/Los_Angeles"); + try { + const foundToken = await ProfileInitialSetupToken.findOne({ token }); + const existingEmail = await userProfile.findOne({ + email: foundToken.email, + }); + if (existingEmail) { + res.status(400).send("email already in use"); + } else { + if (foundToken) { + const expirationMoment = moment(foundToken.expiration); + if (expirationMoment.isAfter(currentMoment)) { + const defaultProject = await Project.findOne({ + projectName: "Orientation and Initial Setup", + }); + + const newUser = new userProfile(); + newUser.password = req.body.password; + newUser.role = "Volunteer"; + newUser.firstName = req.body.firstName; + newUser.lastName = req.body.lastName; + newUser.jobTitle = req.body.jobTitle; + newUser.phoneNumber = req.body.phoneNumber; + newUser.bio = ""; + newUser.weeklycommittedHours = req.body.weeklycommittedHours; + newUser.personalLinks = []; + newUser.adminLinks = []; + newUser.teams = Array.from(new Set([])); + newUser.projects = Array.from(new Set([defaultProject])); + newUser.createdDate = Date.now(); + newUser.email = req.body.email; + newUser.weeklySummaries = [{ summary: "" }]; + newUser.weeklySummariesCount = 0; + newUser.weeklySummaryOption = "Required"; + newUser.mediaUrl = ""; + newUser.collaborationPreference = req.body.collaborationPreference; + newUser.timeZone = req.body.timeZone || "America/Los_Angeles"; + newUser.location = req.body.location; + newUser.bioPosted = "default"; + newUser.privacySettings.email = req.body.privacySettings.email; + newUser.privacySettings.phoneNumber = + req.body.privacySettings.phoneNumber; + newUser.teamCode = ""; + const savedUser = await newUser.save(); + + emailSender( + process.env.MANAGER_EMAIL || "jae@onecommunityglobal.org", // "jae@onecommunityglobal.org" + "NEW USER REGISTERED", + informManagerMessage(savedUser), + null, + null + ); + await ProfileInitialSetupToken.findByIdAndDelete(foundToken._id); + + const jwtPayload = { + userid: savedUser._id, + role: savedUser.role, + permissions: savedUser.permissions, + expiryTimestamp: moment().add( + config.TOKEN.Lifetime, + config.TOKEN.Units + ), + }; + + const token = jwt.sign(jwtPayload, JWT_SECRET); + + res.send({ token }).status(200); + } else { + res.status(400).send("Token is expired"); + } + } else { + res.status(400).send("Invalid token"); + } + } + } catch (error) { + res.status(500).send(`Error: ${error}`); } + }; - /* + /* Function for sending https://opencagedata.com API key: - Checks if token used in the request is valid. - sends the API Key as response */ - const getTimeZoneAPIKeyByToken = async (req, res) => { - const token = req.body.token; - const premiumKey = process.env.TIMEZONE_PREMIUM_KEY; + const getTimeZoneAPIKeyByToken = async (req, res) => { + const token = req.body.token; + const premiumKey = process.env.TIMEZONE_PREMIUM_KEY; - const foundToken = await ProfileInitialSetupToken.findOne({ token }); + const foundToken = await ProfileInitialSetupToken.findOne({ token }); - if (foundToken) { - res.status(200).send({ userAPIKey: premiumKey }); - return; - } else { - res.status(403).send('Unauthorized Request'); - return; - } - - }; - - return { - getSetupToken, - setUpNewUser, - validateSetupToken, - getTimeZoneAPIKeyByToken + if (foundToken) { + res.status(200).send({ userAPIKey: premiumKey }); + return; + } else { + res.status(403).send("Unauthorized Request"); + return; } + }; + + return { + getSetupToken, + setUpNewUser, + validateSetupToken, + getTimeZoneAPIKeyByToken, + }; }; -module.exports = profileInitialSetupController; \ No newline at end of file +module.exports = profileInitialSetupController; From 165fc73cb11a963c8afa360a628e4a39a6428517 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Fri, 29 Sep 2023 13:35:30 -0700 Subject: [PATCH 042/272] add material schema, update item type schema --- src/models/inventoryItemType.js | 21 ++++++++++++--- src/models/inventoryMaterial.js | 46 +++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 src/models/inventoryMaterial.js diff --git a/src/models/inventoryItemType.js b/src/models/inventoryItemType.js index 80e5e0d7b..92139f27d 100644 --- a/src/models/inventoryItemType.js +++ b/src/models/inventoryItemType.js @@ -2,11 +2,24 @@ const mongoose = require('mongoose'); const { Schema } = mongoose; -const InventoryItemType = new Schema({ +// const InventoryItemType = new Schema({ +// name: { type: String, required: true }, +// description: { type: String }, +// imageUrl: { type: String }, +// quantifier: { type: String, default: 'each' }, +// }); + +const InventoryItemType = new Schema({ // creates an item, tracks total amount in organization's stock + type: { type: String, required: true }, // ie Material, Equipment, Tool name: { type: String, required: true }, - description: { type: String }, - imageUrl: { type: String }, - quantifier: { type: String, default: 'each' }, + description: { type: String, required: true, maxLength: 150 }, + uom: { type: String, required: true }, // unit of measurement + totalStock: { type: Number, required: true }, // total amount of all stock acquired + totalAvailable: { type: Number, required: true }, // amount of item available to be checked out + projectsUsing: [String], // ids of projects using the item + imageUrl: { type: String } }); module.exports = mongoose.model('inventoryItemType', InventoryItemType, 'inventoryItemType'); + + diff --git a/src/models/inventoryMaterial.js b/src/models/inventoryMaterial.js new file mode 100644 index 000000000..31b6ce069 --- /dev/null +++ b/src/models/inventoryMaterial.js @@ -0,0 +1,46 @@ +const mongoose = require('mongoose') + +const {Schema} = mongoose + +const InventoryMaterial = new Schema({ + inventoryItemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'inventoryItemType', required: true }, + projectId: {type: Number, required: true }, + stockBought: { type: Number, required: true }, // amount bought for project, affects total stock + stockUsed: { type: Number, required: true }, + stockAvailable: { type: Number, required: true }, + stockHeld: { type: Number, required: true }, + stockWasted: { type: Number, required: true }, + usageRecord: [{ // daily log of amount inventory item used at job site + date: { type: Date, required: true, default: Date.now() }, + createdBy: {type: String, required: true }, + taskId: { type: String, required: true }, + quantityUsed: { type: Number, required: true }, + responsibleUserId: { type: String, required: true } + }], + updateRecord: [{ // incident report affecting quantity/status of inventory item + date: { type: Date, required: true, default: Date.now() }, + createdBy: {type: String, required: true }, + action: { type: String, required: true }, // ex: Add, Reduce, Hold + cause: { type: String, required: true }, // ex: Used, Lost, Wasted, Transfer + quantity: { type: Number, required: true }, + description: { type: String, required: true, maxLength: 150 }, + responsibleUserId: { type: String, required: true }, + imageUrl: { type: String } + }], + purchaseRecord: [{ + date: { type: Date, required: true, default: Date.now() }, + createdBy: {type: String, required: true }, + invoiceId: { type: String, required: true }, + vendor: { type: String, required: true }, + brand: { type: String, required: true }, + amount: { type: Number, required: true }, // amount of item in each unit + quantity: { type: Number, required: true }, // number of units purchased + unitCost: { type: Number, required: true }, + tax: { type: Number, required: true }, + shipping: { type: Number, required: true }, + totalCost: { type: Number, required: true }, + imageUrl: { type: String }, + }] +}) + +module.exports = mongoose.model('inventoryMaterial', InventoryMaterial, 'inventoryMaterial'); From 4f6be0bcec289d7f285f55f8f7546c8506a08f0d Mon Sep 17 00:00:00 2001 From: tsunami776 <43768723+tsunami776@users.noreply.github.com> Date: Fri, 29 Sep 2023 15:40:19 -0500 Subject: [PATCH 043/272] userProfileController checks cache if no results from the database --- src/controllers/userProfileController.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 855aa265a..5aabb6bf2 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -71,19 +71,20 @@ const userProfileController = function (UserProfile) { }) .then((results) => { if (!results) { - res.status(500).send({ error: "User result was invalid" }); - return; + if (cache.getCache("allusers")) { + const getData = JSON.parse(cache.getCache("allusers")); + res.status(200).send(getData); + return; + }else{ + res.status(500).send({ error: "User result was invalid" }); + return; + } } cache.setCache("allusers", JSON.stringify(results)); res.status(200).send(results); }) .catch((error) => res.status(404).send(error)); - - if (cache.getCache('allusers')) { - const getData = JSON.parse(cache.getCache('allusers')); - res.status(200).send(getData); - return; - } + }; const getProjectMembers = async function (req, res) { From cf741ad7005d84f853bdf5c6482338cae15a9759 Mon Sep 17 00:00:00 2001 From: abdelmounaim lallouache Date: Fri, 29 Sep 2023 20:58:15 -0500 Subject: [PATCH 044/272] update setup user email --- src/controllers/profileInitialSetupController.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/controllers/profileInitialSetupController.js b/src/controllers/profileInitialSetupController.js index 052915994..b0afd7b39 100644 --- a/src/controllers/profileInitialSetupController.js +++ b/src/controllers/profileInitialSetupController.js @@ -14,7 +14,7 @@ function sendLinkMessage(Link) {

Please complete all fields and be accurate. If you have any questions or need assistance during the profile setup process, please contact your manager.

Thank you and welcome!

With Gratitude,

-

One Community.

`; +

One Community

`; return message; } @@ -59,7 +59,7 @@ function informManagerMessage(user) {

Thank you,

-

One Community.

`; +

One Community

`; return message; } @@ -201,7 +201,7 @@ const profileInitialSetupController = function ( emailSender( process.env.MANAGER_EMAIL || "jae@onecommunityglobal.org", // "jae@onecommunityglobal.org" - "NEW USER REGISTERED", + `NEW USER REGISTERED: ${savedUser.firstName} ${savedUser.lastName}`, informManagerMessage(savedUser), null, null From beb19d7f2ffe42733ed1b743f11589786712362e Mon Sep 17 00:00:00 2001 From: abdelmounaim lallouache Date: Sat, 30 Sep 2023 14:49:09 -0500 Subject: [PATCH 045/272] update email body for new user setup --- src/controllers/profileInitialSetupController.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/controllers/profileInitialSetupController.js b/src/controllers/profileInitialSetupController.js index b0afd7b39..b688f3963 100644 --- a/src/controllers/profileInitialSetupController.js +++ b/src/controllers/profileInitialSetupController.js @@ -22,7 +22,16 @@ function sendLinkMessage(Link) { function informManagerMessage(user) { const message = `

Hello,

-

New User ${user.firstName} ${user.lastName} has completed their part of setup.
These areas need to now be completed by an Admin: Weekly Committed Hours, Admin Document, Link to Media Files, Assign Projects, and (if applicable) Assign Team.

+

New User ${user.firstName} ${user.lastName} has completed their part of setup.

+

These areas need to now be completed by an Admin:

+
    +
  • Weekly Committed Hours
  • +
  • Admin Document
  • +
  • Link to Media Files
  • +
  • Assign Projects
  • +
  • 4-digit Admin Code
  • +
  • And (if applicable) Assign Team
  • +
From e120df9dc7601cf92efd2022e5d09d5a24cadc6f Mon Sep 17 00:00:00 2001 From: abdelmounaim lallouache Date: Sat, 30 Sep 2023 15:27:46 -0500 Subject: [PATCH 046/272] add style --- src/controllers/profileInitialSetupController.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/controllers/profileInitialSetupController.js b/src/controllers/profileInitialSetupController.js index b688f3963..f671e06a3 100644 --- a/src/controllers/profileInitialSetupController.js +++ b/src/controllers/profileInitialSetupController.js @@ -21,10 +21,10 @@ function sendLinkMessage(Link) { // returns the email body containing the details of the newly created user. function informManagerMessage(user) { const message = ` -

Hello,

-

New User ${user.firstName} ${user.lastName} has completed their part of setup.

+

Hello,

+

New User ${user.firstName} ${user.lastName} has completed their part of setup.

These areas need to now be completed by an Admin:

-
    +
    • Weekly Committed Hours
    • Admin Document
    • Link to Media Files
    • From e2540140d889b31aede0656722eed32c5306d75e Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Mon, 2 Oct 2023 11:46:14 -0700 Subject: [PATCH 047/272] add materials route, router, controller --- .../bmdashboard/bmMaterialsController.js | 12 ++++++++++++ src/routes/bmdashboard/bmMaterialsRouter.js | 13 +++++++++++++ src/startup/routes.js | 2 ++ 3 files changed, 27 insertions(+) create mode 100644 src/controllers/bmdashboard/bmMaterialsController.js create mode 100644 src/routes/bmdashboard/bmMaterialsRouter.js diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js new file mode 100644 index 000000000..11aa4a744 --- /dev/null +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -0,0 +1,12 @@ +const bmMaterialsController = function () { + const bmMaterialsList = async function _matsList(req, res) { + try { + return res.json({ message: "Hello World" }) + } catch (err) { + res.json(err); + } + }; + return { bmMaterialsList }; +}; + +module.exports = bmMaterialsController; \ No newline at end of file diff --git a/src/routes/bmdashboard/bmMaterialsRouter.js b/src/routes/bmdashboard/bmMaterialsRouter.js new file mode 100644 index 000000000..d8cca1aca --- /dev/null +++ b/src/routes/bmdashboard/bmMaterialsRouter.js @@ -0,0 +1,13 @@ +const express = require('express'); + +const routes = function () { +const materialsRouter = express.Router(); +const controller = require('../../controllers/bmdashboard/bmMaterialsController')(); + +materialsRouter.route('/materials') + .get(controller.bmMaterialsList); + + return materialsRouter; +} + +module.exports = routes; \ No newline at end of file diff --git a/src/startup/routes.js b/src/startup/routes.js index 43cd226bd..e0852dac3 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -55,6 +55,7 @@ const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverTe // bm dashboard const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); +const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(); module.exports = function (app) { @@ -88,4 +89,5 @@ module.exports = function (app) { app.use('/api', mouseoverTextRouter); // bm dashboard app.use('/api/bm', bmLoginRouter); + app.use('/api/bm', bmMaterialsRouter); }; From 656509dcd6ab3b6c770876d68a5c70fe7eb0c566 Mon Sep 17 00:00:00 2001 From: Oleksandr Riazantsev Date: Mon, 2 Oct 2023 16:13:42 -0400 Subject: [PATCH 048/272] fix: jobTitle model key, feat: adding isActive status, getting all locations, put new location to a collection --- src/controllers/mapLocationsController.js | 72 +++++++++-------------- src/models/mapLocation.js | 38 +++++++----- 2 files changed, 49 insertions(+), 61 deletions(-) diff --git a/src/controllers/mapLocationsController.js b/src/controllers/mapLocationsController.js index 83526998d..6088de489 100644 --- a/src/controllers/mapLocationsController.js +++ b/src/controllers/mapLocationsController.js @@ -1,62 +1,44 @@ -const mongoose = require('mongoose'); -const mapLocation = require('../models/mapLocation'); -const { hasPermission } = require('../utilities/permissions'); - -const mapLocationsController = function () { +const mapLocationsController = function (mapLocation) { const getAllLocations = function (req, res) { - console.log('controller:') - console.log(req.body) mapLocation.find({}) - .then(results => res.send(results).status(200)) - .catch(error => res.send(error).status(404)); + .then(results => + res.send(results).status(200) + ) + .catch(error => + res.send(error).status(404)); }; const deleteLocation = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'deleteTeam')) { - res.status(403).send({ error: 'You are not authorized to delete teams.' }); + + if (!req.body.requestor.role === 'Administrator' || !req.body.requestor.role === 'Owner') { + res.status(403).send('You are not authorized to make changes in the teams.'); return; } - const { teamId } = req.params; - Team.findById(teamId, (error, record) => { - if (error || record === null) { - res.status(400).send({ error: 'No valid records found' }); - return; - } - const removeteamfromprofile = userProfile.updateMany({}, { $pull: { teams: record._id } }).exec(); - const deleteteam = record.remove(); - - Promise.all([removeteamfromprofile, deleteteam]) - .then(res.status(200).send({ message: ' Team successfully deleted and user profiles updated' })) - .catch((errors) => { - res.status(400).send(errors); - }); - }).catch((error) => { - res.status(400).send(error); - }); }; const putUserLocation = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'putTeam')) { + + if (!req.body.requestor.role === 'Administrator' || !req.body.requestor.role === 'Owner') { res.status(403).send('You are not authorized to make changes in the teams.'); return; } + const locationData = { + firstName: req.body.firstName, + lastName: req.body.lastName, + jobTitle: req.body.jobTitle, + location: req.body.location, + } + const location = new mapLocation(locationData); - const { teamId } = req.params; - - Team.findById(teamId, (error, record) => { - if (error || record === null) { - res.status(400).send('No valid records found'); - return; + try { + const response = await location.save() + if(!response) { + throw new Error('Something went wrong during saving the location...') } - record.teamName = req.body.teamName; - record.isActive = req.body.isActive; - record.createdDatetime = Date.now(); - record.modifiedDatetime = Date.now(); - - record - .save() - .then(results => res.status(201).send(results._id)) - .catch(errors => res.status(400).send(errors)); - }); + res.status(200).send(response); + } catch (err) { + console.log(err.message) + res.status(500).json({message: err.message || 'Something went wrong...'}); + } }; return { diff --git a/src/models/mapLocation.js b/src/models/mapLocation.js index d7b9d82b5..65415239f 100644 --- a/src/models/mapLocation.js +++ b/src/models/mapLocation.js @@ -11,32 +11,38 @@ const mapLocation = new Schema({ type: String, default: 'Prior to HGN Data Collection', }, - title: { + jobTitle: { type: String, default: 'Prior to HGN Data Collection', }, - userProvided: { - type: String, - required: true, + isActive: { + type: Boolean, + default: false, }, - coords: { - lat: { + location: { + userProvided: { type: String, required: true, }, - lng: { + coords: { + lat: { + type: String, + required: true, + }, + lng: { + type: String, + required: true, + } + }, + country: { type: String, required: true, - } - }, - country: { - type: String, - required: true, + }, + city: { + type: String, + default: '', + }, }, - city: { - type: String, - default: '', - } }); module.exports = mongoose.model('MapLocation', mapLocation, 'maplocations'); From 9fdcdb8d4930421928d5deb4d825c7f5f9c6d213 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Mon, 2 Oct 2023 18:09:21 -0700 Subject: [PATCH 049/272] update route, router, controller with updated material schema and new collection fetch --- .../bmdashboard/bmMaterialsController.js | 8 +++- ...ryMaterial.js => inventoryItemMaterial.js} | 38 ++++++++----------- src/routes/bmdashboard/bmMaterialsRouter.js | 4 +- src/startup/routes.js | 4 +- 4 files changed, 25 insertions(+), 29 deletions(-) rename src/models/{inventoryMaterial.js => inventoryItemMaterial.js} (51%) diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index 11aa4a744..797d5730d 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -1,7 +1,11 @@ -const bmMaterialsController = function () { +const mongoose = require('mongoose') + +const bmMaterialsController = function (ItemMaterial, ItemType) { const bmMaterialsList = async function _matsList(req, res) { try { - return res.json({ message: "Hello World" }) + ItemMaterial.find() + .then(results => res.status(200).send(results)) + .catch(error => res.status(500).send(error)) } catch (err) { res.json(err); } diff --git a/src/models/inventoryMaterial.js b/src/models/inventoryItemMaterial.js similarity index 51% rename from src/models/inventoryMaterial.js rename to src/models/inventoryItemMaterial.js index 31b6ce069..b795d2f63 100644 --- a/src/models/inventoryMaterial.js +++ b/src/models/inventoryItemMaterial.js @@ -1,10 +1,10 @@ -const mongoose = require('mongoose') +const mongoose = require('mongoose'); -const {Schema} = mongoose +const { Schema } = mongoose; -const InventoryMaterial = new Schema({ +const InventoryItemMaterial = new Schema({ inventoryItemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'inventoryItemType', required: true }, - projectId: {type: Number, required: true }, + project: { type: mongoose.SchemaTypes.ObjectId, ref: 'project', required: true }, stockBought: { type: Number, required: true }, // amount bought for project, affects total stock stockUsed: { type: Number, required: true }, stockAvailable: { type: Number, required: true }, @@ -12,35 +12,27 @@ const InventoryMaterial = new Schema({ stockWasted: { type: Number, required: true }, usageRecord: [{ // daily log of amount inventory item used at job site date: { type: Date, required: true, default: Date.now() }, - createdBy: {type: String, required: true }, - taskId: { type: String, required: true }, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile', required: true }, quantityUsed: { type: Number, required: true }, - responsibleUserId: { type: String, required: true } }], updateRecord: [{ // incident report affecting quantity/status of inventory item date: { type: Date, required: true, default: Date.now() }, - createdBy: {type: String, required: true }, - action: { type: String, required: true }, // ex: Add, Reduce, Hold - cause: { type: String, required: true }, // ex: Used, Lost, Wasted, Transfer - quantity: { type: Number, required: true }, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile', required: true }, + action: { type: String, required: true }, // ex: Add, Reduce, Hold (updates stock quantities) + cause: { type: String, required: true }, // ex: Used, Lost, Wasted, Transfer (reason for update) + quantity: { type: Number, required: true }, // amount of material affected description: { type: String, required: true, maxLength: 150 }, - responsibleUserId: { type: String, required: true }, - imageUrl: { type: String } }], purchaseRecord: [{ date: { type: Date, required: true, default: Date.now() }, - createdBy: {type: String, required: true }, - invoiceId: { type: String, required: true }, - vendor: { type: String, required: true }, - brand: { type: String, required: true }, - amount: { type: Number, required: true }, // amount of item in each unit - quantity: { type: Number, required: true }, // number of units purchased - unitCost: { type: Number, required: true }, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile', required: true }, + poId: { type: String, required: true }, + sellerId: { type: String, required: true }, + quantity: { type: Number, required: true }, // adds to stockBought + subtotal: { type: Number, required: true }, tax: { type: Number, required: true }, shipping: { type: Number, required: true }, - totalCost: { type: Number, required: true }, - imageUrl: { type: String }, }] }) -module.exports = mongoose.model('inventoryMaterial', InventoryMaterial, 'inventoryMaterial'); +module.exports = mongoose.model('inventoryItemMaterial', InventoryItemMaterial, 'inventoryMaterial'); diff --git a/src/routes/bmdashboard/bmMaterialsRouter.js b/src/routes/bmdashboard/bmMaterialsRouter.js index d8cca1aca..d3e4518da 100644 --- a/src/routes/bmdashboard/bmMaterialsRouter.js +++ b/src/routes/bmdashboard/bmMaterialsRouter.js @@ -1,8 +1,8 @@ const express = require('express'); -const routes = function () { +const routes = function (itemMaterial, itemType) { const materialsRouter = express.Router(); -const controller = require('../../controllers/bmdashboard/bmMaterialsController')(); +const controller = require('../../controllers/bmdashboard/bmMaterialsController')(itemMaterial, itemType); materialsRouter.route('/materials') .get(controller.bmMaterialsList); diff --git a/src/startup/routes.js b/src/startup/routes.js index e0852dac3..cde07c94d 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -20,6 +20,7 @@ const ownerStandardMessage = require('../models/ownerStandardMessage'); const profileInitialSetuptoken = require('../models/profileInitialSetupToken'); const reason = require('../models/reason'); const mouseoverText = require('../models/mouseoverText'); +const inventoryItemMaterial = require('../models/inventoryItemMaterial'); const userProfileRouter = require('../routes/userProfileRouter')(userProfile); const badgeRouter = require('../routes/badgeRouter')(badge); @@ -55,8 +56,7 @@ const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverTe // bm dashboard const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); -const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(); - +const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial, inventoryItemType); module.exports = function (app) { app.use('/api', forgotPwdRouter); From 9da89884167f825caf399c09ae44d0bb6fe35079 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Mon, 2 Oct 2023 20:12:37 -0700 Subject: [PATCH 050/272] update inventoryitemtype schema --- src/models/inventoryItemType.js | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/models/inventoryItemType.js b/src/models/inventoryItemType.js index 92139f27d..207ac77b0 100644 --- a/src/models/inventoryItemType.js +++ b/src/models/inventoryItemType.js @@ -2,21 +2,14 @@ const mongoose = require('mongoose'); const { Schema } = mongoose; -// const InventoryItemType = new Schema({ -// name: { type: String, required: true }, -// description: { type: String }, -// imageUrl: { type: String }, -// quantifier: { type: String, default: 'each' }, -// }); - const InventoryItemType = new Schema({ // creates an item, tracks total amount in organization's stock type: { type: String, required: true }, // ie Material, Equipment, Tool name: { type: String, required: true }, description: { type: String, required: true, maxLength: 150 }, uom: { type: String, required: true }, // unit of measurement totalStock: { type: Number, required: true }, // total amount of all stock acquired - totalAvailable: { type: Number, required: true }, // amount of item available to be checked out - projectsUsing: [String], // ids of projects using the item + totalAvailable: { type: Number, required: true }, + projectsUsing: [ {type: mongoose.SchemaTypes.ObjectId, ref: 'project'} ], imageUrl: { type: String } }); From 60a1fa2348c3a790b3b5c59b3297a41d6074ddb7 Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Tue, 3 Oct 2023 12:46:33 +0800 Subject: [PATCH 051/272] add authorization and regex check in backend --- src/controllers/userProfileController.js | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 40d6eac39..c1c3a2a0a 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -244,6 +244,9 @@ const userProfileController = function (UserProfile) { "putUserProfilePermissions" )) ); + + const canEditTeamCode = req.body.requestor.role === "Owner" || + req.body.requestor.permissions?.frontPermissions.includes("editTeamCode"); if (!isRequestorAuthorized) { res.status(403).send("You are not authorized to update this user"); @@ -305,6 +308,17 @@ const userProfileController = function (UserProfile) { record.totalIntangibleHrs = req.body.totalIntangibleHrs; record.bioPosted = req.body.bioPosted || "default"; record.isFirstTimelog = req.body.isFirstTimelog; + + if(!canEditTeamCode && record.teamCode !== req.body.teamCode){ + res.status(403).send("You are not authorized to edit team code."); + return; + } + + const teamcodeRegex = /^[A-Z]-[A-Z]{3}$/; + if (!teamcodeRegex.test(req.body.teamCode)) { + res.status(400).send("The team code is invalid"); + return; + }; record.teamCode = req.body.teamCode; // find userData in cache @@ -591,6 +605,22 @@ 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.permissions?.frontPermissions.includes("editTeamCode"); + const teamcodeRegex = /^[A-Z]-[A-Z]{3}$/; + + if(!canEditTeamCode){ + res.status(403).send("You are not authorized to edit team code."); + return; + } + + if (!teamcodeRegex.test(value)) { + res.status(400).send("The team code is invalid"); + return; + }; + } + // 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' }); From 2c38d3c65d525d3265f7d64e177a28a492b865fa Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Tue, 3 Oct 2023 17:48:38 +0800 Subject: [PATCH 052/272] hotfix for code regex check --- src/controllers/userProfileController.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index c1c3a2a0a..ad2a0efd9 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -314,7 +314,7 @@ const userProfileController = function (UserProfile) { return; } - const teamcodeRegex = /^[A-Z]-[A-Z]{3}$/; + const teamcodeRegex = /^[a-zA-Z]-[a-zA-Z]{3}$/; if (!teamcodeRegex.test(req.body.teamCode)) { res.status(400).send("The team code is invalid"); return; @@ -608,7 +608,7 @@ const userProfileController = function (UserProfile) { if (key === "teamCode") { const canEditTeamCode = req.body.requestor.role === "Owner" || req.body.requestor.permissions?.frontPermissions.includes("editTeamCode"); - const teamcodeRegex = /^[A-Z]-[A-Z]{3}$/; + const teamcodeRegex = /^[a-zA-Z]-[a-zA-Z]{3}$/; if(!canEditTeamCode){ res.status(403).send("You are not authorized to edit team code."); From 2360136d78c82b61a263b24dc5265cfc1ad04588 Mon Sep 17 00:00:00 2001 From: Nathan Hoffman Date: Tue, 3 Oct 2023 13:18:29 -0700 Subject: [PATCH 053/272] Fix merge conflict extra bracket --- src/controllers/projectController.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/controllers/projectController.js b/src/controllers/projectController.js index b0239835d..a88378985 100644 --- a/src/controllers/projectController.js +++ b/src/controllers/projectController.js @@ -127,7 +127,6 @@ const projectController = function (Project) { if (!await hasPermission(req.body.requestor, 'assignProjectToUsers')) { res.status(403).send({ error: 'You are not authorized to perform this operation' }); return; - } } if (!req.params.projectId || !mongoose.Types.ObjectId.isValid(req.params.projectId) || !req.body.users || (req.body.users.length === 0)) { From 92059d53fff2bc23a21b249f568f172d83849aca Mon Sep 17 00:00:00 2001 From: Nathan Hoffman Date: Tue, 3 Oct 2023 13:22:50 -0700 Subject: [PATCH 054/272] fix another extra bracket --- src/controllers/userProfileController.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 0899ab83b..447b14d94 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -55,7 +55,6 @@ const userProfileController = function (UserProfile) { if (!await hasPermission(req.body.requestor, 'getUserProfiles')) { res.status(403).send('You are not authorized to view all users'); return; - } } if (cache.getCache("allusers")) { From 1e096f26a066587f7eea80e771894ecce4a3f50d Mon Sep 17 00:00:00 2001 From: Jerry Ren Date: Wed, 4 Oct 2023 15:11:44 -0400 Subject: [PATCH 055/272] Created isEmailExists Controller and Router --- src/controllers/isEmailExistsController.js | 25 ++++++++++++++++++++++ src/routes/isEmailExistsRouter.js | 15 +++++++++++++ src/startup/routes.js | 3 +++ 3 files changed, 43 insertions(+) create mode 100644 src/controllers/isEmailExistsController.js create mode 100644 src/routes/isEmailExistsRouter.js diff --git a/src/controllers/isEmailExistsController.js b/src/controllers/isEmailExistsController.js new file mode 100644 index 000000000..2c41efc33 --- /dev/null +++ b/src/controllers/isEmailExistsController.js @@ -0,0 +1,25 @@ +const UserProfile = require('../models/userProfile'); + +const isEmailExistsController = function () { + + const isEmailExists = async function (req, res) { + + try { + const userProfile = await UserProfile.findOne({ email: req.params.email }).lean().exec() + + if (userProfile) { + res.status(200).send(`Email, ${userProfile.email}, found.`) + } else { + res.status(403).send(`Email, ${req.params.email}, not found.`) + } + } catch (err) { + console.log(err) + } + } + + return { + isEmailExists + } +} + +module.exports = isEmailExistsController diff --git a/src/routes/isEmailExistsRouter.js b/src/routes/isEmailExistsRouter.js new file mode 100644 index 000000000..cfb4e6033 --- /dev/null +++ b/src/routes/isEmailExistsRouter.js @@ -0,0 +1,15 @@ + +const express = require('express'); + +const routes = function () { + const controller = require('../controllers/isEmailExistsController')() + + const isEmailExistsRouter = express.Router() + + isEmailExistsRouter.route("/is-email-exists/:email") + .get(controller.isEmailExists) + + return isEmailExistsRouter +} + +module.exports = routes diff --git a/src/startup/routes.js b/src/startup/routes.js index 43cd226bd..296b10b69 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -43,6 +43,8 @@ const taskNotificationRouter = require('../routes/taskNotificationRouter')(taskN const inventoryRouter = require('../routes/inventoryRouter')(inventoryItem, inventoryItemType); const timeZoneAPIRouter = require('../routes/timeZoneAPIRoutes')(); const profileInitialSetupRouter = require('../routes/profileInitialSetupRouter')(profileInitialSetuptoken, userProfile, project); +const isEmailExistsRouter = require('../routes/isEmailExistsRouter')(); + const taskEditSuggestion = require('../models/taskEditSuggestion'); const taskEditSuggestionRouter = require('../routes/taskEditSuggestionRouter')(taskEditSuggestion); @@ -86,6 +88,7 @@ module.exports = function (app) { app.use('/api', reasonRouter); app.use('/api', informationRouter); app.use('/api', mouseoverTextRouter); + app.use('/api', isEmailExistsRouter); // bm dashboard app.use('/api/bm', bmLoginRouter); }; From d4e04bd6c970ec6c27a4b21d48ba64b1b3c8fdfc Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Wed, 4 Oct 2023 16:31:43 -0700 Subject: [PATCH 056/272] populate db fetch with project, inventoryItemType objects --- src/controllers/bmdashboard/bmMaterialsController.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index 797d5730d..b55b70b7e 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -4,6 +4,14 @@ const bmMaterialsController = function (ItemMaterial, ItemType) { const bmMaterialsList = async function _matsList(req, res) { try { ItemMaterial.find() + .populate({ + path: 'project', + select: '_id projectName' + }) + .populate({ + path: 'inventoryItemType', + select: '_id name uom totalStock' + }) .then(results => res.status(200).send(results)) .catch(error => res.status(500).send(error)) } catch (err) { From b7201d5b0a0d542510c1ed2178db7bf6da6312da Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Thu, 5 Oct 2023 16:27:37 +0800 Subject: [PATCH 057/272] allow five-letter code --- src/controllers/userProfileController.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index ad2a0efd9..afafe2488 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -314,7 +314,7 @@ const userProfileController = function (UserProfile) { return; } - const teamcodeRegex = /^[a-zA-Z]-[a-zA-Z]{3}$/; + const teamcodeRegex = /^([a-zA-Z]-[a-zA-Z]{3}|[a-zA-Z]{5})$/; if (!teamcodeRegex.test(req.body.teamCode)) { res.status(400).send("The team code is invalid"); return; @@ -608,7 +608,7 @@ const userProfileController = function (UserProfile) { if (key === "teamCode") { const canEditTeamCode = req.body.requestor.role === "Owner" || req.body.requestor.permissions?.frontPermissions.includes("editTeamCode"); - const teamcodeRegex = /^[a-zA-Z]-[a-zA-Z]{3}$/; + const teamcodeRegex = /^([a-zA-Z]-[a-zA-Z]{3}|[a-zA-Z]{5})$/; if(!canEditTeamCode){ res.status(403).send("You are not authorized to edit team code."); From df10cce04fdf0c5aa9734d05eb3808ce2a5c02dd Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Thu, 5 Oct 2023 19:40:00 +0800 Subject: [PATCH 058/272] add new properties to timeEntry modal and update related function --- src/controllers/projectController.js | 2 +- src/controllers/timeEntryController.js | 194 ++++++++++++++++++++++--- src/models/timeentry.js | 6 +- src/routes/timeentryRouter.js | 9 ++ 4 files changed, 188 insertions(+), 23 deletions(-) diff --git a/src/controllers/projectController.js b/src/controllers/projectController.js index 7f10b0f86..4d5626083 100644 --- a/src/controllers/projectController.js +++ b/src/controllers/projectController.js @@ -28,7 +28,7 @@ const projectController = function (Project) { // find if project has any time enteries associated with it - timeentry.find({ projectId: record._id }, '_id') + timeentry.find({ projectId: record._id, entryType: [ 'default', 'project', null ] }, '_id') .then((timeentries) => { if (timeentries.length > 0) { res.status(400).send({ error: 'This project has associated time entries and cannot be deleted. Consider inactivaing it instead.' }); diff --git a/src/controllers/timeEntryController.js b/src/controllers/timeEntryController.js index e83a7e31b..4e482b085 100644 --- a/src/controllers/timeEntryController.js +++ b/src/controllers/timeEntryController.js @@ -129,6 +129,7 @@ const timeEntrycontroller = function (TimeEntry) { timeEntry.lastModifiedDateTime = moment().utc().toISOString(); timeEntry.projectId = mongoose.Types.ObjectId(req.body.projectId); timeEntry.dateOfWork = moment(req.body.dateOfWork).format('YYYY-MM-DD'); + timeEntry.entryType = req.body.entryType; // Update the hoursLogged field of related tasks based on before and after timeEntries // initialIsTangible is a bealoon value, req.body.isTangible is a string @@ -224,43 +225,80 @@ const timeEntrycontroller = function (TimeEntry) { } const items = []; records.forEach((element) => { - const timeentry = new TimeEntry(); - timeentry.personId = element.personId; - timeentry.projectId = element.projectId; - timeentry.dateOfWork = element.dateOfWork; - timeentry.timeSpent = moment('1900-01-01 00:00:00') - .add(element.totalSeconds, 'seconds') - .format('HH:mm:ss'); - timeentry.notes = element.notes; - timeentry.isTangible = element.isTangible; - items.push(timeentry); + if (element.entryType == 'default' || element.entryType == undefined) { + const timeentry = new TimeEntry(); + timeentry.personId = element.personId; + timeentry.projectId = element.projectId; + timeentry.dateOfWork = element.dateOfWork; + timeentry.timeSpent = moment('1900-01-01 00:00:00') + .add(element.totalSeconds, 'seconds') + .format('HH:mm:ss'); + timeentry.notes = element.notes; + timeentry.isTangible = element.isTangible; + timeentry.entryType = 'default'; + items.push(timeentry); + } }); return res.json(items).status(200); }); }; const postTimeEntry = async function (req, res) { - if ( - !mongoose.Types.ObjectId.isValid(req.body.personId) - || !mongoose.Types.ObjectId.isValid(req.body.projectId) - || !req.body.dateOfWork + const isInvalid = !req.body.dateOfWork || !moment(req.body.dateOfWork).isValid() || !req.body.timeSpent - || !req.body.isTangible - ) { + || !req.body.isTangible; + + const returnErr = (res) => { res.status(400).send({ error: 'Bad request' }); return; + }; + + switch (req.body.entryType) { + case 'default': + if ( + !mongoose.Types.ObjectId.isValid(req.body.personId) + || !mongoose.Types.ObjectId.isValid(req.body.projectId) + || isInvalid + ) { + returnErr(res); + } + break; + case 'person': + if ( + !mongoose.Types.ObjectId.isValid(req.body.personId) || isInvalid + ) { + returnErr(res); + } + break; + case 'project': + if ( + !mongoose.Types.ObjectId.isValid(req.body.projectId) || isInvalid + ) { + returnErr(res); + } + break; + case 'team': + if ( + !mongoose.Types.ObjectId.isValid(req.body.teamId) || isInvalid + ) { + returnErr(res); + } + break; } + const timeentry = new TimeEntry(); const { dateOfWork, timeSpent } = req.body; timeentry.personId = req.body.personId; timeentry.projectId = req.body.projectId; + timeentry.teamId = req.body.teamId; timeentry.dateOfWork = moment(dateOfWork).format('YYYY-MM-DD'); timeentry.totalSeconds = moment.duration(timeSpent).asSeconds(); timeentry.notes = req.body.notes; timeentry.isTangible = req.body.isTangible; timeentry.createdDateTime = moment().utc().toISOString(); timeentry.lastModifiedDateTime = moment().utc().toISOString(); + timeentry.entryType = req.body.entryType; timeentry .save() @@ -272,7 +310,7 @@ const timeEntrycontroller = function (TimeEntry) { .catch(error => res.status(400).send(error)); // Add this tangbile time entry to related task's hoursLogged - if (timeentry.isTangible === true) { + if ((timeentry.entryType == 'default') && timeentry.isTangible === true) { try { const currentTask = await task.findById(req.body.projectId); currentTask.hoursLogged += (timeentry.totalSeconds / 3600); @@ -282,9 +320,11 @@ const timeEntrycontroller = function (TimeEntry) { } } // checking if logged in hours exceed estimated time after timeentry for a task - const record = await userProfile.findById(timeentry.personId.toString()); - const currentTask = await task.findById(req.body.projectId); - checkTaskOvertime(timeentry, record, currentTask); + if (timeentry.entryType == 'default') { + const record = await userProfile.findById(timeentry.personId.toString()); + const currentTask = await task.findById(req.body.projectId); + checkTaskOvertime(timeentry, record, currentTask); + } }; const getTimeEntriesForSpecifiedPeriod = function (req, res) { @@ -307,6 +347,7 @@ const timeEntrycontroller = function (TimeEntry) { TimeEntry.aggregate([ { $match: { + entryType: { $in: [ 'default', null ] }, personId: mongoose.Types.ObjectId(userId), dateOfWork: { $gte: fromdate, $lte: todate }, }, @@ -390,6 +431,7 @@ const timeEntrycontroller = function (TimeEntry) { TimeEntry.find( { + entryType: { $in: [ 'default', null, 'person' ] }, personId: { $in: users }, dateOfWork: { $gte: fromDate, $lte: toDate }, }, @@ -434,6 +476,7 @@ const timeEntrycontroller = function (TimeEntry) { const { projectId } = req.params; TimeEntry.find( { + entryType: [ 'default', null ], projectId, dateOfWork: { $gte: fromDate, $lte: todate }, }, @@ -494,6 +537,114 @@ const timeEntrycontroller = function (TimeEntry) { }); }; + const getLostTimeEntriesForUserList = function (req, res) { + const { users, fromDate, toDate } = req.body; + + TimeEntry.find( + { + entryType: 'person', + personId: { $in: users }, + dateOfWork: { $gte: fromDate, $lte: toDate }, + }, + ' -createdDateTime', + ) + .populate('personId') + .sort({ lastModifiedDateTime: -1 }) + .then((results) => { + const data = []; + results.forEach((element) => { + console.log(element); + const record = {}; + + record._id = element._id; + record.notes = element.notes; + record.isTangible = element.isTangible; + record.personId = element.personId; + record.firstName = element.personId + ? element.personId.firstName + : ''; + record.lastName = element.personId + ? element.personId.lastName + : ''; + record.dateOfWork = element.dateOfWork; + record.entryType = element.entryType; + [record.hours, record.minutes] = formatSeconds(element.totalSeconds); + data.push(record); + }); + res.status(200).send(data); + }) + .catch(error => res.status(400).send(error)); + }; + + const getLostTimeEntriesForProjectList = function (req, res) { + const { projects, fromDate, toDate } = req.body; + + TimeEntry.find( + { + entryType: "project", + projectId: { $in: projects }, + dateOfWork: { $gte: fromDate, $lte: toDate }, + }, + ' -createdDateTime', + ) + .populate('projectId') + .sort({ lastModifiedDateTime: -1 }) + .then((results) => { + const data = []; + results.forEach((element) => { + console.log(element); + const record = {}; + record._id = element._id; + record.notes = element.notes; + record.isTangible = element.isTangible; + record.projectId = element.projectId ? element.projectId._id : ''; + record.projectName = element.projectId + ? element.projectId.projectName + : ''; + record.dateOfWork = element.dateOfWork; + record.entryType = element.entryType; + [record.hours, record.minutes] = formatSeconds(element.totalSeconds); + data.push(record); + }); + res.status(200).send(data); + }) + .catch(error => res.status(400).send(error)); + }; + + const getLostTimeEntriesForTeamList = function (req, res) { + const { teams, fromDate, toDate } = req.body; + + TimeEntry.find( + { + entryType: "team", + teamId: { $in: teams }, + dateOfWork: { $gte: fromDate, $lte: toDate }, + }, + ' -createdDateTime', + ) + .populate('teamId') + .sort({ lastModifiedDateTime: -1 }) + .then((results) => { + const data = []; + results.forEach((element) => { + console.log(element); + const record = {}; + record._id = element._id; + record.notes = element.notes; + record.isTangible = element.isTangible; + record.teamId = element.teamId; + record.teamName = element.teamId + ? element.teamId.teamName + : ''; + record.dateOfWork = element.dateOfWork; + record.entryType = element.entryType; + [record.hours, record.minutes] = formatSeconds(element.totalSeconds); + data.push(record); + }); + res.status(200).send(data); + }) + .catch(error => res.status(400).send(error)); + }; return { getAllTimeEnteries, @@ -504,6 +655,9 @@ const timeEntrycontroller = function (TimeEntry) { deleteTimeEntry, getTimeEntriesForSpecifiedProject, checkTaskOvertime, + getLostTimeEntriesForUserList, + getLostTimeEntriesForProjectList, + getLostTimeEntriesForTeamList, }; }; diff --git a/src/models/timeentry.js b/src/models/timeentry.js index aeef5fdc7..83510773f 100644 --- a/src/models/timeentry.js +++ b/src/models/timeentry.js @@ -4,8 +4,10 @@ const { Schema } = mongoose; const TimeEntry = new Schema({ - personId: { type: Schema.Types.ObjectId, required: [true, 'Resource is a required field'], ref: 'userProfile' }, - projectId: { type: Schema.Types.ObjectId, required: [true, 'Project is a required field'], ref: 'project' }, + entryType: { type: String, required: true, default: 'default' }, + personId: { type: Schema.Types.ObjectId, ref: 'userProfile' }, + projectId: { type: Schema.Types.ObjectId, ref: 'project' }, + teamId: { type: Schema.Types.ObjectId, ref: 'team' }, dateOfWork: { type: String, required: true }, totalSeconds: { type: Number }, notes: { type: String }, diff --git a/src/routes/timeentryRouter.js b/src/routes/timeentryRouter.js index b319aa595..7e0a41797 100644 --- a/src/routes/timeentryRouter.js +++ b/src/routes/timeentryRouter.js @@ -19,6 +19,15 @@ const routes = function (TimeEntry) { TimeEntryRouter.route('/TimeEntry/users') .post(controller.getTimeEntriesForUsersList); + TimeEntryRouter.route('/TimeEntry/lostUsers') + .post(controller.getLostTimeEntriesForUserList); + + TimeEntryRouter.route('/TimeEntry/lostProjects') + .post(controller.getLostTimeEntriesForProjectList); + + TimeEntryRouter.route('/TimeEntry/lostTeams') + .post(controller.getLostTimeEntriesForTeamList); + TimeEntryRouter.route('/TimeEntry/projects/:projectId/:fromDate/:toDate') .get(controller.getTimeEntriesForSpecifiedProject); From 975a858079086a9e3e88249ca0e3f49277d620ae Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Thu, 5 Oct 2023 11:55:09 -0700 Subject: [PATCH 059/272] update populate method --- .../bmdashboard/bmMaterialsController.js | 42 +++++++++++++++---- src/routes/bmdashboard/bmMaterialsRouter.js | 4 +- src/startup/routes.js | 2 +- 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index b55b70b7e..a31ed460e 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -1,17 +1,41 @@ const mongoose = require('mongoose') -const bmMaterialsController = function (ItemMaterial, ItemType) { +const bmMaterialsController = function (ItemMaterial) { const bmMaterialsList = async function _matsList(req, res) { try { ItemMaterial.find() - .populate({ - path: 'project', - select: '_id projectName' - }) - .populate({ - path: 'inventoryItemType', - select: '_id name uom totalStock' - }) + .populate([ + { + path: 'project', + select: '_id projectName' + }, + { + path: 'inventoryItemType', + select: '_id name uom totalStock totalAvailable' + }, + { + path: 'usageRecord', + populate: { + path: 'createdBy', + select: '_id firstName lastName' + } + }, + { + path: 'updateRecord', + populate: { + path: 'createdBy', + select: '_id firstName lastName' + } + }, + { + path: 'purchaseRecord', + populate: { + path: 'createdBy', + select: '_id firstName lastName' + } + } + ]) + .exec() .then(results => res.status(200).send(results)) .catch(error => res.status(500).send(error)) } catch (err) { diff --git a/src/routes/bmdashboard/bmMaterialsRouter.js b/src/routes/bmdashboard/bmMaterialsRouter.js index d3e4518da..ab8a67388 100644 --- a/src/routes/bmdashboard/bmMaterialsRouter.js +++ b/src/routes/bmdashboard/bmMaterialsRouter.js @@ -1,8 +1,8 @@ const express = require('express'); -const routes = function (itemMaterial, itemType) { +const routes = function (itemMaterial) { const materialsRouter = express.Router(); -const controller = require('../../controllers/bmdashboard/bmMaterialsController')(itemMaterial, itemType); +const controller = require('../../controllers/bmdashboard/bmMaterialsController')(itemMaterial); materialsRouter.route('/materials') .get(controller.bmMaterialsList); diff --git a/src/startup/routes.js b/src/startup/routes.js index cde07c94d..bbd22b530 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -56,7 +56,7 @@ const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverTe // bm dashboard const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); -const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial, inventoryItemType); +const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial); module.exports = function (app) { app.use('/api', forgotPwdRouter); From ba03b5b00594cace86a084e12897e05b8669dbe7 Mon Sep 17 00:00:00 2001 From: GaryB93 Date: Thu, 5 Oct 2023 17:05:38 -0500 Subject: [PATCH 060/272] add material routing, inventoryItemMaterial schema --- package-lock.json | 106 +++++++++--------- .../bmdashboard/bmMaterialsController.js | 40 +++++++ src/models/inventoryItemMaterial.js | 36 ++++++ src/routes/bmdashboard/bmMaterialsRouter.js | 14 +++ src/startup/routes.js | 4 +- 5 files changed, 146 insertions(+), 54 deletions(-) create mode 100644 src/controllers/bmdashboard/bmMaterialsController.js create mode 100644 src/models/inventoryItemMaterial.js create mode 100644 src/routes/bmdashboard/bmMaterialsRouter.js diff --git a/package-lock.json b/package-lock.json index 5c6bd6db5..47eb32afb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1414,7 +1414,7 @@ "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, "@types/mime": { @@ -1570,7 +1570,7 @@ "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, "array-includes": { "version": "3.1.6", @@ -2631,7 +2631,7 @@ "bcryptjs": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", - "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" + "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" }, "bignumber.js": { "version": "9.0.2", @@ -2727,7 +2727,7 @@ "buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" }, "buffer-from": { "version": "1.1.2", @@ -2860,7 +2860,7 @@ "clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==" }, "clone-deep": { "version": "4.0.1", @@ -2904,12 +2904,12 @@ "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "concat-stream": { "version": "1.6.2", @@ -2965,7 +2965,7 @@ "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "core-js": { "version": "3.21.1", @@ -3118,7 +3118,7 @@ "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "electron-to-chromium": { "version": "1.4.81", @@ -3134,7 +3134,7 @@ "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" }, "es-abstract": { "version": "1.19.1", @@ -3215,7 +3215,7 @@ "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "escape-string-regexp": { "version": "1.0.5", @@ -4129,7 +4129,7 @@ "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, "event-target-shim": { "version": "5.0.1", @@ -4294,7 +4294,7 @@ "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, "fast-text-encoding": { @@ -4424,7 +4424,7 @@ "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" }, "fs-readdir-recursive": { "version": "1.1.0", @@ -4434,7 +4434,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "fsevents": { "version": "2.3.2", @@ -4812,7 +4812,7 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true }, "indent-string": { @@ -4824,7 +4824,7 @@ "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "requires": { "once": "^1.3.0", "wrappy": "1" @@ -4930,7 +4930,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" }, "is-glob": { "version": "4.0.3", @@ -5032,13 +5032,13 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" }, "js-tokens": { "version": "4.0.0", @@ -5076,7 +5076,7 @@ "json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, "json5": { @@ -5397,7 +5397,7 @@ "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, "lodash.merge": { "version": "4.6.2", @@ -5574,7 +5574,7 @@ "lru_map": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", - "integrity": "sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0=" + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==" }, "make-dir": { "version": "2.1.0", @@ -5588,7 +5588,7 @@ "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" }, "memory-pager": { "version": "1.5.0", @@ -5599,7 +5599,7 @@ "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" }, "merge-stream": { "version": "2.0.0", @@ -5610,7 +5610,7 @@ "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" }, "micromatch": { "version": "4.0.5", @@ -5767,7 +5767,7 @@ "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, "negotiator": { @@ -5845,7 +5845,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" }, "object-inspect": { "version": "1.12.0", @@ -6564,7 +6564,7 @@ "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "requires": { "wrappy": "1" } @@ -6594,7 +6594,7 @@ "os-shim": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz", - "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=", + "integrity": "sha512-jd0cvB8qQ5uVt0lvCIexBaROw1KyKm5sbulg2fWOHjETisuCzWyt+eTZKEMs8v6HwzoGs8xik26jg7eCM6pS+A==", "dev": true }, "p-limit": { @@ -6639,7 +6639,7 @@ "parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==" }, "parseurl": { "version": "1.3.3", @@ -6654,7 +6654,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" }, "path-key": { "version": "3.1.1", @@ -6670,7 +6670,7 @@ "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, "picocolors": { "version": "1.0.0", @@ -6717,7 +6717,7 @@ "pre-commit": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/pre-commit/-/pre-commit-1.2.2.tgz", - "integrity": "sha1-287g7p3nI15X95xW186UZBpp7sY=", + "integrity": "sha512-qokTiqxD6GjODy5ETAIgzsRgnBWWQHQH2ghy86PU7mIn/wuWeTwF3otyNQZxWBwVn8XNr8Tdzj/QfUXpH+gRZA==", "dev": true, "requires": { "cross-spawn": "^5.0.1", @@ -6728,7 +6728,7 @@ "cross-spawn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", "dev": true, "requires": { "lru-cache": "^4.0.1", @@ -6739,7 +6739,7 @@ "which": { "version": "1.2.14", "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", - "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "integrity": "sha512-16uPglFkRPzgiUXYMi1Jf8Z5EzN1iB4V0ZtMXcHZnwsBtQhhHeCqoWw7tsUY42hJGNDWtUsVLTjakIa5BgAxCw==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -6781,7 +6781,7 @@ "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", "dev": true }, "punycode": { @@ -7219,7 +7219,7 @@ "sparse-bitfield": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", "optional": true, "requires": { "memory-pager": "^1.0.2" @@ -7228,7 +7228,7 @@ "spawn-sync": { "version": "1.0.15", "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", - "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=", + "integrity": "sha512-9DWBgrgYZzNghseho0JOuh+5fg9u6QWhAWa51QC7+U5rCheZ/j1DrEZnyE0RBBRqZ9uEXGPgSSM0nky6burpVw==", "dev": true, "requires": { "concat-stream": "^1.4.7", @@ -7623,7 +7623,7 @@ "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true }, "strip-final-newline": { @@ -7654,19 +7654,19 @@ "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" }, "to-regex-range": { "version": "5.0.1", @@ -7684,7 +7684,7 @@ "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "tsconfig-paths": { "version": "3.14.2", @@ -7802,7 +7802,7 @@ "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "dev": true }, "unbox-primitive": { @@ -7843,7 +7843,7 @@ "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" }, "uri-js": { "version": "4.4.1", @@ -7857,17 +7857,17 @@ "url-template": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", - "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" + "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==" }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" }, "uuid": { "version": "3.4.0", @@ -7890,17 +7890,17 @@ "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -8018,7 +8018,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "ws": { "version": "8.8.1", diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js new file mode 100644 index 000000000..558a0f403 --- /dev/null +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -0,0 +1,40 @@ +const mongoose = require('mongoose'); + +const bmMaterialsController = function (ItemMaterial, ItemType) { + const bmMaterialsList = async function (req, res) { + try { + ItemMaterial.find() + .populate({ + path: 'project', + select: '_id projectName' + }) + .populate({ + path: 'inventoryItemType', + select: '_id name uom totalStock' + }) + .then(results => res.status(200).send(results)) + .catch(error => res.status(500).send(error)) + } catch (err) { + res.json(err); + } + }; + + const bmAddMaterials = async function (req, res) { + console.log(req.body); + // if new material or new measurement, add to inventoryItemType collection first + const { material, requestor } = req.body; + if (material.newMaterial || material.newMeasurement) { + const materials = await ItemMaterial.find().exec(); + console.log(materials); + + } + // then either add item material to project or update existing item material + }; + + return { + bmMaterialsList, + bmAddMaterials + }; +}; + +module.exports = bmMaterialsController; \ No newline at end of file diff --git a/src/models/inventoryItemMaterial.js b/src/models/inventoryItemMaterial.js new file mode 100644 index 000000000..0c8aed460 --- /dev/null +++ b/src/models/inventoryItemMaterial.js @@ -0,0 +1,36 @@ +const mongoose = require('mongoose'); +const { Schema } = mongoose; + +const InventoryItemMaterial = new Schema({ + inventoryItemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'inventoryItemType', required: true }, + project: { type: mongoose.SchemaTypes.ObjectId, ref: 'project', required: true }, + stockBought: { type: Number, required: true }, // amount bought for project, affects total stock + stockUsed: { type: Number, required: true }, + stockAvailable: { type: Number, required: true }, + stockHeld: { type: Number, required: true }, + stockWasted: { type: Number, required: true }, + usageRecord: [{ // daily log of amount inventory item used at job site + date: { type: Date, required: true, default: Date.now() }, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile', required: true }, + quantityUsed: { type: Number, required: true }, + }], + updateRecord: [{ // incident report affecting quantity/status of inventory item + date: { type: Date, required: true, default: Date.now() }, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile', required: true }, + action: { type: String, required: true }, // ex: Add, Reduce, Hold (updates stock quantities) + cause: { type: String, required: true }, // ex: Used, Lost, Wasted, Transfer (reason for update) + quantity: { type: Number, required: true }, // amount of material affected + description: { type: String, required: true, maxLength: 150 }, + }], + purchaseRecord: [{ + date: { type: Date, required: true, default: Date.now() }, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile', required: true }, + poId: { type: String, required: true }, + sellerId: { type: String, required: true }, + quantity: { type: Number, required: true }, // adds to stockBought + subtotal: { type: Number, required: true }, + tax: { type: Number, required: true }, + shipping: { type: Number, required: true }, + }] +}) +module.exports = mongoose.model('inventoryItemMaterial', InventoryItemMaterial, 'inventoryMaterial'); \ No newline at end of file diff --git a/src/routes/bmdashboard/bmMaterialsRouter.js b/src/routes/bmdashboard/bmMaterialsRouter.js new file mode 100644 index 000000000..aaded5587 --- /dev/null +++ b/src/routes/bmdashboard/bmMaterialsRouter.js @@ -0,0 +1,14 @@ +const express = require('express'); + +const routes = function (itemMaterial, itemType) { + const materialsRouter = express.Router(); + const controller = require('../../controllers/bmdashboard/bmMaterialsController')(itemMaterial, itemType); + + materialsRouter.route('/materials') + .get(controller.bmMaterialsList) + .post(controller.bmAddMaterials); + + return materialsRouter; +}; + +module.exports = routes; \ No newline at end of file diff --git a/src/startup/routes.js b/src/startup/routes.js index 43cd226bd..a1eed4a7a 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -20,6 +20,7 @@ const ownerStandardMessage = require('../models/ownerStandardMessage'); const profileInitialSetuptoken = require('../models/profileInitialSetupToken'); const reason = require('../models/reason'); const mouseoverText = require('../models/mouseoverText'); +const itemMaterial = require('../models/inventoryItemMaterial'); const userProfileRouter = require('../routes/userProfileRouter')(userProfile); const badgeRouter = require('../routes/badgeRouter')(badge); @@ -55,7 +56,7 @@ const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverTe // bm dashboard const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); - +const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(itemMaterial); module.exports = function (app) { app.use('/api', forgotPwdRouter); @@ -88,4 +89,5 @@ module.exports = function (app) { app.use('/api', mouseoverTextRouter); // bm dashboard app.use('/api/bm', bmLoginRouter); + app.use('/api/bm', bmMaterialsRouter); }; From bbc244e5274541a73f198c58937eaa3ba7bc90aa Mon Sep 17 00:00:00 2001 From: GaryB93 Date: Fri, 6 Oct 2023 14:36:14 -0500 Subject: [PATCH 061/272] controller logic for adding materials, update schemas --- .../bmdashboard/bmMaterialsController.js | 58 +++++++++++++++++-- src/models/inventoryItemMaterial.js | 8 ++- src/models/inventoryItemType.js | 9 ++- src/startup/routes.js | 2 +- 4 files changed, 66 insertions(+), 11 deletions(-) diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index 558a0f403..d9d1c7780 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -21,14 +21,62 @@ const bmMaterialsController = function (ItemMaterial, ItemType) { const bmAddMaterials = async function (req, res) { console.log(req.body); - // if new material or new measurement, add to inventoryItemType collection first const { material, requestor } = req.body; + let itemTypeId = material.material; // if new material: material name / else: itemType id + + // if new material or new measurement, add new inventoryItemType if (material.newMaterial || material.newMeasurement) { - const materials = await ItemMaterial.find().exec(); - console.log(materials); - + try { + const itemType = new ItemType({ + type: 'material', + name: material.material, + description: material.description, + uom: material.measurement, + totalStock: material.quantity, + totalAvailable: material.quantity, + projectsUsing: [material.projectId], + imageUrl: '', + link: material.link, + }); + const newItemType = await itemType.save(); + itemTypeId = newItemType._id; + } catch (err) { + res.status(400).send({ error: 'Error saving new material type'}); + } + } + + try { + const invMaterial = await ItemMaterial.find({ id: material.projectId, inventoryItemType: itemTypeId }).exec(); + // if material already exists in project, add to it + // else, create new material for project + if (invMaterial) { + // TODO + console.log(invMaterial); + } else { + const itemMaterial = new ItemMaterial({ + inventoryItemType: itemTypeId, + project: material.projectId, + stockBought: material.quantity, + stockAvailable: material.quantity, + usageRecord: [], + updateRecord: [], + purchaseRecord: [{ + date: material.purchaseDate, + createdBy: req.requestor.requestorId, + poId: material.invoice, + sellerId: material.phone, + quantity: material.quantity, + unitPrice: material.unitPrice, + subTotal: material.quantity * material.unitPrice, + tax: material.taxRate, + shipping: material.shippingFee, + }], + }); + const newItemMaterial = await itemMaterial.save(); + } + } catch (err) { + res.status(400).send({ error: 'Error adding new material to project'}); } - // then either add item material to project or update existing item material }; return { diff --git a/src/models/inventoryItemMaterial.js b/src/models/inventoryItemMaterial.js index 0c8aed460..09c521e4d 100644 --- a/src/models/inventoryItemMaterial.js +++ b/src/models/inventoryItemMaterial.js @@ -5,10 +5,10 @@ const InventoryItemMaterial = new Schema({ inventoryItemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'inventoryItemType', required: true }, project: { type: mongoose.SchemaTypes.ObjectId, ref: 'project', required: true }, stockBought: { type: Number, required: true }, // amount bought for project, affects total stock - stockUsed: { type: Number, required: true }, + stockUsed: { type: Number, default: 0 }, stockAvailable: { type: Number, required: true }, - stockHeld: { type: Number, required: true }, - stockWasted: { type: Number, required: true }, + stockHeld: { type: Number, default: 0 }, + stockWasted: { type: Number, default: 0 }, usageRecord: [{ // daily log of amount inventory item used at job site date: { type: Date, required: true, default: Date.now() }, createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile', required: true }, @@ -28,6 +28,8 @@ const InventoryItemMaterial = new Schema({ poId: { type: String, required: true }, sellerId: { type: String, required: true }, quantity: { type: Number, required: true }, // adds to stockBought + unitPrice: { type: Number, required: true }, + currency: { type: String, required: true }, subtotal: { type: Number, required: true }, tax: { type: Number, required: true }, shipping: { type: Number, required: true }, diff --git a/src/models/inventoryItemType.js b/src/models/inventoryItemType.js index 80e5e0d7b..20a58c018 100644 --- a/src/models/inventoryItemType.js +++ b/src/models/inventoryItemType.js @@ -3,10 +3,15 @@ const mongoose = require('mongoose'); const { Schema } = mongoose; const InventoryItemType = new Schema({ + type: { type: String, required: true }, // ie Material, Equipment, Tool name: { type: String, required: true }, - description: { type: String }, + description: { type: String, required: true, maxLength: 150 }, + uom: { type: String, required: true }, // unit of measurement + totalStock: { type: Number, required: true }, // total amount of all stock acquired + totalAvailable: { type: Number, required: true }, + projectsUsing: [ {type: mongoose.SchemaTypes.ObjectId, ref: 'project'} ], imageUrl: { type: String }, - quantifier: { type: String, default: 'each' }, + link: { type: String }, }); module.exports = mongoose.model('inventoryItemType', InventoryItemType, 'inventoryItemType'); diff --git a/src/startup/routes.js b/src/startup/routes.js index a1eed4a7a..66f7772dd 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -56,7 +56,7 @@ const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverTe // bm dashboard const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); -const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(itemMaterial); +const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(itemMaterial, inventoryItemType); module.exports = function (app) { app.use('/api', forgotPwdRouter); From 3d56ee05c122529239361e23ed58439218accdea Mon Sep 17 00:00:00 2001 From: robertoooc Date: Sat, 7 Oct 2023 16:51:34 -0700 Subject: [PATCH 062/272] added logic to clear cache when updating badge so user info is up to date --- src/controllers/badgeController.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/controllers/badgeController.js b/src/controllers/badgeController.js index 6238c381e..e3768884a 100644 --- a/src/controllers/badgeController.js +++ b/src/controllers/badgeController.js @@ -2,6 +2,7 @@ const mongoose = require('mongoose'); const UserProfile = require('../models/userProfile'); const { hasPermission, hasIndividualPermission } = require('../utilities/permissions'); const escapeRegex = require('../utilities/escapeRegex'); +const cache = require('../utilities/nodeCache')(); const badgeController = function (Badge) { const getAllBadges = async function (req, res) { @@ -47,6 +48,8 @@ const badgeController = function (Badge) { if (result) { record.badgeCollection = req.body.badgeCollection; + if (cache.hasCache(`user-${userToBeAssigned}`)) cache.removeCache(`user-${userToBeAssigned}`); + record.save() .then(results => res.status(201).send(results._id)) .catch(errors => res.status(500).send(errors)); From 1782d7446115509e54cd88f431be62f78334106a Mon Sep 17 00:00:00 2001 From: Aaron Persaud Date: Sat, 7 Oct 2023 23:53:33 -0400 Subject: [PATCH 063/272] remove 400 errors for invalid team code --- src/controllers/userProfileController.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index afafe2488..80c6d64f0 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -314,11 +314,6 @@ const userProfileController = function (UserProfile) { return; } - const teamcodeRegex = /^([a-zA-Z]-[a-zA-Z]{3}|[a-zA-Z]{5})$/; - if (!teamcodeRegex.test(req.body.teamCode)) { - res.status(400).send("The team code is invalid"); - return; - }; record.teamCode = req.body.teamCode; // find userData in cache @@ -608,17 +603,12 @@ const userProfileController = function (UserProfile) { if (key === "teamCode") { const canEditTeamCode = req.body.requestor.role === "Owner" || req.body.requestor.permissions?.frontPermissions.includes("editTeamCode"); - const teamcodeRegex = /^([a-zA-Z]-[a-zA-Z]{3}|[a-zA-Z]{5})$/; if(!canEditTeamCode){ res.status(403).send("You are not authorized to edit team code."); return; } - if (!teamcodeRegex.test(value)) { - res.status(400).send("The team code is invalid"); - return; - }; } // remove user from cache, it should be loaded next time From 61663e93b974ecb87ecea6daab9ff6fa200f011b Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Mon, 9 Oct 2023 14:09:42 -0700 Subject: [PATCH 064/272] update material, itemType schema --- src/models/inventoryItemMaterial.js | 2 ++ src/models/inventoryItemType.js | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/models/inventoryItemMaterial.js b/src/models/inventoryItemMaterial.js index b795d2f63..e6153af45 100644 --- a/src/models/inventoryItemMaterial.js +++ b/src/models/inventoryItemMaterial.js @@ -29,6 +29,8 @@ const InventoryItemMaterial = new Schema({ poId: { type: String, required: true }, sellerId: { type: String, required: true }, quantity: { type: Number, required: true }, // adds to stockBought + unitPrice: {type: Number, required: true}, + currency: { type: String, required: true }, subtotal: { type: Number, required: true }, tax: { type: Number, required: true }, shipping: { type: Number, required: true }, diff --git a/src/models/inventoryItemType.js b/src/models/inventoryItemType.js index 207ac77b0..321038a84 100644 --- a/src/models/inventoryItemType.js +++ b/src/models/inventoryItemType.js @@ -10,7 +10,8 @@ const InventoryItemType = new Schema({ // creates an item, tracks total amount i totalStock: { type: Number, required: true }, // total amount of all stock acquired totalAvailable: { type: Number, required: true }, projectsUsing: [ {type: mongoose.SchemaTypes.ObjectId, ref: 'project'} ], - imageUrl: { type: String } + imageUrl: { type: String }, + link: { type: String} }); module.exports = mongoose.model('inventoryItemType', InventoryItemType, 'inventoryItemType'); From 545a2582263748f4ea2e8f3d1ff80215d6fdf2d4 Mon Sep 17 00:00:00 2001 From: wang9hu Date: Tue, 10 Oct 2023 13:42:53 -0700 Subject: [PATCH 065/272] add nodemon package for auto restarting upon changes, modify readme command description, change parser from babel-eslint to @babel/eslint-parser in eslintrc --- .eslintrc | 2 +- README.md | 11 ++++++----- package.json | 8 ++++++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.eslintrc b/.eslintrc index f8b746a0a..7e82fa35b 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,6 +1,6 @@ { "extends": ["eslint:recommended", "airbnb-base"], - "parser": "babel-eslint", + "parser": "@babel/eslint-parser", "parserOptions": { "ecmaVersion": 8, "sourceType": "module" diff --git a/README.md b/README.md index 0db749fc6..0c286d922 100644 --- a/README.md +++ b/README.md @@ -30,11 +30,12 @@ JWT_SECRET= To make the process easy create a .env file and put the above text in the file and replace values with the correct values, which you can get from your teammates. Then do an npm run-script build followed by an npm start. By default, the services will start on port 4500 and you can http://localhost:4500/api/ to access the methods. A tools like Postman will be your best friend here, you will need to have an auth token placed in the 'Authorization' header which you can get through the networking tab of the local frontend when you login. -* `npm run lint` command for fixing lint -* `npm run build` command for building server -* `npm run buildw` command for auto rebuild upon change of src -* `npm run start` command for running the server in dist -* `npm run serve` command for running server in src without build +* `npm run lint` -- fix lint +* `npm run build` -- build src server and save in dist +* `npm run buildw` -- auto rebuild upon change of src +* `npm run start` -- run the server in dist +* `npm run serve` -- run the server in src without build +* `npm run dev` -- run the server in src and auto restart upon change of src Note: Once you check in the code in github, the application will be publsihed to the following: Developement : https://hgn-rest-dev.herokuapp.com diff --git a/package.json b/package.json index f9387e933..ec0579a20 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "build": "babel src -d dist", "buildw": "babel src -d dist --watch", "start": "node dist/server.js", - "serve": "node src/server.js" + "dev": "nodemon --exec babel-node src/server.js", + "serve": "babel-node src/server.js" }, "pre-commit": [ "lint" @@ -23,7 +24,6 @@ "@babel/eslint-parser": "^7.15.0", "@types/express": "^4.17.6", "@types/node": "^8.10.61", - "babel-eslint": "^10.1.0", "eslint": "^8.47.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb-base": "^13.1.0", @@ -33,6 +33,7 @@ "eslint-plugin-react": "^7.33.1", "eslint-plugin-react-hooks": "^4.6.0", "lint-staged": "^13.0.3", + "nodemon": "^3.0.1", "pre-commit": "^1.2.2" }, "dependencies": { @@ -66,5 +67,8 @@ "redis": "^4.2.0", "uuid": "^3.4.0", "ws": "^8.8.1" + }, + "nodemonConfig": { + "watch": ["/src/**/*"] } } From a8ebf5b19cb7cb29d27240e9cc41d34f3b391f66 Mon Sep 17 00:00:00 2001 From: wang9hu Date: Tue, 10 Oct 2023 14:01:54 -0700 Subject: [PATCH 066/272] sync package-lock.json --- package-lock.json | 160 +++++++++++++++++++++++++++++++++++++--------- package.json | 4 +- 2 files changed, 134 insertions(+), 30 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5c6bd6db5..f9eb87ba6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1459,6 +1459,12 @@ "@types/node": "*" } }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, "abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -1536,7 +1542,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "optional": true, "requires": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -2494,28 +2499,6 @@ "dequal": "^2.0.3" } }, - "babel-eslint": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", - "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.7.0", - "@babel/traverse": "^7.7.0", - "@babel/types": "^7.7.0", - "eslint-visitor-keys": "^1.0.0", - "resolve": "^1.12.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, "babel-plugin-dynamic-import-node": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", @@ -2641,8 +2624,7 @@ "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "optional": true + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" }, "bl": { "version": "2.2.1", @@ -2773,7 +2755,6 @@ "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "optional": true, "requires": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -4538,7 +4519,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "optional": true, "requires": { "is-glob": "^4.0.1" } @@ -4799,6 +4779,12 @@ "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -4892,7 +4878,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "optional": true, "requires": { "binary-extensions": "^2.0.0" } @@ -5820,6 +5805,68 @@ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.2.tgz", "integrity": "sha512-Dz7zVwlef4k5R71fdmxwR8Q39fiboGbu3xgswkzGwczUfjp873rVxt1O46+Fh0j1ORnAC6L9+heI8uUpO6DT7Q==" }, + "nodemon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz", + "integrity": "sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==", + "dev": true, + "requires": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "requires": { + "abbrev": "1" + } + }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -6784,6 +6831,12 @@ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, "punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", @@ -6841,7 +6894,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "optional": true, "requires": { "picomatch": "^2.2.1" } @@ -7185,6 +7237,41 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "requires": { + "semver": "^7.5.3" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", @@ -7681,6 +7768,15 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "requires": { + "nopt": "~1.0.10" + } + }, "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -7816,6 +7912,12 @@ "which-boxed-primitive": "^1.0.2" } }, + "undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", diff --git a/package.json b/package.json index ec0579a20..1c6b8a5d4 100644 --- a/package.json +++ b/package.json @@ -69,6 +69,8 @@ "ws": "^8.8.1" }, "nodemonConfig": { - "watch": ["/src/**/*"] + "watch": [ + "/src/**/*" + ] } } From e55f980bed651b15bb0fad0202113e70a5ca4214 Mon Sep 17 00:00:00 2001 From: GaryB93 Date: Tue, 10 Oct 2023 18:52:52 -0500 Subject: [PATCH 067/272] save new item type before adding material to project --- .../bmdashboard/bmMaterialsController.js | 33 ++++++++++--------- src/models/inventoryItemMaterial.js | 2 +- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index d9d1c7780..8b53ab35f 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -20,9 +20,8 @@ const bmMaterialsController = function (ItemMaterial, ItemType) { }; const bmAddMaterials = async function (req, res) { - console.log(req.body); const { material, requestor } = req.body; - let itemTypeId = material.material; // if new material: material name / else: itemType id + let itemTypeId = material.material; // either new material or existing itemTypeId // if new material or new measurement, add new inventoryItemType if (material.newMaterial || material.newMeasurement) { @@ -38,20 +37,20 @@ const bmMaterialsController = function (ItemMaterial, ItemType) { imageUrl: '', link: material.link, }); - const newItemType = await itemType.save(); - itemTypeId = newItemType._id; - } catch (err) { - res.status(400).send({ error: 'Error saving new material type'}); + const result = await itemType.save(); + itemTypeId = result._id; + } catch (error) { + res.status(500).send(error); } } try { - const invMaterial = await ItemMaterial.find({ id: material.projectId, inventoryItemType: itemTypeId }).exec(); - // if material already exists in project, add to it - // else, create new material for project + const invMaterial = await ItemMaterial.findOne( + { project: material.projectId, inventoryItemType: itemTypeId }).exec(); + console.log(invMaterial); if (invMaterial) { - // TODO - console.log(invMaterial); + // TODO: update inventoryMaterial with new purchase record + // and updated quantities } else { const itemMaterial = new ItemMaterial({ inventoryItemType: itemTypeId, @@ -62,26 +61,28 @@ const bmMaterialsController = function (ItemMaterial, ItemType) { updateRecord: [], purchaseRecord: [{ date: material.purchaseDate, - createdBy: req.requestor.requestorId, + createdBy: requestor.requestorId, poId: material.invoice, sellerId: material.phone, quantity: material.quantity, unitPrice: material.unitPrice, - subTotal: material.quantity * material.unitPrice, + currency: material.currency, + subtotal: material.quantity, tax: material.taxRate, shipping: material.shippingFee, }], }); const newItemMaterial = await itemMaterial.save(); + console.log(newItemMaterial); } - } catch (err) { - res.status(400).send({ error: 'Error adding new material to project'}); + } catch (error) { + res.status(500).send(error); } }; return { bmMaterialsList, - bmAddMaterials + bmAddMaterials, }; }; diff --git a/src/models/inventoryItemMaterial.js b/src/models/inventoryItemMaterial.js index 09c521e4d..2ffa1fba2 100644 --- a/src/models/inventoryItemMaterial.js +++ b/src/models/inventoryItemMaterial.js @@ -23,7 +23,7 @@ const InventoryItemMaterial = new Schema({ description: { type: String, required: true, maxLength: 150 }, }], purchaseRecord: [{ - date: { type: Date, required: true, default: Date.now() }, + date: { type: String, required: true }, createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile', required: true }, poId: { type: String, required: true }, sellerId: { type: String, required: true }, From a5f7911be6ce912e73f44f1a459231630c5b2b92 Mon Sep 17 00:00:00 2001 From: Bhagyashree Birajdar Date: Wed, 11 Oct 2023 13:06:02 -0700 Subject: [PATCH 068/272] Create blue square reason scheduler for all users --- .gitattributes | 2 +- src/controllers/reasonSchedulingController.js | 68 +++++++++---------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/.gitattributes b/.gitattributes index d528e69e3..6cf651ce7 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,6 @@ # https://warlord0blog.wordpress.com/2019/09/04/vscode-crlf-vs-lf-battle/ - text=lf +# text=lf *.css linguist-vendored eol=lf *.scss linguist-vendored eol=lf *.js linguist-vendored eol=lf diff --git a/src/controllers/reasonSchedulingController.js b/src/controllers/reasonSchedulingController.js index 02706546b..3969f2e91 100644 --- a/src/controllers/reasonSchedulingController.js +++ b/src/controllers/reasonSchedulingController.js @@ -38,13 +38,13 @@ const postReason = async (req, res) => { } // error case 1 - if (requestor.role !== 'Owner' && requestor.role !== 'Administrator') { - return res.status(403).json({ - message: - 'You must be an Owner or Administrator to schedule a reason for a Blue Square', - errorCode: 1, - }); - } + // if (requestor.role !== 'Owner' && requestor.role !== 'Administrator') { + // return res.status(403).json({ + // message: + // 'You must be an Owner or Administrator to schedule a reason for a Blue Square', + // errorCode: 1, + // }); + // } const foundUser = await UserModel.findById(userId); @@ -98,12 +98,12 @@ const getAllReasons = async (req, res) => { const { userId } = req.params; // error case 1 - if (requestor.role !== 'Owner' && requestor.role !== 'Administrator') { - return res.status(403).json({ - message: - 'You must be an Owner or Administrator to get a reason for a Blue Square', - }); - } + // if (requestor.role !== 'Owner' && requestor.role !== 'Administrator') { + // return res.status(403).json({ + // message: + // 'You must be an Owner or Administrator to get a reason for a Blue Square', + // }); + // } const foundUser = await UserModel.findById(userId); @@ -136,13 +136,13 @@ const getSingleReason = async (req, res) => { const { queryDate } = req.query; // error case 1 - if (requestor.role !== 'Administrator' && requestor.role !== 'Owner') { - return res.status(403).json({ - message: - "You must be an Administrator or Owner to be able to get a single reason by the user's ID", - errorCode: 1, - }); - } + // if (requestor.role !== 'Administrator' && requestor.role !== 'Owner') { + // return res.status(403).json({ + // message: + // "You must be an Administrator or Owner to be able to get a single reason by the user's ID", + // errorCode: 1, + // }); + // } const foundUser = await UserModel.findById(userId); // error case 2 @@ -185,13 +185,13 @@ const patchReason = async (req, res) => { const { userId } = req.params; // error case 1 - if (requestor.role !== 'Owner' && requestor.role !== 'Administrator') { - return res.status(403).json({ - message: - 'You must be an Owner or Administrator to schedule a reason for a Blue Square', - errorCode: 1, - }); - } + // if (requestor.role !== 'Owner' && requestor.role !== 'Administrator') { + // return res.status(403).json({ + // message: + // 'You must be an Owner or Administrator to schedule a reason for a Blue Square', + // errorCode: 1, + // }); + // } if (!reasonData.message) { return res.status(400).json({ @@ -244,13 +244,13 @@ const deleteReason = async (req, res) => { const { userId } = req.params; // error case 1 - if (requestor.role !== 'Owner' && requestor.role !== 'Administrator') { - return res.status(403).json({ - message: - 'You must be an Owner or Administrator to schedule a reason for a Blue Square', - errorCode: 1, - }); - } + // if (requestor.role !== 'Owner' && requestor.role !== 'Administrator') { + // return res.status(403).json({ + // message: + // 'You must be an Owner or Administrator to schedule a reason for a Blue Square', + // errorCode: 1, + // }); + // } const foundUser = await UserModel.findById(userId); From 31d1e39d35cf0867ea786ef7eb2e59e294d63d4b Mon Sep 17 00:00:00 2001 From: GaryB93 Date: Wed, 11 Oct 2023 17:29:28 -0500 Subject: [PATCH 069/272] update method to add inventory types --- .../bmdashboard/bmMaterialsController.js | 31 +++---------------- src/controllers/inventoryController.js | 7 ++++- 2 files changed, 10 insertions(+), 28 deletions(-) diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index 8b53ab35f..708c4d884 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -21,39 +21,16 @@ const bmMaterialsController = function (ItemMaterial, ItemType) { const bmAddMaterials = async function (req, res) { const { material, requestor } = req.body; - let itemTypeId = material.material; // either new material or existing itemTypeId - - // if new material or new measurement, add new inventoryItemType - if (material.newMaterial || material.newMeasurement) { - try { - const itemType = new ItemType({ - type: 'material', - name: material.material, - description: material.description, - uom: material.measurement, - totalStock: material.quantity, - totalAvailable: material.quantity, - projectsUsing: [material.projectId], - imageUrl: '', - link: material.link, - }); - const result = await itemType.save(); - itemTypeId = result._id; - } catch (error) { - res.status(500).send(error); - } - } try { - const invMaterial = await ItemMaterial.findOne( - { project: material.projectId, inventoryItemType: itemTypeId }).exec(); - console.log(invMaterial); + const invMaterial = await ItemMaterial.findOne({ project: material.projectId, inventoryItemType: material.material }).exec(); if (invMaterial) { + console.log('found item material in project'); // TODO: update inventoryMaterial with new purchase record // and updated quantities } else { const itemMaterial = new ItemMaterial({ - inventoryItemType: itemTypeId, + inventoryItemType: material.material, project: material.projectId, stockBought: material.quantity, stockAvailable: material.quantity, @@ -73,7 +50,7 @@ const bmMaterialsController = function (ItemMaterial, ItemType) { }], }); const newItemMaterial = await itemMaterial.save(); - console.log(newItemMaterial); + res.status(201).send(newItemMaterial); } } catch (error) { res.status(500).send(error); diff --git a/src/controllers/inventoryController.js b/src/controllers/inventoryController.js index bc0902aeb..d4c9d5261 100644 --- a/src/controllers/inventoryController.js +++ b/src/controllers/inventoryController.js @@ -548,10 +548,15 @@ const inventoryController = function (Item, ItemType) { } const itemType = new ItemType(); + itemType.type = req.body.type; itemType.name = req.body.name; itemType.description = req.body.description; + itemType.uom = req.body.uom; + itemType.totalStock = req.body.totalStock; + itemType.totalAvailable = req.body.totalAvailable; + itemType.projectsUsing = []; itemType.imageUrl = req.body.imageUrl || req.body.imageURL; - itemType.quantifier = req.body.quantifier; + itemType.link = req.body.link; itemType.save() .then(results => res.status(201).send(results)) From 670d86fbfd149163f4ea5495e3bfc5c4ef68d27f Mon Sep 17 00:00:00 2001 From: GaryB93 Date: Thu, 12 Oct 2023 18:53:50 -0500 Subject: [PATCH 070/272] update inventory material quantities and purchase records when adding --- .../bmdashboard/bmMaterialsController.js | 44 +++++++++++-------- src/models/inventoryItemMaterial.js | 2 +- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index 708c4d884..0f1e8a38e 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -20,14 +20,33 @@ const bmMaterialsController = function (ItemMaterial, ItemType) { }; const bmAddMaterials = async function (req, res) { + // add permission check... + const { material, requestor } = req.body; + const purchaseRecord = { + date: material.purchaseDate, + createdBy: requestor.requestorId, + poId: material.invoice, + sellerId: material.phone, + quantity: material.quantity, + unitPrice: material.unitPrice, + currency: material.currency, + subtotal: material.quantity, + tax: material.taxRate, + shipping: material.shippingFee, + }; try { - const invMaterial = await ItemMaterial.findOne({ project: material.projectId, inventoryItemType: material.material }).exec(); - if (invMaterial) { - console.log('found item material in project'); - // TODO: update inventoryMaterial with new purchase record - // and updated quantities + const result = await ItemMaterial.findOneAndUpdate( + { project: material.projectId, inventoryItemType: material.material }, + { + $inc: { stockBought: material.quantity, stockAvailable: material.quantity }, + $push: { purchaseRecord: purchaseRecord }, + }, + { returnDocument: 'after', lean: true }).exec(); + if (result) { + console.log(result); + res.status(201).send(result); } else { const itemMaterial = new ItemMaterial({ inventoryItemType: material.material, @@ -36,18 +55,7 @@ const bmMaterialsController = function (ItemMaterial, ItemType) { stockAvailable: material.quantity, usageRecord: [], updateRecord: [], - purchaseRecord: [{ - date: material.purchaseDate, - createdBy: requestor.requestorId, - poId: material.invoice, - sellerId: material.phone, - quantity: material.quantity, - unitPrice: material.unitPrice, - currency: material.currency, - subtotal: material.quantity, - tax: material.taxRate, - shipping: material.shippingFee, - }], + purchaseRecord: [purchaseRecord], }); const newItemMaterial = await itemMaterial.save(); res.status(201).send(newItemMaterial); @@ -57,7 +65,7 @@ const bmMaterialsController = function (ItemMaterial, ItemType) { } }; - return { + return { bmMaterialsList, bmAddMaterials, }; diff --git a/src/models/inventoryItemMaterial.js b/src/models/inventoryItemMaterial.js index 2ffa1fba2..09c521e4d 100644 --- a/src/models/inventoryItemMaterial.js +++ b/src/models/inventoryItemMaterial.js @@ -23,7 +23,7 @@ const InventoryItemMaterial = new Schema({ description: { type: String, required: true, maxLength: 150 }, }], purchaseRecord: [{ - date: { type: String, required: true }, + date: { type: Date, required: true, default: Date.now() }, createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile', required: true }, poId: { type: String, required: true }, sellerId: { type: String, required: true }, From bc2655be2bb9b3149d13d9b34fa3a84247276e12 Mon Sep 17 00:00:00 2001 From: Chuehleo <122568562+Chuehleo@users.noreply.github.com> Date: Fri, 13 Oct 2023 15:55:00 -0700 Subject: [PATCH 071/272] Update userProfileController.js --- src/controllers/userProfileController.js | 159 +++++++++++------------ 1 file changed, 75 insertions(+), 84 deletions(-) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 6036b9d0f..a388f10db 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -12,7 +12,7 @@ const Badge = require('../models/badge'); const userProfile = require('../models/userProfile'); const yearMonthDayDateValidator = require('../utilities/yearMonthDayDateValidator'); const cache = require('../utilities/nodeCache')(); -const { hasPermission, hasIndividualPermission, canRequestorUpdateUser } = require('../utilities/permissions'); +const { hasPermission, canRequestorUpdateUser } = require('../utilities/permissions'); const escapeRegex = require('../utilities/escapeRegex'); const config = require('../config'); @@ -35,7 +35,20 @@ async function ValidatePassword(req, res) { return; } // Verify request is authorized by self or adminsitrator - if (!userId === requestor.requestorId && !await hasPermission(requestor.role, 'updatePassword')) { + if (userId !== requestor.requestorId && !await hasPermission(requestor.role, 'updatePassword')) { + console.log('User ID:', userId); + console.log('Requestor ID:', requestor.requestorId); + res.status(403).send({ + error: "You are unauthorized to update this user's password", + }); + return; + } + + + // Check permissions + if (userId === requestor.requestorId || !await hasPermission(requestor.role, 'updatePasswordForOthers')) { + console.log('User ID:', userId); + console.log('Requestor ID:', requestor.requestorId); res.status(403).send({ error: "You are unauthorized to update this user's password", }); @@ -52,16 +65,20 @@ async function ValidatePassword(req, res) { const userProfileController = function (UserProfile) { const getUserProfiles = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'getUserProfiles') && + if ( + !(await hasPermission(req.body.requestor.role, "getUserProfiles")) && !req.body.requestor.permissions?.frontPermissions.includes( "putUserProfilePermissions" ) ) { - if (!await hasIndividualPermission(req.body.requestor.requestorId, 'seeProjectManagement') - && !await hasIndividualPermission(req.body.requestor.requestorId, 'seeProjectManagementTab')) { - res.status(403).send('You are not authorized to view all users'); + res.status(403).send("You are not authorized to view all users"); + return; + } + + if (cache.getCache("allusers")) { + const getData = JSON.parse(cache.getCache("allusers")); + res.status(200).send(getData); return; - } } UserProfile.find( @@ -73,20 +90,13 @@ const userProfileController = function (UserProfile) { }) .then((results) => { if (!results) { - if (cache.getCache("allusers")) { - const getData = JSON.parse(cache.getCache("allusers")); - res.status(200).send(getData); - return; - }else{ - res.status(500).send({ error: "User result was invalid" }); - return; - } + res.status(500).send({ error: "User result was invalid" }); + return; } cache.setCache("allusers", JSON.stringify(results)); res.status(200).send(results); }) .catch((error) => res.status(404).send(error)); - }; const getProjectMembers = async function (req, res) { @@ -245,9 +255,6 @@ const userProfileController = function (UserProfile) { "putUserProfilePermissions" )) ); - - const canEditTeamCode = req.body.requestor.role === "Owner" || - req.body.requestor.permissions?.frontPermissions.includes("editTeamCode"); if (!isRequestorAuthorized) { res.status(403).send("You are not authorized to update this user"); @@ -309,12 +316,6 @@ const userProfileController = function (UserProfile) { record.totalIntangibleHrs = req.body.totalIntangibleHrs; record.bioPosted = req.body.bioPosted || "default"; record.isFirstTimelog = req.body.isFirstTimelog; - - if(!canEditTeamCode && record.teamCode !== req.body.teamCode){ - res.status(403).send("You are not authorized to edit team code."); - return; - } - record.teamCode = req.body.teamCode; // find userData in cache @@ -601,17 +602,6 @@ 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.permissions?.frontPermissions.includes("editTeamCode"); - - if(!canEditTeamCode){ - res.status(403).send("You are not authorized to edit team code."); - return; - } - - } - // 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' }); @@ -636,70 +626,71 @@ const userProfileController = function (UserProfile) { const updatepassword = async function (req, res) { const { userId } = req.params; const { requestor } = req.body; + + console.log('User ID:', userId); + console.log('Requestor ID:', requestor.requestorId); + + // Check if userId is valid. if (!mongoose.Types.ObjectId.isValid(userId)) { - return res.status(400).send({ - error: 'Bad Request', - }); + return res.status(400).send({ + error: 'Bad Request', + }); } // Verify correct params in body if (!req.body.currentpassword || !req.body.newpassword || !req.body.confirmnewpassword) { - return res.status(400).send({ - error: 'One of more required fields are missing', - }); - } - // Verify request is authorized by self or adminsitrator - if (!userId === requestor.requestorId && !await hasPermission(requestor.role, 'updatePassword')) { - return res.status(403).send({ - error: "You are unauthorized to update this user's password", - }); + return res.status(400).send({ + error: 'One or more required fields are missing', + }); } - if (canRequestorUpdateUser(requestor.requestorId, userId)) { - return res.status(403).send({ - error: "You are unauthorized to update this user's password", - }); + // Check if the requestor has the permission to update passwords. + const hasUpdatePasswordPermission = await hasPermission(requestor.role, 'updatePassword'); + + // If the requestor is updating their own password, allow them to proceed. + if (userId === requestor.requestorId) { + console.log('Requestor is updating their own password'); + } + // Else if they're updating someone else's password, they need the 'updatePassword' permission. + else if (!hasUpdatePasswordPermission) { + console.log("Requestor is trying to update someone else's password but lacks the 'updatePassword' permission"); + return res.status(403).send({ + error: "You are unauthorized to update this user's password", + }); } // 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', - }); + return res.status(400).send({ + 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', - }); - } + // Process the password change + try { + const user = await UserProfile.findById(userId, 'password'); + const passwordMatch = await bcrypt.compare(req.body.currentpassword, user.password); - return UserProfile.findById(userId, 'password') - .then((user) => { - bcrypt - .compare(req.body.currentpassword, user.password) - .then((passwordMatch) => { - if (!passwordMatch) { - return res.status(400).send({ + if (!passwordMatch) { + return res.status(400).send({ error: 'Incorrect current password', - }); - } - - user.set({ - password: req.body.newpassword, - resetPwd: undefined, }); - return user - .save() - .then(() => res.status(200).send({ message: 'updated password' })) - .catch(error => res.status(500).send(error)); - }) - .catch(error => res.status(500).send(error)); - }) - .catch(error => res.status(500).send(error)); - }; + } + + user.set({ + password: req.body.newpassword, + resetPwd: undefined, + }); + + await user.save(); + + return res.status(200).send({ message: 'Updated password successfully' }); + + } catch (error) { + return res.status(500).send(error); + } +}; + const getreportees = async function (req, res) { if (!mongoose.Types.ObjectId.isValid(req.params.userId)) { From 64a65b99fd4e07a89b7c4dd8f49db3ddc6f15e42 Mon Sep 17 00:00:00 2001 From: Bhagyashree Birajdar Date: Fri, 13 Oct 2023 21:11:18 -0700 Subject: [PATCH 072/272] Add Email Sending on save and update --- src/controllers/reasonSchedulingController.js | 68 ++++++++++++++++--- 1 file changed, 58 insertions(+), 10 deletions(-) diff --git a/src/controllers/reasonSchedulingController.js b/src/controllers/reasonSchedulingController.js index 3969f2e91..39729680f 100644 --- a/src/controllers/reasonSchedulingController.js +++ b/src/controllers/reasonSchedulingController.js @@ -1,6 +1,8 @@ + const moment = require('moment-timezone'); const UserModel = require('../models/userProfile'); const ReasonModel = require('../models/reason'); +const emailSender = require("../utilities/emailSender"); const postReason = async (req, res) => { @@ -37,6 +39,7 @@ const postReason = async (req, res) => { }); } + //Commented this condition to make reason scheduler available to all the users. // error case 1 // if (requestor.role !== 'Owner' && requestor.role !== 'Administrator') { // return res.status(403).json({ @@ -82,8 +85,33 @@ const postReason = async (req, res) => { date: savingDate, userId, }); - await newReason.save(); + + + //await newReason.save(); + console.log("Inside post sending email function."); + const savedData = await newReason.save(); + if(savedData) + { + console.log("Inside if."); + //Upon clicking the "Save" button in the Blue Square Reason Scheduler, an email will be automatically sent to the user and Jae. + const subject = `Blue Square Reason for :${foundUser.firstName} ${foundUser.lastName} has been set`; + + const emailBody = `

      Hi !

      + +

      This email is to let you know that ${foundUser.firstName} ${foundUser.lastName} has set their Blue Square Reason.

      + +

      Blue Square Reason : ${newReason.reason}

      +

      Scheduled date for the Blue Square Reason: : ${newReason.date}

      + +

      Thank you,
      + One Community

      `; + console.log("line before email sender") + + emailSender('shreetesting4@gmail.com', subject, emailBody, null, null); + } + return res.sendStatus(200); + } catch (error) { console.log(error); return res.status(400).json({ @@ -226,7 +254,27 @@ const patchReason = async (req, res) => { } foundReason.reason = reasonData.message; - await foundReason.save(); + console.log("patchReason----------"); + const savedData = await foundReason.save(); + if(savedData) + { + console.log(" Patch - Inside if."); + //Upon clicking the "Save" button in the Blue Square Reason Scheduler, an email will be automatically sent to the user and Jae. + const subject = `Blue Square Reason for :${foundUser.firstName} ${foundUser.lastName} has been updated`; + + const emailBody = `

      Hi !

      + +

      This email is to let you know that ${foundUser.firstName} ${foundUser.lastName} has updated their Blue Square Reason.

      + +

      Updated Blue Square Reason : ${foundReason.reason}

      +

      Scheduled date for the Blue Square Reason: : ${foundReason.date}

      + +

      Thank you,
      + One Community

      `; + console.log("line before email sender") + + emailSender('shreetesting4@gmail.com', subject, emailBody, null, null); + } return res.status(200).json({ message: 'Reason Updated!', @@ -243,14 +291,14 @@ const deleteReason = async (req, res) => { const { reasonData, requestor } = req.body; const { userId } = req.params; - // error case 1 - // if (requestor.role !== 'Owner' && requestor.role !== 'Administrator') { - // return res.status(403).json({ - // message: - // 'You must be an Owner or Administrator to schedule a reason for a Blue Square', - // errorCode: 1, - // }); - // } + //error case 1 + if (requestor.role !== 'Owner' && requestor.role !== 'Administrator') { + return res.status(403).json({ + message: + 'You must be an Owner or Administrator to schedule a reason for a Blue Square', + errorCode: 1, + }); + } const foundUser = await UserModel.findById(userId); From 4d98c53461d9c6150aa306d7a13fa528357181ff Mon Sep 17 00:00:00 2001 From: Nathan Hoffman Date: Sat, 14 Oct 2023 13:41:18 -0700 Subject: [PATCH 073/272] Fix collection name --- src/utilities/createInitialPermissions.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utilities/createInitialPermissions.js b/src/utilities/createInitialPermissions.js index a5c69d87f..6e22eb6a1 100644 --- a/src/utilities/createInitialPermissions.js +++ b/src/utilities/createInitialPermissions.js @@ -265,9 +265,9 @@ const createInitialPermissions = async () => { // 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 roleId = presetDataBase._id; + const presetId = presetDataBase._id; - promises.push(Role.findById(roleId, (_, record) => { + promises.push(RolePreset.findById(presetId, (_, record) => { record.permissions = permissions; record.save(); })); From 82d29effc13a1202d8b83ed69d3c11f92a5dec7c Mon Sep 17 00:00:00 2001 From: Oleksandr Riazantsev Date: Sun, 15 Oct 2023 12:06:40 -0400 Subject: [PATCH 074/272] feat: userprofiles sending totalTangibleHrs, update user controller, all manually locations response structure --- src/controllers/mapLocationsController.js | 85 ++++++++++++++++++++--- src/controllers/userProfileController.js | 2 +- src/routes/mapLocationsRouter.js | 3 +- 3 files changed, 78 insertions(+), 12 deletions(-) diff --git a/src/controllers/mapLocationsController.js b/src/controllers/mapLocationsController.js index 6088de489..f01666558 100644 --- a/src/controllers/mapLocationsController.js +++ b/src/controllers/mapLocationsController.js @@ -1,11 +1,26 @@ -const mapLocationsController = function (mapLocation) { +const userProfile = require('../models/userProfile'); +const cache = require('../utilities/nodeCache')(); + +const mapLocationsController = function (MapLocation) { const getAllLocations = function (req, res) { + const priorText = 'Prior to HGN Data Collection'; + MapLocation.find({}) + .then(results => { + const users = results.map(item => { + return ({ + title: priorText, + firstName: item.firstName !== priorText ? item.firstName : '', + lastName: item.lastName !== priorText ? item.lastName : '', + jobTitle: item.jobTitle !== priorText ? item.jobTitle : '', + location: item.location, + isActive: item.isActive, + _id: item._id + }) + }) + res.send(users).status(200); - mapLocation.find({}) - .then(results => - res.send(results).status(200) - ) - .catch(error => + }) + .catch(error => res.send(error).status(404)); }; const deleteLocation = async function (req, res) { @@ -14,6 +29,11 @@ const mapLocationsController = function (mapLocation) { res.status(403).send('You are not authorized to make changes in the teams.'); return; } + const locationId = req.params.locationId + + MapLocation.findOneAndDelete({ _id: locationId }) + .then(() => res.status(200).send({ message: "The location was successfully removed!" })) + .catch(error => res.status(500).send({ message: error || "Couldn't remove the location" })); }; const putUserLocation = async function (req, res) { @@ -27,24 +47,69 @@ const mapLocationsController = function (mapLocation) { jobTitle: req.body.jobTitle, location: req.body.location, } - const location = new mapLocation(locationData); + const location = new MapLocation(locationData); try { const response = await location.save() - if(!response) { + if (!response) { throw new Error('Something went wrong during saving the location...') } res.status(200).send(response); } catch (err) { console.log(err.message) - res.status(500).json({message: err.message || 'Something went wrong...'}); + res.status(500).json({ message: err.message || 'Something went wrong...' }); } }; + const updateUserLocation = async function (req, res) { + console.log(req.body) + if (!req.body.requestor.role === 'Administrator' || !req.body.requestor.role === 'Owner') { + res.status(403).send('You are not authorized to make changes in the teams.'); + return; + } + const userType = req.body.type; + const userId= req.body._id; + const updateData = { + firstName: req.body.firstName, + lastName: req.body.lastName, + jobTitle: req.body.jobTitle, + location: req.body.location, + _id: req.body._id + } + try { + let response; + if(userType === 'user') { + response = await userProfile.findOneAndUpdate({ _id: userId }, {$set: {...updateData, jobTitle: [updateData.jobTitle]}}, { new: true }); + cache.removeCache('allusers') + cache.removeCache(`user-${userId}`); + cache.setCache(`user-${userId}`, JSON.stringify(response)); + } else { + response = await MapLocation.findOneAndUpdate({ _id: userId }, {$set: updateData}, { new: true }) + } + + if (!response) { + throw new Error('Something went wrong during saving the location...') + } + const newData = { + firstName: response.firstName, + lastName: response.lastName, + jobTitle: response.jobTitle, + location: response.location, + _id: response._id, + type: userType + } + + res.status(200).send(newData); + } catch (err) { + console.log(err.message) + res.status(500).json({ message: err.message || 'Something went wrong...' }); + } + }; return { getAllLocations, deleteLocation, - putUserLocation + putUserLocation, + updateUserLocation }; }; diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 8a866401a..9e6d83894 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -65,7 +65,7 @@ const userProfileController = function (UserProfile) { UserProfile.find( {}, - '_id firstName lastName role weeklycommittedHours email permissions isActive reactivationDate createdDate endDate location jobTitle', + '_id firstName lastName role weeklycommittedHours email permissions isActive reactivationDate createdDate endDate location jobTitle totalTangibleHrs', ) .sort({ lastName: 1, diff --git a/src/routes/mapLocationsRouter.js b/src/routes/mapLocationsRouter.js index e2e780dac..db004ff18 100644 --- a/src/routes/mapLocationsRouter.js +++ b/src/routes/mapLocationsRouter.js @@ -7,7 +7,8 @@ const router = function (mapLocations) { mapRouter.route('/mapLocations') .get(controller.getAllLocations) - .put(controller.putUserLocation); + .put(controller.putUserLocation) + .patch(controller.updateUserLocation); mapRouter.route('/mapLocations/:locationId') .delete(controller.deleteLocation) From 4c4db04f1e252bb6e65a6fbebed97c8280c16b0e Mon Sep 17 00:00:00 2001 From: abdelmounaim lallouache Date: Tue, 17 Oct 2023 20:29:28 -0500 Subject: [PATCH 075/272] add weeklyCommitedHours to setup user, fix updates issues, fix weekly summaries logged hours bug --- .../profileInitialSetupController.js | 41 +++++++++++++++++-- src/models/profileInitialSetupToken.js | 5 +++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/controllers/profileInitialSetupController.js b/src/controllers/profileInitialSetupController.js index f671e06a3..18cf7376c 100644 --- a/src/controllers/profileInitialSetupController.js +++ b/src/controllers/profileInitialSetupController.js @@ -4,6 +4,7 @@ const moment = require("moment-timezone"); const jwt = require("jsonwebtoken"); const emailSender = require("../utilities/emailSender"); const config = require("../config"); +const cache = require('../utilities/nodeCache')(); // returns the email body that includes the setup link for the recipient. function sendLinkMessage(Link) { @@ -25,7 +26,6 @@ function informManagerMessage(user) {

      New User ${user.firstName} ${user.lastName} has completed their part of setup.

      These areas need to now be completed by an Admin:

        -
      • Weekly Committed Hours
      • Admin Document
      • Link to Media Files
      • Assign Projects
      • @@ -57,6 +57,10 @@ function informManagerMessage(user) {
+ + + + @@ -87,7 +91,7 @@ const profileInitialSetupController = function ( - Generates a link using the token and emails it to the recipient. */ const getSetupToken = async (req, res) => { - let { email, baseUrl } = req.body; + let { email, baseUrl,weeklyCommittedHours } = req.body; email = email.toLowerCase(); const token = uuidv4(); const expiration = moment().tz("America/Los_Angeles").add(1, "week"); @@ -103,6 +107,7 @@ const profileInitialSetupController = function ( const newToken = new ProfileInitialSetupToken({ token, email, + weeklyCommittedHours, expiration: expiration.toDate(), }); @@ -187,7 +192,13 @@ const profileInitialSetupController = function ( newUser.jobTitle = req.body.jobTitle; newUser.phoneNumber = req.body.phoneNumber; newUser.bio = ""; - newUser.weeklycommittedHours = req.body.weeklycommittedHours; + newUser.weeklycommittedHours = foundToken.weeklyCommittedHours; + newUser.weeklycommittedHoursHistory = [ + { + hours: newUser.weeklycommittedHours, + dateChanged: Date.now(), + }, + ]; newUser.personalLinks = []; newUser.adminLinks = []; newUser.teams = Array.from(new Set([])); @@ -201,11 +212,17 @@ const profileInitialSetupController = function ( newUser.collaborationPreference = req.body.collaborationPreference; newUser.timeZone = req.body.timeZone || "America/Los_Angeles"; newUser.location = req.body.location; + newUser.permissions = { + frontPermissions: [], + backPermissions: [] + } newUser.bioPosted = "default"; newUser.privacySettings.email = req.body.privacySettings.email; newUser.privacySettings.phoneNumber = req.body.privacySettings.phoneNumber; newUser.teamCode = ""; + newUser.isFirstTimelog = true; + const savedUser = await newUser.save(); emailSender( @@ -230,6 +247,24 @@ const profileInitialSetupController = function ( const token = jwt.sign(jwtPayload, JWT_SECRET); res.send({ token }).status(200); + + const NewUserCache = { + permissions: savedUser.permissions, + isActive: true, + weeklycommittedHours: savedUser.weeklycommittedHours, + createdDate: savedUser.createdDate.toISOString(), + _id: savedUser._id, + role: savedUser.role, + firstName: savedUser.firstName, + lastName: savedUser.lastName, + email: savedUser.email, + }; + + const allUserCache = JSON.parse(cache.getCache("allusers")); + allUserCache.push(NewUserCache); + cache.setCache("allusers", JSON.stringify(allUserCache)); + + } else { res.status(400).send("Token is expired"); } diff --git a/src/models/profileInitialSetupToken.js b/src/models/profileInitialSetupToken.js index fc21bcad5..48413fb77 100644 --- a/src/models/profileInitialSetupToken.js +++ b/src/models/profileInitialSetupToken.js @@ -10,6 +10,11 @@ const profileInitialSetupTokenSchema = new mongoose.Schema({ type: String, required: true, }, + weeklyCommittedHours : { + type: Number, + required: true, + default: 10, + }, expiration: { type: Date, required: true, From 5ffc3d23442fc46a71544a885b3fd42def4a849b Mon Sep 17 00:00:00 2001 From: wang9hu Date: Tue, 17 Oct 2023 20:53:56 -0700 Subject: [PATCH 076/272] finish new timer basic functionality --- src/models/timer.js | 7 +- src/routes/dashboardRouter.js | 1 - src/websockets/TimerService/clientsHandler.js | 286 ++++++++++++++++ .../TimerService/connectionsHandler.js | 50 +++ src/websockets/TimerService/index.js | 308 ------------------ src/websockets/index.js | 153 ++++----- 6 files changed, 394 insertions(+), 411 deletions(-) create mode 100644 src/websockets/TimerService/clientsHandler.js create mode 100644 src/websockets/TimerService/connectionsHandler.js delete mode 100644 src/websockets/TimerService/index.js diff --git a/src/models/timer.js b/src/models/timer.js index c73dfe6c2..8afbad119 100644 --- a/src/models/timer.js +++ b/src/models/timer.js @@ -5,13 +5,12 @@ const { Schema } = mongoose; const timerSchema = new Schema({ userId: { type: Schema.Types.ObjectId, required: true, ref: "userProfile" }, - lastAccess: { type: Date, default: Date.now }, + startAt: { type: Date, default: Date.now }, time: { type: Number, default: 900000 }, - countdown: { type: Boolean, default: true }, goal: { type: Number, default: 900000 }, - paused: { type: Boolean, default: true }, + paused: { type: Boolean, default: false }, forcedPause: { type: Boolean, default: false }, - stopped: { type: Boolean, default: false }, + started: { type: Boolean, default: false }, }); module.exports = mongoose.model("newTimer", timerSchema, "newTimers"); diff --git a/src/routes/dashboardRouter.js b/src/routes/dashboardRouter.js index 33275597c..664c1c802 100644 --- a/src/routes/dashboardRouter.js +++ b/src/routes/dashboardRouter.js @@ -3,7 +3,6 @@ const express = require('express'); const route = function () { const controller = require('../controllers/dashBoardController')(); - const Dashboardrouter = express.Router(); Dashboardrouter.route('/dashboard/:userId') diff --git a/src/websockets/TimerService/clientsHandler.js b/src/websockets/TimerService/clientsHandler.js new file mode 100644 index 000000000..fdf21b8f4 --- /dev/null +++ b/src/websockets/TimerService/clientsHandler.js @@ -0,0 +1,286 @@ +/* eslint-disable no-multi-assign */ +/* eslint-disable radix */ +const moment = require('moment'); +const Timer = require('../../models/timer'); +const logger = require('../../startup/logger'); + +/** + * Here we get the timer. + * If the timer already exists in memory, we return it. + * If it doesn't exist, we try to get it from MongoDB. + * If it doesn't exist in MongoDB, we create it and save it to MongoDB. + * Then we save it to memory and return it. + */ +export const getClient = async (clients, userId) => { + // In case of there is already a connection that is open for this user + // for example user open a new connection + if (!clients.has(userId)) { + try { + let timer = await Timer.findOne({ userId }); + if (!timer) timer = await Timer.create({ userId }); + clients.set(userId, timer); + } catch (e) { + logger.logException(e); + throw new Error( + 'Something happened when trying to retrieve timer from mongo', + ); + } + } + return clients.get(userId); +}; + +/* + * Save client info to database + * Save under these conditions: + * connection is normally closed (paused and closed); + * connection is forced-paused (timer still on and connection closed) + * message: STOP_TIMER + */ +export const saveClient = async (client) => { + try { + await Timer.findOneAndUpdate({ userId: client.userId }, client); + } catch (e) { + logger.logException(e); + throw new Error( + `Something happened when trying to save user timer to mongo, Error: ${e}`, + ); + } +}; + +/* + * This is the contract between client and server. + * The client can send one of the following messages to the server: + */ +export const action = { + START_TIMER: 'START_TIMER', + PAUSE_TIMER: 'PAUSE_TIMER', + STOP_TIMER: 'STOP_TIMER', + CLEAR_TIMER: 'CLEAR_TIMER', + SET_GOAL: 'SET_GOAL=', + ADD_GOAL: 'ADD_TO_GOAL=', + REMOVE_GOAL: 'REMOVE_FROM_GOAL=', + FORCED_PAUSE: 'FORCED_PAUSE', + ACK_FORCED: 'ACK_FORCED', +}; + +const updatedTimeSinceStart = (client) => { + if (!client.started) return client.goal; + const now = moment.utc(); + const startAt = moment(client.startAt); + const timePassed = moment.duration(now.diff(startAt)).asMilliseconds(); + const updatedTime = client.time - timePassed; + return updatedTime > 0 ? updatedTime : 0; +}; + +/** + * Here we start the timer, if it is not already started. + * We set the last access time to now, and set the paused and stopped flags to false. + * If the timer was paused, we need to check if it was paused by the user or by the server. + * If it was paused by the server, we need to set the forcedPause flag to true. + */ +const startTimer = (client) => { + client.startAt = moment.utc(); + client.paused = false; + if (!client.started) { + client.started = true; + client.time = client.goal; + } + if (client.forcedPause) client.forcedPause = false; +}; + +/** + * Here we pause the timer, if it is not already paused. + * We get the total elapsed time since the last access, and set it as the new time. + * We set the last access time to now, and set the paused flag to true. + * If the timer was paused by the server, we need to set the forcedPause flag to true. + * It'll only be triggered when the user closes the connection sudenlly or lacks of ACKs. + */ +const pauseTimer = (client, forced = false) => { + client.time = updatedTimeSinceStart(client); + client.startAt = moment.invalid(); + client.paused = true; + if (forced) client.forcedPause = true; +}; + +// Here we acknowledge the forced pause. To prevent the modal for beeing displayed again. +const ackForcedPause = (client) => { + client.forcedPause = false; + client.paused = true; + client.startAt = moment.invalid(); +}; + +/** + * Here we stop the timer. + * We pause the timer and set the stopped flag to true. + */ +const stopTimer = (client) => { + client.startAt = moment.invalid(); + client.started = false; + client.pause = false; + client.forcedPause = false; +}; + +/** + * Here we clear the timer. + * We pause the timer and check it's mode to set the time to 0 or the goal. + * Then we set the stopped flag to false. + */ +const clearTimer = (client) => { + stopTimer(client); + client.time = client.goal; +}; + + +// /* +// Here we switch the timer mode. +// We pause the timer and check it's mode to set the time to 0 or the goal. +// */ +// const switchMode = (client) => { +// client.countdown = !client.countdown; +// client.time = client.countdown ? client.goal : 0; +// client.paused = true; +// }; + +// Here we get the goal time from the message. +const getGoal = msg => parseInt(msg.split('=')[1]); + +// Here we set the goal and time to the goal time. +const setGoal = (client, msg) => { + const newGoal = getGoal(msg); + if (!client.started) { + client.goal = newGoal; + client.time = newGoal; + } else { + const passedTime = client.goal - client.time; + if (passedTime >= newGoal) { + client.time = 0; + client.goal = passedTime; + } else { + client.time = newGoal - passedTime; + client.goal = newGoal; + } + } +}; + +/** + * Here we add the goal time. + * Each addition add 15min + * First we get the goal time from the message. + * Then we add it to the current goal time and set it as the new goal time. + * We also add it to the current time and set it as the new time. + */ +const addGoal = (client, msg) => { + const duration = getGoal(msg); + const goalAfterAddition = moment + .duration(client.goal) + .add(duration, 'milliseconds') + .asHours(); + + if (goalAfterAddition > 10) return; + + client.goal = moment + .duration(client.goal) + .add(duration, 'milliseconds') + .asMilliseconds() + .toFixed(); + client.time = moment + .duration(client.time) + .add(duration, 'milliseconds') + .asMilliseconds() + .toFixed(); +}; + +/** + * Here we try to remove a goal time. + * First we get the goal time from the message. + * Then we subtract it from the current goal time and set it as the new goal time. + * We also subtract it from the current time and set it as the new time. + * If the new goal time is less than 15 minutes, we don't do anything. + * If the new time is less than 0, we set it to 0. + */ +const removeGoal = (client, msg) => { + const duration = getGoal(msg); + const goalAfterRemoval = moment + .duration(client.goal) + .subtract(duration, 'milliseconds') + .asMinutes(); + const timeAfterRemoval = moment + .duration(client.time) + .subtract(duration, 'milliseconds') + .asMinutes(); + + if (goalAfterRemoval < 15 || timeAfterRemoval < 0) return; + + client.goal = moment + .duration(client.goal) + .subtract(duration, 'milliseconds') + .asMilliseconds() + .toFixed(); + client.time = moment + .duration(client.time) + .subtract(duration, 'milliseconds') + .asMilliseconds() + .toFixed(); +}; + + +/** + * Here is were we handle the messages. + * First we check if the user is in memory, if not, we throw an error. + * Then we parse the request and check which action it is and call the corresponding function. + * If we don't have a match, we just return an error. + * The only operation that we write to Mongo it's the stop timer. Other operations are just in memory. + * So the slowest part of the app is the save to Mongo. + * Then we update the current client in hash map and return the response. + */ +export const handleMessage = async (msg, clients, userId) => { + if (!clients.has(userId)) { + throw new Error('It should have this user in memory'); + } + + const client = clients.get(userId); + let resp = null; + + const req = msg.toString(); + switch (req) { + case action.START_TIMER: + startTimer(client); + break; + case req.match(/SET_GOAL=/i)?.input: + setGoal(client, req); + break; + case req.match(/ADD_TO_GOAL=/i)?.input: + addGoal(client, req); + break; + case req.match(/REMOVE_FROM_GOAL=/i)?.input: + removeGoal(client, req); + break; + case action.PAUSE_TIMER: + pauseTimer(client); + break; + case action.FORCED_PAUSE: + pauseTimer(client, true); + break; + case action.ACK_FORCED: + ackForcedPause(client); + break; + case action.CLEAR_TIMER: + clearTimer(client); + break; + case action.STOP_TIMER: + stopTimer(client); + break; + + default: + resp = { + ...client, + error: `Unknown operation ${req}, please use one of ${action}`, + }; + break; + } + + await saveClient(client); + clients.set(userId, client); + if (resp === null) resp = client; + return JSON.stringify(resp); +}; diff --git a/src/websockets/TimerService/connectionsHandler.js b/src/websockets/TimerService/connectionsHandler.js new file mode 100644 index 000000000..6658321bf --- /dev/null +++ b/src/websockets/TimerService/connectionsHandler.js @@ -0,0 +1,50 @@ +const WebSocket = require('ws'); + +/** + * Here we insert the new connection to the connections map. + * If the user is not in the map, we create a new entry with the user id as key and the connection as value. + * Else we just push the connection to the array of connections. + */ +export function insertNewUser(connections, userId, wsConn) { + const userConnetions = connections.get(userId); + if (!userConnetions) connections.set(userId, [wsConn]); + else userConnetions.push(wsConn); +} + +/** + *Here we remove the connection from the connections map. + *If the user is not in the map, we do nothing. + *Else we remove the connection from the array of connections. + *If the array is empty, we delete the user from the map. + */ +export function removeConnection(connections, userId, connToRemove) { + const userConnetions = connections.get(userId); + if (!userConnetions) return; + + const newConns = userConnetions.filter(conn => conn !== connToRemove); + if (newConns.length === 0) connections.delete(userId); + else connections.set(userId, newConns); +} + +/** + * Here we broadcast the message to all the connections that are connected to the same user. + * We check if the connection is open before sending the message. + */ +export function broadcastToSameUser(connections, userId, data) { + const userConnetions = connections.get(userId); + if (!userConnetions) return; + userConnetions.forEach((conn) => { + if (conn.readyState === WebSocket.OPEN) conn.send(data); + }); +} + +/** + * Here we check if there is another connection to the same user. + * If there is, we return true. + * Else we return false. + */ +export function hasOtherConn(connections, userId, anotherConn) { + if (!connections.has(userId)) return false; + const userConnections = connections.get(userId); + return userConnections.some(con => con !== anotherConn && con.readyState === WebSocket.OPEN); +} diff --git a/src/websockets/TimerService/index.js b/src/websockets/TimerService/index.js deleted file mode 100644 index 9eac199ce..000000000 --- a/src/websockets/TimerService/index.js +++ /dev/null @@ -1,308 +0,0 @@ -/* eslint-disable no-multi-assign */ -/* eslint-disable radix */ -const moment = require('moment'); -const Timer = require('../../models/timer'); -const logger = require('../../startup/logger'); - -/* -This is the contract between client and server. -The client can send one of the following messages to the server: -*/ -export const action = { - START_TIMER: 'START_TIMER', - PAUSE_TIMER: 'PAUSE_TIMER', - STOP_TIMER: 'STOP_TIMER', - GET_TIMER: 'GET_TIMER', - CLEAR_TIMER: 'CLEAR_TIMER', - SWITCH_MODE: 'SWITCH_MODE', - SET_GOAL: 'SET_GOAL=', - ADD_GOAL: 'ADD_GOAL=', - REMOVE_GOAL: 'REMOVE_GOAL=', - FORCED_PAUSE: 'FORCED_PAUSE', - ACK_FORCED: 'ACK_FORCED', -}; - -/* -Here we get the total elapsed time since the last access. -Since we have two modes for the timer, countdown and stopwatch, -we need to know which one is active to calculate the total elapsed time. -If the timer is in countdown mode, we need to subtract the elapsed time from the total time. -if this total time is less than 0, we set it to 0. -If the timer is in stopwatch mode, -we need to add the elapsed time since the last access to the total time. -we then return the total -*/ -const getTotalElapsedTime = (client) => { - const now = moment(); - const lastAccess = moment(client.lastAccess); - const elapSinceLastAccess = moment.duration(now.diff(lastAccess)); - const time = moment.duration(moment(client.time)); - - let total; - if (client.countdown) { - total = time.subtract(elapSinceLastAccess, 'milliseconds'); - if (total.asMilliseconds() < 0) { - total = moment.duration(0); - } - } else total = elapSinceLastAccess.add(client.time, 'milliseconds'); - - return total; -}; - -/* -Here we start the timer, if it is not already started. -We set the last access time to now, and set the paused and stopped flags to false. -If the timer was paused, we need to check if it was paused by the user or by the server. -If it was paused by the server, we need to set the forcedPause flag to true. -*/ -const startTimer = (client) => { - if (!client.paused) { - client.time = getTotalElapsedTime(client).asMilliseconds().toFixed(); - client.lastAccess = moment(); - } - - if (client.paused) { - client.lastAccess = moment(); - client.stopped = false; - client.paused = false; - if (client.forcedPause) client.forcedPause = false; - } -}; - -/* -Here we pause the timer, if it is not already paused. -We get the total elapsed time since the last access, and set it as the new time. -We set the last access time to now, and set the paused flag to true. -If the timer was paused by the server, we need to set the forcedPause flag to true. -It'll only be triggered when the user closes the connection sudenlly or lacks of ACKs. -*/ -const pauseTimer = (client, forced = false) => { - if (!client.paused) { - client.time = getTotalElapsedTime(client).asMilliseconds().toFixed(); - client.lastAccess = moment(); - client.paused = true; - if (forced) client.forcedPause = true; - } -}; - -// Here we acknowledge the forced pause. To prevent the modal for beeing displayed again. -const ackForcedPause = (client) => { - client.forcedPause = false; -}; - -/* -Here we clear the timer. -We pause the timer and check it's mode to set the time to 0 or the goal. -Then we set the stopped flag to false. -*/ -const clearTimer = (client) => { - pauseTimer(client); - client.time = client.countdown ? client.goal : 0; - client.stopped = false; -}; - -/* -Here we stop the timer. -We pause the timer and set the stopped flag to true. -*/ -const stopTimer = (client) => { - pauseTimer(client); - client.stopped = true; -}; - -/* -Here we switch the timer mode. -We pause the timer and check it's mode to set the time to 0 or the goal. -*/ -const switchMode = (client) => { - client.countdown = !client.countdown; - client.time = client.countdown ? client.goal : 0; - client.paused = true; -}; - -// Here we get the goal time from the message. -const getGoal = msg => parseInt(msg.split('=')[1]); - -// Here we set the goal and time to the goal time. -const setGoal = (client, msg) => { - const goal = getGoal(msg); - client.goal = client.time = goal; -}; - -const goalOver10Hours = (client, time) => { - const goal = moment.duration(client.goal).add(time, 'milliseconds').asHours(); - return goal > 10; -}; - -/* -Here we add the goal time. -First we get the goal time from the message. -Then we add it to the current goal time and set it as the new goal time. -We also add it to the current time and set it as the new time. -*/ -const addGoal = (client, msg) => { - const goal = getGoal(msg); - if (goalOver10Hours(client, goal)) return; - - if (!client.paused) { - client.time = getTotalElapsedTime(client).asMilliseconds().toFixed(); - client.lastAccess = moment(); - } - - client.goal = moment - .duration(client.goal) - .add(goal, 'milliseconds') - .asMilliseconds() - .toFixed(); - client.time = moment - .duration(client.time) - .add(goal, 'milliseconds') - .asMilliseconds() - .toFixed(); -}; - -/* - * Here we check if the goal time is less than 15 minutes. - * */ -const goalLessThan15min = (client, time) => { - const goal = moment - .duration(client.goal) - .subtract(time, 'milliseconds') - .asMinutes(); - return goal < 15; -}; - -/* - * Here we try to remove a goal time. - * First we get the goal time from the message. - * Then we subtract it from the current goal time and set it as the new goal time. - * We also subtract it from the current time and set it as the new time. - * If the new goal time is less than 15 minutes, we don't do anything. - * If the new time is less than 0, we set it to 0. - * */ -const removeGoal = (client, msg) => { - const goal = getGoal(msg); - if (goalLessThan15min(client, goal)) return; - - if (!client.paused) { - client.time = getTotalElapsedTime(client).asMilliseconds().toFixed(); - client.lastAccess = moment(); - } - - client.goal = moment - .duration(client.goal) - .subtract(goal, 'milliseconds') - .asMilliseconds() - .toFixed(); - const time = moment - .duration(client.time) - .subtract(goal, 'milliseconds') - .asMilliseconds() - .toFixed(); - client.time = time < 0 ? 0 : time; -}; - -/* -Here we get the timer. -If the timer already exists in memory, we return it. -If it doesn't exist, we try to get it from MongoDB. -If it doesn't exist in MongoDB, we create it and save it to MongoDB. -Then we save it to memory and return it. -*/ -export const getTimer = async (clientsMap, userId) => { - if (clientsMap.has(userId)) return; - - try { - let timer = await Timer.findOne({ userId }); - if (!timer) timer = await Timer.create({ userId }); - clientsMap.set(userId, timer); - } catch (e) { - logger.logException(e); - throw new Error( - 'Something happened when trying to retrieve timer from mongo', - ); - } -}; - -// Here we just save the timer to MongoDB. -const saveClient = async (client) => { - try { - await Timer.findOneAndUpdate({ userId: client.userId }, client); - } catch (e) { - logger.logException(e); - throw new Error( - 'Something happened when trying to save user timer to mongo', - ); - } -}; - -/* -Here is were we handle the messages. -First we check if the user is in memory, if not, we throw an error. -Then we parse the request and check which action it is and call the corresponding function. -If we don't have a match, we just return an error. -The only operation that we write to Mongo it's the stop timer. Other operations are just in memory. -So the slowest part of the app is the save to Mongo. -Then we update the current client in hash map and return the response. -*/ -export const handleMessage = async (msg, clientsMap, userId) => { - if (!clientsMap.has(userId)) { - throw new Error('It should have this user in memory'); - } - - const client = clientsMap.get(userId); - let resp = null; - - const req = msg.toString(); - switch (req) { - case action.GET_TIMER: - break; - case action.START_TIMER: - startTimer(client); - break; - case action.SWITCH_MODE: - switchMode(client); - break; - case req.match(/SET_GOAL=/i)?.input: - setGoal(client, req); - break; - case req.match(/ADD_GOAL=/i)?.input: - addGoal(client, req); - break; - case req.match(/REMOVE_GOAL=/i)?.input: - removeGoal(client, req); - break; - case action.PAUSE_TIMER: - pauseTimer(client); - break; - case action.FORCED_PAUSE: - pauseTimer(client, true); - break; - case action.ACK_FORCED: - ackForcedPause(client); - break; - case action.CLEAR_TIMER: - clearTimer(client); - break; - case action.STOP_TIMER: - stopTimer(client); - break; - - default: - resp = { - ...client, - error: `Unknown operation ${req}, please use one of ${action}`, - }; - break; - } - - if (req === action.STOP_TIMER) { - await saveClient(client).catch((err) => { - resp = { ...client, error: err }; - }); - } - - clientsMap.set(userId, client); - if (resp === null) resp = client; - return JSON.stringify(resp); -}; diff --git a/src/websockets/index.js b/src/websockets/index.js index a733dff25..5da85f729 100644 --- a/src/websockets/index.js +++ b/src/websockets/index.js @@ -7,15 +7,25 @@ const WebSocket = require("ws"); const moment = require("moment"); const jwt = require("jsonwebtoken"); const config = require("../config"); -const { getTimer, handleMessage, action } = require("./TimerService/"); - -/* -Here we authenticate the user. -We get the token from the headers and try to verify it. -If it fails, we throw an error. -Else we check if the token is valid and if it is, we return the user id. +const { + insertNewUser, + removeConnection, + broadcastToSameUser, + hasOtherConn, +} = require("./TimerService/connectionsHandler"); +const { + getClient, + handleMessage, + action, +} = require("./TimerService/clientsHandler"); + +/** +* Here we authenticate the user. +* We get the token from the headers and try to verify it. +* If it fails, we throw an error. +* Else we check if the token is valid and if it is, we return the user id. */ -export const authenticate = (req, res) => { +const authenticate = (req, res) => { const authToken = req.headers?.["sec-websocket-protocol"]; let payload = ""; try { @@ -37,68 +47,13 @@ export const authenticate = (req, res) => { res(null, payload.userid); }; -/* - * Here we insert the new connection to the connections map. - * If the user is not in the map, we create a new entry with the user id as key and the connection as value. - * Else we just push the connection to the array of connections. - */ -const insertNewUser = (connections, userId, wsConn) => { - const userConnetions = connections.get(userId); - if (!userConnetions) connections.set(userId, [wsConn]); - else userConnetions.push(wsConn); -}; - -/* - *Here we remove the connection from the connections map. - *If the user is not in the map, we do nothing. - *Else we remove the connection from the array of connections. - *If the array is empty, we delete the user from the map. - */ -const removeConnection = (connections, userId, connToRemove) => { - const userConnetions = connections.get(userId); - if (!userConnetions) return; - - const newConns = userConnetions.filter(conn => conn !== connToRemove); - if (newConns.length === 0) connections.delete(userId); - else connections.set(userId, newConns); -}; - -/* - * Here we broadcast the message to all the connections that are connected to the same user. - * We check if the connection is open before sending the message. - */ -const broadcastToSameUser = (connections, userId, data) => { - const userConnetions = connections.get(userId); - if (!userConnetions) return; - userConnetions.forEach((conn) => { - if (conn.readyState === WebSocket.OPEN) conn.send(data); - }); -}; - -/* - * Here we check if there is another connection to the same user. - * If there is, we return true. - * Else we return false. - */ -const checkOtherConn = (connections, anotherConn, userId) => { - const userConnetions = connections.get(userId); - if (!userConnetions) return false; - for (const con of userConnetions) { - if (con !== anotherConn && con.readyState === WebSocket.OPEN) return true; - } - return false; -}; - -/* -Here we start the timer service. -First we create a map to store the clients and start the Websockets Server. -Then we set the upgrade event listener to the Express Server, authenticate the user and -if it is valid, we add the user id to the request and handle the upgrade and emit the connection event. +/** +* Here we start the timer service. +* First we create a map to store the clients and start the Websockets Server. +* Then we set the upgrade event listener to the Express Server, authenticate the user and +* if it is valid, we add the user id to the request and handle the upgrade and emit the connection event. */ export default async (expServer) => { - const clients = new Map(); - const connections = new Map(); - const wss = new WebSocket.Server({ noServer: true, path: "/timer-service", @@ -118,64 +73,66 @@ export default async (expServer) => { }); }); - /* - For each new connection we start a timer of 5min to check if the connection is alive. - If it is, we then repeat the process. If it is not, we terminate the connection. - */ + const clients = new Map(); // { userId: timerInfo } + const connections = new Map(); // { userId: connections[] } + wss.on("connection", async (ws, req) => { ws.isAlive = true; + const { userId } = req; + ws.on("pong", () => { ws.isAlive = true; }); - const { userId } = req; - insertNewUser(connections, userId, ws); - /* + /** * Here we get the timer from memory or from the database and send it to the client. - * We don't broadcast it */ - await getTimer(clients, userId); - ws.send(await handleMessage(action.GET_TIMER, clients, userId)); + const clientTimer = await getClient(clients, userId); + ws.send(JSON.stringify(clientTimer)); - /* - Here we handle the messages from the client. - And we broadcast the response to all the clients that are connected to the same user. + /** + * Here we handle the messages from the client. + * And we broadcast the response to all the clients that are connected to the same user. */ ws.on("message", async (data) => { const resp = await handleMessage(data, clients, userId); broadcastToSameUser(connections, userId, resp); }); - /* - Here we handle the close event. - If there is another connection to the same user, we don't do anything. - Else he is the last connection and we do a forced pause if need be. - This may happen if the user closes all the tabs or the browser or he lost connection with - the service - We then remove the connection from the connections map. + /** + * Here we handle the close event. + * If there is another connection to the same user, we don't do anything. + * Else he is the last connection and we do a forced pause if need be. + * This may happen if the user closes all the tabs or the browser or he lost connection with + * the service + * We then remove the connection from the connections map. */ ws.on("close", async () => { - if (!checkOtherConn(connections, ws, userId)) { - await handleMessage(action.FORCED_PAUSE, clients, userId); + if (!hasOtherConn(connections, userId, ws)) { + const client = clients.get(userId); + if (client.started && !client.paused) { + await handleMessage(action.FORCED_PAUSE, clients, userId); + } } removeConnection(connections, userId, ws); }); }); - // The function to check if the connection is alive - const interval = setInterval(async () => { - wss.clients.forEach(async (ws) => { - if (ws.isAlive === false) return ws.terminate(); - + // For each new connection we start a time interval of 1min to check if the connection is alive. + // change to 1min before push + const interval = setInterval(() => { + wss.clients.forEach((ws) => { + if (ws.isAlive === false) { + return ws.close(); + } ws.isAlive = false; ws.ping(); }); - }, 3000000); + }, 10000); - // Here we just clear the interval when the server closes - wss.on("close", () => { + wss.on('close', () => { clearInterval(interval); }); From bc3d082a9959c527e202841f87840d836e957064 Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Thu, 19 Oct 2023 06:43:15 +0800 Subject: [PATCH 077/272] test --- src/controllers/timeEntryController.js | 3 --- src/helpers/dashboardhelper.js | 14 ++++++++++++++ src/helpers/reporthelper.js | 3 +++ src/helpers/taskHelper.js | 6 ++++++ src/helpers/userHelper.js | 3 ++- 5 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/controllers/timeEntryController.js b/src/controllers/timeEntryController.js index 0bd9bb573..094cee9ba 100644 --- a/src/controllers/timeEntryController.js +++ b/src/controllers/timeEntryController.js @@ -553,7 +553,6 @@ const timeEntrycontroller = function (TimeEntry) { .then((results) => { const data = []; results.forEach((element) => { - console.log(element); const record = {}; record._id = element._id; @@ -592,7 +591,6 @@ const timeEntrycontroller = function (TimeEntry) { .then((results) => { const data = []; results.forEach((element) => { - console.log(element); const record = {}; record._id = element._id; record.notes = element.notes; @@ -627,7 +625,6 @@ const timeEntrycontroller = function (TimeEntry) { .then((results) => { const data = []; results.forEach((element) => { - console.log(element); const record = {}; record._id = element._id; record.notes = element.notes; diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index 34d464583..1c03c2f88 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -69,6 +69,9 @@ const dashboardhelper = function () { { $lte: ['$$timeentry.dateOfWork', pdtend], }, + { + $in: ['$$timeentry.entryType', ['default', null]], + }, ], }, }, @@ -162,6 +165,7 @@ const dashboardhelper = function () { .tz('America/Los_Angeles') .endOf('week') .format('YYYY-MM-DD'); + const entryTypes = ['default', null]; return myTeam.aggregate([ { $match: { @@ -283,6 +287,9 @@ const dashboardhelper = function () { { $lte: ['$$timeentry.dateOfWork', pdtend], }, + { + $in: ['$$timeentry.entryType', ['default', null]], + } ], }, }, @@ -438,6 +445,7 @@ const dashboardhelper = function () { $gte: pdtStart, $lte: pdtEnd, }, + eentryType: { $in: [ 'default', null ] }, personId: userId, }); @@ -575,6 +583,9 @@ const dashboardhelper = function () { { $lte: ['$$timeentry.dateOfWork', todate], }, + { + $in: ['$$timeentry.entryType', ['default', null]], + }, ], }, }, @@ -652,6 +663,9 @@ const dashboardhelper = function () { { $lte: ['$$timeentry.dateOfWork', todate], }, + { + $in: ['$$timeentry.entryType', ['default', null]], + }, ], }, }, diff --git a/src/helpers/reporthelper.js b/src/helpers/reporthelper.js index 0c2a8104d..c812ef03c 100644 --- a/src/helpers/reporthelper.js +++ b/src/helpers/reporthelper.js @@ -68,6 +68,9 @@ const reporthelper = function () { moment(pstEnd).format("YYYY-MM-DD"), ], }, + { + $in: ['$$timeentry.entryType', ['default', null]], + }, ], }, }, diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index a94aaee94..30bb220e9 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -113,6 +113,9 @@ const taskHelper = function () { { $lte: ['$$timeentry.dateOfWork', pdtend], }, + { + $in: ['$$timeentry.entryType', ['default', null]], + }, ], }, }, @@ -357,6 +360,9 @@ const taskHelper = function () { { $lte: ['$$timeentry.dateOfWork', pdtend], }, + { + $in: ['$$timeentry.entryType', ['default', null]], + }, ], }, }, diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index af416f1a7..e1ca1fb7f 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -565,7 +565,8 @@ const userHelper = function () { $and: [ { $eq: ["$isTangible", true] }, { $gte: ["$dateOfWork", startOfLastWeek] }, - { $lte: ["$dateOfWork", endOfLastWeek] } + { $lte: ["$dateOfWork", endOfLastWeek] }, + { $in: ['$entryType', 'default', null] } ] } } From c417ad7711ca86d2c15a81f88f7c4cd4ca3c6348 Mon Sep 17 00:00:00 2001 From: Bhagyashree Birajdar Date: Wed, 18 Oct 2023 16:35:47 -0700 Subject: [PATCH 078/272] Send email to 2 recipients - user and other(used for onecommunity email later) --- src/controllers/reasonSchedulingController.js | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/controllers/reasonSchedulingController.js b/src/controllers/reasonSchedulingController.js index 39729680f..98dd152ff 100644 --- a/src/controllers/reasonSchedulingController.js +++ b/src/controllers/reasonSchedulingController.js @@ -94,7 +94,7 @@ const postReason = async (req, res) => { { console.log("Inside if."); //Upon clicking the "Save" button in the Blue Square Reason Scheduler, an email will be automatically sent to the user and Jae. - const subject = `Blue Square Reason for :${foundUser.firstName} ${foundUser.lastName} has been set`; + const subject = `Blue Square Reason for ${foundUser.firstName} ${foundUser.lastName} has been set`; const emailBody = `

Hi !

@@ -107,7 +107,13 @@ const postReason = async (req, res) => { One Community

`; console.log("line before email sender") - emailSender('shreetesting4@gmail.com', subject, emailBody, null, null); + // 1 hardcoded email- emailSender('shreetesting4@gmail.com', subject, emailBody, null, null); + + // 2 user email - + emailSender(`${foundUser.email}`, subject, emailBody, null, null); + + //3 - user email and hardcoded email ( After PR approval hardcode Jae's email) + // emailSender(`${foundUser.email},shreetesting4@gmail.com`, subject, emailBody, null, null); } return res.sendStatus(200); @@ -260,7 +266,7 @@ const patchReason = async (req, res) => { { console.log(" Patch - Inside if."); //Upon clicking the "Save" button in the Blue Square Reason Scheduler, an email will be automatically sent to the user and Jae. - const subject = `Blue Square Reason for :${foundUser.firstName} ${foundUser.lastName} has been updated`; + const subject = `Blue Square Reason for ${foundUser.firstName} ${foundUser.lastName} has been updated`; const emailBody = `

Hi !

@@ -273,7 +279,15 @@ const patchReason = async (req, res) => { One Community

`; console.log("line before email sender") - emailSender('shreetesting4@gmail.com', subject, emailBody, null, null); + // 1 hardcoded email- emailSender('shreetesting4@gmail.com', subject, emailBody, null, null); + + // 2 user email - + emailSender(`${foundUser.email}`, subject, emailBody, null, null); + + //3 - user email and hardcoded email ( After PR approval hardcode Jae's email) + // emailSender(`${foundUser.email},shreetesting4@gmail.com`, subject, emailBody, null, null); + + } return res.status(200).json({ From 9a7bfb948da6f7b0c2beeb7cf310e3addeaa72b6 Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Thu, 19 Oct 2023 10:06:48 +0800 Subject: [PATCH 079/272] add validator of regex and authorization --- src/controllers/teamController.js | 11 ++++++++++- src/models/team.js | 13 ++++++++++++- src/models/userProfile.js | 17 ++++++++++++++--- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/controllers/teamController.js b/src/controllers/teamController.js index 5215b024b..b204875a5 100644 --- a/src/controllers/teamController.js +++ b/src/controllers/teamController.js @@ -70,6 +70,15 @@ const teamcontroller = function (Team) { res.status(400).send('No valid records found'); return; } + + const canEditTeamCode = req.body.requestor.role === 'Owner' + || req.body.requestor.permissions?.frontPermissions.includes('editTeamCode'); + + if (!canEditTeamCode) { + res.status(403).send('You are not authorized to edit team code.'); + return; + } + record.teamName = req.body.teamName; record.isActive = req.body.isActive; record.teamCode = req.body.teamCode; @@ -116,7 +125,7 @@ const teamcontroller = function (Team) { users.forEach((element) => { const { userId, operation } = element; // if user's profile is stored in cache, clear it so when you visit their profile page it will be up to date - if(cache.hasCache(`user-${userId}`)) cache.removeCache(`user-${userId}`); + if (cache.hasCache(`user-${userId}`)) cache.removeCache(`user-${userId}`); if (operation === 'Assign') { assignlist.push(userId); diff --git a/src/models/team.js b/src/models/team.js index a57d7bb27..97f8dc360 100644 --- a/src/models/team.js +++ b/src/models/team.js @@ -13,7 +13,18 @@ const team = new Schema({ addDateTime: { type: Date, default: Date.now(), ref: 'userProfile' }, }, ], - teamCode: { type: 'String', default: '' }, + teamCode: { + type: 'String', + default: '', + validate: { + validator(v) { + const teamCoderegex = /^([a-zA-Z]-[a-zA-Z]{3}|[a-zA-Z]{5})$/; + return teamCoderegex.test(v); + }, + message: + 'Please enter a code in the format of A-AAA or AAAAA', + }, + }, }); module.exports = mongoose.model('team', team, 'teams'); diff --git a/src/models/userProfile.js b/src/models/userProfile.js index a58d1d293..4739a05e7 100644 --- a/src/models/userProfile.js +++ b/src/models/userProfile.js @@ -7,7 +7,7 @@ const bcrypt = require('bcryptjs'); const SALT_ROUNDS = 10; const nextDay = new Date(); -nextDay.setDate(nextDay.getDate()+1); +nextDay.setDate(nextDay.getDate() + 1); const userProfileSchema = new Schema({ password: { @@ -153,8 +153,19 @@ const userProfileSchema = new Schema({ isVisible: { type: Boolean, default: false }, weeklySummaryOption: { type: String }, bioPosted: { type: String, default: 'default' }, - isFirstTimelog: { type: Boolean, default: true}, - teamCode: { type: String, default: '' }, + isFirstTimelog: { type: Boolean, default: true }, + teamCode: { + type: String, + default: '', + validate: { + validator(v) { + const teamCoderegex = /^([a-zA-Z]-[a-zA-Z]{3}|[a-zA-Z]{5})$/; + return teamCoderegex.test(v); + }, + message: + 'Please enter a code in the format of A-AAA or AAAAA', + }, + }, infoCollections: [ { areaName: { type: String }, From f376fa8f049717d07eb12cdfd2eab9bcbf250da2 Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Thu, 19 Oct 2023 22:37:33 +0800 Subject: [PATCH 080/272] add update task status function --- src/controllers/taskController.js | 15 +++++++++++++-- src/routes/taskRouter.js | 3 +++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/controllers/taskController.js b/src/controllers/taskController.js index 7a19fd853..9bcf071de 100644 --- a/src/controllers/taskController.js +++ b/src/controllers/taskController.js @@ -776,7 +776,6 @@ const taskController = function (Task) { }); res.status(200).send(task); - } catch (error) { // Generic error message, you can adjust as needed res.status(500).send({ error: 'Internal Server Error', details: error.message }); @@ -850,6 +849,17 @@ const taskController = function (Task) { } }; + const updateTaskStatus = async (req, res) => { + const { taskId } = req.params; + + Task.findOneAndUpdate( + { _id: mongoose.Types.ObjectId(taskId) }, + { ...req.body, modifiedDatetime: Date.now() }, + ) + .then(() => res.status(201).send()) + .catch(error => res.status(404).send(error)); + }; + const getReviewReqEmailBody = function (name, taskName) { const text = `New Task Review Request From ${name}:

The following task is available to review:

@@ -863,7 +873,7 @@ const taskController = function (Task) { const getRecipients = async function (myUserId) { const recipients = []; const user = await userProfile.findById(myUserId); - const membership = await userProfile.find({ role: ['Administrator', 'Manager', 'Mentor'] }); + const membership = await userProfile.find({ role: { $in: ['Administrator', 'Manager', 'Mentor'] } }); membership.forEach((member) => { if (member.teams.some(team => user.teams.includes(team))) { recipients.push(member.email); @@ -909,6 +919,7 @@ const taskController = function (Task) { moveTask, getTasksByUserList, getTasksForTeamsByUser, + updateTaskStatus, sendReviewReq, }; }; diff --git a/src/routes/taskRouter.js b/src/routes/taskRouter.js index ef972f2cb..46e467c9d 100644 --- a/src/routes/taskRouter.js +++ b/src/routes/taskRouter.js @@ -28,6 +28,9 @@ const routes = function (task, userProfile) { wbsRouter.route('/task/update/:taskId') .put(controller.updateTask); + wbsRouter.route('/task/updateStatus/:taskId') + .put(controller.updateTaskStatus); + wbsRouter.route('/task/updateAllParents/:wbsId/') .put(controller.updateAllParents); From 85f6e2dc0847d2644804acc9227a5fcb1b66fe5c Mon Sep 17 00:00:00 2001 From: Aaron Persaud Date: Fri, 20 Oct 2023 10:13:56 -0400 Subject: [PATCH 081/272] update babel/traverse and mongoose to fix vulnerabilities --- package-lock.json | 211 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 194 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index f9eb87ba6..3fcc98986 100644 --- a/package-lock.json +++ b/package-lock.json @@ -318,6 +318,11 @@ "@babel/types": "^7.16.7" } }, + "@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==" + }, "@babel/helper-validator-identifier": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", @@ -1083,20 +1088,131 @@ } }, "@babel/traverse": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", - "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", - "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.3", - "@babel/types": "^7.17.0", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "requires": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + } + }, + "@babel/generator": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "requires": { + "@babel/types": "^7.23.0", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==" + }, + "@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "requires": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" + }, + "@babel/highlight": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "requires": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==" + }, + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + }, + "@babel/types": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==" + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + } } }, "@babel/types": { @@ -1194,11 +1310,49 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "dependencies": { + "@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + }, + "dependencies": { + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + } + } + } + } + }, "@jridgewell/resolve-uri": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==" }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" + }, "@jridgewell/sourcemap-codec": { "version": "1.4.11", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", @@ -5382,7 +5536,7 @@ "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, "lodash.merge": { "version": "4.6.2", @@ -5666,15 +5820,15 @@ } }, "mongoose": { - "version": "5.13.15", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.15.tgz", - "integrity": "sha512-cxp1Gbb8yUWkaEbajdhspSaKzAvsIvOtRlYD87GN/P2QEUhpd6bIvebi36T6M0tIVAMauNaK9SPA055N3PwF8Q==", + "version": "5.13.21", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.21.tgz", + "integrity": "sha512-EvSrXrCBogenxY131qKasFcT1Pj+9Pg5AXj17vQ8S1mOEArK3CpOx965u1wTIrdnQ7DjFC+SRwPxNcqUjMAVyQ==", "requires": { "@types/bson": "1.x || 4.0.x", "@types/mongodb": "^3.5.27", "bson": "^1.1.4", "kareem": "2.3.2", - "mongodb": "3.7.3", + "mongodb": "3.7.4", "mongoose-legacy-pluralize": "1.0.2", "mpath": "0.8.4", "mquery": "3.2.5", @@ -5686,6 +5840,29 @@ "sliced": "1.0.1" }, "dependencies": { + "mongodb": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.4.tgz", + "integrity": "sha512-K5q8aBqEXMwWdVNh94UQTwZ6BejVbFhh1uB6c5FKtPE9eUMZPUO3sRZdgIEcHSrAWmxzpG/FeODDKL388sqRmw==", + "requires": { + "bl": "^2.2.1", + "bson": "^1.1.4", + "denque": "^1.4.1", + "optional-require": "^1.1.8", + "safe-buffer": "^5.1.2", + "saslprep": "^1.0.0" + }, + "dependencies": { + "optional-require": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.1.8.tgz", + "integrity": "sha512-jq83qaUb0wNg9Krv1c5OQ+58EK+vHde6aBPzLvPPqJm89UQWsvSuFy9X/OSNJnFeSOKo7btE0n8Nl2+nE+z5nA==", + "requires": { + "require-at": "^1.0.6" + } + } + } + }, "optional-require": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz", From 63de1d12b07af4f84cc32fa5407af4e2edeaddb6 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Fri, 20 Oct 2023 09:21:52 -0700 Subject: [PATCH 082/272] add bm proj route, router, controller --- .../bmdashboard/bmProjectsController.js | 18 ++++++++++++++++++ src/routes/bmdashboard/bmMaterialsRouter.js | 4 ++-- src/routes/bmdashboard/bmProjectsRouter.js | 14 ++++++++++++++ src/startup/routes.js | 2 ++ 4 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 src/controllers/bmdashboard/bmProjectsController.js create mode 100644 src/routes/bmdashboard/bmProjectsRouter.js diff --git a/src/controllers/bmdashboard/bmProjectsController.js b/src/controllers/bmdashboard/bmProjectsController.js new file mode 100644 index 000000000..946869bce --- /dev/null +++ b/src/controllers/bmdashboard/bmProjectsController.js @@ -0,0 +1,18 @@ +const mongoose = require('mongoose'); + +const bmMProjectsController = function () { + // fetches projects with reference to BM userProfile id + const bmProjectsSummary = async function _projSumm(req, res) { + try { + res.json({ message: 'Hello world' }); + + // .then(results => res.status(200).send(results)) + // .catch(error => res.status(500).send(error)) + } catch (err) { + res.json(err); + } + }; + return { bmProjectsSummary }; +}; + +module.exports = bmMProjectsController; diff --git a/src/routes/bmdashboard/bmMaterialsRouter.js b/src/routes/bmdashboard/bmMaterialsRouter.js index ab8a67388..1188acf9d 100644 --- a/src/routes/bmdashboard/bmMaterialsRouter.js +++ b/src/routes/bmdashboard/bmMaterialsRouter.js @@ -8,6 +8,6 @@ materialsRouter.route('/materials') .get(controller.bmMaterialsList); return materialsRouter; -} +}; -module.exports = routes; \ No newline at end of file +module.exports = routes; diff --git a/src/routes/bmdashboard/bmProjectsRouter.js b/src/routes/bmdashboard/bmProjectsRouter.js new file mode 100644 index 000000000..204efbfad --- /dev/null +++ b/src/routes/bmdashboard/bmProjectsRouter.js @@ -0,0 +1,14 @@ +const express = require('express'); + +const routes = function () { + const projectsRouter = express.Router(); + const controller = require('../../controllers/bmdashboard/bmProjectsController')(); +// const controller = require('../../controllers/bmdashboard/bmMaterialsController')(itemMaterial); + +projectsRouter.route('/projects') + .get(controller.bmProjectsSummary); + + return projectsRouter; +}; + +module.exports = routes; diff --git a/src/startup/routes.js b/src/startup/routes.js index 2fd7337a6..7208535d8 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -61,6 +61,7 @@ const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverTe // bm dashboard const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial); +const bmProjectsRouter = require('../routes/bmdashboard/bmProjectsRouter')(); module.exports = function (app) { app.use('/api', forgotPwdRouter); @@ -96,4 +97,5 @@ module.exports = function (app) { // bm dashboard app.use('/api/bm', bmLoginRouter); app.use('/api/bm', bmMaterialsRouter); + app.use('/api/bm', bmProjectsRouter); }; From 36d6d23ceee94b95e1d5cc363457f7fd36922a6a Mon Sep 17 00:00:00 2001 From: wang9hu Date: Mon, 23 Oct 2023 20:06:25 -0700 Subject: [PATCH 083/272] make requested changes from last reviews --- src/websockets/TimerService/clientsHandler.js | 41 +++++++++---------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/src/websockets/TimerService/clientsHandler.js b/src/websockets/TimerService/clientsHandler.js index fdf21b8f4..6990ead71 100644 --- a/src/websockets/TimerService/clientsHandler.js +++ b/src/websockets/TimerService/clientsHandler.js @@ -29,7 +29,7 @@ export const getClient = async (clients, userId) => { return clients.get(userId); }; -/* +/** * Save client info to database * Save under these conditions: * connection is normally closed (paused and closed); @@ -47,7 +47,7 @@ export const saveClient = async (client) => { } }; -/* +/** * This is the contract between client and server. * The client can send one of the following messages to the server: */ @@ -63,6 +63,9 @@ export const action = { ACK_FORCED: 'ACK_FORCED', }; +const MAX_HOURS = 5; +const MIN_MINS = 1; + const updatedTimeSinceStart = (client) => { if (!client.started) return client.goal; const now = moment.utc(); @@ -127,26 +130,20 @@ const stopTimer = (client) => { */ const clearTimer = (client) => { stopTimer(client); + client.goal = moment.duration(2, 'hours').asMilliseconds(); client.time = client.goal; }; - -// /* -// Here we switch the timer mode. -// We pause the timer and check it's mode to set the time to 0 or the goal. -// */ -// const switchMode = (client) => { -// client.countdown = !client.countdown; -// client.time = client.countdown ? client.goal : 0; -// client.paused = true; -// }; - -// Here we get the goal time from the message. -const getGoal = msg => parseInt(msg.split('=')[1]); - // Here we set the goal and time to the goal time. +/** + * Here we set the goal. + * if timer has not started, we set both time and goal to the new goal + * if timer has started, we calculate the passed time and remove that from new goal + * and if passed time is greater than new goal, then set time to 0, but this should + * not be prohibited by frontend. + */ const setGoal = (client, msg) => { - const newGoal = getGoal(msg); + const newGoal = parseInt(msg.split('=')[1]); if (!client.started) { client.goal = newGoal; client.time = newGoal; @@ -170,13 +167,13 @@ const setGoal = (client, msg) => { * We also add it to the current time and set it as the new time. */ const addGoal = (client, msg) => { - const duration = getGoal(msg); + const duration = parseInt(msg.split('=')[1]); const goalAfterAddition = moment .duration(client.goal) .add(duration, 'milliseconds') .asHours(); - if (goalAfterAddition > 10) return; + if (goalAfterAddition > MAX_HOURS) return; client.goal = moment .duration(client.goal) @@ -199,7 +196,7 @@ const addGoal = (client, msg) => { * If the new time is less than 0, we set it to 0. */ const removeGoal = (client, msg) => { - const duration = getGoal(msg); + const duration = parseInt(msg.split('=')[1]); const goalAfterRemoval = moment .duration(client.goal) .subtract(duration, 'milliseconds') @@ -209,7 +206,7 @@ const removeGoal = (client, msg) => { .subtract(duration, 'milliseconds') .asMinutes(); - if (goalAfterRemoval < 15 || timeAfterRemoval < 0) return; + if (goalAfterRemoval < MIN_MINS || timeAfterRemoval < 0) return; client.goal = moment .duration(client.goal) @@ -279,7 +276,7 @@ export const handleMessage = async (msg, clients, userId) => { break; } - await saveClient(client); + saveClient(client); clients.set(userId, client); if (resp === null) resp = client; return JSON.stringify(resp); From 55c5e16eacd9071adfa8176e94113637e6efb791 Mon Sep 17 00:00:00 2001 From: Nathan Hoffman Date: Tue, 24 Oct 2023 21:12:17 -0700 Subject: [PATCH 084/272] Fix hasPermission() arguments and add catches. --- src/controllers/rolePresetsController.js | 8 ++++---- src/utilities/permissions.js | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/controllers/rolePresetsController.js b/src/controllers/rolePresetsController.js index 3642627f7..3a7dc18c8 100644 --- a/src/controllers/rolePresetsController.js +++ b/src/controllers/rolePresetsController.js @@ -2,7 +2,7 @@ const { hasPermission } = require('../utilities/permissions'); const rolePresetsController = function (Preset) { const getPresetsByRole = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'putRole')) { + if (!await hasPermission(req.body.requestor, 'putRole')) { res.status(403).send('You are not authorized to make changes to roles.'); return; } @@ -14,7 +14,7 @@ const rolePresetsController = function (Preset) { }; const createNewPreset = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'putRole')) { + if (!await hasPermission(req.body.requestor, 'putRole')) { res.status(403).send('You are not authorized to make changes to roles.'); return; } @@ -34,7 +34,7 @@ const rolePresetsController = function (Preset) { }; const updatePresetById = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'putRole')) { + if (!await hasPermission(req.body.requestor, 'putRole')) { res.status(403).send('You are not authorized to make changes to roles.'); return; } @@ -53,7 +53,7 @@ const rolePresetsController = function (Preset) { }; const deletePresetById = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'putRole')) { + if (!await hasPermission(req.body.requestor, 'putRole')) { res.status(403).send('You are not authorized to make changes to roles.'); return; } diff --git a/src/utilities/permissions.js b/src/utilities/permissions.js index 7b5d4a245..ebf35b2a1 100644 --- a/src/utilities/permissions.js +++ b/src/utilities/permissions.js @@ -4,12 +4,14 @@ const UserProfile = require('../models/userProfile'); const hasRolePermission = async (role, action) => Role.findOne({ roleName: role }) .exec() - .then(({ permissions }) => permissions.includes(action)); + .then(({ permissions }) => permissions.includes(action)) + .catch(false); const hasIndividualPermission = async (userId, action) => UserProfile.findById(userId) .select('permissions') .exec() - .then(({ permissions }) => permissions.frontPermissions.includes(action)); + .then(({ permissions }) => permissions.frontPermissions.includes(action)) + .catch(false); const hasPermission = async (requestor, action) => await hasRolePermission(requestor.role, action) || hasIndividualPermission(requestor.requestorId, action); From 701be2501cf6f82da6eb90723c1d4fc55f5a6eed Mon Sep 17 00:00:00 2001 From: wang9hu Date: Wed, 25 Oct 2023 17:19:35 -0700 Subject: [PATCH 085/272] cleanup old timer related code and files --- src/controllers/REAL_TIME_timerController.js | 155 ------------------- src/models/REAL_TIME_timer.js | 13 -- src/models/oldTimer.js | 14 -- src/routes/timerRouter.js | 15 -- src/startup/routes.js | 3 - 5 files changed, 200 deletions(-) delete mode 100644 src/controllers/REAL_TIME_timerController.js delete mode 100644 src/models/REAL_TIME_timer.js delete mode 100644 src/models/oldTimer.js delete mode 100644 src/routes/timerRouter.js diff --git a/src/controllers/REAL_TIME_timerController.js b/src/controllers/REAL_TIME_timerController.js deleted file mode 100644 index 699dcddef..000000000 --- a/src/controllers/REAL_TIME_timerController.js +++ /dev/null @@ -1,155 +0,0 @@ - -const logger = require('../startup/logger'); -const OldTimer = require('../models/oldTimer'); - -const timerController = function (Timer) { - const getTimerFromDatabase = async ({ userId }) => { - try { - const timerObject = await Timer.findOne({ userId }).exec(); - if (!timerObject) { - const newRecord = { - userId, - totalSeconds: 0, - isRunning: false, - isApplicationPaused: false, - isUserPaused: false, - }; - const newTimer = await Timer.create(newRecord); - return newTimer; - } - return timerObject; - } catch (e) { - logger.logException(e); - throw new Error('Issue trying to retrieve timer data from MongoDB'); - } - }; - - const setTimerToDatabase = async ({ - userId, - timerObject: { - totalSeconds, - isRunning, - isUserPaused, - isApplicationPaused, - } = {}, - } = {}) => { - try { - const update = { - $set: { - totalSeconds, - isRunning, - isUserPaused, - isApplicationPaused, - }, - }; - - const options = { - upsert: true, - new: true, - setDefaultsOnInsert: true, - rawResult: true, - }; - - return await Timer.findOneAndUpdate({ userId }, update, options).exec(); - } catch (e) { - logger.logException(e); - throw new Error('Issue trying to set timer data from MongoDB'); - } - }; - - const putTimer = function (req, res) { - const { userId } = req.params; - - const query = { userId }; - const update = { - $set: { - pausedAt: req.body.pausedAt, - isWorking: req.body.isWorking, - started: req.body.isWorking ? Date.now() : null, - lastAccess: Date.now(), - }, - }; - const options = { - upsert: true, new: true, setDefaultsOnInsert: true, rawResult: true, - }; - - OldTimer.findOneAndUpdate(query, update, options, (error, rawResult) => { - if (error) { - return res.status(500).send({ error }); - } - - if (rawResult === null || rawResult.value === undefined || rawResult.value === null - || rawResult.lastErrorObject === null || rawResult.lastErrorObject === undefined - || rawResult.value.length === 0) { - return res.status(500).send('Update/Upsert timer date failed'); - } - - if (rawResult.lastErrorObject.updatedExisting === true) { - return res.status(200).send({ message: 'updated timer data' }); - } - if (rawResult.lastErrorObject.updatedExisting === false - && rawResult.lastErrorObject.upserted !== undefined && rawResult.lastErrorObject.upserted !== null) { - return res.status(201).send({ _id: rawResult.lastErrorObject.upserted }); - } - return res.status(500).send('Update/Upsert timer date failed'); - }); - }; - - const timePassed = (timer) => { - if (!timer.started) { return 0; } - const now = timer.timedOut ? timer.lastAccess : Date.now(); - return Math.floor((now - timer.started) / 1000); - }; - - const adjust = (timer, cb) => { - const oneMin = 60 * 1000; - const fiveMin = 5 * oneMin; - const timeSinceLastAccess = timer.lastAccess ? (Date.now() - timer.lastAccess) : 0; - const setLastAccess = !timer.lastAccess || (timeSinceLastAccess > oneMin); - - timer.timedOut = timer.isWorking && (timeSinceLastAccess > fiveMin); - timer.seconds = timer.pausedAt + timePassed(timer); - - if (timer.timedOut) { - return OldTimer.findOneAndUpdate({ userId: timer.userId }, { - isWorking: false, - pauseAt: timer.seconds, - started: null, - lastAccess: Date.now(), - }).then(() => cb(timer)); - } - if (setLastAccess) { - return OldTimer.findOneAndUpdate({ userId: timer.userId }, { lastAccess: Date.now() }).then(() => cb(timer)); - } - - return cb(timer); - }; - - const getTimer = function (req, res) { - const { userId } = req.params; - - OldTimer.findOne({ userId }).lean().exec((error, record) => { - if (error) { - return res.status(500).send(error); - } - if (record === null) { - if (req.body.requestor.requestorId === userId) { - const newRecord = { - userId, - pausedAt: 0, - isWorking: false, - }; - return OldTimer.create(newRecord).then(result => res.status(200).send(result)).catch(() => res.status(400).send('Timer record not found for the given user ID')); - } - return res.status(400).send('Timer record not found for the given user ID'); - } - return adjust(record, (timer) => { res.status(200).send(timer); }); - }); - }; - - return { - putTimer, getTimer, getTimerFromDatabase, setTimerToDatabase, - }; -}; - -module.exports = timerController; diff --git a/src/models/REAL_TIME_timer.js b/src/models/REAL_TIME_timer.js deleted file mode 100644 index 4e143aeaa..000000000 --- a/src/models/REAL_TIME_timer.js +++ /dev/null @@ -1,13 +0,0 @@ -const mongoose = require('mongoose'); - -const { Schema } = mongoose; - -const timerSchema = new Schema({ - userId: { type: Schema.Types.ObjectId, required: true, ref: 'userProfile' }, - totalSeconds: { type: Number, default: 0 }, - isRunning: { type: Boolean, default: false }, - isUserPaused: { type: Boolean, default: false }, - isApplicationPaused: { type: Boolean, default: false }, -}); - -module.exports = mongoose.model('newTimer', timerSchema, 'newTimers'); diff --git a/src/models/oldTimer.js b/src/models/oldTimer.js deleted file mode 100644 index dca0ade1a..000000000 --- a/src/models/oldTimer.js +++ /dev/null @@ -1,14 +0,0 @@ -const mongoose = require('mongoose'); - -const { Schema } = mongoose; - -const timerSchema = new Schema({ - userId: { type: Schema.Types.ObjectId, required: true, ref: 'userProfile' }, - pausedAt: { type: Number, default: 0 }, - isWorking: { type: Boolean, default: false }, - started: { type: Date }, - lastAccess: { type: Date }, - }); - - -module.exports = mongoose.model('timer', timerSchema, 'timers'); diff --git a/src/routes/timerRouter.js b/src/routes/timerRouter.js deleted file mode 100644 index 094b2ba81..000000000 --- a/src/routes/timerRouter.js +++ /dev/null @@ -1,15 +0,0 @@ -const express = require('express'); - -const routes = function (Timer) { - const TimerRouter = express.Router(); - - const controller = require('../controllers/REAL_TIME_timerController')(Timer); - - TimerRouter.route('/timer/:userId') - .put(controller.putTimer) - .get(controller.getTimer); - - return TimerRouter; -}; - -module.exports = routes; diff --git a/src/startup/routes.js b/src/startup/routes.js index 2fd7337a6..eae746e24 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -7,7 +7,6 @@ const actionItem = require('../models/actionItem'); const notification = require('../models/notification'); const wbs = require('../models/wbs'); const task = require('../models/task'); -const timer = require('../models/timer'); const popup = require('../models/popupEditor'); const popupBackup = require('../models/popupEditorBackup'); const taskNotification = require('../models/taskNotification'); @@ -38,7 +37,6 @@ const forcePwdRouter = require('../routes/forcePwdRouter')(userProfile); const reportsRouter = require('../routes/reportsRouter')(); const wbsRouter = require('../routes/wbsRouter')(wbs); const taskRouter = require('../routes/taskRouter')(task); -const timerRouter = require('../routes/timerRouter')(timer); const popupRouter = require('../routes/popupEditorRouter')(popup); const popupBackupRouter = require('../routes/popupEditorBackupRouter')(popupBackup); const taskNotificationRouter = require('../routes/taskNotificationRouter')(taskNotification); @@ -76,7 +74,6 @@ module.exports = function (app) { app.use('/api', reportsRouter); app.use('/api', wbsRouter); app.use('/api', taskRouter); - app.use('/api', timerRouter); app.use('/api', popupRouter); app.use('/api', popupBackupRouter); app.use('/api', taskNotificationRouter); From 467cbb84140103fcdd0ad97c728584d1d6156229 Mon Sep 17 00:00:00 2001 From: wang9hu Date: Wed, 25 Oct 2023 18:31:29 -0700 Subject: [PATCH 086/272] remove 2h default time when clear timer --- src/websockets/TimerService/clientsHandler.js | 77 +------------------ 1 file changed, 1 insertion(+), 76 deletions(-) diff --git a/src/websockets/TimerService/clientsHandler.js b/src/websockets/TimerService/clientsHandler.js index 6990ead71..e9e932fd7 100644 --- a/src/websockets/TimerService/clientsHandler.js +++ b/src/websockets/TimerService/clientsHandler.js @@ -4,13 +4,6 @@ const moment = require('moment'); const Timer = require('../../models/timer'); const logger = require('../../startup/logger'); -/** - * Here we get the timer. - * If the timer already exists in memory, we return it. - * If it doesn't exist, we try to get it from MongoDB. - * If it doesn't exist in MongoDB, we create it and save it to MongoDB. - * Then we save it to memory and return it. - */ export const getClient = async (clients, userId) => { // In case of there is already a connection that is open for this user // for example user open a new connection @@ -29,13 +22,6 @@ export const getClient = async (clients, userId) => { return clients.get(userId); }; -/** - * Save client info to database - * Save under these conditions: - * connection is normally closed (paused and closed); - * connection is forced-paused (timer still on and connection closed) - * message: STOP_TIMER - */ export const saveClient = async (client) => { try { await Timer.findOneAndUpdate({ userId: client.userId }, client); @@ -47,10 +33,6 @@ export const saveClient = async (client) => { } }; -/** - * This is the contract between client and server. - * The client can send one of the following messages to the server: - */ export const action = { START_TIMER: 'START_TIMER', PAUSE_TIMER: 'PAUSE_TIMER', @@ -75,12 +57,6 @@ const updatedTimeSinceStart = (client) => { return updatedTime > 0 ? updatedTime : 0; }; -/** - * Here we start the timer, if it is not already started. - * We set the last access time to now, and set the paused and stopped flags to false. - * If the timer was paused, we need to check if it was paused by the user or by the server. - * If it was paused by the server, we need to set the forcedPause flag to true. - */ const startTimer = (client) => { client.startAt = moment.utc(); client.paused = false; @@ -91,31 +67,19 @@ const startTimer = (client) => { if (client.forcedPause) client.forcedPause = false; }; -/** - * Here we pause the timer, if it is not already paused. - * We get the total elapsed time since the last access, and set it as the new time. - * We set the last access time to now, and set the paused flag to true. - * If the timer was paused by the server, we need to set the forcedPause flag to true. - * It'll only be triggered when the user closes the connection sudenlly or lacks of ACKs. - */ const pauseTimer = (client, forced = false) => { client.time = updatedTimeSinceStart(client); - client.startAt = moment.invalid(); + client.startAt = moment.invalid(); // invalid can not be saved in database client.paused = true; if (forced) client.forcedPause = true; }; -// Here we acknowledge the forced pause. To prevent the modal for beeing displayed again. const ackForcedPause = (client) => { client.forcedPause = false; client.paused = true; client.startAt = moment.invalid(); }; -/** - * Here we stop the timer. - * We pause the timer and set the stopped flag to true. - */ const stopTimer = (client) => { client.startAt = moment.invalid(); client.started = false; @@ -123,25 +87,11 @@ const stopTimer = (client) => { client.forcedPause = false; }; -/** - * Here we clear the timer. - * We pause the timer and check it's mode to set the time to 0 or the goal. - * Then we set the stopped flag to false. - */ const clearTimer = (client) => { stopTimer(client); - client.goal = moment.duration(2, 'hours').asMilliseconds(); client.time = client.goal; }; -// Here we set the goal and time to the goal time. -/** - * Here we set the goal. - * if timer has not started, we set both time and goal to the new goal - * if timer has started, we calculate the passed time and remove that from new goal - * and if passed time is greater than new goal, then set time to 0, but this should - * not be prohibited by frontend. - */ const setGoal = (client, msg) => { const newGoal = parseInt(msg.split('=')[1]); if (!client.started) { @@ -159,13 +109,6 @@ const setGoal = (client, msg) => { } }; -/** - * Here we add the goal time. - * Each addition add 15min - * First we get the goal time from the message. - * Then we add it to the current goal time and set it as the new goal time. - * We also add it to the current time and set it as the new time. - */ const addGoal = (client, msg) => { const duration = parseInt(msg.split('=')[1]); const goalAfterAddition = moment @@ -187,14 +130,6 @@ const addGoal = (client, msg) => { .toFixed(); }; -/** - * Here we try to remove a goal time. - * First we get the goal time from the message. - * Then we subtract it from the current goal time and set it as the new goal time. - * We also subtract it from the current time and set it as the new time. - * If the new goal time is less than 15 minutes, we don't do anything. - * If the new time is less than 0, we set it to 0. - */ const removeGoal = (client, msg) => { const duration = parseInt(msg.split('=')[1]); const goalAfterRemoval = moment @@ -220,16 +155,6 @@ const removeGoal = (client, msg) => { .toFixed(); }; - -/** - * Here is were we handle the messages. - * First we check if the user is in memory, if not, we throw an error. - * Then we parse the request and check which action it is and call the corresponding function. - * If we don't have a match, we just return an error. - * The only operation that we write to Mongo it's the stop timer. Other operations are just in memory. - * So the slowest part of the app is the save to Mongo. - * Then we update the current client in hash map and return the response. - */ export const handleMessage = async (msg, clients, userId) => { if (!clients.has(userId)) { throw new Error('It should have this user in memory'); From 29e9bb2c3fddcf4d1a47607691c0ba2e0a4d0d12 Mon Sep 17 00:00:00 2001 From: wang9hu Date: Wed, 25 Oct 2023 23:36:47 -0700 Subject: [PATCH 087/272] make timer keep remaining time as goal after log time, and add initial goal in timer modal --- src/models/timer.js | 1 + src/websockets/TimerService/clientsHandler.js | 24 +++++++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/models/timer.js b/src/models/timer.js index 8afbad119..09c2f89da 100644 --- a/src/models/timer.js +++ b/src/models/timer.js @@ -8,6 +8,7 @@ const timerSchema = new Schema({ startAt: { type: Date, default: Date.now }, time: { type: Number, default: 900000 }, goal: { type: Number, default: 900000 }, + initialGoal: { type: Number, default: 900000 }, paused: { type: Boolean, default: false }, forcedPause: { type: Boolean, default: false }, started: { type: Boolean, default: false }, diff --git a/src/websockets/TimerService/clientsHandler.js b/src/websockets/TimerService/clientsHandler.js index e9e932fd7..3bb2c358d 100644 --- a/src/websockets/TimerService/clientsHandler.js +++ b/src/websockets/TimerService/clientsHandler.js @@ -81,32 +81,30 @@ const ackForcedPause = (client) => { }; const stopTimer = (client) => { + if (client.started) pauseTimer(client); client.startAt = moment.invalid(); client.started = false; client.pause = false; client.forcedPause = false; + if (client.time === 0) { + client.goal = client.initialGoal; + client.time = client.goal; + } else { + client.goal = client.time; + } }; const clearTimer = (client) => { stopTimer(client); + client.goal = client.initialGoal; client.time = client.goal; }; const setGoal = (client, msg) => { const newGoal = parseInt(msg.split('=')[1]); - if (!client.started) { - client.goal = newGoal; - client.time = newGoal; - } else { - const passedTime = client.goal - client.time; - if (passedTime >= newGoal) { - client.time = 0; - client.goal = passedTime; - } else { - client.time = newGoal - passedTime; - client.goal = newGoal; - } - } + client.goal = newGoal; + client.time = newGoal; + client.initialGoal = newGoal; }; const addGoal = (client, msg) => { From 8d37664a8b3ca4603ee5e9cd9f8f55d5c98c50a0 Mon Sep 17 00:00:00 2001 From: Carl Bebli Date: Thu, 26 Oct 2023 16:56:16 +0000 Subject: [PATCH 088/272] included replyTo field to the emailOptions --- src/utilities/emailSender.js | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/utilities/emailSender.js b/src/utilities/emailSender.js index 4841d1410..98ca3e337 100644 --- a/src/utilities/emailSender.js +++ b/src/utilities/emailSender.js @@ -1,7 +1,6 @@ -const nodemailer = require('nodemailer'); -const { google } = require('googleapis'); -const logger = require('../startup/logger'); - +const nodemailer = require("nodemailer"); +const { google } = require("googleapis"); +const logger = require("../startup/logger"); const closure = () => { const queue = []; @@ -13,9 +12,9 @@ const closure = () => { const REFRESH_TOKEN = process.env.REACT_APP_EMAIL_REFRESH_TOKEN; // Create the email envelope (transport) const transporter = nodemailer.createTransport({ - service: 'gmail', + service: "gmail", auth: { - type: 'OAuth2', + type: "OAuth2", user: CLIENT_EMAIL, clientId: CLIENT_ID, clientSecret: CLIENT_SECRET, @@ -25,7 +24,7 @@ const closure = () => { const OAuth2Client = new google.auth.OAuth2( CLIENT_ID, CLIENT_SECRET, - REDIRECT_URI, + REDIRECT_URI ); OAuth2Client.setCredentials({ refresh_token: REFRESH_TOKEN }); @@ -35,9 +34,7 @@ const closure = () => { if (!nextItem) return; - const { - recipient, subject, message, cc, bcc, - } = nextItem; + const { recipient, subject, message, cc, bcc, replyTo } = nextItem; try { // Generate the accessToken on the fly @@ -51,6 +48,7 @@ const closure = () => { bcc, subject, html: message, + replyTo, auth: { user: CLIENT_EMAIL, refreshToken: REFRESH_TOKEN, @@ -65,10 +63,22 @@ const closure = () => { } }, process.env.MAIL_QUEUE_INTERVAL || 1000); - const emailSender = function (recipient, subject, message, cc = null, bcc = null) { + const emailSender = function ( + recipient, + subject, + message, + cc = null, + bcc = null, + replyTo = null + ) { if (process.env.sendEmail) { queue.push({ - recipient, subject, message, cc, bcc, + recipient, + subject, + message, + cc, + bcc, + replyTo, }); } }; From 326f7fece0a63501551c69ff5e1a7c87cc19a28e Mon Sep 17 00:00:00 2001 From: Carl Bebli Date: Thu, 26 Oct 2023 16:57:01 +0000 Subject: [PATCH 089/272] improved the message received by one community when a user makes a suggestion --- src/controllers/dashBoardController.js | 120 ++++++++++++++----------- 1 file changed, 66 insertions(+), 54 deletions(-) diff --git a/src/controllers/dashBoardController.js b/src/controllers/dashBoardController.js index c9cdbd588..aacc915dd 100644 --- a/src/controllers/dashBoardController.js +++ b/src/controllers/dashBoardController.js @@ -1,8 +1,8 @@ -const mongoose = require("mongoose"); -const path = require("path"); -const fs = require("fs/promises"); -const dashboardhelper = require("../helpers/dashboardhelper")(); -const emailSender = require("../utilities/emailSender"); +const path = require('path'); +const fs = require('fs/promises'); +const mongoose = require('mongoose'); +const dashboardhelper = require('../helpers/dashboardhelper')(); +const emailSender = require('../utilities/emailSender'); const dashboardcontroller = function () { const dashboarddata = function (req, res) { @@ -20,13 +20,13 @@ const dashboardcontroller = function () { const laborthismonth = dashboardhelper.laborthismonth( userId, req.params.fromDate, - req.params.toDate + req.params.toDate, ); laborthismonth.then((results) => { if (!results || results.length === 0) { const emptyresult = [ { - projectName: "", + projectName: '', timeSpent_hrs: 0, }, ]; @@ -42,7 +42,7 @@ const dashboardcontroller = function () { const laborthisweek = dashboardhelper.laborthisweek( userId, req.params.fromDate, - req.params.toDate + req.params.toDate, ); laborthisweek.then((results) => { res.send(results).status(200); @@ -63,7 +63,7 @@ const dashboardcontroller = function () { }); } }) - .catch((error) => res.status(400).send(error)); + .catch(error => res.status(400).send(error)); }; const orgData = function (req, res) { @@ -73,7 +73,7 @@ const dashboardcontroller = function () { .then((results) => { res.status(200).send(results[0]); }) - .catch((error) => res.status(400).send(error)); + .catch(error => res.status(400).send(error)); }; const getBugReportEmailBody = function ( @@ -85,7 +85,7 @@ const dashboardcontroller = function () { expected, actual, visual, - severity + severity, ) { const text = `New Bug Report From ${firstName} ${lastName}:

[Feature Name] Bug Title:

@@ -130,32 +130,32 @@ const dashboardcontroller = function () { expected, actual, visual, - severity + severity, ); try { emailSender( - "onecommunityglobal@gmail.com", + 'onecommunityglobal@gmail.com', `Bug Rport from ${firstName} ${lastName}`, emailBody, - email + email, ); - res.status(200).send("Success"); + res.status(200).send('Success'); } catch { - res.status(500).send("Failed"); + res.status(500).send('Failed'); } }; const suggestionData = { suggestion: [ - "Identify and remedy poor client and/or user service experiences", - "Identify bright spots and enhance positive service experiences", - "Make fundamental changes to our programs and/or operations", - "Inform the development of new programs/projects", - "Identify where we are less inclusive or equitable across demographic groups", - "Strengthen relationships with the people we serve", + 'Identify and remedy poor client and/or user service experiences', + 'Identify bright spots and enhance positive service experiences', + 'Make fundamental changes to our programs and/or operations', + 'Inform the development of new programs/projects', + 'Identify where we are less inclusive or equitable across demographic groups', + 'Strengthen relationships with the people we serve', "Understand people's needs and how we can help them achieve their goals", - "Other", + 'Other', ], field: [], }; @@ -164,42 +164,54 @@ const dashboardcontroller = function () { let fieldaaray = []; if (suggestionData.field.length) { fieldaaray = suggestionData.field.map( - (item) => `

${item}

-

${args[3][item]}

` + item => `

${item}

+

${args[3][item]}

`, ); } - const text = `New Suggestion: -

Suggestion Category:

-

${args[0]}

-

Suggestion:

-

${args[1]}

- ${fieldaaray.length > 0 ? fieldaaray : ""} -

Wants Feedback:

-

${args[2]}

-

Thank you,
- One Community

`; + const text = `New Suggestion From ${args[3].firstName} ${ + args[3].lastName + }: +

Suggestion Category:

+

${args[0]}

+

Suggestion:

+

${args[1]}

+ ${fieldaaray.length > 0 ? fieldaaray : ''} +

Name of Suggester:

+

${args[3].firstName} ${args[3].lastName}

+

Email of Suggester:

+

${args[4]}

+

Wants Feedback:

+

${args[2]}

+

Thank you,
+ One Community

`; return text; }; // send suggestion email const sendMakeSuggestion = async (req, res) => { - const { suggestioncate, suggestion, confirm, ...rest } = req.body; + const { + suggestioncate, suggestion, confirm, email, ...rest +} = req.body; const emailBody = await getsuggestionEmailBody( suggestioncate, suggestion, confirm, - rest + rest, + email, ); try { emailSender( - "onecommunityglobal@gmail.com", - "A new suggestion", - emailBody + 'beblicarl.cb@gmail.com', + 'A new suggestion', + emailBody, + null, + null, + email, ); - res.status(200).send("Success"); + res.status(200).send('Success'); } catch { - res.status(500).send("Failed"); + res.status(500).send('Failed'); } }; @@ -208,40 +220,40 @@ const dashboardcontroller = function () { if (suggestionData) { res.status(200).send(suggestionData); } else { - res.status(404).send("Suggestion data not found."); + res.status(404).send('Suggestion data not found.'); } } catch (error) { - console.error("Error getting suggestion data:", error); - res.status(500).send("Internal Server Error"); + console.error('Error getting suggestion data:', error); + res.status(500).send('Internal Server Error'); } }; const editSuggestionOption = async (req, res) => { try { if (req.body.suggestion) { - if (req.body.action === "add") { + if (req.body.action === 'add') { suggestionData.suggestion.unshift(req.body.newField); } - if (req.body.action === "delete") { + if (req.body.action === 'delete') { suggestionData.suggestion = suggestionData.suggestion.filter( - (item, index) => index + 1 !== +req.body.newField + (item, index) => index + 1 !== +req.body.newField, ); } } else { - if (req.body.action === "add") { + if (req.body.action === 'add') { suggestionData.field.unshift(req.body.newField); } - if (req.body.action === "delete") { + if (req.body.action === 'delete') { suggestionData.field = suggestionData.field.filter( - (item) => item !== req.body.newField + item => item !== req.body.newField, ); } } - res.status(200).send("success"); + res.status(200).send('success'); } catch (error) { - console.error("Error editing suggestion option:", error); - res.status(500).send("Internal Server Error"); + console.error('Error editing suggestion option:', error); + res.status(500).send('Internal Server Error'); } }; From 815b0f5ae588efb855fbde13fa65f301280b7686 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Thu, 26 Oct 2023 13:23:24 -0700 Subject: [PATCH 090/272] update projects controller to return basic proj info --- .../bmdashboard/bmMaterialsController.js | 24 +++++++++---------- .../bmdashboard/bmProjectsController.js | 23 ++++++++++++++---- src/routes/bmdashboard/bmProjectsRouter.js | 7 +++--- src/startup/routes.js | 2 +- 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index a31ed460e..fb6003e90 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -1,4 +1,4 @@ -const mongoose = require('mongoose') +const mongoose = require('mongoose'); const bmMaterialsController = function (ItemMaterial) { const bmMaterialsList = async function _matsList(req, res) { @@ -7,37 +7,37 @@ const bmMaterialsController = function (ItemMaterial) { .populate([ { path: 'project', - select: '_id projectName' + select: '_id projectName', }, { path: 'inventoryItemType', - select: '_id name uom totalStock totalAvailable' + select: '_id name uom totalStock totalAvailable', }, { path: 'usageRecord', populate: { path: 'createdBy', - select: '_id firstName lastName' - } + select: '_id firstName lastName', + }, }, { path: 'updateRecord', populate: { path: 'createdBy', - select: '_id firstName lastName' - } + select: '_id firstName lastName', + }, }, { path: 'purchaseRecord', populate: { path: 'createdBy', - select: '_id firstName lastName' - } - } + select: '_id firstName lastName', + }, + }, ]) .exec() .then(results => res.status(200).send(results)) - .catch(error => res.status(500).send(error)) + .catch(error => res.status(500).send(error)); } catch (err) { res.json(err); } @@ -45,4 +45,4 @@ const bmMaterialsController = function (ItemMaterial) { return { bmMaterialsList }; }; -module.exports = bmMaterialsController; \ No newline at end of file +module.exports = bmMaterialsController; diff --git a/src/controllers/bmdashboard/bmProjectsController.js b/src/controllers/bmdashboard/bmProjectsController.js index 946869bce..f80eea6c0 100644 --- a/src/controllers/bmdashboard/bmProjectsController.js +++ b/src/controllers/bmdashboard/bmProjectsController.js @@ -1,13 +1,26 @@ const mongoose = require('mongoose'); -const bmMProjectsController = function () { - // fetches projects with reference to BM userProfile id +const bmMProjectsController = function (UserProfile) { const bmProjectsSummary = async function _projSumm(req, res) { + const { userId } = req.params; try { - res.json({ message: 'Hello world' }); + const projectData = await UserProfile + // fetch user profile, return only projects array + .findOne({ _id: userId }, { projects: 1 }) + // populate data with projects documents using the ObjectId in the projects array + .populate({ + path: 'projects', + // limit to projects with category value 'Housing' + match: { category: 'Housing' }, + // returns only these fields + select: '_id projectName isActive createdDatetime', + }) + .exec() + .then(result => result.projects) + .catch(error => res.status(500).send(error)); - // .then(results => res.status(200).send(results)) - // .catch(error => res.status(500).send(error)) + // for each project, find all materials in the project + res.status(200).send(projectData); } catch (err) { res.json(err); } diff --git a/src/routes/bmdashboard/bmProjectsRouter.js b/src/routes/bmdashboard/bmProjectsRouter.js index 204efbfad..05adfa59d 100644 --- a/src/routes/bmdashboard/bmProjectsRouter.js +++ b/src/routes/bmdashboard/bmProjectsRouter.js @@ -1,11 +1,10 @@ const express = require('express'); -const routes = function () { +const routes = function (userProfile) { const projectsRouter = express.Router(); - const controller = require('../../controllers/bmdashboard/bmProjectsController')(); -// const controller = require('../../controllers/bmdashboard/bmMaterialsController')(itemMaterial); + const controller = require('../../controllers/bmdashboard/bmProjectsController')(userProfile); -projectsRouter.route('/projects') +projectsRouter.route('/projects/:userId') .get(controller.bmProjectsSummary); return projectsRouter; diff --git a/src/startup/routes.js b/src/startup/routes.js index 7208535d8..aa786dbbd 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -61,7 +61,7 @@ const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverTe // bm dashboard const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial); -const bmProjectsRouter = require('../routes/bmdashboard/bmProjectsRouter')(); +const bmProjectsRouter = require('../routes/bmdashboard/bmProjectsRouter')(userProfile); module.exports = function (app) { app.use('/api', forgotPwdRouter); From c58cdd3401d8364653dca9d039dd06e5c36f679e Mon Sep 17 00:00:00 2001 From: Vishala Ramasamy Date: Thu, 26 Oct 2023 16:04:14 -0700 Subject: [PATCH 091/272] update record api for material , get bm active projects api --- .../bmdashboard/bmMaterialsController.js | 24 ++++++++++++- .../bmdashboard/bmProjectsController.js | 35 +++++++++++++++++++ src/routes/bmdashboard/bmMaterialsRouter.js | 3 ++ src/routes/bmdashboard/bmProjectsRouter.js | 13 +++++++ src/startup/routes.js | 2 ++ 5 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 src/controllers/bmdashboard/bmProjectsController.js create mode 100644 src/routes/bmdashboard/bmProjectsRouter.js diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index a31ed460e..1fb1fc792 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -42,7 +42,29 @@ const bmMaterialsController = function (ItemMaterial) { res.json(err); } }; - return { bmMaterialsList }; + + const bmPostMaterialUpdateRecord = function (req, res) { + console.log(req.body); + ItemMaterial.update( + { "_id": req.body.material._id }, + { + $push: { + updateRecord: { + date : req.body.date, + createdBy : req.body.requestor.requestorId, + action : req.body.action, + cause : req.body.cause, + quantity : req.body.quantity, + description : req.body.description + } + } + } + ) + .then(results => res.status(200).send(results)) + .catch(error => res.status(500).send(error)) + }; + return { bmMaterialsList, + bmPostMaterialUpdateRecord }; }; module.exports = bmMaterialsController; \ No newline at end of file diff --git a/src/controllers/bmdashboard/bmProjectsController.js b/src/controllers/bmdashboard/bmProjectsController.js new file mode 100644 index 000000000..42ee507eb --- /dev/null +++ b/src/controllers/bmdashboard/bmProjectsController.js @@ -0,0 +1,35 @@ +const mongoose = require('mongoose'); +const UserProfile = require('../../models/userProfile') + +const bmProjectsController = function () { + + //Get current user's Housing/Building projects + const getUserActiveBMProjects = function (req, res) { + try { + const userId = req.body.requestor.requestorId; + UserProfile.findById(userId) + .populate([ + { + path: 'projects', + select: '_id projectName category isActive', + match: { category: 'Housing' }, + } + ]) + .select({ + projects: 1 + }) + .then((results) => { + res.status(200).send(results); + }) + .catch(error => res.status(500).send(error)); + } + + catch (err) { + res.json(err); + } + + }; + return { getUserActiveBMProjects }; +} + +module.exports = bmProjectsController; \ No newline at end of file diff --git a/src/routes/bmdashboard/bmMaterialsRouter.js b/src/routes/bmdashboard/bmMaterialsRouter.js index ab8a67388..0be779cd7 100644 --- a/src/routes/bmdashboard/bmMaterialsRouter.js +++ b/src/routes/bmdashboard/bmMaterialsRouter.js @@ -7,6 +7,9 @@ const controller = require('../../controllers/bmdashboard/bmMaterialsController' materialsRouter.route('/materials') .get(controller.bmMaterialsList); +materialsRouter.route('/addUpdateMaterialRecord') + .post(controller.bmPostMaterialUpdateRecord); + return materialsRouter; } diff --git a/src/routes/bmdashboard/bmProjectsRouter.js b/src/routes/bmdashboard/bmProjectsRouter.js new file mode 100644 index 000000000..cec4b16e9 --- /dev/null +++ b/src/routes/bmdashboard/bmProjectsRouter.js @@ -0,0 +1,13 @@ +const express = require('express'); + +const routes = function () { +const materialsRouter = express.Router(); +const controller = require('../../controllers/bmdashboard/bmProjectsController')(); + +materialsRouter.route('/getUserActiveBMProjects') + .get(controller.getUserActiveBMProjects); + + return materialsRouter; +} + +module.exports = routes; \ No newline at end of file diff --git a/src/startup/routes.js b/src/startup/routes.js index 2fd7337a6..00d8a3fec 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -61,6 +61,7 @@ const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverTe // bm dashboard const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial); +const bmProjectsRouter = require('../routes/bmdashboard/bmProjectsRouter')() module.exports = function (app) { app.use('/api', forgotPwdRouter); @@ -96,4 +97,5 @@ module.exports = function (app) { // bm dashboard app.use('/api/bm', bmLoginRouter); app.use('/api/bm', bmMaterialsRouter); + app.use('/api/bm', bmProjectsRouter); }; From edcdbba50d80d6334f0ae02466185588802d2fd7 Mon Sep 17 00:00:00 2001 From: Vishala Ramasamy Date: Thu, 26 Oct 2023 16:04:40 -0700 Subject: [PATCH 092/272] update record api for material , get bm active projects api --- .../bmdashboard/bmMaterialsController.js | 52 +- .../bmdashboard/bmProjectsController.js | 18 +- src/controllers/dashBoardController.js | 92 +-- src/controllers/isEmailExistsController.js | 22 +- .../profileInitialSetupController.js | 89 ++- src/controllers/teamController.js | 2 +- src/controllers/userProfileController.js | 106 ++- src/helpers/dashboardhelper.js | 4 +- src/helpers/reporthelper.js | 94 +-- src/helpers/taskHelper.js | 4 +- src/helpers/userHelper.js | 603 +++++++++--------- src/models/badge.js | 2 +- src/models/inventoryItemMaterial.js | 6 +- src/models/inventoryItemType.js | 6 +- src/models/profileInitialSetupToken.js | 4 +- src/models/userProfile.js | 4 +- src/routes/bmdashboard/bmMaterialsRouter.js | 4 +- src/routes/bmdashboard/bmProjectsRouter.js | 4 +- src/routes/isEmailExistsRouter.js | 14 +- src/routes/profileInitialSetupRouter.js | 6 +- src/startup/routes.js | 2 +- 21 files changed, 548 insertions(+), 590 deletions(-) diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index 1fb1fc792..09fa91ab8 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -1,4 +1,4 @@ -const mongoose = require('mongoose') +const mongoose = require('mongoose'); const bmMaterialsController = function (ItemMaterial) { const bmMaterialsList = async function _matsList(req, res) { @@ -7,37 +7,37 @@ const bmMaterialsController = function (ItemMaterial) { .populate([ { path: 'project', - select: '_id projectName' + select: '_id projectName', }, { path: 'inventoryItemType', - select: '_id name uom totalStock totalAvailable' + select: '_id name uom totalStock totalAvailable', }, { path: 'usageRecord', populate: { path: 'createdBy', - select: '_id firstName lastName' - } + select: '_id firstName lastName', + }, }, { path: 'updateRecord', populate: { path: 'createdBy', - select: '_id firstName lastName' - } + select: '_id firstName lastName', + }, }, { path: 'purchaseRecord', populate: { path: 'createdBy', - select: '_id firstName lastName' - } - } + select: '_id firstName lastName', + }, + }, ]) .exec() .then(results => res.status(200).send(results)) - .catch(error => res.status(500).send(error)) + .catch(error => res.status(500).send(error)); } catch (err) { res.json(err); } @@ -46,25 +46,27 @@ const bmMaterialsController = function (ItemMaterial) { const bmPostMaterialUpdateRecord = function (req, res) { console.log(req.body); ItemMaterial.update( - { "_id": req.body.material._id }, + { _id: req.body.material._id }, { $push: { updateRecord: { - date : req.body.date, - createdBy : req.body.requestor.requestorId, - action : req.body.action, - cause : req.body.cause, - quantity : req.body.quantity, - description : req.body.description - } - } - } + date: req.body.date, + createdBy: req.body.requestor.requestorId, + action: req.body.action, + cause: req.body.cause, + quantity: req.body.quantity, + description: req.body.description, + }, + }, + }, ) .then(results => res.status(200).send(results)) - .catch(error => res.status(500).send(error)) + .catch(error => res.status(500).send(error)); }; - return { bmMaterialsList, - bmPostMaterialUpdateRecord }; + return { + bmMaterialsList, + bmPostMaterialUpdateRecord, +}; }; -module.exports = bmMaterialsController; \ No newline at end of file +module.exports = bmMaterialsController; diff --git a/src/controllers/bmdashboard/bmProjectsController.js b/src/controllers/bmdashboard/bmProjectsController.js index 42ee507eb..3ff0f851a 100644 --- a/src/controllers/bmdashboard/bmProjectsController.js +++ b/src/controllers/bmdashboard/bmProjectsController.js @@ -1,9 +1,8 @@ const mongoose = require('mongoose'); -const UserProfile = require('../../models/userProfile') +const UserProfile = require('../../models/userProfile'); const bmProjectsController = function () { - - //Get current user's Housing/Building projects + // Get current user's Housing/Building projects const getUserActiveBMProjects = function (req, res) { try { const userId = req.body.requestor.requestorId; @@ -13,23 +12,20 @@ const bmProjectsController = function () { path: 'projects', select: '_id projectName category isActive', match: { category: 'Housing' }, - } + }, ]) .select({ - projects: 1 + projects: 1, }) .then((results) => { res.status(200).send(results); }) .catch(error => res.status(500).send(error)); - } - - catch (err) { + } catch (err) { res.json(err); } - }; return { getUserActiveBMProjects }; -} +}; -module.exports = bmProjectsController; \ No newline at end of file +module.exports = bmProjectsController; diff --git a/src/controllers/dashBoardController.js b/src/controllers/dashBoardController.js index c9cdbd588..c7f9c3973 100644 --- a/src/controllers/dashBoardController.js +++ b/src/controllers/dashBoardController.js @@ -1,8 +1,8 @@ -const mongoose = require("mongoose"); -const path = require("path"); -const fs = require("fs/promises"); -const dashboardhelper = require("../helpers/dashboardhelper")(); -const emailSender = require("../utilities/emailSender"); +const path = require('path'); +const fs = require('fs/promises'); +const mongoose = require('mongoose'); +const dashboardhelper = require('../helpers/dashboardhelper')(); +const emailSender = require('../utilities/emailSender'); const dashboardcontroller = function () { const dashboarddata = function (req, res) { @@ -20,13 +20,13 @@ const dashboardcontroller = function () { const laborthismonth = dashboardhelper.laborthismonth( userId, req.params.fromDate, - req.params.toDate + req.params.toDate, ); laborthismonth.then((results) => { if (!results || results.length === 0) { const emptyresult = [ { - projectName: "", + projectName: '', timeSpent_hrs: 0, }, ]; @@ -42,7 +42,7 @@ const dashboardcontroller = function () { const laborthisweek = dashboardhelper.laborthisweek( userId, req.params.fromDate, - req.params.toDate + req.params.toDate, ); laborthisweek.then((results) => { res.send(results).status(200); @@ -63,7 +63,7 @@ const dashboardcontroller = function () { }); } }) - .catch((error) => res.status(400).send(error)); + .catch(error => res.status(400).send(error)); }; const orgData = function (req, res) { @@ -73,7 +73,7 @@ const dashboardcontroller = function () { .then((results) => { res.status(200).send(results[0]); }) - .catch((error) => res.status(400).send(error)); + .catch(error => res.status(400).send(error)); }; const getBugReportEmailBody = function ( @@ -85,7 +85,7 @@ const dashboardcontroller = function () { expected, actual, visual, - severity + severity, ) { const text = `New Bug Report From ${firstName} ${lastName}:

[Feature Name] Bug Title:

@@ -130,32 +130,32 @@ const dashboardcontroller = function () { expected, actual, visual, - severity + severity, ); try { emailSender( - "onecommunityglobal@gmail.com", + 'onecommunityglobal@gmail.com', `Bug Rport from ${firstName} ${lastName}`, emailBody, - email + email, ); - res.status(200).send("Success"); + res.status(200).send('Success'); } catch { - res.status(500).send("Failed"); + res.status(500).send('Failed'); } }; const suggestionData = { suggestion: [ - "Identify and remedy poor client and/or user service experiences", - "Identify bright spots and enhance positive service experiences", - "Make fundamental changes to our programs and/or operations", - "Inform the development of new programs/projects", - "Identify where we are less inclusive or equitable across demographic groups", - "Strengthen relationships with the people we serve", + 'Identify and remedy poor client and/or user service experiences', + 'Identify bright spots and enhance positive service experiences', + 'Make fundamental changes to our programs and/or operations', + 'Inform the development of new programs/projects', + 'Identify where we are less inclusive or equitable across demographic groups', + 'Strengthen relationships with the people we serve', "Understand people's needs and how we can help them achieve their goals", - "Other", + 'Other', ], field: [], }; @@ -164,8 +164,8 @@ const dashboardcontroller = function () { let fieldaaray = []; if (suggestionData.field.length) { fieldaaray = suggestionData.field.map( - (item) => `

${item}

-

${args[3][item]}

` + item => `

${item}

+

${args[3][item]}

`, ); } const text = `New Suggestion: @@ -173,7 +173,7 @@ const dashboardcontroller = function () {

${args[0]}

Suggestion:

${args[1]}

- ${fieldaaray.length > 0 ? fieldaaray : ""} + ${fieldaaray.length > 0 ? fieldaaray : ''}

Wants Feedback:

${args[2]}

Thank you,
@@ -184,22 +184,24 @@ const dashboardcontroller = function () { // send suggestion email const sendMakeSuggestion = async (req, res) => { - const { suggestioncate, suggestion, confirm, ...rest } = req.body; + const { + suggestioncate, suggestion, confirm, ...rest +} = req.body; const emailBody = await getsuggestionEmailBody( suggestioncate, suggestion, confirm, - rest + rest, ); try { emailSender( - "onecommunityglobal@gmail.com", - "A new suggestion", - emailBody + 'onecommunityglobal@gmail.com', + 'A new suggestion', + emailBody, ); - res.status(200).send("Success"); + res.status(200).send('Success'); } catch { - res.status(500).send("Failed"); + res.status(500).send('Failed'); } }; @@ -208,40 +210,40 @@ const dashboardcontroller = function () { if (suggestionData) { res.status(200).send(suggestionData); } else { - res.status(404).send("Suggestion data not found."); + res.status(404).send('Suggestion data not found.'); } } catch (error) { - console.error("Error getting suggestion data:", error); - res.status(500).send("Internal Server Error"); + console.error('Error getting suggestion data:', error); + res.status(500).send('Internal Server Error'); } }; const editSuggestionOption = async (req, res) => { try { if (req.body.suggestion) { - if (req.body.action === "add") { + if (req.body.action === 'add') { suggestionData.suggestion.unshift(req.body.newField); } - if (req.body.action === "delete") { + if (req.body.action === 'delete') { suggestionData.suggestion = suggestionData.suggestion.filter( - (item, index) => index + 1 !== +req.body.newField + (item, index) => index + 1 !== +req.body.newField, ); } } else { - if (req.body.action === "add") { + if (req.body.action === 'add') { suggestionData.field.unshift(req.body.newField); } - if (req.body.action === "delete") { + if (req.body.action === 'delete') { suggestionData.field = suggestionData.field.filter( - (item) => item !== req.body.newField + item => item !== req.body.newField, ); } } - res.status(200).send("success"); + res.status(200).send('success'); } catch (error) { - console.error("Error editing suggestion option:", error); - res.status(500).send("Internal Server Error"); + console.error('Error editing suggestion option:', error); + res.status(500).send('Internal Server Error'); } }; diff --git a/src/controllers/isEmailExistsController.js b/src/controllers/isEmailExistsController.js index 2c41efc33..f6009a3c5 100644 --- a/src/controllers/isEmailExistsController.js +++ b/src/controllers/isEmailExistsController.js @@ -1,25 +1,23 @@ const UserProfile = require('../models/userProfile'); const isEmailExistsController = function () { - const isEmailExists = async function (req, res) { - - try { - const userProfile = await UserProfile.findOne({ email: req.params.email }).lean().exec() + try { + const userProfile = await UserProfile.findOne({ email: req.params.email }).lean().exec(); if (userProfile) { - res.status(200).send(`Email, ${userProfile.email}, found.`) + res.status(200).send(`Email, ${userProfile.email}, found.`); } else { - res.status(403).send(`Email, ${req.params.email}, not found.`) + res.status(403).send(`Email, ${req.params.email}, not found.`); } } catch (err) { - console.log(err) + console.log(err); } - } + }; return { - isEmailExists - } -} + isEmailExists, + }; +}; -module.exports = isEmailExistsController +module.exports = isEmailExistsController; diff --git a/src/controllers/profileInitialSetupController.js b/src/controllers/profileInitialSetupController.js index 18cf7376c..6914cf48a 100644 --- a/src/controllers/profileInitialSetupController.js +++ b/src/controllers/profileInitialSetupController.js @@ -1,9 +1,9 @@ -const mongoose = require("mongoose"); -const { v4: uuidv4 } = require("uuid"); -const moment = require("moment-timezone"); -const jwt = require("jsonwebtoken"); -const emailSender = require("../utilities/emailSender"); -const config = require("../config"); +const mongoose = require('mongoose'); +const { v4: uuidv4 } = require('uuid'); +const moment = require('moment-timezone'); +const jwt = require('jsonwebtoken'); +const emailSender = require('../utilities/emailSender'); +const config = require('../config'); const cache = require('../utilities/nodeCache')(); // returns the email body that includes the setup link for the recipient. @@ -79,7 +79,7 @@ function informManagerMessage(user) { const profileInitialSetupController = function ( ProfileInitialSetupToken, userProfile, - Project + Project, ) { const { JWT_SECRET } = config; @@ -91,16 +91,16 @@ const profileInitialSetupController = function ( - Generates a link using the token and emails it to the recipient. */ const getSetupToken = async (req, res) => { - let { email, baseUrl,weeklyCommittedHours } = req.body; + let { email, baseUrl, weeklyCommittedHours } = req.body; email = email.toLowerCase(); const token = uuidv4(); - const expiration = moment().tz("America/Los_Angeles").add(1, "week"); + const expiration = moment().tz('America/Los_Angeles').add(1, 'week'); try { const existingEmail = await userProfile.findOne({ - email: email, + email, }); if (existingEmail) { - res.status(400).send("email already in use"); + res.status(400).send('email already in use'); } else { await ProfileInitialSetupToken.findOneAndDelete({ email }); @@ -116,10 +116,10 @@ const profileInitialSetupController = function ( emailSender( email, - "NEEDED: Complete your One Community profile setup", + 'NEEDED: Complete your One Community profile setup', sendLinkMessage(link), null, - null + null, ); res.status(200).send(link); @@ -136,7 +136,7 @@ const profileInitialSetupController = function ( */ const validateSetupToken = async (req, res) => { const { token } = req.body; - const currentMoment = moment.tz("America/Los_Angeles"); + const currentMoment = moment.tz('America/Los_Angeles'); try { const foundToken = await ProfileInitialSetupToken.findOne({ token }); @@ -146,10 +146,10 @@ const profileInitialSetupController = function ( if (expirationMoment.isAfter(currentMoment)) { res.status(200).send(foundToken); } else { - res.status(400).send("Invalid token"); + res.status(400).send('Invalid token'); } } else { - res.status(404).send("Token not found"); + res.status(404).send('Token not found'); } } catch (error) { res.status(500).send(`Error finding token: ${error}`); @@ -167,31 +167,30 @@ const profileInitialSetupController = function ( */ const setUpNewUser = async (req, res) => { const { token } = req.body; - const currentMoment = moment.tz("America/Los_Angeles"); + const currentMoment = moment.tz('America/Los_Angeles'); try { const foundToken = await ProfileInitialSetupToken.findOne({ token }); const existingEmail = await userProfile.findOne({ email: foundToken.email, }); if (existingEmail) { - res.status(400).send("email already in use"); - } else { - if (foundToken) { + res.status(400).send('email already in use'); + } else if (foundToken) { const expirationMoment = moment(foundToken.expiration); if (expirationMoment.isAfter(currentMoment)) { const defaultProject = await Project.findOne({ - projectName: "Orientation and Initial Setup", + projectName: 'Orientation and Initial Setup', }); const newUser = new userProfile(); newUser.password = req.body.password; - newUser.role = "Volunteer"; + newUser.role = 'Volunteer'; newUser.firstName = req.body.firstName; newUser.lastName = req.body.lastName; newUser.jobTitle = req.body.jobTitle; newUser.phoneNumber = req.body.phoneNumber; - newUser.bio = ""; + newUser.bio = ''; newUser.weeklycommittedHours = foundToken.weeklyCommittedHours; newUser.weeklycommittedHoursHistory = [ { @@ -205,32 +204,31 @@ const profileInitialSetupController = function ( newUser.projects = Array.from(new Set([defaultProject])); newUser.createdDate = Date.now(); newUser.email = req.body.email; - newUser.weeklySummaries = [{ summary: "" }]; + newUser.weeklySummaries = [{ summary: '' }]; newUser.weeklySummariesCount = 0; - newUser.weeklySummaryOption = "Required"; - newUser.mediaUrl = ""; + newUser.weeklySummaryOption = 'Required'; + newUser.mediaUrl = ''; newUser.collaborationPreference = req.body.collaborationPreference; - newUser.timeZone = req.body.timeZone || "America/Los_Angeles"; + newUser.timeZone = req.body.timeZone || 'America/Los_Angeles'; newUser.location = req.body.location; newUser.permissions = { frontPermissions: [], - backPermissions: [] - } - newUser.bioPosted = "default"; + backPermissions: [], + }; + newUser.bioPosted = 'default'; newUser.privacySettings.email = req.body.privacySettings.email; - newUser.privacySettings.phoneNumber = - req.body.privacySettings.phoneNumber; - newUser.teamCode = ""; + newUser.privacySettings.phoneNumber = req.body.privacySettings.phoneNumber; + newUser.teamCode = ''; newUser.isFirstTimelog = true; const savedUser = await newUser.save(); emailSender( - process.env.MANAGER_EMAIL || "jae@onecommunityglobal.org", // "jae@onecommunityglobal.org" + process.env.MANAGER_EMAIL || 'jae@onecommunityglobal.org', // "jae@onecommunityglobal.org" `NEW USER REGISTERED: ${savedUser.firstName} ${savedUser.lastName}`, informManagerMessage(savedUser), null, - null + null, ); await ProfileInitialSetupToken.findByIdAndDelete(foundToken._id); @@ -240,14 +238,14 @@ const profileInitialSetupController = function ( permissions: savedUser.permissions, expiryTimestamp: moment().add( config.TOKEN.Lifetime, - config.TOKEN.Units + config.TOKEN.Units, ), }; const token = jwt.sign(jwtPayload, JWT_SECRET); res.send({ token }).status(200); - + const NewUserCache = { permissions: savedUser.permissions, isActive: true, @@ -260,18 +258,15 @@ const profileInitialSetupController = function ( email: savedUser.email, }; - const allUserCache = JSON.parse(cache.getCache("allusers")); + const allUserCache = JSON.parse(cache.getCache('allusers')); allUserCache.push(NewUserCache); - cache.setCache("allusers", JSON.stringify(allUserCache)); - - + cache.setCache('allusers', JSON.stringify(allUserCache)); } else { - res.status(400).send("Token is expired"); + res.status(400).send('Token is expired'); } } else { - res.status(400).send("Invalid token"); + res.status(400).send('Invalid token'); } - } } catch (error) { res.status(500).send(`Error: ${error}`); } @@ -283,17 +278,15 @@ const profileInitialSetupController = function ( - sends the API Key as response */ const getTimeZoneAPIKeyByToken = async (req, res) => { - const token = req.body.token; + const { token } = req.body; const premiumKey = process.env.TIMEZONE_PREMIUM_KEY; const foundToken = await ProfileInitialSetupToken.findOne({ token }); if (foundToken) { res.status(200).send({ userAPIKey: premiumKey }); - return; } else { - res.status(403).send("Unauthorized Request"); - return; + res.status(403).send('Unauthorized Request'); } }; diff --git a/src/controllers/teamController.js b/src/controllers/teamController.js index c82b9e5ce..756f386d5 100644 --- a/src/controllers/teamController.js +++ b/src/controllers/teamController.js @@ -115,7 +115,7 @@ const teamcontroller = function (Team) { users.forEach((element) => { const { userId, operation } = element; // if user's profile is stored in cache, clear it so when you visit their profile page it will be up to date - if(cache.hasCache(`user-${userId}`)) cache.removeCache(`user-${userId}`); + if (cache.hasCache(`user-${userId}`)) cache.removeCache(`user-${userId}`); if (operation === 'Assign') { assignlist.push(userId); diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 6dc571b39..aed8f1788 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -59,27 +59,25 @@ const userProfileController = function (UserProfile) { 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; - }else{ - res.status(500).send({ error: "User result was invalid" }); - return; } + 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)); - + .catch(error => res.status(404).send(error)); }; const getProjectMembers = async function (req, res) { @@ -93,14 +91,14 @@ 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); - } + }, ); }; @@ -118,15 +116,15 @@ const userProfileController = function (UserProfile) { 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; } @@ -145,8 +143,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; } @@ -160,8 +158,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; } @@ -188,15 +186,15 @@ 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.save() @@ -218,11 +216,11 @@ 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)); }) - .catch((error) => res.status(501).send(error)); + .catch(error => res.status(501).send(error)); }; const putUserProfile = async function (req, res) { @@ -233,12 +231,12 @@ const userProfileController = function (UserProfile) { || req.body.requestor.requestorId === userid ) ); - - const canEditTeamCode = req.body.requestor.role === "Owner" || - req.body.requestor.permissions?.frontPermissions.includes("editTeamCode"); + + const canEditTeamCode = req.body.requestor.role === 'Owner' + || req.body.requestor.permissions?.frontPermissions.includes('editTeamCode'); 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; } @@ -250,7 +248,7 @@ const userProfileController = function (UserProfile) { 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 @@ -269,8 +267,7 @@ const userProfileController = function (UserProfile) { : []; record.jobTitle = req.body.jobTitle; record.emailPubliclyAccessible = req.body.emailPubliclyAccessible; - record.phoneNumberPubliclyAccessible = - req.body.phoneNumberPubliclyAccessible; + record.phoneNumberPubliclyAccessible = req.body.phoneNumberPubliclyAccessible; record.profilePic = req.body.profilePic; record.firstName = req.body.firstName; @@ -292,24 +289,24 @@ const userProfileController = function (UserProfile) { record.isVisible = req.body.isVisible || false; record.isRehireable = req.body.isRehireable || false; record.totalIntangibleHrs = req.body.totalIntangibleHrs; - record.bioPosted = req.body.bioPosted || "default"; + record.bioPosted = req.body.bioPosted || 'default'; record.isFirstTimelog = req.body.isFirstTimelog; - if(!canEditTeamCode && record.teamCode !== req.body.teamCode){ - res.status(403).send("You are not authorized to edit team code."); + if (!canEditTeamCode && record.teamCode !== req.body.teamCode) { + res.status(403).send('You are not authorized to edit team code.'); return; } record.teamCode = req.body.teamCode; // 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")); - userIdx = allUserData.findIndex((users) => users._id === userid); + allUserData = JSON.parse(cache.getCache('allusers')); + userIdx = allUserData.findIndex(users => users._id === userid); userData = allUserData[userIdx]; } if (await hasPermission(req.body.requestor, 'putUserProfileImportantInfo')) { @@ -324,11 +321,11 @@ const userProfileController = function (UserProfile) { // If their last update was made today, remove that const lasti = record.weeklycommittedHoursHistory.length - 1; const lastChangeDate = moment( - record.weeklycommittedHoursHistory[lasti].dateChanged + record.weeklycommittedHoursHistory[lasti].dateChanged, ); const now = moment(); - if (lastChangeDate.isSame(now, "day")) { + if (lastChangeDate.isSame(now, 'day')) { record.weeklycommittedHoursHistory.pop(); } @@ -341,8 +338,7 @@ const userProfileController = function (UserProfile) { record.weeklycommittedHoursHistory.push(newEntry); } - record.missedHours = - req.body.role === "Core Team" ? req.body?.missedHours ?? 0 : 0; + record.missedHours = req.body.role === 'Core Team' ? req.body?.missedHours ?? 0 : 0; record.adminLinks = req.body.adminLinks; record.teams = Array.from(new Set(req.body.teams)); record.projects = Array.from(new Set(req.body.projects)); @@ -374,8 +370,7 @@ 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; } record.bioPosted = req.body.bioPosted || 'default'; @@ -390,7 +385,7 @@ const userProfileController = function (UserProfile) { userData.endDate = record.endDate.toISOString(); } } else { - record.set("endDate", undefined, { strict: false }); + record.set('endDate', undefined, { strict: false }); } if (isUserInCache) { userData.role = record.role; @@ -412,7 +407,7 @@ const userProfileController = function (UserProfile) { results.infringements, results.firstName, results.lastName, - results.email + results.email, ); res.status(200).json({ _id: record._id, @@ -421,10 +416,10 @@ 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)); + .catch(error => res.status(400).send(error)); }); }; @@ -569,15 +564,14 @@ 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.permissions?.frontPermissions.includes("editTeamCode"); + if (key === 'teamCode') { + const canEditTeamCode = req.body.requestor.role === 'Owner' + || req.body.requestor.permissions?.frontPermissions.includes('editTeamCode'); - if(!canEditTeamCode){ - res.status(403).send("You are not authorized to edit team code."); + if (!canEditTeamCode) { + res.status(403).send('You are not authorized to edit team code.'); return; } - } // remove user from cache, it should be loaded next time diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index 34d464583..fe2007281 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -192,7 +192,7 @@ const dashboardhelper = function () { // leaderboard user roles hierarchy $or: [ { - role: { $in: ['Owner', 'Core Team'] }, + role: { $in: ['Owner', 'Core Team'] }, }, { $and: [ @@ -200,7 +200,7 @@ const dashboardhelper = function () { role: 'Administrator', }, { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, - ] + ], }, { $and: [ diff --git a/src/helpers/reporthelper.js b/src/helpers/reporthelper.js index 0c2a8104d..3826aa8ed 100644 --- a/src/helpers/reporthelper.js +++ b/src/helpers/reporthelper.js @@ -1,5 +1,5 @@ -const moment = require("moment-timezone"); -const userProfile = require("../models/userProfile"); +const moment = require('moment-timezone'); +const userProfile = require('../models/userProfile'); /** * @@ -8,9 +8,9 @@ const userProfile = require("../models/userProfile"); * @returns The absolute value of the difference in weeks between the two input dates. */ const absoluteDifferenceInWeeks = (dateOfWork, pstEnd) => { - dateOfWork = moment(dateOfWork).endOf("week"); - pstEnd = moment(pstEnd).tz("America/Los_Angeles").endOf("week"); - return Math.abs(dateOfWork.diff(pstEnd, "weeks")); + dateOfWork = moment(dateOfWork).endOf('week'); + pstEnd = moment(pstEnd).tz('America/Los_Angeles').endOf('week'); + return Math.abs(dateOfWork.diff(pstEnd, 'weeks')); }; const reporthelper = function () { @@ -23,14 +23,14 @@ const reporthelper = function () { */ const weeklySummaries = async (startWeekIndex, endWeekIndex) => { const pstStart = moment() - .tz("America/Los_Angeles") - .startOf("week") - .subtract(startWeekIndex, "week") + .tz('America/Los_Angeles') + .startOf('week') + .subtract(startWeekIndex, 'week') .toDate(); const pstEnd = moment() - .tz("America/Los_Angeles") - .endOf("week") - .subtract(endWeekIndex, "week") + .tz('America/Los_Angeles') + .endOf('week') + .subtract(endWeekIndex, 'week') .toDate(); const results = await userProfile.aggregate([ @@ -39,33 +39,33 @@ const reporthelper = function () { }, { $lookup: { - from: "timeEntries", - localField: "_id", - foreignField: "personId", - as: "timeEntries", + from: 'timeEntries', + localField: '_id', + foreignField: 'personId', + as: 'timeEntries', }, }, { - $set: { totalTangibleHrs: { $objectToArray: "$hoursByCategory" } }, + $set: { totalTangibleHrs: { $objectToArray: '$hoursByCategory' } }, }, { $project: { timeEntries: { $filter: { - input: "$timeEntries", - as: "timeEntry", + input: '$timeEntries', + as: 'timeEntry', cond: { $and: [ { $gte: [ - "$$timeEntry.dateOfWork", - moment(pstStart).format("YYYY-MM-DD"), + '$$timeEntry.dateOfWork', + moment(pstStart).format('YYYY-MM-DD'), ], }, { $lte: [ - "$$timeEntry.dateOfWork", - moment(pstEnd).format("YYYY-MM-DD"), + '$$timeEntry.dateOfWork', + moment(pstEnd).format('YYYY-MM-DD'), ], }, ], @@ -86,22 +86,22 @@ const reporthelper = function () { bioPosted: 1, badgeCollection: { $filter: { - input: "$badgeCollection", - as: "badge", + input: '$badgeCollection', + as: 'badge', cond: { $or: [ { $and: [ { $gte: [ - "$$badge.earnedDate", - moment(pstStart).format("YYYY-MM-DD"), + '$$badge.earnedDate', + moment(pstStart).format('YYYY-MM-DD'), ], }, { $lte: [ - "$$badge.earnedDate", - moment(pstEnd).format("YYYY-MM-DD"), + '$$badge.earnedDate', + moment(pstEnd).format('YYYY-MM-DD'), ], }, ], @@ -109,10 +109,10 @@ const reporthelper = function () { { $and: [ { - $gte: ["$$badge.lastModified", pstStart], + $gte: ['$$badge.lastModified', pstStart], }, { - $lte: ["$$badge.lastModified", pstEnd], + $lte: ['$$badge.lastModified', pstEnd], }, ], }, @@ -126,15 +126,15 @@ const reporthelper = function () { role: 1, weeklySummaries: { $filter: { - input: "$weeklySummaries", - as: "ws", + input: '$weeklySummaries', + as: 'ws', cond: { $and: [ { - $gte: ["$$ws.dueDate", pstStart], + $gte: ['$$ws.dueDate', pstStart], }, { - $lte: ["$$ws.dueDate", pstEnd], + $lte: ['$$ws.dueDate', pstEnd], }, ], }, @@ -142,13 +142,13 @@ const reporthelper = function () { }, weeklySummariesCount: 1, isTangible: 1, - totalTangibleHrs: { $sum: "$totalTangibleHrs.v" }, + totalTangibleHrs: { $sum: '$totalTangibleHrs.v' }, daysInTeam: { $dateDiff: { - startDate: "$createdDate", + startDate: '$createdDate', endDate: new Date(), - unit: "day", - timezone: "America/Los_Angeles", + unit: 'day', + timezone: 'America/Los_Angeles', }, }, }, @@ -162,8 +162,8 @@ const reporthelper = function () { result.timeEntries.forEach((entry) => { const index = absoluteDifferenceInWeeks(entry.dateOfWork, pstEnd); if ( - result.totalSeconds[index] === undefined || - result.totalSeconds[index] === null + result.totalSeconds[index] === undefined + || result.totalSeconds[index] === null ) { result.totalSeconds[index] = 0; } @@ -189,16 +189,16 @@ const reporthelper = function () { */ const doesDateBelongToWeek = function (dueDate, weekIndex) { const pstStartOfWeek = moment() - .tz("America/Los_Angeles") - .startOf("week") - .subtract(weekIndex, "week"); + .tz('America/Los_Angeles') + .startOf('week') + .subtract(weekIndex, 'week'); const pstEndOfWeek = moment() - .tz("America/Los_Angeles") - .endOf("week") - .subtract(weekIndex, "week"); + .tz('America/Los_Angeles') + .endOf('week') + .subtract(weekIndex, 'week'); const fromDate = moment(pstStartOfWeek).toDate(); const toDate = moment(pstEndOfWeek).toDate(); - return moment(dueDate).isBetween(fromDate, toDate, undefined, "[]"); + return moment(dueDate).isBetween(fromDate, toDate, undefined, '[]'); }; /** diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index a94aaee94..f59dedcbc 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -43,7 +43,7 @@ const taskHelper = function () { // dashboard tasks user roles hierarchy $or: [ { - role: { $in: ['Owner', 'Core Team'] }, + role: { $in: ['Owner', 'Core Team'] }, }, { $and: [ @@ -51,7 +51,7 @@ const taskHelper = function () { role: 'Administrator', }, { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, - ] + ], }, { $and: [ diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index af416f1a7..a1fd6265a 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -1,28 +1,28 @@ /* eslint-disable no-continue */ /* eslint-disable no-await-in-loop */ -const mongoose = require("mongoose"); -const moment = require("moment-timezone"); -const _ = require("lodash"); -const userProfile = require("../models/userProfile"); -const timeEntries = require("../models/timeentry"); -const badge = require("../models/badge"); -const myTeam = require("./helperModels/myTeam"); -const dashboardHelper = require("./dashboardhelper")(); -const reportHelper = require("./reporthelper")(); -const emailSender = require("../utilities/emailSender"); -const logger = require("../startup/logger"); -const hasPermission = require("../utilities/permissions"); -const Reason = require("../models/reason"); -const token = require("../models/profileInitialSetupToken") +const mongoose = require('mongoose'); +const moment = require('moment-timezone'); +const _ = require('lodash'); +const userProfile = require('../models/userProfile'); +const timeEntries = require('../models/timeentry'); +const badge = require('../models/badge'); +const myTeam = require('./helperModels/myTeam'); +const dashboardHelper = require('./dashboardhelper')(); +const reportHelper = require('./reporthelper')(); +const emailSender = require('../utilities/emailSender'); +const logger = require('../startup/logger'); +const hasPermission = require('../utilities/permissions'); +const Reason = require('../models/reason'); +const token = require('../models/profileInitialSetupToken'); const userHelper = function () { const getTeamMembers = function (user) { const userId = mongoose.Types.ObjectId(user._id); // var teamid = userdetails.teamId; return myTeam.findById(userId).select({ - "myTeam._id": 0, - "myTeam.role": 0, - "myTeam.fullName": 0, + 'myTeam._id': 0, + 'myTeam.role': 0, + 'myTeam.fullName': 0, _id: 0, }); }; @@ -46,40 +46,39 @@ const userHelper = function () { const getUserName = async function (userId) { const userid = mongoose.Types.ObjectId(userId); - return userProfile.findById(userid, "firstName lastName"); + return userProfile.findById(userid, 'firstName lastName'); }; const validateProfilePic = function (profilePic) { - const picParts = profilePic.split("base64"); + const picParts = profilePic.split('base64'); let result = true; const errors = []; if (picParts.length < 2) { return { result: false, - errors: "Invalid image" + errors: 'Invalid image', }; } // validate size const imageSize = picParts[1].length; - const sizeInBytes = - (4 * Math.ceil(imageSize / 3) * 0.5624896334383812) / 1024; + const sizeInBytes = (4 * Math.ceil(imageSize / 3) * 0.5624896334383812) / 1024; if (sizeInBytes > 50) { - errors.push("Image size should not exceed 50KB"); + errors.push('Image size should not exceed 50KB'); result = false; } - const imageType = picParts[0].split("/")[1]; - if (imageType !== "jpeg;" && imageType !== "png;") { - errors.push("Image type shoud be either jpeg or png."); + const imageType = picParts[0].split('/')[1]; + if (imageType !== 'jpeg;' && imageType !== 'png;') { + errors.push('Image type shoud be either jpeg or png.'); result = false; } return { result, - errors + errors, }; }; @@ -87,7 +86,7 @@ const userHelper = function () { firstName, lastName, infringement, - totalInfringements + totalInfringements, ) { const text = `Dear ${firstName} ${lastName},

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

@@ -114,11 +113,11 @@ const userHelper = function () { */ const emailWeeklySummariesForAllUsers = async (weekIndex = 1) => { const currentFormattedDate = moment() - .tz("America/Los_Angeles") + .tz('America/Los_Angeles') .format(); logger.logInfo( - `Job for emailing all users' weekly summaries starting at ${currentFormattedDate}` + `Job for emailing all users' weekly summaries starting at ${currentFormattedDate}`, ); const emails = []; @@ -126,13 +125,11 @@ const userHelper = function () { try { const results = await reportHelper.weeklySummaries(weekIndex, weekIndex); - let emailBody = "

Weekly Summaries for all active users:

"; + let emailBody = '

Weekly Summaries for all active users:

'; - const weeklySummaryNotProvidedMessage = - '
Weekly Summary: Not provided!
'; + const weeklySummaryNotProvidedMessage = '
Weekly Summary: Not provided!
'; - const weeklySummaryNotRequiredMessage = - '
Weekly Summary: Not required for this user
'; + const weeklySummaryNotRequiredMessage = '
Weekly Summary: Not required for this user
'; results.sort((a, b) => `${a.firstName} ${a.lastName}`.localeCompare(`${b.firstName} ${b.lastname}`)); @@ -146,7 +143,7 @@ const userHelper = function () { mediaUrl, weeklySummariesCount, weeklycommittedHours, - weeklySummaryOption + weeklySummaryOption, } = result; if (email !== undefined && email !== null) { @@ -163,14 +160,14 @@ const userHelper = function () { let weeklySummaryMessage = weeklySummaryNotProvidedMessage; const colorStyle = (() => { switch (weeklySummaryOption) { - case "Team": + case 'Team': return 'style="color: magenta;"'; - case "Not Required": + case 'Not Required': return 'style="color: green"'; - case "Required": - return ""; + case 'Required': + return ''; default: - return result.weeklySummaryNotReq ? 'style="color: green"' : ""; + return result.weeklySummaryNotReq ? 'style="color: green"' : ''; } })(); // weeklySummaries array should only have one item if any, hence weeklySummaries[0] needs be used to access it. @@ -181,8 +178,8 @@ const userHelper = function () {
Weekly Summary (for the week ending on ${moment(dueDate) - .tz("America/Los_Angeles") - .format("YYYY-MMM-DD")}): + .tz('America/Los_Angeles') + .format('YYYY-MMM-DD')}):
${summary} @@ -207,15 +204,15 @@ const userHelper = function () {

${weeklySummariesCount === 8 ? `

Total Valid Weekly Summaries: ${weeklySummariesCount}

` - : `

Total Valid Weekly Summaries: ${weeklySummariesCount || - "No valid submissions yet!"}

` + : `

Total Valid Weekly Summaries: ${weeklySummariesCount + || 'No valid submissions yet!'}

` } ${hoursLogged >= weeklycommittedHours ? `

Hours logged: ${hoursLogged.toFixed(2)} / ${weeklycommittedHours}

` : `

Hours logged: ${hoursLogged.toFixed( - 2 + 2, )} / ${weeklycommittedHours}

` } ${weeklySummaryMessage} @@ -225,10 +222,8 @@ const userHelper = function () { // Necessary because our version of node is outdated // and doesn't have String.prototype.replaceAll let emailString = [...new Set(emails)].toString(); - while (emailString.includes(",")) - emailString = emailString.replace(",", "\n"); - while (emailString.includes("\n")) - emailString = emailString.replace("\n", ", "); + while (emailString.includes(',')) emailString = emailString.replace(',', '\n'); + while (emailString.includes('\n')) emailString = emailString.replace('\n', ', '); emailBody += `\n
@@ -240,10 +235,10 @@ const userHelper = function () { `; emailSender( - "onecommunityglobal@gmail.com, sangam.pravah@gmail.com, onecommunityhospitality@gmail.com", - "Weekly Summaries for all active users...", + 'onecommunityglobal@gmail.com, sangam.pravah@gmail.com, onecommunityhospitality@gmail.com', + 'Weekly Summaries for all active users...', emailBody, - null + null, ); } catch (err) { logger.logException(err); @@ -265,15 +260,15 @@ const userHelper = function () { $each: [ { dueDate: moment() - .tz("America/Los_Angeles") - .endOf("week"), - summary: "" - } + .tz('America/Los_Angeles') + .endOf('week'), + summary: '', + }, ], $position: 0, - $slice: 4 - } - } + $slice: 4, + }, + }, }) .catch(error => logger.logException(error)); }; @@ -287,11 +282,11 @@ const userHelper = function () { const assignBlueSquareForTimeNotMet = async () => { try { const currentFormattedDate = moment() - .tz("America/Los_Angeles") + .tz('America/Los_Angeles') .format(); const currentUTCDate = moment - .tz("America/Los_Angeles") - .startOf("day") + .tz('America/Los_Angeles') + .startOf('day') .toISOString(); logger.logInfo( @@ -301,24 +296,24 @@ const userHelper = function () { ); const pdtStartOfLastWeek = moment() - .tz("America/Los_Angeles") - .startOf("week") - .subtract(1, "week"); + .tz('America/Los_Angeles') + .startOf('week') + .subtract(1, 'week'); const pdtEndOfLastWeek = moment() - .tz("America/Los_Angeles") - .endOf("week") - .subtract(1, "week"); + .tz('America/Los_Angeles') + .endOf('week') + .subtract(1, 'week'); const users = await userProfile.find( { isActive: true }, - "_id weeklycommittedHours weeklySummaries missedHours" + '_id weeklycommittedHours weeklySummaries missedHours', ); - //this part is supposed to be a for, so it'll be slower when sending emails, so the emails will not be - //targeted as spam - //There's no need to put Promise.all here + // this part is supposed to be a for, so it'll be slower when sending emails, so the emails will not be + // targeted as spam + // There's no need to put Promise.all here for (let i = 0; i < users.length; i += 1) { const user = users[i]; @@ -345,13 +340,12 @@ const userHelper = function () { const results = await dashboardHelper.laborthisweek( personId, pdtStartOfLastWeek, - pdtEndOfLastWeek + pdtEndOfLastWeek, ); const { timeSpent_hrs: timeSpent } = results[0]; - const weeklycommittedHours = - user.weeklycommittedHours + (user.missedHours ?? 0); + const weeklycommittedHours = user.weeklycommittedHours + (user.missedHours ?? 0); const timeNotMet = timeSpent < weeklycommittedHours; let description; @@ -360,19 +354,19 @@ const userHelper = function () { personId, { $inc: { - totalTangibleHrs: timeSpent || 0 + totalTangibleHrs: timeSpent || 0, }, $max: { - personalBestMaxHrs: timeSpent || 0 + personalBestMaxHrs: timeSpent || 0, }, $push: { - savedTangibleHrs: { $each: [timeSpent || 0], $slice: -200 } + savedTangibleHrs: { $each: [timeSpent || 0], $slice: -200 }, }, $set: { - lastWeekTangibleHrs: timeSpent || 0 - } + lastWeekTangibleHrs: timeSpent || 0, + }, }, - { new: true } + { new: true }, ); if ( @@ -384,13 +378,13 @@ const userHelper = function () { hasWeeklySummary = true; } - const cutOffDate = moment().subtract(1, "year"); + const cutOffDate = moment().subtract(1, 'year'); const oldInfringements = []; for (let k = 0; k < updateResult?.infringements.length; k += 1) { if ( - updateResult?.infringements && - moment(updateResult?.infringements[k].date).diff(cutOffDate) >= 0 + updateResult?.infringements + && moment(updateResult?.infringements[k].date).diff(cutOffDate) >= 0 ) { oldInfringements.push(updateResult.infringements[k]); } else { @@ -403,72 +397,70 @@ const userHelper = function () { personId, { $push: { - oldInfringements: { $each: oldInfringements, $slice: -10 } - } + oldInfringements: { $each: oldInfringements, $slice: -10 }, + }, }, - { new: true } + { new: true }, ); } if (timeNotMet || !hasWeeklySummary) { if (foundReason) { description = foundReason.reason; - } else { - if (timeNotMet && !hasWeeklySummary) { + } else if (timeNotMet && !hasWeeklySummary) { description = `System auto-assigned infringement for two reasons: not meeting weekly volunteer time commitment as well as not submitting a weekly summary. For the hours portion, you logged ${timeSpent.toFixed(2)} hours against committed effort of ${weeklycommittedHours} hours in the week starting ${pdtStartOfLastWeek.format( - "dddd YYYY-MM-DD" - )} and ending ${pdtEndOfLastWeek.format("dddd YYYY-MM-DD")}.`; + 'dddd YYYY-MM-DD', + )} and ending ${pdtEndOfLastWeek.format('dddd YYYY-MM-DD')}.`; } else if (timeNotMet) { description = `System auto-assigned infringement for not meeting weekly volunteer time commitment. You logged ${timeSpent.toFixed(2)} hours against committed effort of ${weeklycommittedHours} hours in the week starting ${pdtStartOfLastWeek.format( - "dddd YYYY-MM-DD" - )} and ending ${pdtEndOfLastWeek.format("dddd YYYY-MM-DD")}.`; + 'dddd YYYY-MM-DD', + )} and ending ${pdtEndOfLastWeek.format('dddd YYYY-MM-DD')}.`; } else { description = `System auto-assigned infringement for not submitting a weekly summary for the week starting ${pdtStartOfLastWeek.format( - "dddd YYYY-MM-DD" - )} and ending ${pdtEndOfLastWeek.format("dddd YYYY-MM-DD")}.`; + 'dddd YYYY-MM-DD', + )} and ending ${pdtEndOfLastWeek.format('dddd YYYY-MM-DD')}.`; } - } const infringement = { date: moment() .utc() - .format("YYYY-MM-DD"), - description + .format('YYYY-MM-DD'), + description, }; const status = await userProfile.findByIdAndUpdate( personId, { $push: { - infringements: infringement - } + infringements: infringement, + }, }, - { new: true } + { new: true }, ); emailSender( status.email, - "New Infringement Assigned", + 'New Infringement Assigned', getInfringementEmailBody( status.firstName, status.lastName, infringement, - status.infringements.length + status.infringements.length, ), null, - "onecommunityglobal@gmail.com" + 'onecommunityglobal@gmail.com', ); const categories = await dashboardHelper.laborThisWeekByCategory( personId, pdtStartOfLastWeek, - pdtEndOfLastWeek + pdtEndOfLastWeek, ); if (Array.isArray(categories) && categories.length > 0) { await userProfile.findOneAndUpdate( { _id: personId, categoryTangibleHrs: { $exists: false } }, - { $set: { categoryTangibleHrs: [] } } + { $set: { categoryTangibleHrs: [] } }, ); } else { continue; @@ -478,29 +470,29 @@ const userHelper = function () { const elem = categories[j]; if (elem._id == null) { - elem._id = "Other"; + elem._id = 'Other'; } const updateResult2 = await userProfile.findOneAndUpdate( - { _id: personId, "categoryTangibleHrs.category": elem._id }, - { $inc: { "categoryTangibleHrs.$.hrs": elem.timeSpent_hrs } }, - { new: true } + { _id: personId, 'categoryTangibleHrs.category': elem._id }, + { $inc: { 'categoryTangibleHrs.$.hrs': elem.timeSpent_hrs } }, + { new: true }, ); if (!updateResult2) { await userProfile.findOneAndUpdate( { _id: personId, - "categoryTangibleHrs.category": { $ne: elem._id } + 'categoryTangibleHrs.category': { $ne: elem._id }, }, { $addToSet: { categoryTangibleHrs: { category: elem._id, - hrs: elem.timeSpent_hrs - } - } - } + hrs: elem.timeSpent_hrs, + }, + }, + }, ); } } @@ -512,12 +504,11 @@ const userHelper = function () { // processWeeklySummaries for nonActive users try { - const inactiveUsers = await userProfile.find({ isActive: false }, "_id"); + const inactiveUsers = await userProfile.find({ isActive: false }, '_id'); for (let i = 0; i < inactiveUsers.length; i += 1) { const user = inactiveUsers[i]; await processWeeklySummariesByUserId(mongoose.Types.ObjectId(user._id), false); - } } catch (err) { logger.logException(err); @@ -527,52 +518,52 @@ const userHelper = function () { const applyMissedHourForCoreTeam = async () => { try { const currentDate = moment() - .tz("America/Los_Angeles") + .tz('America/Los_Angeles') .format(); logger.logInfo( - `Job for applying missed hours for Core Team members starting at ${currentDate}` + `Job for applying missed hours for Core Team members starting at ${currentDate}`, ); const startOfLastWeek = moment() - .tz("America/Los_Angeles") - .startOf("week") - .subtract(1, "week") - .format("YYYY-MM-DD"); + .tz('America/Los_Angeles') + .startOf('week') + .subtract(1, 'week') + .format('YYYY-MM-DD'); const endOfLastWeek = moment() - .tz("America/Los_Angeles") - .endOf("week") - .subtract(1, "week") - .format("YYYY-MM-DD"); + .tz('America/Los_Angeles') + .endOf('week') + .subtract(1, 'week') + .format('YYYY-MM-DD'); const missedHours = await userProfile.aggregate([ { $match: { - role: "Core Team", - isActive: true - } + role: 'Core Team', + isActive: true, + }, }, { $lookup: { - from: "timeEntries", - localField: "_id", - foreignField: "personId", + from: 'timeEntries', + localField: '_id', + foreignField: 'personId', pipeline: [ { $match: { $expr: { $and: [ - { $eq: ["$isTangible", true] }, - { $gte: ["$dateOfWork", startOfLastWeek] }, - { $lte: ["$dateOfWork", endOfLastWeek] } - ] - } - } - } + { $eq: ['$isTangible', true] }, + { $gte: ['$dateOfWork', startOfLastWeek] }, + { $lte: ['$dateOfWork', endOfLastWeek] }, + ], + }, + }, + }, ], - as: "timeEntries" - } + as: 'timeEntries', + }, }, { $project: { @@ -591,31 +582,31 @@ const userHelper = function () { { $sum: { $map: { - input: "$timeEntries", - in: "$$this.totalSeconds" - } - } + input: '$timeEntries', + in: '$$this.totalSeconds', + }, + }, }, - 3600 - ] - } - ] + 3600, + ], + }, + ], }, - 0 - ] - } - } - } + 0, + ], + }, + }, + }, ]); const bulkOps = []; - missedHours.forEach(obj => { + missedHours.forEach((obj) => { bulkOps.push({ updateOne: { filter: { _id: obj._id }, - update: { missedHours: obj.missedHours } - } + update: { missedHours: obj.missedHours }, + }, }); }); @@ -627,16 +618,16 @@ const userHelper = function () { const deleteBlueSquareAfterYear = async () => { const currentFormattedDate = moment() - .tz("America/Los_Angeles") + .tz('America/Los_Angeles') .format(); logger.logInfo( - `Job for deleting blue squares older than 1 year starting at ${currentFormattedDate}` + `Job for deleting blue squares older than 1 year starting at ${currentFormattedDate}`, ); const cutOffDate = moment() - .subtract(1, "year") - .format("YYYY-MM-DD"); + .subtract(1, 'year') + .format('YYYY-MM-DD'); try { const results = await userProfile.updateMany( @@ -645,11 +636,11 @@ const userHelper = function () { $pull: { infringements: { date: { - $lte: cutOffDate - } - } - } - } + $lte: cutOffDate, + }, + }, + }, + }, ); logger.logInfo(results); @@ -660,17 +651,17 @@ const userHelper = function () { const reActivateUser = async () => { const currentFormattedDate = moment() - .tz("America/Los_Angeles") + .tz('America/Los_Angeles') .format(); logger.logInfo( - `Job for activating users based on scheduled re-activation date starting at ${currentFormattedDate}` + `Job for activating users based on scheduled re-activation date starting at ${currentFormattedDate}`, ); try { const users = await userProfile.find( { isActive: false, reactivationDate: { $exists: true } }, - "_id isActive reactivationDate" + '_id isActive reactivationDate', ); for (let i = 0; i < users.length; i += 1) { const user = users[i]; @@ -679,18 +670,18 @@ const userHelper = function () { user._id, { $set: { - isActive: true + isActive: true, }, $unset: { - endDate: user.endDate - } + endDate: user.endDate, + }, }, - { new: true } + { new: true }, ); logger.logInfo( `User with id: ${user._id} was re-acticated at ${moment() - .tz("America/Los_Angeles") - .format()}.` + .tz('America/Los_Angeles') + .format()}.`, ); const id = user._id; const person = await userProfile.findById(id); @@ -712,7 +703,6 @@ const userHelper = function () { emailSender('onecommunityglobal@gmail.com', subject, emailBody, null, null); - } } } catch (err) { @@ -722,7 +712,6 @@ const userHelper = function () { const notifyInfringements = function (original, current, firstName, lastName, emailAddress) { - if (!current) return; const newOriginal = original.toObject(); const newCurrent = current.toObject(); @@ -737,43 +726,43 @@ const userHelper = function () { getInfringementEmailBody(firstName, lastName, element, totalInfringements), null, - "onecommunityglobal@gmail.com" + 'onecommunityglobal@gmail.com', ); }); }; const replaceBadge = async function (personId, oldBadgeId, newBadgeId) { userProfile.updateOne( - { _id: personId, "badgeCollection.badge": oldBadgeId }, + { _id: personId, 'badgeCollection.badge': oldBadgeId }, { $set: { - "badgeCollection.$.badge": newBadgeId, - "badgeCollection.$.lastModified": Date.now().toString(), - "badgeCollection.$.count": 1 - } + 'badgeCollection.$.badge': newBadgeId, + 'badgeCollection.$.lastModified': Date.now().toString(), + 'badgeCollection.$.count': 1, + }, }, - err => { + (err) => { if (err) { throw new Error(err); } - } + }, ); }; const increaseBadgeCount = async function (personId, badgeId) { - console.log("Increase Badge Count", personId, badgeId); + console.log('Increase Badge Count', personId, badgeId); userProfile.updateOne( - { _id: personId, "badgeCollection.badge": badgeId }, + { _id: personId, 'badgeCollection.badge': badgeId }, { - $inc: { "badgeCollection.$.count": 1 }, - $set: { "badgeCollection.$.lastModified": Date.now().toString() }, - $push: { "badgeCollection.$.earnedDate": earnedDateBadge() } + $inc: { 'badgeCollection.$.count': 1 }, + $set: { 'badgeCollection.$.lastModified': Date.now().toString() }, + $push: { 'badgeCollection.$.earnedDate': earnedDateBadge() }, }, - err => { + (err) => { if (err) { console.log(err); } - } + }, ); }; @@ -781,7 +770,7 @@ const userHelper = function () { personId, badgeId, count = 1, - featured = false + featured = false, ) { console.log('Adding Badge'); userProfile.findByIdAndUpdate( @@ -793,11 +782,11 @@ const userHelper = function () { }, }, }, - err => { + (err) => { if (err) { throw new Error(err); } - } + }, ); }; @@ -806,14 +795,14 @@ const userHelper = function () { personId, { $pull: { - badgeCollection: { badge: badgeId } - } + badgeCollection: { badge: badgeId }, + }, }, - err => { + (err) => { if (err) { throw new Error(err); } - } + }, ); }; @@ -822,18 +811,18 @@ const userHelper = function () { removeDupBadge(personId, badgeId); } else if (count) { userProfile.updateOne( - { _id: personId, "badgeCollection.badge": badgeId }, + { _id: personId, 'badgeCollection.badge': badgeId }, { $set: { - "badgeCollection.$.count": count, - "badgeCollection.$.lastModified": Date.now().toString() - } + 'badgeCollection.$.count': count, + 'badgeCollection.$.lastModified': Date.now().toString(), + }, }, - err => { + (err) => { if (err) { throw new Error(err); } - } + }, ); } }; @@ -841,7 +830,6 @@ const userHelper = function () { // remove the last badge you earned on this streak(not including 1) const removePrevHrBadge = async function (personId, user, badgeCollection, hrs, weeks) { - // Check each Streak Greater than One to check if it works if (weeks < 3) { return; @@ -851,24 +839,24 @@ const userHelper = function () { .aggregate([ { $match: { - type: "X Hours for X Week Streak", + type: 'X Hours for X Week Streak', weeks: { $gt: 1, $lt: weeks }, - totalHrs: hrs - } + totalHrs: hrs, + }, }, { $sort: { weeks: -1, totalHrs: -1 } }, { $group: { - _id: "$weeks", + _id: '$weeks', badges: { - $push: { _id: "$_id", hrs: "$totalHrs", weeks: "$weeks" } - } - } - } + $push: { _id: '$_id', hrs: '$totalHrs', weeks: '$weeks' }, + }, + }, + }, ]) - .then(results => { - results.forEach(streak => { - streak.badges.every(bdge => { + .then((results) => { + results.forEach((streak) => { + streak.badges.every((bdge) => { for (let i = 0; i < badgeCollection.length; i += 1) { if ( @@ -881,7 +869,7 @@ const userHelper = function () { changeBadgeCount( personId, badgeCollection[i].badge._id, - badgeCollection[i].badge.count - 1 + badgeCollection[i].badge.count - 1, ); removed = true; return false; @@ -903,7 +891,6 @@ const userHelper = function () { removeDupBadge(personId, badgeOfType._id); badgeOfType = badgeCollection[i].badge; } else if (badgeOfType && badgeOfType.months > badgeCollection[i].badge.months) { - removeDupBadge(personId, badgeCollection[i].badge._id); } else if (!badgeOfType) { badgeOfType = badgeCollection[i].badge; @@ -911,23 +898,21 @@ const userHelper = function () { } } await badge - .find({ type: "No Infringement Streak" }) + .find({ type: 'No Infringement Streak' }) .sort({ months: -1 }) - .then(results => { + .then((results) => { if (!Array.isArray(results) || !results.length) { return; } - results.every(elem => { + results.every((elem) => { // Cannot account for time paused yet if (elem.months <= 12) { - if (moment().diff(moment(user.createdDate), 'months', true) >= elem.months) { - if ( - user.infringements.length === 0 || - Math.abs( + user.infringements.length === 0 + || Math.abs( moment().diff( moment(user.infringements[user.infringements?.length - 1].date), @@ -942,7 +927,7 @@ const userHelper = function () { replaceBadge( personId, mongoose.Types.ObjectId(badgeOfType._id), - mongoose.Types.ObjectId(elem._id) + mongoose.Types.ObjectId(elem._id), ); } return false; @@ -952,12 +937,10 @@ const userHelper = function () { } } } else if (user?.infringements?.length === 0) { - if (moment().diff(moment(user.createdDate), 'months', true) >= elem.months) { - if ( - user.oldInfringements.length === 0 || - Math.abs( + user.oldInfringements.length === 0 + || Math.abs( moment().diff( moment(user.oldInfringements[user.oldInfringements?.length - 1].date), @@ -973,7 +956,7 @@ const userHelper = function () { replaceBadge( personId, mongoose.Types.ObjectId(badgeOfType._id), - mongoose.Types.ObjectId(elem._id) + mongoose.Types.ObjectId(elem._id), ); } return false; @@ -992,11 +975,11 @@ const userHelper = function () { const checkMinHoursMultiple = async function ( personId, user, - badgeCollection + badgeCollection, ) { const badgesOfType = badgeCollection .map(obj => obj.badge) - .filter(badge => badge.type === 'Minimum Hours Multiple') + .filter(badge => badge.type === 'Minimum Hours Multiple'); await badge .find({ type: 'Minimum Hours Multiple' }) .sort({ multiple: -1 }) @@ -1009,49 +992,47 @@ const userHelper = function () { const elem = results[i]; // making variable elem accessible for below code if ( - user.lastWeekTangibleHrs / user.weeklycommittedHours >= - elem.multiple + user.lastWeekTangibleHrs / user.weeklycommittedHours + >= elem.multiple ) { const theBadge = badgesOfType.find( - (badge) => badge._id.toString() === elem._id.toString() + badge => badge._id.toString() === elem._id.toString(), ); return theBadge ? increaseBadgeCount( personId, - mongoose.Types.ObjectId(theBadge._id) + mongoose.Types.ObjectId(theBadge._id), ) : addBadge(personId, mongoose.Types.ObjectId(elem._id)); } } - }) + }); }; // 'Personal Max', const checkPersonalMax = async function (personId, user, badgeCollection) { let badgeOfType; for (let i = 0; i < badgeCollection.length; i += 1) { - if (badgeCollection[i].badge?.type === "Personal Max") { + if (badgeCollection[i].badge?.type === 'Personal Max') { if (badgeOfType) { removeDupBadge(personId, badgeOfType._id); } } } - await badge.findOne({ type: "Personal Max" }).then(results => { + await badge.findOne({ type: 'Personal Max' }).then((results) => { if ( - user.lastWeekTangibleHrs && - user.lastWeekTangibleHrs >= 1 && - user.lastWeekTangibleHrs === user.personalBestMaxHrs + user.lastWeekTangibleHrs + && user.lastWeekTangibleHrs >= 1 + && user.lastWeekTangibleHrs === user.personalBestMaxHrs ) { if (badgeOfType) { changeBadgeCount( personId, mongoose.Types.ObjectId(badgeOfType._id), - user.personalBestMaxHrs + user.personalBestMaxHrs, ); } else { - addBadge(personId, mongoose.Types.ObjectId(results._id), user.personalBestMaxHrs); - } } }); @@ -1071,22 +1052,21 @@ const userHelper = function () { userProfile .aggregate([ { $match: { isActive: true } }, - { $group: { _id: 1, maxHours: { $max: "$lastWeekTangibleHrs" } } }, + { $group: { _id: 1, maxHours: { $max: '$lastWeekTangibleHrs' } } }, ]) .then((userResults) => { if (badgeOfType.length > 1) { removeDupBadge(user._id, badgeOfType[0]._id); - } if ( - user.lastWeekTangibleHrs && - user.lastWeekTangibleHrs >= userResults[0].maxHours + user.lastWeekTangibleHrs + && user.lastWeekTangibleHrs >= userResults[0].maxHours ) { if (badgeOfType.length) { increaseBadgeCount( personId, - mongoose.Types.ObjectId(badgeOfType[0]._id) + mongoose.Types.ObjectId(badgeOfType[0]._id), ); } else { addBadge(personId, mongoose.Types.ObjectId(results._id)); @@ -1102,15 +1082,15 @@ const userHelper = function () { // Handle Increasing the 1 week streak badges const badgesOfType = []; for (let i = 0; i < badgeCollection.length; i += 1) { - if (badgeCollection[i].badge?.type === "X Hours for X Week Streak") { + if (badgeCollection[i].badge?.type === 'X Hours for X Week Streak') { badgesOfType.push(badgeCollection[i].badge); } } await badge - .find({ type: "X Hours for X Week Streak", weeks: 1 }) + .find({ type: 'X Hours for X Week Streak', weeks: 1 }) .sort({ totalHrs: -1 }) - .then(results => { - results.every(elem => { + .then((results) => { + results.every((elem) => { if (elem.totalHrs <= user.lastWeekTangibleHrs) { let theBadge; for (let i = 0; i < badgesOfType.length; i += 1) { @@ -1132,21 +1112,21 @@ const userHelper = function () { // Check each Streak Greater than One to check if it works await badge .aggregate([ - { $match: { type: "X Hours for X Week Streak", weeks: { $gt: 1 } } }, + { $match: { type: 'X Hours for X Week Streak', weeks: { $gt: 1 } } }, { $sort: { weeks: -1, totalHrs: -1 } }, { $group: { - _id: "$weeks", + _id: '$weeks', badges: { - $push: { _id: "$_id", hrs: "$totalHrs", weeks: "$weeks" } - } - } - } + $push: { _id: '$_id', hrs: '$totalHrs', weeks: '$weeks' }, + }, + }, + }, ]) - .then(results => { + .then((results) => { let lastHr = -1; - results.forEach(streak => { - streak.badges.every(bdge => { + results.forEach((streak) => { + streak.badges.every((bdge) => { let badgeOfType; for (let i = 0; i < badgeCollection.length; i += 1) { if ( @@ -1155,12 +1135,11 @@ const userHelper = function () { && badgeCollection[i].badge?.weeks === bdge.weeks ) { if (badgeOfType && badgeOfType.totalHrs <= badgeCollection[i].badge.totalHrs) { - removeDupBadge(personId, badgeOfType._id); badgeOfType = badgeCollection[i].badge; } else if ( - badgeOfType && - badgeOfType.totalHrs > badgeCollection[i].badge.totalHrs + badgeOfType + && badgeOfType.totalHrs > badgeCollection[i].badge.totalHrs ) { removeDupBadge(personId, badgeCollection[i].badge._id); } else if (!badgeOfType) { @@ -1185,7 +1164,7 @@ const userHelper = function () { replaceBadge( personId, mongoose.Types.ObjectId(badgeOfType._id), - mongoose.Types.ObjectId(bdge._id) + mongoose.Types.ObjectId(bdge._id), ); removePrevHrBadge(personId, user, badgeCollection, bdge.hrs, bdge.weeks); @@ -1196,12 +1175,11 @@ const userHelper = function () { user, badgeCollection, bdge.hrs, - bdge.weeks + bdge.weeks, ); } else if (badgeOfType && badgeOfType.totalHrs === bdge.hrs) { increaseBadgeCount(personId, mongoose.Types.ObjectId(badgeOfType._id)); removePrevHrBadge(personId, user, badgeCollection, bdge.hrs, bdge.weeks); - } return false; } @@ -1222,8 +1200,8 @@ const userHelper = function () { let teamMembers; await getTeamMembers({ - _id: personId - }).then(results => { + _id: personId, + }).then((results) => { if (results) { teamMembers = results.myteam; } else { @@ -1242,13 +1220,11 @@ const userHelper = function () { }); let badgeOfType; for (let i = 0; i < badgeCollection.length; i += 1) { - if (badgeCollection[i].badge?.type === 'Lead a team of X+') { if (badgeOfType && badgeOfType.people <= badgeCollection[i].badge.people) { removeDupBadge(personId, badgeOfType._id); badgeOfType = badgeCollection[i].badge; } else if (badgeOfType && badgeOfType.people > badgeCollection[i].badge.people) { - removeDupBadge(personId, badgeCollection[i].badge._id); } else if (!badgeOfType) { badgeOfType = badgeCollection[i].badge; @@ -1256,9 +1232,9 @@ const userHelper = function () { } } await badge - .find({ type: "Lead a team of X+" }) + .find({ type: 'Lead a team of X+' }) .sort({ people: -1 }) - .then(results => { + .then((results) => { if (!Array.isArray(results) || !results.length) { return; } @@ -1292,40 +1268,40 @@ const userHelper = function () { const checkTotalHrsInCat = async function (personId, user, badgeCollection) { const hoursByCategory = user.hoursByCategory || {}; const categories = [ - "food", - "energy", - "housing", - "education", - "society", - "economics", - "stewardship" + 'food', + 'energy', + 'housing', + 'education', + 'society', + 'economics', + 'stewardship', ]; const badgesOfType = badgeCollection - .filter(object => object.badge.type === "Total Hrs in Category") + .filter(object => object.badge.type === 'Total Hrs in Category') .map(object => object.badge); - categories.forEach(async category => { + categories.forEach(async (category) => { const categoryHrs = Object.keys(hoursByCategory).find( - elem => elem === category + elem => elem === category, ); let badgeOfType; for (let i = 0; i < badgeCollection.length; i += 1) { if ( - badgeCollection[i].badge?.type === "Total Hrs in Category" && - badgeCollection[i].badge?.category === category + badgeCollection[i].badge?.type === 'Total Hrs in Category' + && badgeCollection[i].badge?.category === category ) { if ( - badgeOfType && - badgeOfType.totalHrs <= badgeCollection[i].badge.totalHrs + badgeOfType + && badgeOfType.totalHrs <= badgeCollection[i].badge.totalHrs ) { removeDupBadge(personId, badgeOfType._id); badgeOfType = badgeCollection[i].badge; } else if ( - badgeOfType && - badgeOfType.totalHrs > badgeCollection[i].badge.totalHrs + badgeOfType + && badgeOfType.totalHrs > badgeCollection[i].badge.totalHrs ) { removeDupBadge(personId, badgeCollection[i].badge._id); } else if (!badgeOfType) { @@ -1340,15 +1316,15 @@ const userHelper = function () { await badge.find({ type: 'Total Hrs in Category', category: newCatg }) .sort({ totalHrs: -1 }) - .then(results => { + .then((results) => { if (!Array.isArray(results) || !results.length || !categoryHrs) { return; } - results.every(elem => { + results.every((elem) => { if ( - hoursByCategory[categoryHrs] >= 100 && - hoursByCategory[categoryHrs] >= elem.totalHrs + hoursByCategory[categoryHrs] >= 100 + && hoursByCategory[categoryHrs] >= elem.totalHrs ) { let theBadge; for (let i = 0; i < badgesOfType.length; i += 1) { @@ -1363,13 +1339,13 @@ const userHelper = function () { } if (badgeOfType) { if ( - badgeOfType._id.toString() !== elem._id.toString() && - badgeOfType.totalHrs < elem.totalHrs + badgeOfType._id.toString() !== elem._id.toString() + && badgeOfType.totalHrs < elem.totalHrs ) { replaceBadge( personId, mongoose.Types.ObjectId(badgeOfType._id), - mongoose.Types.ObjectId(elem._id) + mongoose.Types.ObjectId(elem._id), ); } return false; @@ -1384,9 +1360,8 @@ const userHelper = function () { }; const awardNewBadges = async () => { - console.log("Awarding"); + console.log('Awarding'); try { - const users = await userProfile.find({ isActive: true }).populate('badgeCollection.badge'); @@ -1419,14 +1394,14 @@ const userHelper = function () { { personId: userId, dateOfWork: { $gte: pdtstart, $lte: pdtend }, - isTangible: true + isTangible: true, }, - "totalSeconds" + 'totalSeconds', ) - .then(results => { + .then((results) => { const totalTangibleWeeklySeconds = results.reduce( (acc, { totalSeconds }) => acc + totalSeconds, - 0 + 0, ); return (totalTangibleWeeklySeconds / 3600).toFixed(2); }); @@ -1436,19 +1411,19 @@ const userHelper = function () { try { const users = await userProfile.find( { isActive: true, endDate: { $exists: true } }, - "_id isActive endDate" + '_id isActive endDate', ); for (let i = 0; i < users.length; i += 1) { const user = users[i]; const { endDate } = user; endDate.setHours(endDate.getHours() + 7); - if (moment().isAfter(moment(endDate).add(1, "days"))) { + if (moment().isAfter(moment(endDate).add(1, 'days'))) { await userProfile.findByIdAndUpdate( user._id, user.set({ - isActive: false + isActive: false, }), - { new: true } + { new: true }, ); const id = user._id; const person = await userProfile.findById(id); @@ -1485,7 +1460,7 @@ const userHelper = function () { } catch (error) { logger.logException(err); } - } + }; return { @@ -1502,7 +1477,7 @@ const userHelper = function () { emailWeeklySummariesForAllUsers, awardNewBadges, getTangibleHoursReportedThisWeekByUserId, - deleteExpiredTokens + deleteExpiredTokens, }; }; diff --git a/src/models/badge.js b/src/models/badge.js index 8b2c754e7..e3e93eaaf 100644 --- a/src/models/badge.js +++ b/src/models/badge.js @@ -19,7 +19,7 @@ const Badge = new Schema({ imageUrl: { type: String }, ranking: { type: Number }, description: { type: String }, - showReport: {type: Boolean}, + showReport: { type: Boolean }, }); module.exports = mongoose.model('badge', Badge, 'badges'); diff --git a/src/models/inventoryItemMaterial.js b/src/models/inventoryItemMaterial.js index e6153af45..8460ecd6e 100644 --- a/src/models/inventoryItemMaterial.js +++ b/src/models/inventoryItemMaterial.js @@ -29,12 +29,12 @@ const InventoryItemMaterial = new Schema({ poId: { type: String, required: true }, sellerId: { type: String, required: true }, quantity: { type: Number, required: true }, // adds to stockBought - unitPrice: {type: Number, required: true}, + unitPrice: { type: Number, required: true }, currency: { type: String, required: true }, subtotal: { type: Number, required: true }, tax: { type: Number, required: true }, shipping: { type: Number, required: true }, - }] -}) + }], +}); module.exports = mongoose.model('inventoryItemMaterial', InventoryItemMaterial, 'inventoryMaterial'); diff --git a/src/models/inventoryItemType.js b/src/models/inventoryItemType.js index 321038a84..b7b3ec46f 100644 --- a/src/models/inventoryItemType.js +++ b/src/models/inventoryItemType.js @@ -9,11 +9,9 @@ const InventoryItemType = new Schema({ // creates an item, tracks total amount i uom: { type: String, required: true }, // unit of measurement totalStock: { type: Number, required: true }, // total amount of all stock acquired totalAvailable: { type: Number, required: true }, - projectsUsing: [ {type: mongoose.SchemaTypes.ObjectId, ref: 'project'} ], + projectsUsing: [{ type: mongoose.SchemaTypes.ObjectId, ref: 'project' }], imageUrl: { type: String }, - link: { type: String} + link: { type: String }, }); module.exports = mongoose.model('inventoryItemType', InventoryItemType, 'inventoryItemType'); - - diff --git a/src/models/profileInitialSetupToken.js b/src/models/profileInitialSetupToken.js index 48413fb77..77b830229 100644 --- a/src/models/profileInitialSetupToken.js +++ b/src/models/profileInitialSetupToken.js @@ -10,7 +10,7 @@ const profileInitialSetupTokenSchema = new mongoose.Schema({ type: String, required: true, }, - weeklyCommittedHours : { + weeklyCommittedHours: { type: Number, required: true, default: 10, @@ -21,4 +21,4 @@ const profileInitialSetupTokenSchema = new mongoose.Schema({ }, }); -module.exports = mongoose.model('profileInitialSetupToken', profileInitialSetupTokenSchema, 'profileInitialSetupToken'); \ No newline at end of file +module.exports = mongoose.model('profileInitialSetupToken', profileInitialSetupTokenSchema, 'profileInitialSetupToken'); diff --git a/src/models/userProfile.js b/src/models/userProfile.js index a58d1d293..1a29ec3e0 100644 --- a/src/models/userProfile.js +++ b/src/models/userProfile.js @@ -7,7 +7,7 @@ const bcrypt = require('bcryptjs'); const SALT_ROUNDS = 10; const nextDay = new Date(); -nextDay.setDate(nextDay.getDate()+1); +nextDay.setDate(nextDay.getDate() + 1); const userProfileSchema = new Schema({ password: { @@ -153,7 +153,7 @@ const userProfileSchema = new Schema({ isVisible: { type: Boolean, default: false }, weeklySummaryOption: { type: String }, bioPosted: { type: String, default: 'default' }, - isFirstTimelog: { type: Boolean, default: true}, + isFirstTimelog: { type: Boolean, default: true }, teamCode: { type: String, default: '' }, infoCollections: [ { diff --git a/src/routes/bmdashboard/bmMaterialsRouter.js b/src/routes/bmdashboard/bmMaterialsRouter.js index 0be779cd7..a0f8dfea6 100644 --- a/src/routes/bmdashboard/bmMaterialsRouter.js +++ b/src/routes/bmdashboard/bmMaterialsRouter.js @@ -11,6 +11,6 @@ materialsRouter.route('/addUpdateMaterialRecord') .post(controller.bmPostMaterialUpdateRecord); return materialsRouter; -} +}; -module.exports = routes; \ No newline at end of file +module.exports = routes; diff --git a/src/routes/bmdashboard/bmProjectsRouter.js b/src/routes/bmdashboard/bmProjectsRouter.js index cec4b16e9..a171fc4cd 100644 --- a/src/routes/bmdashboard/bmProjectsRouter.js +++ b/src/routes/bmdashboard/bmProjectsRouter.js @@ -8,6 +8,6 @@ materialsRouter.route('/getUserActiveBMProjects') .get(controller.getUserActiveBMProjects); return materialsRouter; -} +}; -module.exports = routes; \ No newline at end of file +module.exports = routes; diff --git a/src/routes/isEmailExistsRouter.js b/src/routes/isEmailExistsRouter.js index cfb4e6033..d19b14fe2 100644 --- a/src/routes/isEmailExistsRouter.js +++ b/src/routes/isEmailExistsRouter.js @@ -2,14 +2,14 @@ const express = require('express'); const routes = function () { - const controller = require('../controllers/isEmailExistsController')() + const controller = require('../controllers/isEmailExistsController')(); - const isEmailExistsRouter = express.Router() + const isEmailExistsRouter = express.Router(); - isEmailExistsRouter.route("/is-email-exists/:email") - .get(controller.isEmailExists) + isEmailExistsRouter.route('/is-email-exists/:email') + .get(controller.isEmailExists); - return isEmailExistsRouter -} + return isEmailExistsRouter; +}; -module.exports = routes +module.exports = routes; diff --git a/src/routes/profileInitialSetupRouter.js b/src/routes/profileInitialSetupRouter.js index a23c6a868..2091afcad 100644 --- a/src/routes/profileInitialSetupRouter.js +++ b/src/routes/profileInitialSetupRouter.js @@ -5,9 +5,9 @@ const routes = function (ProfileInitialSetupToken, userProfile, Project) { const controller = require('../controllers/profileInitialSetupController')(ProfileInitialSetupToken, userProfile, Project); ProfileInitialSetup.route('/getInitialSetuptoken') .post(controller.getSetupToken); - ProfileInitialSetup.route('/ProfileInitialSetup').post(controller.setUpNewUser) - ProfileInitialSetup.route('/validateToken').post(controller.validateSetupToken) - ProfileInitialSetup.route('/getTimeZoneAPIKeyByToken').post(controller.getTimeZoneAPIKeyByToken) + ProfileInitialSetup.route('/ProfileInitialSetup').post(controller.setUpNewUser); + ProfileInitialSetup.route('/validateToken').post(controller.validateSetupToken); + ProfileInitialSetup.route('/getTimeZoneAPIKeyByToken').post(controller.getTimeZoneAPIKeyByToken); return ProfileInitialSetup; }; diff --git a/src/startup/routes.js b/src/startup/routes.js index 00d8a3fec..7208535d8 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -61,7 +61,7 @@ const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverTe // bm dashboard const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial); -const bmProjectsRouter = require('../routes/bmdashboard/bmProjectsRouter')() +const bmProjectsRouter = require('../routes/bmdashboard/bmProjectsRouter')(); module.exports = function (app) { app.use('/api', forgotPwdRouter); From bd8f4de8a7ff455500408c608a32f81ddb4c79a3 Mon Sep 17 00:00:00 2001 From: wang9hu Date: Sun, 29 Oct 2023 14:49:00 -0700 Subject: [PATCH 093/272] make timer chime consistent over all tabs --- src/models/timer.js | 1 + src/websockets/TimerService/clientsHandler.js | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/src/models/timer.js b/src/models/timer.js index 09c2f89da..f50921fb3 100644 --- a/src/models/timer.js +++ b/src/models/timer.js @@ -9,6 +9,7 @@ const timerSchema = new Schema({ time: { type: Number, default: 900000 }, goal: { type: Number, default: 900000 }, initialGoal: { type: Number, default: 900000 }, + chiming: { type: Boolean, default: false }, paused: { type: Boolean, default: false }, forcedPause: { type: Boolean, default: false }, started: { type: Boolean, default: false }, diff --git a/src/websockets/TimerService/clientsHandler.js b/src/websockets/TimerService/clientsHandler.js index 3bb2c358d..60eb33fa4 100644 --- a/src/websockets/TimerService/clientsHandler.js +++ b/src/websockets/TimerService/clientsHandler.js @@ -43,6 +43,7 @@ export const action = { REMOVE_GOAL: 'REMOVE_FROM_GOAL=', FORCED_PAUSE: 'FORCED_PAUSE', ACK_FORCED: 'ACK_FORCED', + START_CHIME: 'START_CHIME', }; const MAX_HOURS = 5; @@ -69,11 +70,17 @@ const startTimer = (client) => { const pauseTimer = (client, forced = false) => { client.time = updatedTimeSinceStart(client); + if (client.time === 0) client.chiming = true; client.startAt = moment.invalid(); // invalid can not be saved in database client.paused = true; if (forced) client.forcedPause = true; }; +const startChime = (client, msg) => { + const state = msg.split('=')[1]; + client.chiming = state === 'true'; +}; + const ackForcedPause = (client) => { client.forcedPause = false; client.paused = true; @@ -86,6 +93,7 @@ const stopTimer = (client) => { client.started = false; client.pause = false; client.forcedPause = false; + if (client.chiming) client.chiming = false; if (client.time === 0) { client.goal = client.initialGoal; client.time = client.goal; @@ -97,6 +105,7 @@ const stopTimer = (client) => { const clearTimer = (client) => { stopTimer(client); client.goal = client.initialGoal; + client.chiming = false; client.time = client.goal; }; @@ -175,6 +184,9 @@ export const handleMessage = async (msg, clients, userId) => { case req.match(/REMOVE_FROM_GOAL=/i)?.input: removeGoal(client, req); break; + case req.match(/START_CHIME=/i)?.input: + startChime(client, req); + break; case action.PAUSE_TIMER: pauseTimer(client); break; From 64f6c4121012e4e10d01568e847a6172562a2512 Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Tue, 31 Oct 2023 16:04:22 +0800 Subject: [PATCH 094/272] set default value for createdDatetime --- src/models/team.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/team.js b/src/models/team.js index 97f8dc360..00fbaf8e3 100644 --- a/src/models/team.js +++ b/src/models/team.js @@ -5,7 +5,7 @@ const { Schema } = mongoose; const team = new Schema({ teamName: { type: 'String', required: true }, isActive: { type: 'Boolean', required: true, default: true }, - createdDatetime: { type: Date }, + createdDatetime: { type: Date, default: Date.now() }, modifiedDatetime: { type: Date, default: Date.now() }, members: [ { From 8036f37181e6f41b064d702357d542d0b90aac45 Mon Sep 17 00:00:00 2001 From: tsunami776 <43768723+tsunami776@users.noreply.github.com> Date: Tue, 31 Oct 2023 20:07:56 -0500 Subject: [PATCH 095/272] Tried to fix old approach --- src/controllers/dashBoardController.js | 20 ++++++++++++++++++++ src/models/dashBoardData.js | 10 ++++++++++ src/routes/dashboardRouter.js | 4 ++++ src/startup/routes.js | 3 ++- 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/models/dashBoardData.js diff --git a/src/controllers/dashBoardController.js b/src/controllers/dashBoardController.js index c9cdbd588..3a203481f 100644 --- a/src/controllers/dashBoardController.js +++ b/src/controllers/dashBoardController.js @@ -3,6 +3,7 @@ const path = require("path"); const fs = require("fs/promises"); const dashboardhelper = require("../helpers/dashboardhelper")(); const emailSender = require("../utilities/emailSender"); +const DashboardData = require('../models/dashBoardData'); const dashboardcontroller = function () { const dashboarddata = function (req, res) { @@ -15,6 +16,23 @@ const dashboardcontroller = function () { }); }; + const updateDashboardData = function (req, res) { + if (req.body.requestor.role === 'Owner') { + DashboardData.findOneAndUpdate({ _id: 'ai-prompt' }, { ...req.body, aIPromptText: req.body.aIPromptText }) + .then(() => { + res.status(200).send('Successfully saved AI prompt.'); + }).catch(error => res.status(500).send(error)); + } + }; + + const getDashBoardData = function (req, res) { + DashboardData.findById({ _id: 'ai-prompt' }) + .then((results) => { + res.status(200).send(results); + }) + .catch(error => res.status(500).send(error)); + }; + const monthlydata = function (req, res) { const userId = mongoose.Types.ObjectId(req.params.userId); const laborthismonth = dashboardhelper.laborthismonth( @@ -247,6 +265,8 @@ const dashboardcontroller = function () { return { dashboarddata, + getDashBoardData, + updateDashboardData, monthlydata, weeklydata, leaderboarddata, diff --git a/src/models/dashBoardData.js b/src/models/dashBoardData.js new file mode 100644 index 000000000..2ae3a5482 --- /dev/null +++ b/src/models/dashBoardData.js @@ -0,0 +1,10 @@ +const mongoose = require('mongoose'); + +const { Schema } = mongoose; + +const DashboardData = new Schema({ + _id: { type: mongoose.Schema.Types.String }, + aIPromptText: { type: String }, +}); + +module.exports = mongoose.model('dashboardData', DashboardData, 'dashboard'); diff --git a/src/routes/dashboardRouter.js b/src/routes/dashboardRouter.js index 664c1c802..7b55fcb89 100644 --- a/src/routes/dashboardRouter.js +++ b/src/routes/dashboardRouter.js @@ -5,6 +5,10 @@ const route = function () { const Dashboardrouter = express.Router(); + Dashboardrouter.route('/dashboard/aiPrompt') + .get(controller.getDashBoardData) + .put(controller.updateDashboardData); + Dashboardrouter.route('/dashboard/:userId') .get(controller.dashboarddata); diff --git a/src/startup/routes.js b/src/startup/routes.js index 2fd7337a6..41b63a5ec 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -18,6 +18,7 @@ const role = require('../models/role'); const rolePreset = require('../models/rolePreset'); const ownerMessage = require('../models/ownerMessage'); const ownerStandardMessage = require('../models/ownerStandardMessage'); +const dashboardData = require('../models/dashBoardData'); const profileInitialSetuptoken = require('../models/profileInitialSetupToken'); const reason = require('../models/reason'); const mouseoverText = require('../models/mouseoverText'); @@ -25,7 +26,7 @@ const inventoryItemMaterial = require('../models/inventoryItemMaterial'); const userProfileRouter = require('../routes/userProfileRouter')(userProfile); const badgeRouter = require('../routes/badgeRouter')(badge); -const dashboardRouter = require('../routes/dashboardRouter')(); +const dashboardRouter = require('../routes/dashboardRouter')(dashboardData); const timeEntryRouter = require('../routes/timeentryRouter')(timeEntry); const projectRouter = require('../routes/projectRouter')(project); const informationRouter = require('../routes/informationRouter')(information); From 66c6c3c8d8d1f637efc7cb850b03f269149f428c Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Wed, 1 Nov 2023 09:22:24 -0700 Subject: [PATCH 096/272] add building project schema. update project summary controller. --- .../bmdashboard/bmProjectController.js | 27 ++++++++++++++++ .../bmdashboard/bmProjectsController.js | 31 ------------------- src/models/bmdashboard/buildingProject.js | 15 +++++++++ src/models/inventoryItemMaterial.js | 6 ++-- src/routes/bmdashboard/bmProjectRouter.js | 13 ++++++++ src/routes/bmdashboard/bmProjectsRouter.js | 13 -------- src/startup/routes.js | 6 ++-- 7 files changed, 62 insertions(+), 49 deletions(-) create mode 100644 src/controllers/bmdashboard/bmProjectController.js delete mode 100644 src/controllers/bmdashboard/bmProjectsController.js create mode 100644 src/models/bmdashboard/buildingProject.js create mode 100644 src/routes/bmdashboard/bmProjectRouter.js delete mode 100644 src/routes/bmdashboard/bmProjectsRouter.js diff --git a/src/controllers/bmdashboard/bmProjectController.js b/src/controllers/bmdashboard/bmProjectController.js new file mode 100644 index 000000000..96f19ab60 --- /dev/null +++ b/src/controllers/bmdashboard/bmProjectController.js @@ -0,0 +1,27 @@ +const bmMProjectController = function (BuildingProject) { + const bmProjectSummary = async function _projSumm(req, res) { + try { + const projectData = await BuildingProject + .find() + .populate([ + { + path: 'buildingManager', + select: '_id firstName lastName email', + }, + { + path: 'team', + select: '_id firstName lastName email', + }, + ]) + .exec() + .then(result => result) + .catch(error => res.status(500).send(error)); + res.status(200).send(projectData); + } catch (err) { + res.json(err); + } + }; + return { bmProjectSummary }; +}; + +module.exports = bmMProjectController; diff --git a/src/controllers/bmdashboard/bmProjectsController.js b/src/controllers/bmdashboard/bmProjectsController.js deleted file mode 100644 index f80eea6c0..000000000 --- a/src/controllers/bmdashboard/bmProjectsController.js +++ /dev/null @@ -1,31 +0,0 @@ -const mongoose = require('mongoose'); - -const bmMProjectsController = function (UserProfile) { - const bmProjectsSummary = async function _projSumm(req, res) { - const { userId } = req.params; - try { - const projectData = await UserProfile - // fetch user profile, return only projects array - .findOne({ _id: userId }, { projects: 1 }) - // populate data with projects documents using the ObjectId in the projects array - .populate({ - path: 'projects', - // limit to projects with category value 'Housing' - match: { category: 'Housing' }, - // returns only these fields - select: '_id projectName isActive createdDatetime', - }) - .exec() - .then(result => result.projects) - .catch(error => res.status(500).send(error)); - - // for each project, find all materials in the project - res.status(200).send(projectData); - } catch (err) { - res.json(err); - } - }; - return { bmProjectsSummary }; -}; - -module.exports = bmMProjectsController; diff --git a/src/models/bmdashboard/buildingProject.js b/src/models/bmdashboard/buildingProject.js new file mode 100644 index 000000000..566bc124e --- /dev/null +++ b/src/models/bmdashboard/buildingProject.js @@ -0,0 +1,15 @@ +const mongoose = require('mongoose'); + +const { Schema } = mongoose; + +const buildingProject = new Schema({ + isActive: Boolean, + name: String, + template: String, // construction template (ie Earthbag Village) + location: String, // use lat/lng instead? + dateCreated: { type: Date, default: Date.now }, + buildingManager: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, // BM's id + team: [{ type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }], +}); + +module.exports = mongoose.model('buildingProject', buildingProject, 'buildingProjects'); diff --git a/src/models/inventoryItemMaterial.js b/src/models/inventoryItemMaterial.js index e6153af45..8460ecd6e 100644 --- a/src/models/inventoryItemMaterial.js +++ b/src/models/inventoryItemMaterial.js @@ -29,12 +29,12 @@ const InventoryItemMaterial = new Schema({ poId: { type: String, required: true }, sellerId: { type: String, required: true }, quantity: { type: Number, required: true }, // adds to stockBought - unitPrice: {type: Number, required: true}, + unitPrice: { type: Number, required: true }, currency: { type: String, required: true }, subtotal: { type: Number, required: true }, tax: { type: Number, required: true }, shipping: { type: Number, required: true }, - }] -}) + }], +}); module.exports = mongoose.model('inventoryItemMaterial', InventoryItemMaterial, 'inventoryMaterial'); diff --git a/src/routes/bmdashboard/bmProjectRouter.js b/src/routes/bmdashboard/bmProjectRouter.js new file mode 100644 index 000000000..6bd535ae1 --- /dev/null +++ b/src/routes/bmdashboard/bmProjectRouter.js @@ -0,0 +1,13 @@ +const express = require('express'); + +const routes = function (buildingProject) { + const projectRouter = express.Router(); + const controller = require('../../controllers/bmdashboard/bmProjectController')(buildingProject); + +projectRouter.route('/projects') + .get(controller.bmProjectSummary); + + return projectRouter; +}; + +module.exports = routes; diff --git a/src/routes/bmdashboard/bmProjectsRouter.js b/src/routes/bmdashboard/bmProjectsRouter.js deleted file mode 100644 index 05adfa59d..000000000 --- a/src/routes/bmdashboard/bmProjectsRouter.js +++ /dev/null @@ -1,13 +0,0 @@ -const express = require('express'); - -const routes = function (userProfile) { - const projectsRouter = express.Router(); - const controller = require('../../controllers/bmdashboard/bmProjectsController')(userProfile); - -projectsRouter.route('/projects/:userId') - .get(controller.bmProjectsSummary); - - return projectsRouter; -}; - -module.exports = routes; diff --git a/src/startup/routes.js b/src/startup/routes.js index aa786dbbd..7f9446315 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -22,6 +22,8 @@ const profileInitialSetuptoken = require('../models/profileInitialSetupToken'); const reason = require('../models/reason'); const mouseoverText = require('../models/mouseoverText'); const inventoryItemMaterial = require('../models/inventoryItemMaterial'); +const buildingProject = require('../models/bmdashboard/buildingProject'); + const userProfileRouter = require('../routes/userProfileRouter')(userProfile); const badgeRouter = require('../routes/badgeRouter')(badge); @@ -61,7 +63,7 @@ const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverTe // bm dashboard const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial); -const bmProjectsRouter = require('../routes/bmdashboard/bmProjectsRouter')(userProfile); +const bmProjectRouter = require('../routes/bmdashboard/bmProjectRouter')(buildingProject); module.exports = function (app) { app.use('/api', forgotPwdRouter); @@ -97,5 +99,5 @@ module.exports = function (app) { // bm dashboard app.use('/api/bm', bmLoginRouter); app.use('/api/bm', bmMaterialsRouter); - app.use('/api/bm', bmProjectsRouter); + app.use('/api/bm', bmProjectRouter); }; From cf9d773e07f5d671e1b147af9a56c80ebaef15a2 Mon Sep 17 00:00:00 2001 From: Oleksandr Riazantsev Date: Wed, 1 Nov 2023 12:58:36 -0400 Subject: [PATCH 097/272] fix: moving part of logic from the frontend, bug fixes feat: updating timezone --- src/controllers/mapLocationsController.js | 88 ++++++++++++++--------- src/models/mapLocation.js | 15 ++-- 2 files changed, 58 insertions(+), 45 deletions(-) diff --git a/src/controllers/mapLocationsController.js b/src/controllers/mapLocationsController.js index f01666558..9fa214080 100644 --- a/src/controllers/mapLocationsController.js +++ b/src/controllers/mapLocationsController.js @@ -1,27 +1,32 @@ -const userProfile = require('../models/userProfile'); +const UserProfile = require('../models/userProfile'); const cache = require('../utilities/nodeCache')(); + const mapLocationsController = function (MapLocation) { - const getAllLocations = function (req, res) { - const priorText = 'Prior to HGN Data Collection'; - MapLocation.find({}) - .then(results => { - const users = results.map(item => { - return ({ - title: priorText, - firstName: item.firstName !== priorText ? item.firstName : '', - lastName: item.lastName !== priorText ? item.lastName : '', - jobTitle: item.jobTitle !== priorText ? item.jobTitle : '', - location: item.location, - isActive: item.isActive, - _id: item._id - }) - }) - res.send(users).status(200); - - }) - .catch(error => - res.send(error).status(404)); + const getAllLocations = async function (req, res) { + + try { + const users = []; + const results = await UserProfile.find({}, + '_id firstName lastName isActive location jobTitle totalTangibleHrs hoursByCategory' + ); + + results.forEach((item) => { + if ( + (item.location?.coords.lat && item.location?.coords.lng && item.totalTangibleHrs >= 10) || + (item.location?.coords.lat && item.location?.coords.lng && calculateTotalHours(item.hoursByCategory) >= 10) + ) { + users.push(item); + } + }); + + const m_users = await MapLocation.find({}); + + res.status(200).send({ users, m_users }); + } catch (err) { + res.status(404).send(err); + } + }; const deleteLocation = async function (req, res) { @@ -37,7 +42,7 @@ const mapLocationsController = function (MapLocation) { }; const putUserLocation = async function (req, res) { - if (!req.body.requestor.role === 'Administrator' || !req.body.requestor.role === 'Owner') { + if (!req.body.requestor.role === 'Owner') { res.status(403).send('You are not authorized to make changes in the teams.'); return; } @@ -61,32 +66,36 @@ const mapLocationsController = function (MapLocation) { } }; const updateUserLocation = async function (req, res) { - console.log(req.body) - if (!req.body.requestor.role === 'Administrator' || !req.body.requestor.role === 'Owner') { + if (!req.body.requestor.role === 'Owner') { res.status(403).send('You are not authorized to make changes in the teams.'); return; } const userType = req.body.type; - const userId= req.body._id; + const userId = req.body._id; const updateData = { - firstName: req.body.firstName, - lastName: req.body.lastName, - jobTitle: req.body.jobTitle, - location: req.body.location, - _id: req.body._id + firstName: req.body.firstName, + lastName: req.body.lastName, + jobTitle: req.body.jobTitle, + location: req.body.location, + } + + if (req.body.timeZone) { + updateData.timeZone = req.body.timeZone } try { let response; - if(userType === 'user') { - response = await userProfile.findOneAndUpdate({ _id: userId }, {$set: {...updateData, jobTitle: [updateData.jobTitle]}}, { new: true }); + if (userType === 'user') { + console.log('updateData----', updateData); + response = await UserProfile.findOneAndUpdate({ _id: userId }, { $set: { ...updateData, jobTitle: [updateData.jobTitle] } }, { new: true }); cache.removeCache('allusers') cache.removeCache(`user-${userId}`); + cache.setCache(`user-${userId}`, JSON.stringify(response)); } else { - response = await MapLocation.findOneAndUpdate({ _id: userId }, {$set: updateData}, { new: true }) + response = await MapLocation.findOneAndUpdate({ _id: userId }, { $set: updateData }, { new: true }) } - + if (!response) { throw new Error('Something went wrong during saving the location...') } @@ -98,13 +107,22 @@ const mapLocationsController = function (MapLocation) { _id: response._id, type: userType } - + res.status(200).send(newData); } catch (err) { console.log(err.message) res.status(500).json({ message: err.message || 'Something went wrong...' }); } }; + + function calculateTotalHours(hoursByCategory) { + let hours = 0; + Object.keys(hoursByCategory).forEach((x) => { + hours += hoursByCategory[x]; + }); + return hours; + } + return { getAllLocations, deleteLocation, diff --git a/src/models/mapLocation.js b/src/models/mapLocation.js index 65415239f..851587dc3 100644 --- a/src/models/mapLocation.js +++ b/src/models/mapLocation.js @@ -3,18 +3,13 @@ const mongoose = require('mongoose'); const { Schema } = mongoose; const mapLocation = new Schema({ - firstName: { + title: { type: String, - default: 'Prior to HGN Data Collection', - }, - lastName: { - type: String, - default: 'Prior to HGN Data Collection', - }, - jobTitle: { - type: String, - default: 'Prior to HGN Data Collection', + default: 'Prior to HGN Data Collection' }, + firstName: String, + lastName: String, + jobTitle: String, isActive: { type: Boolean, default: false, From 37942f92fa5b215e3d6cead862b455cfc2384087 Mon Sep 17 00:00:00 2001 From: leonzh2k Date: Thu, 6 Jul 2023 17:55:26 -0400 Subject: [PATCH 098/272] add new fields to send in UserProfileController Add jobTitle and location fields to the userProfile objects that are sent back to the client when requesting all userProfiles. These two bits of info are displayed on the interactive map. --- src/controllers/userProfileController.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 6dc571b39..b9b3bb8a0 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -57,9 +57,15 @@ const userProfileController = function (UserProfile) { return; } + if (cache.getCache('allusers')) { + const getData = JSON.parse(cache.getCache('allusers')); + res.status(200).send(getData); + 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, From f63e1e8c19ebef62acfd09d63510911fe32eec4e Mon Sep 17 00:00:00 2001 From: xaanders Date: Thu, 14 Sep 2023 16:40:41 -0400 Subject: [PATCH 099/272] feat: adding location object to user profile schema --- src/models/userProfile.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/models/userProfile.js b/src/models/userProfile.js index a58d1d293..fc0787e57 100644 --- a/src/models/userProfile.js +++ b/src/models/userProfile.js @@ -7,7 +7,7 @@ const bcrypt = require('bcryptjs'); const SALT_ROUNDS = 10; const nextDay = new Date(); -nextDay.setDate(nextDay.getDate()+1); +nextDay.setDate(nextDay.getDate() + 1); const userProfileSchema = new Schema({ password: { @@ -81,7 +81,16 @@ const userProfileSchema = new Schema({ infringements: [ { date: { type: String, required: true }, description: { type: String, required: true } }, ], - location: { type: String, default: '' }, + location: { + userProvided: { type: String, default: '' }, + coords: { + lat: { type: Number, default: '' }, + lng: { type: Number, default: '' }, + }, + country: { type: String, default: '' }, + city: { type: String, default: '' } + + }, oldInfringements: [ { date: { type: String, required: true }, description: { type: String, required: true } }, ], @@ -157,9 +166,9 @@ const userProfileSchema = new Schema({ teamCode: { type: String, default: '' }, infoCollections: [ { - areaName: { type: String }, + areaName: { type: String }, areaContent: { type: String }, - }], + }], }); userProfileSchema.pre('save', function (next) { From 61a4357cc1704455f26e8d4db1a475c06fb240a1 Mon Sep 17 00:00:00 2001 From: xaanders Date: Sat, 16 Sep 2023 12:02:02 -0400 Subject: [PATCH 100/272] fix: editing email message after new user creating --- src/controllers/profileInitialSetupController.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/profileInitialSetupController.js b/src/controllers/profileInitialSetupController.js index 18cf7376c..b4230f1a4 100644 --- a/src/controllers/profileInitialSetupController.js +++ b/src/controllers/profileInitialSetupController.js @@ -67,7 +67,7 @@ function informManagerMessage(user) {
- +
First Name:Job Title: ${user.jobTitle}
Weekly Commited Hours:${user.weeklycommittedHours}
Time Zone: ${user.timeZone}
Location:${user.location}${user.location.userProvided}, ${user.location.country}

From 2e4a2afe95deb0a8cc75dc731baf45836a1a9a3d Mon Sep 17 00:00:00 2001 From: xaanders Date: Fri, 22 Sep 2023 19:58:43 -0400 Subject: [PATCH 101/272] feat: adding a initial functionality for adding new people to the map(maplocation controller, maplocation router, maplocation model) --- src/controllers/mapLocationsController.js | 69 +++++++++++++++++++++++ src/models/mapLocation.js | 42 ++++++++++++++ src/routes/mapLocationsRouter.js | 18 ++++++ src/startup/routes.js | 4 ++ 4 files changed, 133 insertions(+) create mode 100644 src/controllers/mapLocationsController.js create mode 100644 src/models/mapLocation.js create mode 100644 src/routes/mapLocationsRouter.js diff --git a/src/controllers/mapLocationsController.js b/src/controllers/mapLocationsController.js new file mode 100644 index 000000000..83526998d --- /dev/null +++ b/src/controllers/mapLocationsController.js @@ -0,0 +1,69 @@ +const mongoose = require('mongoose'); +const mapLocation = require('../models/mapLocation'); +const { hasPermission } = require('../utilities/permissions'); + +const mapLocationsController = function () { + const getAllLocations = function (req, res) { + console.log('controller:') + console.log(req.body) + + mapLocation.find({}) + .then(results => res.send(results).status(200)) + .catch(error => res.send(error).status(404)); + }; + const deleteLocation = async function (req, res) { + if (!await hasPermission(req.body.requestor.role, 'deleteTeam')) { + res.status(403).send({ error: 'You are not authorized to delete teams.' }); + return; + } + const { teamId } = req.params; + Team.findById(teamId, (error, record) => { + if (error || record === null) { + res.status(400).send({ error: 'No valid records found' }); + return; + } + const removeteamfromprofile = userProfile.updateMany({}, { $pull: { teams: record._id } }).exec(); + const deleteteam = record.remove(); + + Promise.all([removeteamfromprofile, deleteteam]) + .then(res.status(200).send({ message: ' Team successfully deleted and user profiles updated' })) + .catch((errors) => { + res.status(400).send(errors); + }); + }).catch((error) => { + res.status(400).send(error); + }); + }; + const putUserLocation = async function (req, res) { + if (!await hasPermission(req.body.requestor.role, 'putTeam')) { + res.status(403).send('You are not authorized to make changes in the teams.'); + return; + } + + const { teamId } = req.params; + + Team.findById(teamId, (error, record) => { + if (error || record === null) { + res.status(400).send('No valid records found'); + return; + } + record.teamName = req.body.teamName; + record.isActive = req.body.isActive; + record.createdDatetime = Date.now(); + record.modifiedDatetime = Date.now(); + + record + .save() + .then(results => res.status(201).send(results._id)) + .catch(errors => res.status(400).send(errors)); + }); + }; + + return { + getAllLocations, + deleteLocation, + putUserLocation + }; +}; + +module.exports = mapLocationsController; diff --git a/src/models/mapLocation.js b/src/models/mapLocation.js new file mode 100644 index 000000000..d7b9d82b5 --- /dev/null +++ b/src/models/mapLocation.js @@ -0,0 +1,42 @@ +const mongoose = require('mongoose'); + +const { Schema } = mongoose; + +const mapLocation = new Schema({ + firstName: { + type: String, + default: 'Prior to HGN Data Collection', + }, + lastName: { + type: String, + default: 'Prior to HGN Data Collection', + }, + title: { + type: String, + default: 'Prior to HGN Data Collection', + }, + userProvided: { + type: String, + required: true, + }, + coords: { + lat: { + type: String, + required: true, + }, + lng: { + type: String, + required: true, + } + }, + country: { + type: String, + required: true, + }, + city: { + type: String, + default: '', + } +}); + +module.exports = mongoose.model('MapLocation', mapLocation, 'maplocations'); diff --git a/src/routes/mapLocationsRouter.js b/src/routes/mapLocationsRouter.js new file mode 100644 index 000000000..e2e780dac --- /dev/null +++ b/src/routes/mapLocationsRouter.js @@ -0,0 +1,18 @@ +const express = require('express'); + +const router = function (mapLocations) { + const controller = require('../controllers/mapLocationsController')(mapLocations); + + const mapRouter = express.Router(); + + mapRouter.route('/mapLocations') + .get(controller.getAllLocations) + .put(controller.putUserLocation); + + mapRouter.route('/mapLocations/:locationId') + .delete(controller.deleteLocation) + + return mapRouter; +}; + +module.exports = router; diff --git a/src/startup/routes.js b/src/startup/routes.js index eae746e24..0f4c7308c 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -21,6 +21,7 @@ const profileInitialSetuptoken = require('../models/profileInitialSetupToken'); const reason = require('../models/reason'); const mouseoverText = require('../models/mouseoverText'); const inventoryItemMaterial = require('../models/inventoryItemMaterial'); +const mapLocations = require('../models/mapLocation'); const userProfileRouter = require('../routes/userProfileRouter')(userProfile); const badgeRouter = require('../routes/badgeRouter')(badge); @@ -56,6 +57,8 @@ const ownerStandardMessageRouter = require('../routes/ownerStandardMessageRouter const reasonRouter = require('../routes/reasonRouter')(reason, userProfile); const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverText); +const mapLocationRouter = require('../routes/mapLocationsRouter')(mapLocations); + // bm dashboard const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial); @@ -90,6 +93,7 @@ module.exports = function (app) { app.use('/api', informationRouter); app.use('/api', mouseoverTextRouter); app.use('/api', isEmailExistsRouter); + app.use('/api', mapLocationRouter); // bm dashboard app.use('/api/bm', bmLoginRouter); app.use('/api/bm', bmMaterialsRouter); From fb1841d56ccc85322ba724465a7e3ab4f889d315 Mon Sep 17 00:00:00 2001 From: Oleksandr Riazantsev Date: Mon, 2 Oct 2023 16:13:42 -0400 Subject: [PATCH 102/272] fix: jobTitle model key, feat: adding isActive status, getting all locations, put new location to a collection --- src/controllers/mapLocationsController.js | 72 +++++++++-------------- src/models/mapLocation.js | 38 +++++++----- 2 files changed, 49 insertions(+), 61 deletions(-) diff --git a/src/controllers/mapLocationsController.js b/src/controllers/mapLocationsController.js index 83526998d..6088de489 100644 --- a/src/controllers/mapLocationsController.js +++ b/src/controllers/mapLocationsController.js @@ -1,62 +1,44 @@ -const mongoose = require('mongoose'); -const mapLocation = require('../models/mapLocation'); -const { hasPermission } = require('../utilities/permissions'); - -const mapLocationsController = function () { +const mapLocationsController = function (mapLocation) { const getAllLocations = function (req, res) { - console.log('controller:') - console.log(req.body) mapLocation.find({}) - .then(results => res.send(results).status(200)) - .catch(error => res.send(error).status(404)); + .then(results => + res.send(results).status(200) + ) + .catch(error => + res.send(error).status(404)); }; const deleteLocation = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'deleteTeam')) { - res.status(403).send({ error: 'You are not authorized to delete teams.' }); + + if (!req.body.requestor.role === 'Administrator' || !req.body.requestor.role === 'Owner') { + res.status(403).send('You are not authorized to make changes in the teams.'); return; } - const { teamId } = req.params; - Team.findById(teamId, (error, record) => { - if (error || record === null) { - res.status(400).send({ error: 'No valid records found' }); - return; - } - const removeteamfromprofile = userProfile.updateMany({}, { $pull: { teams: record._id } }).exec(); - const deleteteam = record.remove(); - - Promise.all([removeteamfromprofile, deleteteam]) - .then(res.status(200).send({ message: ' Team successfully deleted and user profiles updated' })) - .catch((errors) => { - res.status(400).send(errors); - }); - }).catch((error) => { - res.status(400).send(error); - }); }; const putUserLocation = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'putTeam')) { + + if (!req.body.requestor.role === 'Administrator' || !req.body.requestor.role === 'Owner') { res.status(403).send('You are not authorized to make changes in the teams.'); return; } + const locationData = { + firstName: req.body.firstName, + lastName: req.body.lastName, + jobTitle: req.body.jobTitle, + location: req.body.location, + } + const location = new mapLocation(locationData); - const { teamId } = req.params; - - Team.findById(teamId, (error, record) => { - if (error || record === null) { - res.status(400).send('No valid records found'); - return; + try { + const response = await location.save() + if(!response) { + throw new Error('Something went wrong during saving the location...') } - record.teamName = req.body.teamName; - record.isActive = req.body.isActive; - record.createdDatetime = Date.now(); - record.modifiedDatetime = Date.now(); - - record - .save() - .then(results => res.status(201).send(results._id)) - .catch(errors => res.status(400).send(errors)); - }); + res.status(200).send(response); + } catch (err) { + console.log(err.message) + res.status(500).json({message: err.message || 'Something went wrong...'}); + } }; return { diff --git a/src/models/mapLocation.js b/src/models/mapLocation.js index d7b9d82b5..65415239f 100644 --- a/src/models/mapLocation.js +++ b/src/models/mapLocation.js @@ -11,32 +11,38 @@ const mapLocation = new Schema({ type: String, default: 'Prior to HGN Data Collection', }, - title: { + jobTitle: { type: String, default: 'Prior to HGN Data Collection', }, - userProvided: { - type: String, - required: true, + isActive: { + type: Boolean, + default: false, }, - coords: { - lat: { + location: { + userProvided: { type: String, required: true, }, - lng: { + coords: { + lat: { + type: String, + required: true, + }, + lng: { + type: String, + required: true, + } + }, + country: { type: String, required: true, - } - }, - country: { - type: String, - required: true, + }, + city: { + type: String, + default: '', + }, }, - city: { - type: String, - default: '', - } }); module.exports = mongoose.model('MapLocation', mapLocation, 'maplocations'); From f2a6e41f321eb7e16aa9e75fc1d2f51039ab9adc Mon Sep 17 00:00:00 2001 From: Oleksandr Riazantsev Date: Sun, 15 Oct 2023 12:06:40 -0400 Subject: [PATCH 103/272] feat: userprofiles sending totalTangibleHrs, update user controller, all manually locations response structure --- src/controllers/mapLocationsController.js | 85 ++++++++++++++++++++--- src/routes/mapLocationsRouter.js | 3 +- 2 files changed, 77 insertions(+), 11 deletions(-) diff --git a/src/controllers/mapLocationsController.js b/src/controllers/mapLocationsController.js index 6088de489..f01666558 100644 --- a/src/controllers/mapLocationsController.js +++ b/src/controllers/mapLocationsController.js @@ -1,11 +1,26 @@ -const mapLocationsController = function (mapLocation) { +const userProfile = require('../models/userProfile'); +const cache = require('../utilities/nodeCache')(); + +const mapLocationsController = function (MapLocation) { const getAllLocations = function (req, res) { + const priorText = 'Prior to HGN Data Collection'; + MapLocation.find({}) + .then(results => { + const users = results.map(item => { + return ({ + title: priorText, + firstName: item.firstName !== priorText ? item.firstName : '', + lastName: item.lastName !== priorText ? item.lastName : '', + jobTitle: item.jobTitle !== priorText ? item.jobTitle : '', + location: item.location, + isActive: item.isActive, + _id: item._id + }) + }) + res.send(users).status(200); - mapLocation.find({}) - .then(results => - res.send(results).status(200) - ) - .catch(error => + }) + .catch(error => res.send(error).status(404)); }; const deleteLocation = async function (req, res) { @@ -14,6 +29,11 @@ const mapLocationsController = function (mapLocation) { res.status(403).send('You are not authorized to make changes in the teams.'); return; } + const locationId = req.params.locationId + + MapLocation.findOneAndDelete({ _id: locationId }) + .then(() => res.status(200).send({ message: "The location was successfully removed!" })) + .catch(error => res.status(500).send({ message: error || "Couldn't remove the location" })); }; const putUserLocation = async function (req, res) { @@ -27,24 +47,69 @@ const mapLocationsController = function (mapLocation) { jobTitle: req.body.jobTitle, location: req.body.location, } - const location = new mapLocation(locationData); + const location = new MapLocation(locationData); try { const response = await location.save() - if(!response) { + if (!response) { throw new Error('Something went wrong during saving the location...') } res.status(200).send(response); } catch (err) { console.log(err.message) - res.status(500).json({message: err.message || 'Something went wrong...'}); + res.status(500).json({ message: err.message || 'Something went wrong...' }); } }; + const updateUserLocation = async function (req, res) { + console.log(req.body) + if (!req.body.requestor.role === 'Administrator' || !req.body.requestor.role === 'Owner') { + res.status(403).send('You are not authorized to make changes in the teams.'); + return; + } + const userType = req.body.type; + const userId= req.body._id; + const updateData = { + firstName: req.body.firstName, + lastName: req.body.lastName, + jobTitle: req.body.jobTitle, + location: req.body.location, + _id: req.body._id + } + try { + let response; + if(userType === 'user') { + response = await userProfile.findOneAndUpdate({ _id: userId }, {$set: {...updateData, jobTitle: [updateData.jobTitle]}}, { new: true }); + cache.removeCache('allusers') + cache.removeCache(`user-${userId}`); + cache.setCache(`user-${userId}`, JSON.stringify(response)); + } else { + response = await MapLocation.findOneAndUpdate({ _id: userId }, {$set: updateData}, { new: true }) + } + + if (!response) { + throw new Error('Something went wrong during saving the location...') + } + const newData = { + firstName: response.firstName, + lastName: response.lastName, + jobTitle: response.jobTitle, + location: response.location, + _id: response._id, + type: userType + } + + res.status(200).send(newData); + } catch (err) { + console.log(err.message) + res.status(500).json({ message: err.message || 'Something went wrong...' }); + } + }; return { getAllLocations, deleteLocation, - putUserLocation + putUserLocation, + updateUserLocation }; }; diff --git a/src/routes/mapLocationsRouter.js b/src/routes/mapLocationsRouter.js index e2e780dac..db004ff18 100644 --- a/src/routes/mapLocationsRouter.js +++ b/src/routes/mapLocationsRouter.js @@ -7,7 +7,8 @@ const router = function (mapLocations) { mapRouter.route('/mapLocations') .get(controller.getAllLocations) - .put(controller.putUserLocation); + .put(controller.putUserLocation) + .patch(controller.updateUserLocation); mapRouter.route('/mapLocations/:locationId') .delete(controller.deleteLocation) From f556211d1ed6d46711eda0b89ef1d603d0ee0731 Mon Sep 17 00:00:00 2001 From: Oleksandr Riazantsev Date: Wed, 1 Nov 2023 12:58:36 -0400 Subject: [PATCH 104/272] fix: moving part of logic from the frontend, bug fixes feat: updating timezone --- src/controllers/mapLocationsController.js | 88 ++++++++++++++--------- src/models/mapLocation.js | 15 ++-- 2 files changed, 58 insertions(+), 45 deletions(-) diff --git a/src/controllers/mapLocationsController.js b/src/controllers/mapLocationsController.js index f01666558..9fa214080 100644 --- a/src/controllers/mapLocationsController.js +++ b/src/controllers/mapLocationsController.js @@ -1,27 +1,32 @@ -const userProfile = require('../models/userProfile'); +const UserProfile = require('../models/userProfile'); const cache = require('../utilities/nodeCache')(); + const mapLocationsController = function (MapLocation) { - const getAllLocations = function (req, res) { - const priorText = 'Prior to HGN Data Collection'; - MapLocation.find({}) - .then(results => { - const users = results.map(item => { - return ({ - title: priorText, - firstName: item.firstName !== priorText ? item.firstName : '', - lastName: item.lastName !== priorText ? item.lastName : '', - jobTitle: item.jobTitle !== priorText ? item.jobTitle : '', - location: item.location, - isActive: item.isActive, - _id: item._id - }) - }) - res.send(users).status(200); - - }) - .catch(error => - res.send(error).status(404)); + const getAllLocations = async function (req, res) { + + try { + const users = []; + const results = await UserProfile.find({}, + '_id firstName lastName isActive location jobTitle totalTangibleHrs hoursByCategory' + ); + + results.forEach((item) => { + if ( + (item.location?.coords.lat && item.location?.coords.lng && item.totalTangibleHrs >= 10) || + (item.location?.coords.lat && item.location?.coords.lng && calculateTotalHours(item.hoursByCategory) >= 10) + ) { + users.push(item); + } + }); + + const m_users = await MapLocation.find({}); + + res.status(200).send({ users, m_users }); + } catch (err) { + res.status(404).send(err); + } + }; const deleteLocation = async function (req, res) { @@ -37,7 +42,7 @@ const mapLocationsController = function (MapLocation) { }; const putUserLocation = async function (req, res) { - if (!req.body.requestor.role === 'Administrator' || !req.body.requestor.role === 'Owner') { + if (!req.body.requestor.role === 'Owner') { res.status(403).send('You are not authorized to make changes in the teams.'); return; } @@ -61,32 +66,36 @@ const mapLocationsController = function (MapLocation) { } }; const updateUserLocation = async function (req, res) { - console.log(req.body) - if (!req.body.requestor.role === 'Administrator' || !req.body.requestor.role === 'Owner') { + if (!req.body.requestor.role === 'Owner') { res.status(403).send('You are not authorized to make changes in the teams.'); return; } const userType = req.body.type; - const userId= req.body._id; + const userId = req.body._id; const updateData = { - firstName: req.body.firstName, - lastName: req.body.lastName, - jobTitle: req.body.jobTitle, - location: req.body.location, - _id: req.body._id + firstName: req.body.firstName, + lastName: req.body.lastName, + jobTitle: req.body.jobTitle, + location: req.body.location, + } + + if (req.body.timeZone) { + updateData.timeZone = req.body.timeZone } try { let response; - if(userType === 'user') { - response = await userProfile.findOneAndUpdate({ _id: userId }, {$set: {...updateData, jobTitle: [updateData.jobTitle]}}, { new: true }); + if (userType === 'user') { + console.log('updateData----', updateData); + response = await UserProfile.findOneAndUpdate({ _id: userId }, { $set: { ...updateData, jobTitle: [updateData.jobTitle] } }, { new: true }); cache.removeCache('allusers') cache.removeCache(`user-${userId}`); + cache.setCache(`user-${userId}`, JSON.stringify(response)); } else { - response = await MapLocation.findOneAndUpdate({ _id: userId }, {$set: updateData}, { new: true }) + response = await MapLocation.findOneAndUpdate({ _id: userId }, { $set: updateData }, { new: true }) } - + if (!response) { throw new Error('Something went wrong during saving the location...') } @@ -98,13 +107,22 @@ const mapLocationsController = function (MapLocation) { _id: response._id, type: userType } - + res.status(200).send(newData); } catch (err) { console.log(err.message) res.status(500).json({ message: err.message || 'Something went wrong...' }); } }; + + function calculateTotalHours(hoursByCategory) { + let hours = 0; + Object.keys(hoursByCategory).forEach((x) => { + hours += hoursByCategory[x]; + }); + return hours; + } + return { getAllLocations, deleteLocation, diff --git a/src/models/mapLocation.js b/src/models/mapLocation.js index 65415239f..851587dc3 100644 --- a/src/models/mapLocation.js +++ b/src/models/mapLocation.js @@ -3,18 +3,13 @@ const mongoose = require('mongoose'); const { Schema } = mongoose; const mapLocation = new Schema({ - firstName: { + title: { type: String, - default: 'Prior to HGN Data Collection', - }, - lastName: { - type: String, - default: 'Prior to HGN Data Collection', - }, - jobTitle: { - type: String, - default: 'Prior to HGN Data Collection', + default: 'Prior to HGN Data Collection' }, + firstName: String, + lastName: String, + jobTitle: String, isActive: { type: Boolean, default: false, From 883a00b2107ccf81441b78b6122f54f6dd61c3b0 Mon Sep 17 00:00:00 2001 From: Oleksandr Riazantsev Date: Thu, 2 Nov 2023 10:21:10 -0400 Subject: [PATCH 105/272] fix: modifying users before sent --- src/controllers/mapLocationsController.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/controllers/mapLocationsController.js b/src/controllers/mapLocationsController.js index 9fa214080..c9edd53b8 100644 --- a/src/controllers/mapLocationsController.js +++ b/src/controllers/mapLocationsController.js @@ -19,10 +19,17 @@ const mapLocationsController = function (MapLocation) { users.push(item); } }); - - const m_users = await MapLocation.find({}); - - res.status(200).send({ users, m_users }); + const modifiedUsers = users.map(item => ({ + location: item.location, + isActive: item.isActive, + jobTitle: item.jobTitle[0], + _id: item._id, + firstName: item.firstName, + lastName: item.lastName + })); + + const mUsers = await MapLocation.find({}); + res.status(200).send({ users: modifiedUsers, mUsers }); } catch (err) { res.status(404).send(err); } @@ -86,7 +93,6 @@ const mapLocationsController = function (MapLocation) { try { let response; if (userType === 'user') { - console.log('updateData----', updateData); response = await UserProfile.findOneAndUpdate({ _id: userId }, { $set: { ...updateData, jobTitle: [updateData.jobTitle] } }, { new: true }); cache.removeCache('allusers') cache.removeCache(`user-${userId}`); From e5380d28843c933ce203902b30da1bde6f8d53a9 Mon Sep 17 00:00:00 2001 From: leonzh2k Date: Thu, 6 Jul 2023 17:55:26 -0400 Subject: [PATCH 106/272] add new fields to send in UserProfileController Add jobTitle and location fields to the userProfile objects that are sent back to the client when requesting all userProfiles. These two bits of info are displayed on the interactive map. --- src/controllers/userProfileController.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index b9b3bb8a0..b0ff9eeee 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -65,7 +65,7 @@ const userProfileController = function (UserProfile) { UserProfile.find( {}, - '_id firstName lastName role weeklycommittedHours email permissions isActive reactivationDate createdDate endDate', + '_id firstName lastName role weeklycommittedHours email permissions isActive reactivationDate createdDate endDate location jobTitle', ) .sort({ lastName: 1, From 632ef2007b53650b57d3ff6e06e694d6be8a7879 Mon Sep 17 00:00:00 2001 From: Oleksandr Riazantsev Date: Sun, 15 Oct 2023 12:06:40 -0400 Subject: [PATCH 107/272] feat: userprofiles sending totalTangibleHrs, update user controller, all manually locations response structure --- src/controllers/mapLocationsController.js | 29 +++++++++++++++++++++++ src/controllers/userProfileController.js | 2 +- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/controllers/mapLocationsController.js b/src/controllers/mapLocationsController.js index c9edd53b8..97ae88b09 100644 --- a/src/controllers/mapLocationsController.js +++ b/src/controllers/mapLocationsController.js @@ -129,6 +129,35 @@ const mapLocationsController = function (MapLocation) { return hours; } + try { + let response; + if(userType === 'user') { + response = await userProfile.findOneAndUpdate({ _id: userId }, {$set: {...updateData, jobTitle: [updateData.jobTitle]}}, { new: true }); + cache.removeCache('allusers') + cache.removeCache(`user-${userId}`); + cache.setCache(`user-${userId}`, JSON.stringify(response)); + } else { + response = await MapLocation.findOneAndUpdate({ _id: userId }, {$set: updateData}, { new: true }) + } + + if (!response) { + throw new Error('Something went wrong during saving the location...') + } + const newData = { + firstName: response.firstName, + lastName: response.lastName, + jobTitle: response.jobTitle, + location: response.location, + _id: response._id, + type: userType + } + + res.status(200).send(newData); + } catch (err) { + console.log(err.message) + res.status(500).json({ message: err.message || 'Something went wrong...' }); + } + }; return { getAllLocations, deleteLocation, diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index b0ff9eeee..d91b08739 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -65,7 +65,7 @@ const userProfileController = function (UserProfile) { UserProfile.find( {}, - '_id firstName lastName role weeklycommittedHours email permissions isActive reactivationDate createdDate endDate location jobTitle', + '_id firstName lastName role weeklycommittedHours email permissions isActive reactivationDate createdDate endDate location jobTitle totalTangibleHrs', ) .sort({ lastName: 1, From f7b7d125361fe3e910b3cf6e45aea1c3a315f558 Mon Sep 17 00:00:00 2001 From: Oleksandr Riazantsev Date: Wed, 1 Nov 2023 12:58:36 -0400 Subject: [PATCH 108/272] fix: moving part of logic from the frontend, bug fixes feat: updating timezone --- src/controllers/mapLocationsController.js | 31 +---------------------- 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/src/controllers/mapLocationsController.js b/src/controllers/mapLocationsController.js index 97ae88b09..29af9e3d6 100644 --- a/src/controllers/mapLocationsController.js +++ b/src/controllers/mapLocationsController.js @@ -128,36 +128,7 @@ const mapLocationsController = function (MapLocation) { }); return hours; } - - try { - let response; - if(userType === 'user') { - response = await userProfile.findOneAndUpdate({ _id: userId }, {$set: {...updateData, jobTitle: [updateData.jobTitle]}}, { new: true }); - cache.removeCache('allusers') - cache.removeCache(`user-${userId}`); - cache.setCache(`user-${userId}`, JSON.stringify(response)); - } else { - response = await MapLocation.findOneAndUpdate({ _id: userId }, {$set: updateData}, { new: true }) - } - - if (!response) { - throw new Error('Something went wrong during saving the location...') - } - const newData = { - firstName: response.firstName, - lastName: response.lastName, - jobTitle: response.jobTitle, - location: response.location, - _id: response._id, - type: userType - } - - res.status(200).send(newData); - } catch (err) { - console.log(err.message) - res.status(500).json({ message: err.message || 'Something went wrong...' }); - } - }; + return { getAllLocations, deleteLocation, From e7f23406597cc7ef13df73ea490d32f31d8d0e4b Mon Sep 17 00:00:00 2001 From: Oleksandr Riazantsev Date: Thu, 2 Nov 2023 13:10:56 -0400 Subject: [PATCH 109/272] rebasing and resolving conflicts --- src/controllers/userProfileController.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index d91b08739..6dc571b39 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -57,15 +57,9 @@ const userProfileController = function (UserProfile) { return; } - if (cache.getCache('allusers')) { - const getData = JSON.parse(cache.getCache('allusers')); - res.status(200).send(getData); - return; - } - UserProfile.find( {}, - '_id firstName lastName role weeklycommittedHours email permissions isActive reactivationDate createdDate endDate location jobTitle totalTangibleHrs', + "_id firstName lastName role weeklycommittedHours email permissions isActive reactivationDate createdDate endDate" ) .sort({ lastName: 1, From 26e5f806ddc67af1d8dafdbe684fe6c4ee080ecf Mon Sep 17 00:00:00 2001 From: Vishala Ramasamy Date: Thu, 2 Nov 2023 11:30:39 -0700 Subject: [PATCH 110/272] update material 1 api --- .../bmdashboard/bmMaterialsController.js | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index 09fa91ab8..54ec65967 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -44,23 +44,30 @@ const bmMaterialsController = function (ItemMaterial) { }; const bmPostMaterialUpdateRecord = function (req, res) { - console.log(req.body); - ItemMaterial.update( + + let quantityUsed = +req.body.quantityUsed; + let quantityWasted = +req.body.quantityWasted; + let material = req.body.material; + if(req.body.QtyUsedLogUnit=='percent' && quantityWasted>=0) + { + quantityUsed = (+quantityUsed / 100) * material.stockAvailable; + } + if(req.body.QtyWastedLogUnit=='percent' && quantityUsed>=0) + { + quantityWasted = (+quantityWasted / 100) * material.stockAvailable; + } + + ItemMaterial.updateOne( { _id: req.body.material._id }, { - $push: { - updateRecord: { - date: req.body.date, - createdBy: req.body.requestor.requestorId, - action: req.body.action, - cause: req.body.cause, - quantity: req.body.quantity, - description: req.body.description, - }, - }, - }, + $inc: { + 'stockUsed': quantityUsed, + 'stockWasted': quantityWasted, + 'stockAvailable': -(quantityUsed+quantityWasted) + } + } ) - .then(results => res.status(200).send(results)) + .then(results => {res.status(200).send(results)}) .catch(error => res.status(500).send(error)); }; return { From b9e28592e96eb5378ff5e071783f0926e4e46e7d Mon Sep 17 00:00:00 2001 From: leonzh2k Date: Thu, 6 Jul 2023 17:55:26 -0400 Subject: [PATCH 111/272] add new fields to send in UserProfileController Add jobTitle and location fields to the userProfile objects that are sent back to the client when requesting all userProfiles. These two bits of info are displayed on the interactive map. --- src/controllers/userProfileController.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 737b1bc6a..70d774042 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -57,9 +57,15 @@ const userProfileController = function (UserProfile) { return; } + if (cache.getCache('allusers')) { + const getData = JSON.parse(cache.getCache('allusers')); + res.status(200).send(getData); + 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, From c2d332fd937967793017f315f6363ab89fcc89ef Mon Sep 17 00:00:00 2001 From: xaanders Date: Thu, 14 Sep 2023 16:40:41 -0400 Subject: [PATCH 112/272] feat: adding location object to user profile schema --- src/models/userProfile.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/models/userProfile.js b/src/models/userProfile.js index 4739a05e7..a5bb3bfa3 100644 --- a/src/models/userProfile.js +++ b/src/models/userProfile.js @@ -81,7 +81,16 @@ const userProfileSchema = new Schema({ infringements: [ { date: { type: String, required: true }, description: { type: String, required: true } }, ], - location: { type: String, default: '' }, + location: { + userProvided: { type: String, default: '' }, + coords: { + lat: { type: Number, default: '' }, + lng: { type: Number, default: '' }, + }, + country: { type: String, default: '' }, + city: { type: String, default: '' } + + }, oldInfringements: [ { date: { type: String, required: true }, description: { type: String, required: true } }, ], @@ -168,9 +177,9 @@ const userProfileSchema = new Schema({ }, infoCollections: [ { - areaName: { type: String }, + areaName: { type: String }, areaContent: { type: String }, - }], + }], }); userProfileSchema.pre('save', function (next) { From 3d5e4546ce199508f2ab7f1989d25ddd8c4bcaf2 Mon Sep 17 00:00:00 2001 From: xaanders Date: Sat, 16 Sep 2023 12:02:02 -0400 Subject: [PATCH 113/272] fix: editing email message after new user creating --- src/controllers/profileInitialSetupController.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/profileInitialSetupController.js b/src/controllers/profileInitialSetupController.js index 18cf7376c..b4230f1a4 100644 --- a/src/controllers/profileInitialSetupController.js +++ b/src/controllers/profileInitialSetupController.js @@ -67,7 +67,7 @@ function informManagerMessage(user) { Location: - ${user.location} + ${user.location.userProvided}, ${user.location.country}
From 35662d57c7f729203b6b2ecfa17ce35af4e11a58 Mon Sep 17 00:00:00 2001 From: xaanders Date: Fri, 22 Sep 2023 19:58:43 -0400 Subject: [PATCH 114/272] feat: adding a initial functionality for adding new people to the map(maplocation controller, maplocation router, maplocation model) --- src/controllers/mapLocationsController.js | 69 +++++++++++++++++++++++ src/models/mapLocation.js | 42 ++++++++++++++ src/routes/mapLocationsRouter.js | 18 ++++++ src/startup/routes.js | 4 ++ 4 files changed, 133 insertions(+) create mode 100644 src/controllers/mapLocationsController.js create mode 100644 src/models/mapLocation.js create mode 100644 src/routes/mapLocationsRouter.js diff --git a/src/controllers/mapLocationsController.js b/src/controllers/mapLocationsController.js new file mode 100644 index 000000000..83526998d --- /dev/null +++ b/src/controllers/mapLocationsController.js @@ -0,0 +1,69 @@ +const mongoose = require('mongoose'); +const mapLocation = require('../models/mapLocation'); +const { hasPermission } = require('../utilities/permissions'); + +const mapLocationsController = function () { + const getAllLocations = function (req, res) { + console.log('controller:') + console.log(req.body) + + mapLocation.find({}) + .then(results => res.send(results).status(200)) + .catch(error => res.send(error).status(404)); + }; + const deleteLocation = async function (req, res) { + if (!await hasPermission(req.body.requestor.role, 'deleteTeam')) { + res.status(403).send({ error: 'You are not authorized to delete teams.' }); + return; + } + const { teamId } = req.params; + Team.findById(teamId, (error, record) => { + if (error || record === null) { + res.status(400).send({ error: 'No valid records found' }); + return; + } + const removeteamfromprofile = userProfile.updateMany({}, { $pull: { teams: record._id } }).exec(); + const deleteteam = record.remove(); + + Promise.all([removeteamfromprofile, deleteteam]) + .then(res.status(200).send({ message: ' Team successfully deleted and user profiles updated' })) + .catch((errors) => { + res.status(400).send(errors); + }); + }).catch((error) => { + res.status(400).send(error); + }); + }; + const putUserLocation = async function (req, res) { + if (!await hasPermission(req.body.requestor.role, 'putTeam')) { + res.status(403).send('You are not authorized to make changes in the teams.'); + return; + } + + const { teamId } = req.params; + + Team.findById(teamId, (error, record) => { + if (error || record === null) { + res.status(400).send('No valid records found'); + return; + } + record.teamName = req.body.teamName; + record.isActive = req.body.isActive; + record.createdDatetime = Date.now(); + record.modifiedDatetime = Date.now(); + + record + .save() + .then(results => res.status(201).send(results._id)) + .catch(errors => res.status(400).send(errors)); + }); + }; + + return { + getAllLocations, + deleteLocation, + putUserLocation + }; +}; + +module.exports = mapLocationsController; diff --git a/src/models/mapLocation.js b/src/models/mapLocation.js new file mode 100644 index 000000000..d7b9d82b5 --- /dev/null +++ b/src/models/mapLocation.js @@ -0,0 +1,42 @@ +const mongoose = require('mongoose'); + +const { Schema } = mongoose; + +const mapLocation = new Schema({ + firstName: { + type: String, + default: 'Prior to HGN Data Collection', + }, + lastName: { + type: String, + default: 'Prior to HGN Data Collection', + }, + title: { + type: String, + default: 'Prior to HGN Data Collection', + }, + userProvided: { + type: String, + required: true, + }, + coords: { + lat: { + type: String, + required: true, + }, + lng: { + type: String, + required: true, + } + }, + country: { + type: String, + required: true, + }, + city: { + type: String, + default: '', + } +}); + +module.exports = mongoose.model('MapLocation', mapLocation, 'maplocations'); diff --git a/src/routes/mapLocationsRouter.js b/src/routes/mapLocationsRouter.js new file mode 100644 index 000000000..e2e780dac --- /dev/null +++ b/src/routes/mapLocationsRouter.js @@ -0,0 +1,18 @@ +const express = require('express'); + +const router = function (mapLocations) { + const controller = require('../controllers/mapLocationsController')(mapLocations); + + const mapRouter = express.Router(); + + mapRouter.route('/mapLocations') + .get(controller.getAllLocations) + .put(controller.putUserLocation); + + mapRouter.route('/mapLocations/:locationId') + .delete(controller.deleteLocation) + + return mapRouter; +}; + +module.exports = router; diff --git a/src/startup/routes.js b/src/startup/routes.js index eae746e24..0f4c7308c 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -21,6 +21,7 @@ const profileInitialSetuptoken = require('../models/profileInitialSetupToken'); const reason = require('../models/reason'); const mouseoverText = require('../models/mouseoverText'); const inventoryItemMaterial = require('../models/inventoryItemMaterial'); +const mapLocations = require('../models/mapLocation'); const userProfileRouter = require('../routes/userProfileRouter')(userProfile); const badgeRouter = require('../routes/badgeRouter')(badge); @@ -56,6 +57,8 @@ const ownerStandardMessageRouter = require('../routes/ownerStandardMessageRouter const reasonRouter = require('../routes/reasonRouter')(reason, userProfile); const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverText); +const mapLocationRouter = require('../routes/mapLocationsRouter')(mapLocations); + // bm dashboard const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial); @@ -90,6 +93,7 @@ module.exports = function (app) { app.use('/api', informationRouter); app.use('/api', mouseoverTextRouter); app.use('/api', isEmailExistsRouter); + app.use('/api', mapLocationRouter); // bm dashboard app.use('/api/bm', bmLoginRouter); app.use('/api/bm', bmMaterialsRouter); From 3e76b43ab0737f4e51d6dd34d8f465c28a02c692 Mon Sep 17 00:00:00 2001 From: Oleksandr Riazantsev Date: Mon, 2 Oct 2023 16:13:42 -0400 Subject: [PATCH 115/272] fix: jobTitle model key, feat: adding isActive status, getting all locations, put new location to a collection --- src/controllers/mapLocationsController.js | 72 +++++++++-------------- src/models/mapLocation.js | 38 +++++++----- 2 files changed, 49 insertions(+), 61 deletions(-) diff --git a/src/controllers/mapLocationsController.js b/src/controllers/mapLocationsController.js index 83526998d..6088de489 100644 --- a/src/controllers/mapLocationsController.js +++ b/src/controllers/mapLocationsController.js @@ -1,62 +1,44 @@ -const mongoose = require('mongoose'); -const mapLocation = require('../models/mapLocation'); -const { hasPermission } = require('../utilities/permissions'); - -const mapLocationsController = function () { +const mapLocationsController = function (mapLocation) { const getAllLocations = function (req, res) { - console.log('controller:') - console.log(req.body) mapLocation.find({}) - .then(results => res.send(results).status(200)) - .catch(error => res.send(error).status(404)); + .then(results => + res.send(results).status(200) + ) + .catch(error => + res.send(error).status(404)); }; const deleteLocation = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'deleteTeam')) { - res.status(403).send({ error: 'You are not authorized to delete teams.' }); + + if (!req.body.requestor.role === 'Administrator' || !req.body.requestor.role === 'Owner') { + res.status(403).send('You are not authorized to make changes in the teams.'); return; } - const { teamId } = req.params; - Team.findById(teamId, (error, record) => { - if (error || record === null) { - res.status(400).send({ error: 'No valid records found' }); - return; - } - const removeteamfromprofile = userProfile.updateMany({}, { $pull: { teams: record._id } }).exec(); - const deleteteam = record.remove(); - - Promise.all([removeteamfromprofile, deleteteam]) - .then(res.status(200).send({ message: ' Team successfully deleted and user profiles updated' })) - .catch((errors) => { - res.status(400).send(errors); - }); - }).catch((error) => { - res.status(400).send(error); - }); }; const putUserLocation = async function (req, res) { - if (!await hasPermission(req.body.requestor.role, 'putTeam')) { + + if (!req.body.requestor.role === 'Administrator' || !req.body.requestor.role === 'Owner') { res.status(403).send('You are not authorized to make changes in the teams.'); return; } + const locationData = { + firstName: req.body.firstName, + lastName: req.body.lastName, + jobTitle: req.body.jobTitle, + location: req.body.location, + } + const location = new mapLocation(locationData); - const { teamId } = req.params; - - Team.findById(teamId, (error, record) => { - if (error || record === null) { - res.status(400).send('No valid records found'); - return; + try { + const response = await location.save() + if(!response) { + throw new Error('Something went wrong during saving the location...') } - record.teamName = req.body.teamName; - record.isActive = req.body.isActive; - record.createdDatetime = Date.now(); - record.modifiedDatetime = Date.now(); - - record - .save() - .then(results => res.status(201).send(results._id)) - .catch(errors => res.status(400).send(errors)); - }); + res.status(200).send(response); + } catch (err) { + console.log(err.message) + res.status(500).json({message: err.message || 'Something went wrong...'}); + } }; return { diff --git a/src/models/mapLocation.js b/src/models/mapLocation.js index d7b9d82b5..65415239f 100644 --- a/src/models/mapLocation.js +++ b/src/models/mapLocation.js @@ -11,32 +11,38 @@ const mapLocation = new Schema({ type: String, default: 'Prior to HGN Data Collection', }, - title: { + jobTitle: { type: String, default: 'Prior to HGN Data Collection', }, - userProvided: { - type: String, - required: true, + isActive: { + type: Boolean, + default: false, }, - coords: { - lat: { + location: { + userProvided: { type: String, required: true, }, - lng: { + coords: { + lat: { + type: String, + required: true, + }, + lng: { + type: String, + required: true, + } + }, + country: { type: String, required: true, - } - }, - country: { - type: String, - required: true, + }, + city: { + type: String, + default: '', + }, }, - city: { - type: String, - default: '', - } }); module.exports = mongoose.model('MapLocation', mapLocation, 'maplocations'); From f3832a31ce438bb39542cc30f0d2a4f28a5868d4 Mon Sep 17 00:00:00 2001 From: Oleksandr Riazantsev Date: Sun, 15 Oct 2023 12:06:40 -0400 Subject: [PATCH 116/272] feat: userprofiles sending totalTangibleHrs, update user controller, all manually locations response structure --- src/controllers/mapLocationsController.js | 85 ++++++++++++++++++++--- src/routes/mapLocationsRouter.js | 3 +- 2 files changed, 77 insertions(+), 11 deletions(-) diff --git a/src/controllers/mapLocationsController.js b/src/controllers/mapLocationsController.js index 6088de489..f01666558 100644 --- a/src/controllers/mapLocationsController.js +++ b/src/controllers/mapLocationsController.js @@ -1,11 +1,26 @@ -const mapLocationsController = function (mapLocation) { +const userProfile = require('../models/userProfile'); +const cache = require('../utilities/nodeCache')(); + +const mapLocationsController = function (MapLocation) { const getAllLocations = function (req, res) { + const priorText = 'Prior to HGN Data Collection'; + MapLocation.find({}) + .then(results => { + const users = results.map(item => { + return ({ + title: priorText, + firstName: item.firstName !== priorText ? item.firstName : '', + lastName: item.lastName !== priorText ? item.lastName : '', + jobTitle: item.jobTitle !== priorText ? item.jobTitle : '', + location: item.location, + isActive: item.isActive, + _id: item._id + }) + }) + res.send(users).status(200); - mapLocation.find({}) - .then(results => - res.send(results).status(200) - ) - .catch(error => + }) + .catch(error => res.send(error).status(404)); }; const deleteLocation = async function (req, res) { @@ -14,6 +29,11 @@ const mapLocationsController = function (mapLocation) { res.status(403).send('You are not authorized to make changes in the teams.'); return; } + const locationId = req.params.locationId + + MapLocation.findOneAndDelete({ _id: locationId }) + .then(() => res.status(200).send({ message: "The location was successfully removed!" })) + .catch(error => res.status(500).send({ message: error || "Couldn't remove the location" })); }; const putUserLocation = async function (req, res) { @@ -27,24 +47,69 @@ const mapLocationsController = function (mapLocation) { jobTitle: req.body.jobTitle, location: req.body.location, } - const location = new mapLocation(locationData); + const location = new MapLocation(locationData); try { const response = await location.save() - if(!response) { + if (!response) { throw new Error('Something went wrong during saving the location...') } res.status(200).send(response); } catch (err) { console.log(err.message) - res.status(500).json({message: err.message || 'Something went wrong...'}); + res.status(500).json({ message: err.message || 'Something went wrong...' }); } }; + const updateUserLocation = async function (req, res) { + console.log(req.body) + if (!req.body.requestor.role === 'Administrator' || !req.body.requestor.role === 'Owner') { + res.status(403).send('You are not authorized to make changes in the teams.'); + return; + } + const userType = req.body.type; + const userId= req.body._id; + const updateData = { + firstName: req.body.firstName, + lastName: req.body.lastName, + jobTitle: req.body.jobTitle, + location: req.body.location, + _id: req.body._id + } + try { + let response; + if(userType === 'user') { + response = await userProfile.findOneAndUpdate({ _id: userId }, {$set: {...updateData, jobTitle: [updateData.jobTitle]}}, { new: true }); + cache.removeCache('allusers') + cache.removeCache(`user-${userId}`); + cache.setCache(`user-${userId}`, JSON.stringify(response)); + } else { + response = await MapLocation.findOneAndUpdate({ _id: userId }, {$set: updateData}, { new: true }) + } + + if (!response) { + throw new Error('Something went wrong during saving the location...') + } + const newData = { + firstName: response.firstName, + lastName: response.lastName, + jobTitle: response.jobTitle, + location: response.location, + _id: response._id, + type: userType + } + + res.status(200).send(newData); + } catch (err) { + console.log(err.message) + res.status(500).json({ message: err.message || 'Something went wrong...' }); + } + }; return { getAllLocations, deleteLocation, - putUserLocation + putUserLocation, + updateUserLocation }; }; diff --git a/src/routes/mapLocationsRouter.js b/src/routes/mapLocationsRouter.js index e2e780dac..db004ff18 100644 --- a/src/routes/mapLocationsRouter.js +++ b/src/routes/mapLocationsRouter.js @@ -7,7 +7,8 @@ const router = function (mapLocations) { mapRouter.route('/mapLocations') .get(controller.getAllLocations) - .put(controller.putUserLocation); + .put(controller.putUserLocation) + .patch(controller.updateUserLocation); mapRouter.route('/mapLocations/:locationId') .delete(controller.deleteLocation) From ac823a55717273c4675f55d21529c26f948093f5 Mon Sep 17 00:00:00 2001 From: Oleksandr Riazantsev Date: Wed, 1 Nov 2023 12:58:36 -0400 Subject: [PATCH 117/272] fix: moving part of logic from the frontend, bug fixes feat: updating timezone --- src/controllers/mapLocationsController.js | 88 ++++++++++++++--------- src/models/mapLocation.js | 15 ++-- 2 files changed, 58 insertions(+), 45 deletions(-) diff --git a/src/controllers/mapLocationsController.js b/src/controllers/mapLocationsController.js index f01666558..9fa214080 100644 --- a/src/controllers/mapLocationsController.js +++ b/src/controllers/mapLocationsController.js @@ -1,27 +1,32 @@ -const userProfile = require('../models/userProfile'); +const UserProfile = require('../models/userProfile'); const cache = require('../utilities/nodeCache')(); + const mapLocationsController = function (MapLocation) { - const getAllLocations = function (req, res) { - const priorText = 'Prior to HGN Data Collection'; - MapLocation.find({}) - .then(results => { - const users = results.map(item => { - return ({ - title: priorText, - firstName: item.firstName !== priorText ? item.firstName : '', - lastName: item.lastName !== priorText ? item.lastName : '', - jobTitle: item.jobTitle !== priorText ? item.jobTitle : '', - location: item.location, - isActive: item.isActive, - _id: item._id - }) - }) - res.send(users).status(200); - - }) - .catch(error => - res.send(error).status(404)); + const getAllLocations = async function (req, res) { + + try { + const users = []; + const results = await UserProfile.find({}, + '_id firstName lastName isActive location jobTitle totalTangibleHrs hoursByCategory' + ); + + results.forEach((item) => { + if ( + (item.location?.coords.lat && item.location?.coords.lng && item.totalTangibleHrs >= 10) || + (item.location?.coords.lat && item.location?.coords.lng && calculateTotalHours(item.hoursByCategory) >= 10) + ) { + users.push(item); + } + }); + + const m_users = await MapLocation.find({}); + + res.status(200).send({ users, m_users }); + } catch (err) { + res.status(404).send(err); + } + }; const deleteLocation = async function (req, res) { @@ -37,7 +42,7 @@ const mapLocationsController = function (MapLocation) { }; const putUserLocation = async function (req, res) { - if (!req.body.requestor.role === 'Administrator' || !req.body.requestor.role === 'Owner') { + if (!req.body.requestor.role === 'Owner') { res.status(403).send('You are not authorized to make changes in the teams.'); return; } @@ -61,32 +66,36 @@ const mapLocationsController = function (MapLocation) { } }; const updateUserLocation = async function (req, res) { - console.log(req.body) - if (!req.body.requestor.role === 'Administrator' || !req.body.requestor.role === 'Owner') { + if (!req.body.requestor.role === 'Owner') { res.status(403).send('You are not authorized to make changes in the teams.'); return; } const userType = req.body.type; - const userId= req.body._id; + const userId = req.body._id; const updateData = { - firstName: req.body.firstName, - lastName: req.body.lastName, - jobTitle: req.body.jobTitle, - location: req.body.location, - _id: req.body._id + firstName: req.body.firstName, + lastName: req.body.lastName, + jobTitle: req.body.jobTitle, + location: req.body.location, + } + + if (req.body.timeZone) { + updateData.timeZone = req.body.timeZone } try { let response; - if(userType === 'user') { - response = await userProfile.findOneAndUpdate({ _id: userId }, {$set: {...updateData, jobTitle: [updateData.jobTitle]}}, { new: true }); + if (userType === 'user') { + console.log('updateData----', updateData); + response = await UserProfile.findOneAndUpdate({ _id: userId }, { $set: { ...updateData, jobTitle: [updateData.jobTitle] } }, { new: true }); cache.removeCache('allusers') cache.removeCache(`user-${userId}`); + cache.setCache(`user-${userId}`, JSON.stringify(response)); } else { - response = await MapLocation.findOneAndUpdate({ _id: userId }, {$set: updateData}, { new: true }) + response = await MapLocation.findOneAndUpdate({ _id: userId }, { $set: updateData }, { new: true }) } - + if (!response) { throw new Error('Something went wrong during saving the location...') } @@ -98,13 +107,22 @@ const mapLocationsController = function (MapLocation) { _id: response._id, type: userType } - + res.status(200).send(newData); } catch (err) { console.log(err.message) res.status(500).json({ message: err.message || 'Something went wrong...' }); } }; + + function calculateTotalHours(hoursByCategory) { + let hours = 0; + Object.keys(hoursByCategory).forEach((x) => { + hours += hoursByCategory[x]; + }); + return hours; + } + return { getAllLocations, deleteLocation, diff --git a/src/models/mapLocation.js b/src/models/mapLocation.js index 65415239f..851587dc3 100644 --- a/src/models/mapLocation.js +++ b/src/models/mapLocation.js @@ -3,18 +3,13 @@ const mongoose = require('mongoose'); const { Schema } = mongoose; const mapLocation = new Schema({ - firstName: { + title: { type: String, - default: 'Prior to HGN Data Collection', - }, - lastName: { - type: String, - default: 'Prior to HGN Data Collection', - }, - jobTitle: { - type: String, - default: 'Prior to HGN Data Collection', + default: 'Prior to HGN Data Collection' }, + firstName: String, + lastName: String, + jobTitle: String, isActive: { type: Boolean, default: false, From ac4aa7ba8a289b6d54b839ec606e49fe5797e09c Mon Sep 17 00:00:00 2001 From: Oleksandr Riazantsev Date: Thu, 2 Nov 2023 10:21:10 -0400 Subject: [PATCH 118/272] fix: modifying users before sent --- src/controllers/mapLocationsController.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/controllers/mapLocationsController.js b/src/controllers/mapLocationsController.js index 9fa214080..c9edd53b8 100644 --- a/src/controllers/mapLocationsController.js +++ b/src/controllers/mapLocationsController.js @@ -19,10 +19,17 @@ const mapLocationsController = function (MapLocation) { users.push(item); } }); - - const m_users = await MapLocation.find({}); - - res.status(200).send({ users, m_users }); + const modifiedUsers = users.map(item => ({ + location: item.location, + isActive: item.isActive, + jobTitle: item.jobTitle[0], + _id: item._id, + firstName: item.firstName, + lastName: item.lastName + })); + + const mUsers = await MapLocation.find({}); + res.status(200).send({ users: modifiedUsers, mUsers }); } catch (err) { res.status(404).send(err); } @@ -86,7 +93,6 @@ const mapLocationsController = function (MapLocation) { try { let response; if (userType === 'user') { - console.log('updateData----', updateData); response = await UserProfile.findOneAndUpdate({ _id: userId }, { $set: { ...updateData, jobTitle: [updateData.jobTitle] } }, { new: true }); cache.removeCache('allusers') cache.removeCache(`user-${userId}`); From 23bb45dfab1a7440cbc540c2ebc736e86f426b51 Mon Sep 17 00:00:00 2001 From: leonzh2k Date: Thu, 6 Jul 2023 17:55:26 -0400 Subject: [PATCH 119/272] add new fields to send in UserProfileController Add jobTitle and location fields to the userProfile objects that are sent back to the client when requesting all userProfiles. These two bits of info are displayed on the interactive map. --- src/controllers/userProfileController.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 70d774042..ae41bec5f 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -65,7 +65,7 @@ const userProfileController = function (UserProfile) { UserProfile.find( {}, - '_id firstName lastName role weeklycommittedHours email permissions isActive reactivationDate createdDate endDate', + '_id firstName lastName role weeklycommittedHours email permissions isActive reactivationDate createdDate endDate location jobTitle', ) .sort({ lastName: 1, From 082fd3f132db23f175bcf501b08ad67d1f5efce7 Mon Sep 17 00:00:00 2001 From: Oleksandr Riazantsev Date: Sun, 15 Oct 2023 12:06:40 -0400 Subject: [PATCH 120/272] feat: userprofiles sending totalTangibleHrs, update user controller, all manually locations response structure --- src/controllers/mapLocationsController.js | 29 +++++++++++++++++++++++ src/controllers/userProfileController.js | 2 +- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/controllers/mapLocationsController.js b/src/controllers/mapLocationsController.js index c9edd53b8..97ae88b09 100644 --- a/src/controllers/mapLocationsController.js +++ b/src/controllers/mapLocationsController.js @@ -129,6 +129,35 @@ const mapLocationsController = function (MapLocation) { return hours; } + try { + let response; + if(userType === 'user') { + response = await userProfile.findOneAndUpdate({ _id: userId }, {$set: {...updateData, jobTitle: [updateData.jobTitle]}}, { new: true }); + cache.removeCache('allusers') + cache.removeCache(`user-${userId}`); + cache.setCache(`user-${userId}`, JSON.stringify(response)); + } else { + response = await MapLocation.findOneAndUpdate({ _id: userId }, {$set: updateData}, { new: true }) + } + + if (!response) { + throw new Error('Something went wrong during saving the location...') + } + const newData = { + firstName: response.firstName, + lastName: response.lastName, + jobTitle: response.jobTitle, + location: response.location, + _id: response._id, + type: userType + } + + res.status(200).send(newData); + } catch (err) { + console.log(err.message) + res.status(500).json({ message: err.message || 'Something went wrong...' }); + } + }; return { getAllLocations, deleteLocation, diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index ae41bec5f..1cc7f133c 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -65,7 +65,7 @@ const userProfileController = function (UserProfile) { UserProfile.find( {}, - '_id firstName lastName role weeklycommittedHours email permissions isActive reactivationDate createdDate endDate location jobTitle', + '_id firstName lastName role weeklycommittedHours email permissions isActive reactivationDate createdDate endDate location jobTitle totalTangibleHrs', ) .sort({ lastName: 1, From d6122b319d12231c057404b5458fe0eba1cba16b Mon Sep 17 00:00:00 2001 From: Oleksandr Riazantsev Date: Wed, 1 Nov 2023 12:58:36 -0400 Subject: [PATCH 121/272] fix: moving part of logic from the frontend, bug fixes feat: updating timezone --- src/controllers/mapLocationsController.js | 31 +---------------------- 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/src/controllers/mapLocationsController.js b/src/controllers/mapLocationsController.js index 97ae88b09..29af9e3d6 100644 --- a/src/controllers/mapLocationsController.js +++ b/src/controllers/mapLocationsController.js @@ -128,36 +128,7 @@ const mapLocationsController = function (MapLocation) { }); return hours; } - - try { - let response; - if(userType === 'user') { - response = await userProfile.findOneAndUpdate({ _id: userId }, {$set: {...updateData, jobTitle: [updateData.jobTitle]}}, { new: true }); - cache.removeCache('allusers') - cache.removeCache(`user-${userId}`); - cache.setCache(`user-${userId}`, JSON.stringify(response)); - } else { - response = await MapLocation.findOneAndUpdate({ _id: userId }, {$set: updateData}, { new: true }) - } - - if (!response) { - throw new Error('Something went wrong during saving the location...') - } - const newData = { - firstName: response.firstName, - lastName: response.lastName, - jobTitle: response.jobTitle, - location: response.location, - _id: response._id, - type: userType - } - - res.status(200).send(newData); - } catch (err) { - console.log(err.message) - res.status(500).json({ message: err.message || 'Something went wrong...' }); - } - }; + return { getAllLocations, deleteLocation, From 1effe936b57d19eb32a02015314dd4a25fe20116 Mon Sep 17 00:00:00 2001 From: leonzh2k Date: Thu, 6 Jul 2023 17:55:26 -0400 Subject: [PATCH 122/272] add new fields to send in UserProfileController Add jobTitle and location fields to the userProfile objects that are sent back to the client when requesting all userProfiles. These two bits of info are displayed on the interactive map. --- src/controllers/userProfileController.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 1cc7f133c..ae41bec5f 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -65,7 +65,7 @@ const userProfileController = function (UserProfile) { UserProfile.find( {}, - '_id firstName lastName role weeklycommittedHours email permissions isActive reactivationDate createdDate endDate location jobTitle totalTangibleHrs', + '_id firstName lastName role weeklycommittedHours email permissions isActive reactivationDate createdDate endDate location jobTitle', ) .sort({ lastName: 1, From b2b2cb0810a2a4cc2358b5c04d99bf523181fd23 Mon Sep 17 00:00:00 2001 From: Oleksandr Riazantsev Date: Thu, 2 Nov 2023 13:10:56 -0400 Subject: [PATCH 123/272] rebasing and resolving conflicts --- src/controllers/userProfileController.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index ae41bec5f..737b1bc6a 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -57,15 +57,9 @@ const userProfileController = function (UserProfile) { return; } - if (cache.getCache('allusers')) { - const getData = JSON.parse(cache.getCache('allusers')); - res.status(200).send(getData); - return; - } - UserProfile.find( {}, - '_id firstName lastName role weeklycommittedHours email permissions isActive reactivationDate createdDate endDate location jobTitle', + "_id firstName lastName role weeklycommittedHours email permissions isActive reactivationDate createdDate endDate" ) .sort({ lastName: 1, From 34a6f5594c82243eb974b7943b2d45c3ee855a39 Mon Sep 17 00:00:00 2001 From: Vishala Ramasamy Date: Sat, 4 Nov 2023 14:41:07 -0700 Subject: [PATCH 124/272] update material --- .../bmdashboard/bmMaterialsController.js | 89 +++++++++++++++++-- src/routes/bmdashboard/bmMaterialsRouter.js | 5 ++ 2 files changed, 85 insertions(+), 9 deletions(-) diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index 54ec65967..0e96b5bbb 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -57,22 +57,93 @@ const bmMaterialsController = function (ItemMaterial) { quantityWasted = (+quantityWasted / 100) * material.stockAvailable; } - ItemMaterial.updateOne( - { _id: req.body.material._id }, + if(quantityUsed>material.stockAvailable || quantityWasted>material.stockAvailable || (quantityUsed+quantityWasted)>material.stockAvailable) + { + res.status(500).send('Please check the used and wasted stock values. Either individual values or their sum exceeds the total stock available.') + } + else + { + quantityUsed = Number.parseFloat(quantityUsed.toFixed(2)); + quantityWasted = Number.parseFloat(quantityWasted.toFixed(2)); + let newAvailable = Number.parseFloat(quantityUsed+quantityWasted); + + ItemMaterial.updateOne( + { _id: req.body.material._id }, + { + $inc: { + 'stockUsed': quantityUsed, + 'stockWasted': quantityWasted, + 'stockAvailable': -(newAvailable) + }, + $push: { + updateRecord: { + date: req.body.date, + createdBy: req.body.requestor.requestorId, + quantity: -(quantityUsed+quantityWasted), + }, + } + } + ) + .then(results => {res.status(200).send(results)}) + .catch(error => res.status(500).send({'message':error})); + } + }; + + const bmPostMaterialUpdateBulk = function (req, res) { + const materialUpdates= req.body; + const updateRecordsToBeAdded = materialUpdates.map(payload => { + let quantityUsed = +payload.quantityUsed; + let quantityWasted = +payload.quantityWasted; + let material = payload.material; + if(payload.QtyUsedLogUnit=='percent' && quantityWasted>=0) { - $inc: { + quantityUsed = (+quantityUsed / 100) * material.stockAvailable; + } + if(payload.QtyWastedLogUnit=='percent' && quantityUsed>=0) + { + quantityWasted = (+quantityWasted / 100) * material.stockAvailable; + } + + quantityUsed = Number.parseFloat(quantityUsed.toFixed(2)); + quantityWasted = Number.parseFloat(quantityWasted.toFixed(2)); + let newAvailable = Number.parseFloat(quantityUsed+quantityWasted); + + return ({ + updateId: material._id, + increment: { 'stockUsed': quantityUsed, 'stockWasted': quantityWasted, - 'stockAvailable': -(quantityUsed+quantityWasted) - } - } - ) - .then(results => {res.status(200).send(results)}) - .catch(error => res.status(500).send(error)); + 'stockAvailable': -(newAvailable) + }, + updateValue: { + createdBy: req.body.requestor.requestorId, + quantity: -(quantityUsed+quantityWasted), + date: payload.date, + }}); + + }); + console.log(updateRecordsToBeAdded); + + try { + const updatePromises = updateRecordsToBeAdded.map(updateItem => ItemMaterial.updateOne( + { _id: updateItem.updateId }, + { + $inc: updateItem.increment , + $push: { usageRecord: updateItem.updateValue } }, + ).exec()); + Promise.all(updatePromises) + .then((results) => { + res.status(200).send({ result: `Successfully posted log for ${results.length} Material records.` }); + }) + .catch(error => res.status(500).send(error)); + } catch (err) { + res.json(err); + } }; return { bmMaterialsList, bmPostMaterialUpdateRecord, + bmPostMaterialUpdateBulk }; }; diff --git a/src/routes/bmdashboard/bmMaterialsRouter.js b/src/routes/bmdashboard/bmMaterialsRouter.js index a0f8dfea6..35a887b9b 100644 --- a/src/routes/bmdashboard/bmMaterialsRouter.js +++ b/src/routes/bmdashboard/bmMaterialsRouter.js @@ -10,6 +10,11 @@ materialsRouter.route('/materials') materialsRouter.route('/addUpdateMaterialRecord') .post(controller.bmPostMaterialUpdateRecord); + materialsRouter.route('/UpdateMaterialRecordBulk') + .post(controller.bmPostMaterialUpdateBulk); + + + return materialsRouter; }; From 4e318bc4046fb42324a9b12b0adc5c1522208f5c Mon Sep 17 00:00:00 2001 From: wang9hu Date: Sat, 4 Nov 2023 17:01:10 -0700 Subject: [PATCH 125/272] add empty string in teamCode validator for creating new user --- src/models/userProfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/userProfile.js b/src/models/userProfile.js index 4739a05e7..3219fec18 100644 --- a/src/models/userProfile.js +++ b/src/models/userProfile.js @@ -159,7 +159,7 @@ const userProfileSchema = new Schema({ default: '', validate: { validator(v) { - const teamCoderegex = /^([a-zA-Z]-[a-zA-Z]{3}|[a-zA-Z]{5})$/; + const teamCoderegex = /^([a-zA-Z]-[a-zA-Z]{3}|[a-zA-Z]{5})$|^$/; return teamCoderegex.test(v); }, message: From b568f900b655b8a2654eee9d3ed0ca3f3ea4e137 Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Mon, 6 Nov 2023 14:40:30 +0800 Subject: [PATCH 126/272] implemented edit and delete functions --- src/controllers/timeEntryController.js | 164 ++++++++++++++--------- src/controllers/userProfileController.js | 11 +- src/routes/timeentryRouter.js | 2 +- 3 files changed, 106 insertions(+), 71 deletions(-) diff --git a/src/controllers/timeEntryController.js b/src/controllers/timeEntryController.js index d2a4b3df4..aa7eff6ae 100644 --- a/src/controllers/timeEntryController.js +++ b/src/controllers/timeEntryController.js @@ -90,13 +90,16 @@ const timeEntrycontroller = function (TimeEntry) { const session = await mongoose.startSession(); session.startTransaction(); + const type = req.body.entryType; + try { if (!req.params.timeEntryId) { return res.status(400).send({ error: 'ObjectId in request param is not in correct format' }); } - if (!mongoose.Types.ObjectId.isValid(req.params.timeEntryId) || !mongoose.Types.ObjectId.isValid(req.body.projectId)) { - return res.status(400).send({ error: 'ObjectIds are not correctly formed' }); + if (!mongoose.Types.ObjectId.isValid(req.params.timeEntryId) + || ((type === 'default' || type === 'project') && !mongoose.Types.ObjectId.isValid(req.body.projectId))) { + return res.status(400).send({ error: 'ObjectIds are not correctly formed' }); } // Get initial timeEntry by timeEntryId @@ -106,7 +109,8 @@ const timeEntrycontroller = function (TimeEntry) { return res.status(400).send({ error: `No valid records found for ${req.params.timeEntryId}` }); } - if (!(await hasPermission(req.body.requestor, 'editTimeEntry') || timeEntry.personId.toString() === req.body.requestor.requestorId.toString())) { + if (!(await hasPermission(req.body.requestor, 'editTimeEntry') + || ((type === 'default' || type === 'person') && timeEntry.personId.toString() === req.body.requestor.requestorId.toString()))) { return res.status(403).send({ error: 'Unauthorized request' }); } @@ -115,7 +119,7 @@ const timeEntrycontroller = function (TimeEntry) { const totalSeconds = moment.duration(`${hours}:${minutes}`).asSeconds(); - if (timeEntry.isTangible === true && totalSeconds !== timeEntry.totalSeconds) { + if (type === 'default' && timeEntry.isTangible === true && totalSeconds !== timeEntry.totalSeconds) { notifyEditByEmail(timeEntry.personId.toString(), timeEntry, totalSeconds, req.body); } @@ -134,24 +138,27 @@ const timeEntrycontroller = function (TimeEntry) { // Update the hoursLogged field of related tasks based on before and after timeEntries // initialIsTangible is a bealoon value, req.body.isTangible is a string // initialProjectId may be a task id or project id, so do not throw error. - try { - if (initialIsTangible === true) { - const initialTask = await task.findById(initialProjectId); - initialTask.hoursLogged -= (initialSeconds / 3600); - await initialTask.save(); - } + if (type === 'default') { + try { + if (initialIsTangible === true) { + const initialTask = await task.findById(initialProjectId); + initialTask.hoursLogged -= (initialSeconds / 3600); + await initialTask.save(); + } - if (req.body.isTangible === true) { - const editedTask = await task.findById(req.body.projectId); - editedTask.hoursLogged += (totalSeconds / 3600); - await editedTask.save(); + if (req.body.isTangible === true) { + const editedTask = await task.findById(req.body.projectId); + editedTask.hoursLogged += (totalSeconds / 3600); + await editedTask.save(); + } + } catch (error) { + console.log('Failed to find task by id'); } - } catch (error) { - console.log('Failed to find task by id'); } // Update edit history - if (initialSeconds !== totalSeconds + if ((type === 'default' || type === 'person') + && initialSeconds !== totalSeconds && timeEntry.isTangible && req.body.requestor.requestorId === timeEntry.personId.toString() && !await hasPermission(req.body.requestor, 'editTimeEntry') @@ -163,37 +170,39 @@ const timeEntrycontroller = function (TimeEntry) { newSeconds: totalSeconds, }); - // Issue infraction if edit history contains more than 5 edits in the last year - let totalRecentEdits = 0; + if (type === 'default') { + // Issue infraction if edit history contains more than 5 edits in the last year + let totalRecentEdits = 0; - requestor.timeEntryEditHistory.forEach((edit) => { - if (moment().tz('America/Los_Angeles').diff(edit.date, 'days') <= 365) { - totalRecentEdits += 1; - } - }); - - if (totalRecentEdits >= 5) { - requestor.infringements.push({ - date: moment().tz('America/Los_Angeles'), - description: `${totalRecentEdits} time entry edits in the last calendar year`, + requestor.timeEntryEditHistory.forEach((edit) => { + if (moment().tz('America/Los_Angeles').diff(edit.date, 'days') <= 365) { + totalRecentEdits += 1; + } }); - emailSender('onecommunityglobal@gmail.com', `${requestor.firstName} ${requestor.lastName} was issued a blue square for for editing a time entry ${totalRecentEdits} times`, ` -

- ${requestor.firstName} ${requestor.lastName} (${requestor.email}) was issued a blue square for editing their time entries ${totalRecentEdits} times - within the last calendar year. -

-

- This is the ${totalRecentEdits}th edit within the past 365 days. -

+ if (totalRecentEdits >= 5) { + requestor.infringements.push({ + date: moment().tz('America/Los_Angeles'), + description: `${totalRecentEdits} time entry edits in the last calendar year`, + }); + + emailSender('onecommunityglobal@gmail.com', `${requestor.firstName} ${requestor.lastName} was issued a blue square for for editing a time entry ${totalRecentEdits} times`, ` +

+ ${requestor.firstName} ${requestor.lastName} (${requestor.email}) was issued a blue square for editing their time entries ${totalRecentEdits} times + within the last calendar year. +

+

+ This is the ${totalRecentEdits}th edit within the past 365 days. +

`); - const emailInfringement = { - date: moment().tz('America/Los_Angeles').format('MMMM-DD-YY'), - description: `You edited your time entries ${totalRecentEdits} times within the last 365 days, exceeding the limit of 4 times per year you can edit them without penalty.`, - }; + const emailInfringement = { + date: moment().tz('America/Los_Angeles').format('MMMM-DD-YY'), + description: `You edited your time entries ${totalRecentEdits} times within the last 365 days, exceeding the limit of 4 times per year you can edit them without penalty.`, + }; - emailSender(requestor.email, 'You\'ve been issued a blue square for editing your time entry', getInfringementEmailBody(requestor.firstName, requestor.lastName, emailInfringement, requestor.infringements.length)); + emailSender(requestor.email, 'You\'ve been issued a blue square for editing your time entry', getInfringementEmailBody(requestor.firstName, requestor.lastName, emailInfringement, requestor.infringements.length)); + } } await requestor.save(); @@ -204,10 +213,12 @@ const timeEntrycontroller = function (TimeEntry) { res.status(200).send({ message: 'Successfully updated time entry' }); - // checking if logged in hours exceed estimated time after timeentry edit for a task - const record = await userProfile.findById(timeEntry.personId.toString()); - const currentTask = await task.findById(req.body.projectId); - checkTaskOvertime(timeEntry, record, currentTask); + if (type === 'default') { + // checking if logged in hours exceed estimated time after timeentry edit for a task + const record = await userProfile.findById(timeEntry.personId.toString()); + const currentTask = await task.findById(req.body.projectId); + checkTaskOvertime(timeEntry, record, currentTask); + } } catch (err) { await session.abortTransaction(); return res.status(400).send({ error: err.toString() }); @@ -249,9 +260,8 @@ const timeEntrycontroller = function (TimeEntry) { || !req.body.timeSpent || !req.body.isTangible; - const returnErr = (res) => { - res.status(400).send({ error: 'Bad request' }); - return; + const returnErr = (result) => { + result.status(400).send({ error: 'Bad request' }); }; switch (req.body.entryType) { @@ -307,10 +317,12 @@ const timeEntrycontroller = function (TimeEntry) { .status(200) .send({ message: `Time Entry saved with id as ${results._id}` }); }) - .catch(error => res.status(400).send(error)); + .catch((error) => { + res.status(400).send(error); + }); // Add this tangbile time entry to related task's hoursLogged - if ((timeentry.entryType == 'default') && timeentry.isTangible === true) { + if ((timeentry.entryType === 'default') && timeentry.isTangible === true) { try { const currentTask = await task.findById(req.body.projectId); currentTask.hoursLogged += (timeentry.totalSeconds / 3600); @@ -320,7 +332,7 @@ const timeEntrycontroller = function (TimeEntry) { } } // checking if logged in hours exceed estimated time after timeentry for a task - if (timeentry.entryType == 'default') { + if (timeentry.entryType === 'default') { const record = await userProfile.findById(timeentry.personId.toString()); const currentTask = await task.findById(req.body.projectId); checkTaskOvertime(timeentry, record, currentTask); @@ -347,7 +359,7 @@ const timeEntrycontroller = function (TimeEntry) { TimeEntry.aggregate([ { $match: { - entryType: { $in: [ 'default', null ] }, + entryType: { $in: ['default', null] }, personId: mongoose.Types.ObjectId(userId), dateOfWork: { $gte: fromdate, $lte: todate }, }, @@ -423,7 +435,9 @@ const timeEntrycontroller = function (TimeEntry) { }, ]).then((results) => { res.status(200).send(results); - }).catch(error => res.status(400).send(error)); + }).catch((error) => { + res.status(400).send(error); + }); }; const getTimeEntriesForUsersList = function (req, res) { @@ -431,7 +445,7 @@ const timeEntrycontroller = function (TimeEntry) { TimeEntry.find( { - entryType: { $in: [ 'default', null, 'person' ] }, + entryType: { $in: ['default', null, 'person'] }, personId: { $in: users }, dateOfWork: { $gte: fromDate, $lte: toDate }, }, @@ -458,7 +472,9 @@ const timeEntrycontroller = function (TimeEntry) { }); res.status(200).send(data); }) - .catch(error => res.status(400).send(error)); + .catch((error) => { + res.status(400).send(error); + }); }; const getTimeEntriesForSpecifiedProject = function (req, res) { @@ -476,7 +492,7 @@ const timeEntrycontroller = function (TimeEntry) { const { projectId } = req.params; TimeEntry.find( { - entryType: [ 'default', null ], + entryType: ['default', null], projectId, dateOfWork: { $gte: fromDate, $lte: todate }, }, @@ -487,7 +503,9 @@ const timeEntrycontroller = function (TimeEntry) { .then((results) => { res.status(200).send(results); }) - .catch(error => res.status(400).send(error)); + .catch((error) => { + res.status(400).send(error); + }); }; const deleteTimeEntry = async function (req, res) { @@ -503,6 +521,18 @@ const timeEntrycontroller = function (TimeEntry) { return; } + if (record.entryType === 'project' || record.entryType === 'person' || record.entryType === 'team') { + record + .remove() + .then(() => { + res.status(200).send({ message: 'Successfully deleted' }); + }) + .catch((error) => { + res.status(500).send(error); + }); + return; + } + if ( record.personId.toString() === req.body.requestor.requestorId.toString() @@ -572,7 +602,9 @@ const timeEntrycontroller = function (TimeEntry) { }); res.status(200).send(data); }) - .catch(error => res.status(400).send(error)); + .catch((error) => { + res.status(400).send(error); + }); }; const getLostTimeEntriesForProjectList = function (req, res) { @@ -580,7 +612,7 @@ const timeEntrycontroller = function (TimeEntry) { TimeEntry.find( { - entryType: "project", + entryType: 'project', projectId: { $in: projects }, dateOfWork: { $gte: fromDate, $lte: toDate }, }, @@ -606,7 +638,9 @@ const timeEntrycontroller = function (TimeEntry) { }); res.status(200).send(data); }) - .catch(error => res.status(400).send(error)); + .catch((error) => { + res.status(400).send(error); + }); }; const getLostTimeEntriesForTeamList = function (req, res) { @@ -614,7 +648,7 @@ const timeEntrycontroller = function (TimeEntry) { TimeEntry.find( { - entryType: "team", + entryType: 'team', teamId: { $in: teams }, dateOfWork: { $gte: fromDate, $lte: toDate }, }, @@ -629,7 +663,7 @@ const timeEntrycontroller = function (TimeEntry) { record._id = element._id; record.notes = element.notes; record.isTangible = element.isTangible; - record.teamId = element.teamId; + record.teamId = element.teamId ? element.teamId._id : ''; record.teamName = element.teamId ? element.teamId.teamName : ''; @@ -640,7 +674,9 @@ const timeEntrycontroller = function (TimeEntry) { }); res.status(200).send(data); }) - .catch(error => res.status(400).send(error)); + .catch((error) => { + res.status(400).send(error); + }); }; return { diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index 6dc571b39..440ce765e 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -569,15 +569,14 @@ 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.permissions?.frontPermissions.includes("editTeamCode"); + if (key === 'teamCode') { + const canEditTeamCode = req.body.requestor.role === 'Owner' + || req.body.requestor.permissions?.frontPermissions.includes('editTeamCode'); - if(!canEditTeamCode){ - res.status(403).send("You are not authorized to edit team code."); + if (!canEditTeamCode) { + res.status(403).send('You are not authorized to edit team code.'); return; } - } // remove user from cache, it should be loaded next time diff --git a/src/routes/timeentryRouter.js b/src/routes/timeentryRouter.js index 7e0a41797..0562f49ed 100644 --- a/src/routes/timeentryRouter.js +++ b/src/routes/timeentryRouter.js @@ -21,7 +21,7 @@ const routes = function (TimeEntry) { TimeEntryRouter.route('/TimeEntry/lostUsers') .post(controller.getLostTimeEntriesForUserList); - + TimeEntryRouter.route('/TimeEntry/lostProjects') .post(controller.getLostTimeEntriesForProjectList); From 0058b42a8bd1b7ad00cd4e9aeec2007ec40c6c2d Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Mon, 6 Nov 2023 13:02:46 -0800 Subject: [PATCH 127/272] add fetch single project api. update fetch all projects query. --- .../bmdashboard/bmProjectController.js | 43 +++++++++++++++++-- src/routes/bmdashboard/bmProjectRouter.js | 7 ++- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/controllers/bmdashboard/bmProjectController.js b/src/controllers/bmdashboard/bmProjectController.js index 96f19ab60..3e88ea08a 100644 --- a/src/controllers/bmdashboard/bmProjectController.js +++ b/src/controllers/bmdashboard/bmProjectController.js @@ -1,8 +1,10 @@ const bmMProjectController = function (BuildingProject) { - const bmProjectSummary = async function _projSumm(req, res) { - try { + // fetches all projects by building manager id + const fetchAllProjects = async (req, res) => { + const { userId } = req.params; + try { const projectData = await BuildingProject - .find() + .find({ buildingManager: userId }) .populate([ { path: 'buildingManager', @@ -21,7 +23,40 @@ const bmMProjectController = function (BuildingProject) { res.json(err); } }; - return { bmProjectSummary }; + + // fetches single project by project id + const fetchSingleProject = async (req, res) => { + const { userId, projectId } = req.params; + try { + BuildingProject + .findById(projectId) + .populate([ + { + path: 'buildingManager', + select: '_id firstName lastName email', + }, + { + path: 'team', + select: '_id firstName lastName email', + }, + ]) + .exec() + .then((project) => { + // authenticate request by comparing userId param with buildingManager id field + // ObjectId must be converted to string + if (userId !== project.buildingManager._id.toString()) { + return res.status(403).send({ + message: 'You are not authorized to view this record.', + }); + } + return res.status(200).send(project); + }) + .catch(error => res.status(500).send(error)); + } catch (err) { + res.json(err); + } + }; + return { fetchAllProjects, fetchSingleProject }; }; module.exports = bmMProjectController; diff --git a/src/routes/bmdashboard/bmProjectRouter.js b/src/routes/bmdashboard/bmProjectRouter.js index 6bd535ae1..7069950dc 100644 --- a/src/routes/bmdashboard/bmProjectRouter.js +++ b/src/routes/bmdashboard/bmProjectRouter.js @@ -4,8 +4,11 @@ const routes = function (buildingProject) { const projectRouter = express.Router(); const controller = require('../../controllers/bmdashboard/bmProjectController')(buildingProject); -projectRouter.route('/projects') - .get(controller.bmProjectSummary); +projectRouter.route('/projects/:userId') + .get(controller.fetchAllProjects); + +projectRouter.route('/projects/:userId/:projectId') + .get(controller.fetchSingleProject); return projectRouter; }; From ec5d40584a18cd5de8d8b6f255dc54acc68a2f20 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Tue, 7 Nov 2023 12:41:53 -0800 Subject: [PATCH 128/272] update project routes. add auth checks to controllers. --- .../bmdashboard/bmProjectController.js | 47 +++++++++++++------ src/routes/bmdashboard/bmProjectRouter.js | 4 +- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/controllers/bmdashboard/bmProjectController.js b/src/controllers/bmdashboard/bmProjectController.js index 3e88ea08a..929aba4ba 100644 --- a/src/controllers/bmdashboard/bmProjectController.js +++ b/src/controllers/bmdashboard/bmProjectController.js @@ -1,10 +1,21 @@ +// TODO: uncomment when executing auth checks +// const jwt = require('jsonwebtoken'); +// const config = require('../../config'); + const bmMProjectController = function (BuildingProject) { - // fetches all projects by building manager id + // TODO: uncomment when executing auth checks + // const { JWT_SECRET } = config; + const fetchAllProjects = async (req, res) => { - const { userId } = req.params; - try { + //! Note: for easier testing this route currently returns all projects from the db + // TODO: uncomment the lines below to return only projects where field buildingManager === userid + // const token = req.headers.authorization; + // const { userid } = jwt.verify(token, JWT_SECRET); + try { const projectData = await BuildingProject - .find({ buildingManager: userId }) + // TODO: uncomment this line to filter by buildingManager field + // .find({ buildingManager: userid }) + .find() .populate([ { path: 'buildingManager', @@ -26,7 +37,11 @@ const bmMProjectController = function (BuildingProject) { // fetches single project by project id const fetchSingleProject = async (req, res) => { - const { userId, projectId } = req.params; + //! Note: for easier testing this route currently returns the project without an auth check + // TODO: uncomment the lines below to check the user's ability to view the current project + // const token = req.headers.authorization; + // const { userid } = jwt.verify(token, JWT_SECRET); + const { projectId } = req.params; try { BuildingProject .findById(projectId) @@ -41,16 +56,18 @@ const bmMProjectController = function (BuildingProject) { }, ]) .exec() - .then((project) => { - // authenticate request by comparing userId param with buildingManager id field - // ObjectId must be converted to string - if (userId !== project.buildingManager._id.toString()) { - return res.status(403).send({ - message: 'You are not authorized to view this record.', - }); - } - return res.status(200).send(project); - }) + .then(project => res.status(200).send(project)) + // TODO: uncomment this block to execute the auth check + // authenticate request by comparing userId param with buildingManager id field + // Note: _id has type object and must be converted to string + // .then((project) => { + // if (userid !== project.buildingManager._id.toString()) { + // return res.status(403).send({ + // message: 'You are not authorized to view this record.', + // }); + // } + // return res.status(200).send(project); + // }) .catch(error => res.status(500).send(error)); } catch (err) { res.json(err); diff --git a/src/routes/bmdashboard/bmProjectRouter.js b/src/routes/bmdashboard/bmProjectRouter.js index 7069950dc..d60ea9b2b 100644 --- a/src/routes/bmdashboard/bmProjectRouter.js +++ b/src/routes/bmdashboard/bmProjectRouter.js @@ -4,10 +4,10 @@ const routes = function (buildingProject) { const projectRouter = express.Router(); const controller = require('../../controllers/bmdashboard/bmProjectController')(buildingProject); -projectRouter.route('/projects/:userId') +projectRouter.route('/projects') .get(controller.fetchAllProjects); -projectRouter.route('/projects/:userId/:projectId') +projectRouter.route('/project/:projectId') .get(controller.fetchSingleProject); return projectRouter; From dbfc6bef60dbf37e0f9f8da70b55ee947fec4a73 Mon Sep 17 00:00:00 2001 From: wang9hu Date: Tue, 7 Nov 2023 23:05:08 -0800 Subject: [PATCH 129/272] make sure escapeRegex check entire string for existing info name --- src/utilities/escapeRegex.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utilities/escapeRegex.js b/src/utilities/escapeRegex.js index 10fa2e61e..01a65ea50 100644 --- a/src/utilities/escapeRegex.js +++ b/src/utilities/escapeRegex.js @@ -1,6 +1,6 @@ const escapeRegex = function (text) { - return text.replace(/[[\]{}()*+?.\\^$|]/g, '\\$&'); + return `^${text.replace(/[[\]{}()*+?.\\^$|]/g, '\\$&')}&`; }; module.exports = escapeRegex; From a7ebfdd40fd5fbedcbcf21e423ab0cb353228d97 Mon Sep 17 00:00:00 2001 From: Chuehleo <122568562+Chuehleo@users.noreply.github.com> Date: Thu, 9 Nov 2023 01:33:16 -0700 Subject: [PATCH 130/272] Update userProfileController.js --- src/controllers/userProfileController.js | 107 ++++++++++++++--------- 1 file changed, 68 insertions(+), 39 deletions(-) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index a39b3c9ff..a388f10db 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -34,7 +34,6 @@ async function ValidatePassword(req, res) { }); return; } - // Verify request is authorized by self or adminsitrator if (userId !== requestor.requestorId && !await hasPermission(requestor.role, 'updatePassword')) { console.log('User ID:', userId); @@ -50,6 +49,11 @@ async function ValidatePassword(req, res) { if (userId === requestor.requestorId || !await hasPermission(requestor.role, 'updatePasswordForOthers')) { console.log('User ID:', userId); console.log('Requestor ID:', requestor.requestorId); + res.status(403).send({ + error: "You are unauthorized to update this user's password", + }); + return; + } // Verify new and confirm new password are correct if (req.body.newpassword !== req.body.confirmnewpassword) { @@ -61,8 +65,19 @@ async function ValidatePassword(req, res) { 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.role, "getUserProfiles")) && + !req.body.requestor.permissions?.frontPermissions.includes( + "putUserProfilePermissions" + ) + ) { + res.status(403).send("You are not authorized to view all users"); + return; + } + + if (cache.getCache("allusers")) { + const getData = JSON.parse(cache.getCache("allusers")); + res.status(200).send(getData); return; } @@ -85,8 +100,8 @@ const userProfileController = function (UserProfile) { }; 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.role, "getProjectMembers"))) { + res.status(403).send("You are not authorized to view all users"); return; } UserProfile.find( @@ -107,13 +122,16 @@ 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.role, "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')) { - res.status(403).send('You are not authorized to create new owners'); + if ( + req.body.role === "Owner" && + !(await hasPermission(req.body.requestor.role, "addDeleteEditOwners")) + ) { + res.status(403).send("You are not authorized to create new owners"); return; } @@ -230,10 +248,12 @@ 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.role, "putUserProfile")) || + req.body.requestor.requestorId === userid || + req.body.requestor.permissions?.frontPermissions.includes( + "putUserProfilePermissions" + )) ); if (!isRequestorAuthorized) { @@ -241,8 +261,11 @@ const userProfileController = function (UserProfile) { return; } - if (req.body.role === 'Owner' && !await hasPermission(req.body.requestor, 'addDeleteEditOwners')) { - res.status(403).send('You are not authorized to update this user'); + if ( + req.body.role === "Owner" && + !(await hasPermission(req.body.requestor.role, "addDeleteEditOwners")) + ) { + res.status(403).send("You are not authorized to update this user"); return; } @@ -295,12 +318,6 @@ const userProfileController = function (UserProfile) { record.isFirstTimelog = req.body.isFirstTimelog; record.teamCode = req.body.teamCode; - if(!canEditTeamCode && record.teamCode !== req.body.teamCode){ - res.status(403).send("You are not authorized to edit team code."); - return; - } - record.teamCode = req.body.teamCode; - // find userData in cache const isUserInCache = cache.hasCache("allusers"); let allUserData; @@ -311,7 +328,15 @@ 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.role, + "putUserProfileImportantInfo" + )) || + req.body.requestor.permissions?.frontPermissions.includes( + "putUserProfilePermissions" + ) + ) { record.role = req.body.role; record.isRehireable = req.body.isRehireable; record.isActive = req.body.isActive; @@ -377,9 +402,16 @@ const userProfileController = function (UserProfile) { record.createdDate; } - record.bioPosted = req.body.bioPosted || 'default'; - - if (await hasPermission(req.body.requestor, 'putUserProfilePermissions')) { + record.bioPosted = req.body.bioPosted || "default"; + if ( + (await hasPermission( + req.body.requestor.role, + "putUserProfilePermissions" + )) || + req.body.requestor.permissions?.frontPermissions.includes( + "putUserProfilePermissions" + ) + ) { record.permissions = req.body.permissions; } @@ -399,7 +431,9 @@ const userProfileController = function (UserProfile) { userData.createdDate = record.createdDate.toISOString(); } } - if (await hasPermission(req.body.requestor, 'infringementAuthorizer')) { + if ( + await hasPermission(req.body.requestor.role, "infringementAuthorizer") + ) { record.infringements = req.body.infringements; } @@ -429,12 +463,12 @@ const userProfileController = function (UserProfile) { const deleteUserProfile = async function (req, res) { const { option, userId } = req.body; - if (!await hasPermission(req.body.requestor, 'deleteUserProfile')) { + if (!await hasPermission(req.body.requestor.role, 'deleteUserProfile')) { res.status(403).send('You are not authorized to delete users'); return; } - if (req.body.role === 'Owner' && !await hasPermission(req.body.requestor, 'addDeleteEditOwners')) { + if (req.body.role === 'Owner' && !await hasPermission(req.body.requestor.role, 'addDeleteEditOwners')) { res.status(403).send('You are not authorized to delete this user'); return; } @@ -605,15 +639,9 @@ const userProfileController = function (UserProfile) { // Verify correct params in body if (!req.body.currentpassword || !req.body.newpassword || !req.body.confirmnewpassword) { - return res.status(400).send({ - error: 'One of more required fields are missing', - }); - } - // Verify request is authorized by self or adminsitrator - if (userId !== requestor.requestorId && !await hasPermission(req.body.requestor, 'updatePassword')) { - return res.status(403).send({ - error: "You are unauthorized to update this user's password", - }); + return res.status(400).send({ + error: 'One or more required fields are missing', + }); } // Check if the requestor has the permission to update passwords. @@ -673,10 +701,11 @@ const userProfileController = function (UserProfile) { } const userid = mongoose.Types.ObjectId(req.params.userId); + const { role } = req.body.requestor; let validroles = ['Volunteer', 'Manager', 'Administrator', 'Core Team', 'Owner', 'Mentor']; - if (await hasPermission(req.body.requestor, 'getReporteesLimitRoles')) { + if (await hasPermission(role, 'getReporteesLimitRoles')) { validroles = ['Volunteer', 'Manager']; } @@ -747,7 +776,7 @@ const userProfileController = function (UserProfile) { }); return; } - if (!await hasPermission(req.body.requestor, 'changeUserStatus')) { + if (!await hasPermission(req.body.requestor.role, 'changeUserStatus')) { res.status(403).send('You are not authorized to change user status'); return; } From 92bf9a85e5594ec943c1f5446817f7c070f52d06 Mon Sep 17 00:00:00 2001 From: Chuehleo <122568562+Chuehleo@users.noreply.github.com> Date: Thu, 9 Nov 2023 02:07:31 -0700 Subject: [PATCH 131/272] Update userProfileController.js --- src/controllers/userProfileController.js | 194 +++++++++++------------ 1 file changed, 90 insertions(+), 104 deletions(-) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index a388f10db..5968e3dd6 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -35,20 +35,15 @@ async function ValidatePassword(req, res) { return; } // Verify request is authorized by self or adminsitrator - if (userId !== requestor.requestorId && !await hasPermission(requestor.role, 'updatePassword')) { - console.log('User ID:', userId); - console.log('Requestor ID:', requestor.requestorId); + if (userId !== requestor.requestorId && !await hasPermission(req.body.requestor, 'updatePassword')) { res.status(403).send({ error: "You are unauthorized to update this user's password", }); return; } - - // Check permissions - if (userId === requestor.requestorId || !await hasPermission(requestor.role, 'updatePasswordForOthers')) { - console.log('User ID:', userId); - console.log('Requestor ID:', requestor.requestorId); + // Verify request is authorized by self or adminsitrator + if (userId === requestor.requestorId || !await hasPermission(req.body.requestor, 'updatePassword')) { res.status(403).send({ error: "You are unauthorized to update this user's password", }); @@ -65,19 +60,8 @@ async function ValidatePassword(req, res) { const userProfileController = function (UserProfile) { const getUserProfiles = async function (req, res) { - if ( - !(await hasPermission(req.body.requestor.role, "getUserProfiles")) && - !req.body.requestor.permissions?.frontPermissions.includes( - "putUserProfilePermissions" - ) - ) { - res.status(403).send("You are not authorized to view all users"); - return; - } - - if (cache.getCache("allusers")) { - const getData = JSON.parse(cache.getCache("allusers")); - res.status(200).send(getData); + if (!await hasPermission(req.body.requestor, 'getUserProfiles')) { + res.status(403).send('You are not authorized to view all users'); return; } @@ -90,18 +74,25 @@ const userProfileController = function (UserProfile) { }) .then((results) => { if (!results) { - res.status(500).send({ error: "User result was invalid" }); - return; + if (cache.getCache("allusers")) { + const getData = JSON.parse(cache.getCache("allusers")); + res.status(200).send(getData); + return; + }else{ + res.status(500).send({ error: "User result was invalid" }); + return; + } } 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.role, "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( @@ -122,16 +113,13 @@ const userProfileController = function (UserProfile) { }; const postUserProfile = async function (req, res) { - if (!(await hasPermission(req.body.requestor.role, "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.role, "addDeleteEditOwners")) - ) { - res.status(403).send("You are not authorized to create new owners"); + if (req.body.role === 'Owner' && !await hasPermission(req.body.requestor, 'addDeleteEditOwners')) { + res.status(403).send('You are not authorized to create new owners'); return; } @@ -248,24 +236,22 @@ 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.role, "putUserProfile")) || - req.body.requestor.requestorId === userid || - req.body.requestor.permissions?.frontPermissions.includes( - "putUserProfilePermissions" - )) + canRequestorUpdateUser(req.body.requestor.requestorId, userid) && ( + await hasPermission(req.body.requestor, 'putUserProfile') + || req.body.requestor.requestorId === userid + ) ); + + const canEditTeamCode = req.body.requestor.role === "Owner" || + req.body.requestor.permissions?.frontPermissions.includes("editTeamCode"); if (!isRequestorAuthorized) { res.status(403).send("You are not authorized to update this user"); return; } - if ( - req.body.role === "Owner" && - !(await hasPermission(req.body.requestor.role, "addDeleteEditOwners")) - ) { - res.status(403).send("You are not authorized to update this user"); + if (req.body.role === 'Owner' && !await hasPermission(req.body.requestor, 'addDeleteEditOwners')) { + res.status(403).send('You are not authorized to update this user'); return; } @@ -318,6 +304,13 @@ const userProfileController = function (UserProfile) { record.isFirstTimelog = req.body.isFirstTimelog; record.teamCode = req.body.teamCode; + if(!canEditTeamCode && record.teamCode !== req.body.teamCode){ + res.status(403).send("You are not authorized to edit team code."); + return; + } + + record.teamCode = req.body.teamCode; + // find userData in cache const isUserInCache = cache.hasCache("allusers"); let allUserData; @@ -328,15 +321,7 @@ const userProfileController = function (UserProfile) { userIdx = allUserData.findIndex((users) => users._id === userid); userData = allUserData[userIdx]; } - if ( - (await hasPermission( - req.body.requestor.role, - "putUserProfileImportantInfo" - )) || - req.body.requestor.permissions?.frontPermissions.includes( - "putUserProfilePermissions" - ) - ) { + if (await hasPermission(req.body.requestor, 'putUserProfileImportantInfo')) { record.role = req.body.role; record.isRehireable = req.body.isRehireable; record.isActive = req.body.isActive; @@ -402,16 +387,9 @@ const userProfileController = function (UserProfile) { record.createdDate; } - record.bioPosted = req.body.bioPosted || "default"; - if ( - (await hasPermission( - req.body.requestor.role, - "putUserProfilePermissions" - )) || - req.body.requestor.permissions?.frontPermissions.includes( - "putUserProfilePermissions" - ) - ) { + record.bioPosted = req.body.bioPosted || 'default'; + + if (await hasPermission(req.body.requestor, 'putUserProfilePermissions')) { record.permissions = req.body.permissions; } @@ -431,9 +409,7 @@ const userProfileController = function (UserProfile) { userData.createdDate = record.createdDate.toISOString(); } } - if ( - await hasPermission(req.body.requestor.role, "infringementAuthorizer") - ) { + if (await hasPermission(req.body.requestor, 'infringementAuthorizer')) { record.infringements = req.body.infringements; } @@ -463,12 +439,12 @@ const userProfileController = function (UserProfile) { const deleteUserProfile = async function (req, res) { const { option, userId } = req.body; - if (!await hasPermission(req.body.requestor.role, 'deleteUserProfile')) { + 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.role, 'addDeleteEditOwners')) { + if (req.body.role === 'Owner' && !await hasPermission(req.body.requestor, 'addDeleteEditOwners')) { res.status(403).send('You are not authorized to delete this user'); return; } @@ -602,6 +578,17 @@ 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.permissions?.frontPermissions.includes("editTeamCode"); + + if(!canEditTeamCode){ + res.status(403).send("You are not authorized to edit team code."); + return; + } + + } + // 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' }); @@ -626,24 +613,18 @@ const userProfileController = function (UserProfile) { const updatepassword = async function (req, res) { const { userId } = req.params; const { requestor } = req.body; - - console.log('User ID:', userId); - console.log('Requestor ID:', requestor.requestorId); - - // Check if userId is valid. if (!mongoose.Types.ObjectId.isValid(userId)) { - return res.status(400).send({ - error: 'Bad Request', - }); + return res.status(400).send({ + error: 'Bad Request', + }); } // Verify correct params in body if (!req.body.currentpassword || !req.body.newpassword || !req.body.confirmnewpassword) { - return res.status(400).send({ - error: 'One or more required fields are missing', - }); + 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.role, 'updatePassword'); @@ -666,31 +647,37 @@ const userProfileController = function (UserProfile) { }); } - // Process the password change - try { - const user = await UserProfile.findById(userId, 'password'); - const passwordMatch = await bcrypt.compare(req.body.currentpassword, user.password); + // 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', + }); + } - if (!passwordMatch) { - return res.status(400).send({ + 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', - }); - } - - user.set({ - password: req.body.newpassword, - resetPwd: undefined, - }); - - await user.save(); - - return res.status(200).send({ message: 'Updated password successfully' }); - - } catch (error) { - return res.status(500).send(error); - } -}; + }); + } + user.set({ + password: req.body.newpassword, + resetPwd: undefined, + }); + return user + .save() + .then(() => res.status(200).send({ message: 'updated password' })) + .catch(error => res.status(500).send(error)); + }) + .catch(error => res.status(500).send(error)); + }) + .catch(error => res.status(500).send(error)); + }; const getreportees = async function (req, res) { if (!mongoose.Types.ObjectId.isValid(req.params.userId)) { @@ -701,11 +688,10 @@ const userProfileController = function (UserProfile) { } const userid = mongoose.Types.ObjectId(req.params.userId); - const { role } = req.body.requestor; let validroles = ['Volunteer', 'Manager', 'Administrator', 'Core Team', 'Owner', 'Mentor']; - if (await hasPermission(role, 'getReporteesLimitRoles')) { + if (await hasPermission(req.body.requestor, 'getReporteesLimitRoles')) { validroles = ['Volunteer', 'Manager']; } @@ -776,7 +762,7 @@ const userProfileController = function (UserProfile) { }); return; } - if (!await hasPermission(req.body.requestor.role, 'changeUserStatus')) { + if (!await hasPermission(req.body.requestor, 'changeUserStatus')) { res.status(403).send('You are not authorized to change user status'); return; } From fa3b768b0642e87cc273b8a4cb2f90071cf9af27 Mon Sep 17 00:00:00 2001 From: tsunami776 <43768723+tsunami776@users.noreply.github.com> Date: Thu, 9 Nov 2023 10:05:04 -0600 Subject: [PATCH 132/272] Create default prompt when there is no prompt --- src/controllers/dashBoardController.js | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/controllers/dashBoardController.js b/src/controllers/dashBoardController.js index 3a203481f..40037297a 100644 --- a/src/controllers/dashBoardController.js +++ b/src/controllers/dashBoardController.js @@ -27,10 +27,26 @@ const dashboardcontroller = function () { const getDashBoardData = function (req, res) { DashboardData.findById({ _id: 'ai-prompt' }) - .then((results) => { - res.status(200).send(results); - }) - .catch(error => res.status(500).send(error)); + .then((result) => { + if (result) { + // If the GPT prompt exists, send it back. + res.status(200).send(result); + } else { + // If the GPT prompt does not exist, create it. + const defaultPrompt = { + _id: 'ai-prompt', + aIPromptText: "Please edit the following summary of my week's work. Make sure it is professionally written in 3rd person format.\nWrite it as only one paragraph. It must be only one paragraph. Keep it less than 500 words. Start the paragraph with 'This week'.\nMake sure the paragraph contains no links or URLs and write it in a tone that is matter-of-fact and without embellishment.\nDo not add flowery language, keep it simple and factual. Do not add a final summary sentence. Apply all this to the following:" + }; + DashboardData.create(defaultPrompt) + .then((newResult) => { + res.status(200).send(newResult); + }) + .catch((creationError) => { + res.status(500).send(creationError); + }); + } + }) + .catch(error => res.status(500).send(error)); }; const monthlydata = function (req, res) { From 4eb13e71cbc4271f6e4296ca94faf1bcae844e96 Mon Sep 17 00:00:00 2001 From: robertoooc Date: Thu, 9 Nov 2023 18:12:53 -0800 Subject: [PATCH 133/272] adds logic to prevent server from throwing errors when a time entry is edited and not related to task --- src/controllers/timeEntryController.js | 66 ++++++++++++++++---------- 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/src/controllers/timeEntryController.js b/src/controllers/timeEntryController.js index bea25d0a6..962f30170 100644 --- a/src/controllers/timeEntryController.js +++ b/src/controllers/timeEntryController.js @@ -122,6 +122,8 @@ const timeEntrycontroller = function (TimeEntry) { const initialSeconds = timeEntry.totalSeconds; const initialProjectId = timeEntry.projectId; const initialIsTangible = timeEntry.isTangible; + // Get the task related to this time entry, if not found, then it's a project and will be null + const findTask = await task.findById(initialProjectId); timeEntry.notes = req.body.notes; timeEntry.totalSeconds = totalSeconds; @@ -134,19 +136,19 @@ const timeEntrycontroller = function (TimeEntry) { // initialIsTangible is a bealoon value, req.body.isTangible is a string // initialProjectId may be a task id or project id, so do not throw error. try { - if (initialIsTangible === true) { - const initialTask = await task.findById(initialProjectId); - initialTask.hoursLogged -= (initialSeconds / 3600); - await initialTask.save(); - } + if (findTask) { + if (initialIsTangible === true) { + findTask.hoursLogged -= (initialSeconds / 3600); + } + + if (req.body.isTangible === true) { + findTask.hoursLogged += (totalSeconds / 3600); + } - if (req.body.isTangible === true) { - const editedTask = await task.findById(req.body.projectId); - editedTask.hoursLogged += (totalSeconds / 3600); - await editedTask.save(); + await findTask.save(); } } catch (error) { - console.log('Failed to find task by id'); + throw new Error(error); } // Update edit history @@ -203,10 +205,13 @@ const timeEntrycontroller = function (TimeEntry) { res.status(200).send({ message: 'Successfully updated time entry' }); - // checking if logged in hours exceed estimated time after timeentry edit for a task - const record = await userProfile.findById(timeEntry.personId.toString()); - const currentTask = await task.findById(req.body.projectId); - checkTaskOvertime(timeEntry, record, currentTask); + // If the time entry isn't related to a task (i.e. it's a project), then don't check for overtime (Most likely pr team) + if (findTask) { + // checking if logged in hours exceed estimated time after timeentry edit for a task + const record = await userProfile.findById(timeEntry.personId.toString()); + const currentTask = await task.findById(req.body.projectId); + checkTaskOvertime(timeEntry, record, currentTask); + } } catch (err) { await session.abortTransaction(); return res.status(400).send({ error: err.toString() }); @@ -271,20 +276,28 @@ const timeEntrycontroller = function (TimeEntry) { }) .catch(error => res.status(400).send(error)); - // Add this tangbile time entry to related task's hoursLogged - if (timeentry.isTangible === true) { + // Get the task related to this time entry, if not found, then it's a project sets to null + const currentTask = await task.findById(req.body.projectId).catch(() => null); + + // Add this tangbile time entry to related task's hoursLogged and checks if timeEntry is related to a task + if (timeentry.isTangible === true && currentTask) { try { - const currentTask = await task.findById(req.body.projectId); - currentTask.hoursLogged += (timeentry.totalSeconds / 3600); + currentTask.hoursLogged += timeentry.totalSeconds / 3600; await currentTask.save(); } catch (error) { - throw new Error('Failed to find the task by id'); + throw new Error(error); + } + } + + // checking if logged in hours exceed estimated time after timeentry for a task, only if the time entry is related to a task (It might not be, if it's a project) + if (currentTask) { + try { + const record = await userProfile.findById(timeentry.personId.toString()); + checkTaskOvertime(timeentry, record, currentTask); + } catch (error) { + throw new Error(error); } } - // checking if logged in hours exceed estimated time after timeentry for a task - const record = await userProfile.findById(timeentry.personId.toString()); - const currentTask = await task.findById(req.body.projectId); - checkTaskOvertime(timeentry, record, currentTask); }; const getTimeEntriesForSpecifiedPeriod = function (req, res) { @@ -469,8 +482,11 @@ const timeEntrycontroller = function (TimeEntry) { if (record.isTangible === true) { task.findById(record.projectId) .then((currentTask) => { - currentTask.hoursLogged -= (record.totalSeconds / 3600); - currentTask.save(); + // If the time entry isn't related to a task (i.e. it's a project), then don't revert hours (Most likely pr team) + if (currentTask) { + currentTask.hoursLogged -= (record.totalSeconds / 3600); + currentTask.save(); + } }) .catch((error) => { throw new Error(error); From 8a634b4dfdd9339a89d8dae939925a5ac10abb74 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Fri, 10 Nov 2023 09:31:52 -0800 Subject: [PATCH 134/272] add new inventory models, invtype router and controller --- .../bmdashboard/bmInventoryTypeController.js | 19 +++++++++++++ .../bmdashboard/buildingInventoryType.js | 13 +++++++++ src/models/bmdashboard/buildingMaterial.js | 28 +++++++++++++++++++ .../bmdashboard/bmInventoryTypeRouter.js | 13 +++++++++ 4 files changed, 73 insertions(+) create mode 100644 src/controllers/bmdashboard/bmInventoryTypeController.js create mode 100644 src/models/bmdashboard/buildingInventoryType.js create mode 100644 src/models/bmdashboard/buildingMaterial.js create mode 100644 src/routes/bmdashboard/bmInventoryTypeRouter.js diff --git a/src/controllers/bmdashboard/bmInventoryTypeController.js b/src/controllers/bmdashboard/bmInventoryTypeController.js new file mode 100644 index 000000000..b9ced243e --- /dev/null +++ b/src/controllers/bmdashboard/bmInventoryTypeController.js @@ -0,0 +1,19 @@ +const bmInventoryTypeController = function (InvType) { + const fetchMaterialTypes = async (req, res) => { + try { + InvType + .find() + .exec() + .then(result => res.status(200).send(result)) + .catch(error => res.status(500).send(error)); + } catch (err) { + res.json(err); + } + }; + + return { + fetchMaterialTypes, + }; +}; + +module.exports = bmInventoryTypeController; diff --git a/src/models/bmdashboard/buildingInventoryType.js b/src/models/bmdashboard/buildingInventoryType.js new file mode 100644 index 000000000..71285fa24 --- /dev/null +++ b/src/models/bmdashboard/buildingInventoryType.js @@ -0,0 +1,13 @@ +const mongoose = require('mongoose'); + +const { Schema } = mongoose; + +const buildingInventoryType = new Schema({ + category: String, // Consumable, Material, Tool, Equipment + name: String, + description: String, + unit: String, // unit of measurement + imageUrl: String, +}); + +module.exports = mongoose.model('buildingInventoryType', buildingInventoryType, 'buildingInventoryTypes'); diff --git a/src/models/bmdashboard/buildingMaterial.js b/src/models/bmdashboard/buildingMaterial.js new file mode 100644 index 000000000..714ba4ae7 --- /dev/null +++ b/src/models/bmdashboard/buildingMaterial.js @@ -0,0 +1,28 @@ +const mongoose = require('mongoose'); + +const { Schema } = mongoose; + +const buildingMaterial = new Schema({ + itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, + project: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingProject' }, + stockBought: { type: Number, default: 0 }, // total amount of item bought for use in the project + stockUsed: { type: Number, default: 0 }, // total amount of item used successfully in the project + stockWasted: { type: Number, default: 0 }, // total amount of item wasted/ruined/lost in the project + stockAvailable: { type: Number, default: 0 }, // bought - (used + wasted) + purchaseRecord: [{ + _id: false, // do not add _id field to subdocument + date: { type: Date, default: Date.now() }, + requestedBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + quantity: Number, + status: { type: String, default: 'Pending' }, // Pending, Rejected, Approved + }], + updateRecord: [{ + _id: false, + date: Date, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + quantityUsed: String, // '10 cubic yards' + quantityWasted: Number, + }], +}); + +module.exports = mongoose.model('buildingMaterial', buildingMaterial, 'buildingMaterials'); diff --git a/src/routes/bmdashboard/bmInventoryTypeRouter.js b/src/routes/bmdashboard/bmInventoryTypeRouter.js new file mode 100644 index 000000000..ceae439dc --- /dev/null +++ b/src/routes/bmdashboard/bmInventoryTypeRouter.js @@ -0,0 +1,13 @@ +const express = require('express'); + +const routes = function (invType) { + const inventoryTypeRouter = express.Router(); + const controller = require('../../controllers/bmdashboard/bmInventoryTypeController')(invType); + + inventoryTypeRouter.route('/invtypes/materials') + .get(controller.fetchMaterialTypes); + + return inventoryTypeRouter; +}; + +module.exports = routes; From cff986158da264ab65cc78e960d86b7bb4f3f58f Mon Sep 17 00:00:00 2001 From: Vishala Ramasamy Date: Fri, 10 Nov 2023 17:17:54 -0800 Subject: [PATCH 135/272] building inventory --- package-lock.json | 7 +- package.json | 1 + .../bmdashboard/bmMaterialsController.js | 68 +++++++++---------- src/models/buildingInventoryType.js | 10 +++ src/models/buildingMaterial.js | 23 +++++++ src/models/buildingProject.js | 12 ++++ src/models/inventoryItemMaterial.js | 4 +- src/routes/bmdashboard/bmMaterialsRouter.js | 4 +- src/startup/routes.js | 6 +- 9 files changed, 94 insertions(+), 41 deletions(-) create mode 100644 src/models/buildingInventoryType.js create mode 100644 src/models/buildingMaterial.js create mode 100644 src/models/buildingProject.js diff --git a/package-lock.json b/package-lock.json index 3fcc98986..d26330d5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5536,7 +5536,7 @@ "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" }, "lodash.merge": { "version": "4.6.2", @@ -5806,6 +5806,11 @@ "moment": ">= 2.9.0" } }, + "mongo-round": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mongo-round/-/mongo-round-1.0.0.tgz", + "integrity": "sha512-lwvLJv827Uks+3HnTOt1I/Qr78Avke3du1oMaFqFpTwtRKtOposNOKkfpGXQN4ZGpRN3XAS8fEppIJ4TUj0xQw==" + }, "mongodb": { "version": "3.7.3", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz", diff --git a/package.json b/package.json index 1c6b8a5d4..32d23ee6a 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "lodash": "^4.17.21", "moment": "^2.29.4", "moment-timezone": "^0.5.35", + "mongo-round": "^1.0.0", "mongodb": "^3.7.3", "mongoose": "^5.13.15", "mongoose-validator": "^2.1.0", diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index 0e96b5bbb..4529546da 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -7,18 +7,11 @@ const bmMaterialsController = function (ItemMaterial) { .populate([ { path: 'project', - select: '_id projectName', + select: '_id name', }, { - path: 'inventoryItemType', - select: '_id name uom totalStock totalAvailable', - }, - { - path: 'usageRecord', - populate: { - path: 'createdBy', - select: '_id firstName lastName', - }, + path: 'itemType', + select: '_id name unit', }, { path: 'updateRecord', @@ -30,14 +23,17 @@ const bmMaterialsController = function (ItemMaterial) { { path: 'purchaseRecord', populate: { - path: 'createdBy', + path: 'requestedBy', select: '_id firstName lastName', }, }, ]) .exec() .then(results => res.status(200).send(results)) - .catch(error => res.status(500).send(error)); + .catch(error => { + console.log(error) + res.status(500).send(error) + }); } catch (err) { res.json(err); } @@ -63,26 +59,28 @@ const bmMaterialsController = function (ItemMaterial) { } else { - quantityUsed = Number.parseFloat(quantityUsed.toFixed(2)); - quantityWasted = Number.parseFloat(quantityWasted.toFixed(2)); - let newAvailable = Number.parseFloat(quantityUsed+quantityWasted); + quantityUsed = +material.stockUsed + parseFloat(quantityUsed.toFixed(4)); + quantityWasted = +material.stockWasted + parseFloat(quantityWasted.toFixed(4)); + let newAvailable = +material.stockAvailable - parseFloat(quantityUsed+quantityWasted); ItemMaterial.updateOne( { _id: req.body.material._id }, - { - $inc: { + + { + $set: { 'stockUsed': quantityUsed, 'stockWasted': quantityWasted, 'stockAvailable': -(newAvailable) }, - $push: { - updateRecord: { - date: req.body.date, - createdBy: req.body.requestor.requestorId, - quantity: -(quantityUsed+quantityWasted), - }, + $push: { + updateRecord: { + date: req.body.date, + createdBy: req.body.requestor.requestorId, + quantity: -(quantityUsed+quantityWasted), + }, + } } - } + ) .then(results => {res.status(200).send(results)}) .catch(error => res.status(500).send({'message':error})); @@ -104,20 +102,21 @@ const bmMaterialsController = function (ItemMaterial) { quantityWasted = (+quantityWasted / 100) * material.stockAvailable; } - quantityUsed = Number.parseFloat(quantityUsed.toFixed(2)); - quantityWasted = Number.parseFloat(quantityWasted.toFixed(2)); - let newAvailable = Number.parseFloat(quantityUsed+quantityWasted); - + quantityUsed = +material.stockUsed + parseFloat(quantityUsed.toFixed(4)); + quantityWasted = +material.stockWasted + parseFloat(quantityWasted.toFixed(4)); + let newAvailable = +material.stockAvailable - parseFloat(quantityUsed+quantityWasted); + newAvailable = parseFloat(newAvailable.toFixed(4)); + console.log(quantityUsed,quantityWasted,newAvailable); return ({ updateId: material._id, - increment: { + set: { 'stockUsed': quantityUsed, 'stockWasted': quantityWasted, - 'stockAvailable': -(newAvailable) + 'stockAvailable': -newAvailable }, updateValue: { createdBy: req.body.requestor.requestorId, - quantity: -(quantityUsed+quantityWasted), + quantity: -(newAvailable), date: payload.date, }}); @@ -127,9 +126,10 @@ const bmMaterialsController = function (ItemMaterial) { try { const updatePromises = updateRecordsToBeAdded.map(updateItem => ItemMaterial.updateOne( { _id: updateItem.updateId }, - { - $inc: updateItem.increment , - $push: { usageRecord: updateItem.updateValue } }, + { + $set : updateItem.set, + $push: { updateRecord: updateItem.updateValue } + }, ).exec()); Promise.all(updatePromises) .then((results) => { diff --git a/src/models/buildingInventoryType.js b/src/models/buildingInventoryType.js new file mode 100644 index 000000000..3981b3f5a --- /dev/null +++ b/src/models/buildingInventoryType.js @@ -0,0 +1,10 @@ +const mongoose = require('mongoose'); +const { Schema } = mongoose; +const buildingInventoryType = new Schema({ + category: String, // Consumable, Material, Tool, Equipment + name: String, + description: String, + unit: String, // unit of measurement + imageUrl: String, +}); +module.exports = mongoose.model('buildingInventoryType', buildingInventoryType, 'buildingInventoryTypes'); \ No newline at end of file diff --git a/src/models/buildingMaterial.js b/src/models/buildingMaterial.js new file mode 100644 index 000000000..c1d74b879 --- /dev/null +++ b/src/models/buildingMaterial.js @@ -0,0 +1,23 @@ +const mongoose = require('mongoose'); +const { Schema } = mongoose; +const buildingMaterial = new Schema({ + itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, + project: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingProject' }, + stockBought: Number, // total amount of item bought for use in the project + stockUsed: Number, // total amount of item used successfully in the project + stockWasted: Number, // total amount of item wasted/ruined/lost in the project + stockAvailable: Number, // bought - (used + wasted) + purchaseRecord: [{ + date: { type: Date, default: Date.now() }, + requestedBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + quantity: Number, + status: { type: String, default: 'Pending' }, // Pending, Rejected, Approved + }], + updateRecord: [{ + date: Date, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + quantityUsed: String, // '10 cubic yards' + quantityWasted: Number, + }], +}); +module.exports = mongoose.model('buildingMaterial', buildingMaterial, 'buildingMaterials'); diff --git a/src/models/buildingProject.js b/src/models/buildingProject.js new file mode 100644 index 000000000..20d26fc41 --- /dev/null +++ b/src/models/buildingProject.js @@ -0,0 +1,12 @@ +const mongoose = require('mongoose'); +const { Schema } = mongoose; +const buildingProject = new Schema({ + isActive: Boolean, + name: String, + template: String, // construction template (ie Earthbag Village) + location: String, // use lat/lng instead? + dateCreated: { type: Date, default: Date.now }, + buildingManager: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, // BM's id + team: [{ type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }], +}); +module.exports = mongoose.model('buildingProject', buildingProject, 'buildingProjects'); \ No newline at end of file diff --git a/src/models/inventoryItemMaterial.js b/src/models/inventoryItemMaterial.js index 8460ecd6e..3cc7a9966 100644 --- a/src/models/inventoryItemMaterial.js +++ b/src/models/inventoryItemMaterial.js @@ -7,9 +7,9 @@ const InventoryItemMaterial = new Schema({ project: { type: mongoose.SchemaTypes.ObjectId, ref: 'project', required: true }, stockBought: { type: Number, required: true }, // amount bought for project, affects total stock stockUsed: { type: Number, required: true }, - stockAvailable: { type: Number, required: true }, + stockAvailable: { type: Number, required: true}, stockHeld: { type: Number, required: true }, - stockWasted: { type: Number, required: true }, + stockWasted: { type: Number, required: true }, usageRecord: [{ // daily log of amount inventory item used at job site date: { type: Date, required: true, default: Date.now() }, createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile', required: true }, diff --git a/src/routes/bmdashboard/bmMaterialsRouter.js b/src/routes/bmdashboard/bmMaterialsRouter.js index 35a887b9b..d56c682bd 100644 --- a/src/routes/bmdashboard/bmMaterialsRouter.js +++ b/src/routes/bmdashboard/bmMaterialsRouter.js @@ -1,8 +1,8 @@ const express = require('express'); -const routes = function (itemMaterial) { +const routes = function (buildingMaterial) { const materialsRouter = express.Router(); -const controller = require('../../controllers/bmdashboard/bmMaterialsController')(itemMaterial); +const controller = require('../../controllers/bmdashboard/bmMaterialsController')(buildingMaterial); materialsRouter.route('/materials') .get(controller.bmMaterialsList); diff --git a/src/startup/routes.js b/src/startup/routes.js index 7208535d8..798ae969e 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -21,7 +21,9 @@ const ownerStandardMessage = require('../models/ownerStandardMessage'); const profileInitialSetuptoken = require('../models/profileInitialSetupToken'); const reason = require('../models/reason'); const mouseoverText = require('../models/mouseoverText'); -const inventoryItemMaterial = require('../models/inventoryItemMaterial'); +const buildingMaterial = require('../models/buildingMaterial'); +const buildingProject = require('../models/buildingProject'); +const buildingInventoryType = require('../models/buildingInventoryType'); const userProfileRouter = require('../routes/userProfileRouter')(userProfile); const badgeRouter = require('../routes/badgeRouter')(badge); @@ -60,7 +62,7 @@ const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverTe // bm dashboard const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); -const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial); +const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(buildingMaterial); const bmProjectsRouter = require('../routes/bmdashboard/bmProjectsRouter')(); module.exports = function (app) { From 36dd97298dcf2ec8e34801c1ba7b2f7de074f028 Mon Sep 17 00:00:00 2001 From: Vishala Ramasamy Date: Fri, 10 Nov 2023 19:17:11 -0800 Subject: [PATCH 136/272] building material update --- .../bmdashboard/bmMaterialsController.js | 60 ++++++++++--------- .../bmdashboard/bmProjectsController.js | 31 ---------- .../buildingInventoryType.js | 0 .../{ => bmdashboard}/buildingMaterial.js | 0 src/models/buildingProject.js | 12 ---- src/routes/bmdashboard/bmMaterialsRouter.js | 4 +- src/routes/bmdashboard/bmProjectsRouter.js | 13 ---- src/startup/routes.js | 9 ++- 8 files changed, 38 insertions(+), 91 deletions(-) delete mode 100644 src/controllers/bmdashboard/bmProjectsController.js rename src/models/{ => bmdashboard}/buildingInventoryType.js (100%) rename src/models/{ => bmdashboard}/buildingMaterial.js (100%) delete mode 100644 src/models/buildingProject.js delete mode 100644 src/routes/bmdashboard/bmProjectsRouter.js diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index ebf5798fa..c5403de21 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -37,18 +37,18 @@ const bmMaterialsController = function (ItemMaterial) { }; const bmPostMaterialUpdateRecord = function (req, res) { - + let payload = req.body; let quantityUsed = +req.body.quantityUsed; let quantityWasted = +req.body.quantityWasted; let material = req.body.material; - if(req.body.QtyUsedLogUnit=='percent' && quantityWasted>=0) - { - quantityUsed = (+quantityUsed / 100) * material.stockAvailable; - } - if(req.body.QtyWastedLogUnit=='percent' && quantityUsed>=0) - { - quantityWasted = (+quantityWasted / 100) * material.stockAvailable; - } + if(payload.QtyUsedLogUnit=='percent' && quantityWasted>=0) + { + quantityUsed = +((+quantityUsed / 100) * material.stockAvailable).toFixed(4); + } + if(payload.QtyWastedLogUnit=='percent' && quantityUsed>=0) + { + quantityWasted = +((+quantityWasted / 100) * material.stockAvailable).toFixed(4); + } if(quantityUsed>material.stockAvailable || quantityWasted>material.stockAvailable || (quantityUsed+quantityWasted)>material.stockAvailable) { @@ -56,24 +56,27 @@ const bmMaterialsController = function (ItemMaterial) { } else { - quantityUsed = +material.stockUsed + parseFloat(quantityUsed.toFixed(4)); - quantityWasted = +material.stockWasted + parseFloat(quantityWasted.toFixed(4)); - let newAvailable = +material.stockAvailable - parseFloat(quantityUsed+quantityWasted); - + let newStockUsed = +material.stockUsed + parseFloat(quantityUsed); + let newStockWasted = +material.stockWasted + parseFloat(quantityWasted); + let newAvailable = +material.stockAvailable - parseFloat(quantityUsed) - parseFloat(quantityWasted); + newStockUsed = parseFloat(newStockUsed.toFixed(4)); + newStockWasted = parseFloat(newStockWasted.toFixed(4)); + newAvailable = parseFloat(newAvailable.toFixed(4)); ItemMaterial.updateOne( { _id: req.body.material._id }, { $set: { - 'stockUsed': quantityUsed, - 'stockWasted': quantityWasted, - 'stockAvailable': -(newAvailable) + 'stockUsed': newStockUsed, + 'stockWasted': newStockWasted, + 'stockAvailable': newAvailable }, $push: { updateRecord: { date: req.body.date, createdBy: req.body.requestor.requestorId, - quantity: -(quantityUsed+quantityWasted), + quantityUsed: quantityUsed + ' ' + material.itemType.unit, + quantityWasted: quantityWasted }, } } @@ -92,33 +95,34 @@ const bmMaterialsController = function (ItemMaterial) { let material = payload.material; if(payload.QtyUsedLogUnit=='percent' && quantityWasted>=0) { - quantityUsed = (+quantityUsed / 100) * material.stockAvailable; + quantityUsed = +((+quantityUsed / 100) * material.stockAvailable).toFixed(4); } if(payload.QtyWastedLogUnit=='percent' && quantityUsed>=0) { - quantityWasted = (+quantityWasted / 100) * material.stockAvailable; + quantityWasted = +((+quantityWasted / 100) * material.stockAvailable).toFixed(4); } - quantityUsed = +material.stockUsed + parseFloat(quantityUsed.toFixed(4)); - quantityWasted = +material.stockWasted + parseFloat(quantityWasted.toFixed(4)); - let newAvailable = +material.stockAvailable - parseFloat(quantityUsed+quantityWasted); + let newStockUsed = +material.stockUsed + parseFloat(quantityUsed); + let newStockWasted = +material.stockWasted + parseFloat(quantityWasted); + let newAvailable = +material.stockAvailable - parseFloat(quantityUsed) - parseFloat(quantityWasted); + newStockUsed = parseFloat(newStockUsed.toFixed(4)); + newStockWasted = parseFloat(newStockWasted.toFixed(4)); newAvailable = parseFloat(newAvailable.toFixed(4)); - console.log(quantityUsed,quantityWasted,newAvailable); return ({ updateId: material._id, set: { - 'stockUsed': quantityUsed, - 'stockWasted': quantityWasted, - 'stockAvailable': -newAvailable + 'stockUsed': newStockUsed, + 'stockWasted': newStockWasted, + 'stockAvailable': newAvailable }, updateValue: { createdBy: req.body.requestor.requestorId, - quantity: -(newAvailable), + quantityUsed: quantityUsed + ' ' + material.itemType.unit, + quantityWasted: quantityWasted, date: payload.date, }}); }); - console.log(updateRecordsToBeAdded); try { const updatePromises = updateRecordsToBeAdded.map(updateItem => ItemMaterial.updateOne( diff --git a/src/controllers/bmdashboard/bmProjectsController.js b/src/controllers/bmdashboard/bmProjectsController.js deleted file mode 100644 index 3ff0f851a..000000000 --- a/src/controllers/bmdashboard/bmProjectsController.js +++ /dev/null @@ -1,31 +0,0 @@ -const mongoose = require('mongoose'); -const UserProfile = require('../../models/userProfile'); - -const bmProjectsController = function () { - // Get current user's Housing/Building projects - const getUserActiveBMProjects = function (req, res) { - try { - const userId = req.body.requestor.requestorId; - UserProfile.findById(userId) - .populate([ - { - path: 'projects', - select: '_id projectName category isActive', - match: { category: 'Housing' }, - }, - ]) - .select({ - projects: 1, - }) - .then((results) => { - res.status(200).send(results); - }) - .catch(error => res.status(500).send(error)); - } catch (err) { - res.json(err); - } - }; - return { getUserActiveBMProjects }; -}; - -module.exports = bmProjectsController; diff --git a/src/models/buildingInventoryType.js b/src/models/bmdashboard/buildingInventoryType.js similarity index 100% rename from src/models/buildingInventoryType.js rename to src/models/bmdashboard/buildingInventoryType.js diff --git a/src/models/buildingMaterial.js b/src/models/bmdashboard/buildingMaterial.js similarity index 100% rename from src/models/buildingMaterial.js rename to src/models/bmdashboard/buildingMaterial.js diff --git a/src/models/buildingProject.js b/src/models/buildingProject.js deleted file mode 100644 index 20d26fc41..000000000 --- a/src/models/buildingProject.js +++ /dev/null @@ -1,12 +0,0 @@ -const mongoose = require('mongoose'); -const { Schema } = mongoose; -const buildingProject = new Schema({ - isActive: Boolean, - name: String, - template: String, // construction template (ie Earthbag Village) - location: String, // use lat/lng instead? - dateCreated: { type: Date, default: Date.now }, - buildingManager: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, // BM's id - team: [{ type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }], -}); -module.exports = mongoose.model('buildingProject', buildingProject, 'buildingProjects'); \ No newline at end of file diff --git a/src/routes/bmdashboard/bmMaterialsRouter.js b/src/routes/bmdashboard/bmMaterialsRouter.js index d56c682bd..a07d82b5c 100644 --- a/src/routes/bmdashboard/bmMaterialsRouter.js +++ b/src/routes/bmdashboard/bmMaterialsRouter.js @@ -7,10 +7,10 @@ const controller = require('../../controllers/bmdashboard/bmMaterialsController' materialsRouter.route('/materials') .get(controller.bmMaterialsList); -materialsRouter.route('/addUpdateMaterialRecord') +materialsRouter.route('/updateMaterialRecord') .post(controller.bmPostMaterialUpdateRecord); - materialsRouter.route('/UpdateMaterialRecordBulk') + materialsRouter.route('/updateMaterialRecordBulk') .post(controller.bmPostMaterialUpdateBulk); diff --git a/src/routes/bmdashboard/bmProjectsRouter.js b/src/routes/bmdashboard/bmProjectsRouter.js deleted file mode 100644 index a171fc4cd..000000000 --- a/src/routes/bmdashboard/bmProjectsRouter.js +++ /dev/null @@ -1,13 +0,0 @@ -const express = require('express'); - -const routes = function () { -const materialsRouter = express.Router(); -const controller = require('../../controllers/bmdashboard/bmProjectsController')(); - -materialsRouter.route('/getUserActiveBMProjects') - .get(controller.getUserActiveBMProjects); - - return materialsRouter; -}; - -module.exports = routes; diff --git a/src/startup/routes.js b/src/startup/routes.js index 201c777b9..1713d6a67 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -20,9 +20,9 @@ const ownerStandardMessage = require('../models/ownerStandardMessage'); const profileInitialSetuptoken = require('../models/profileInitialSetupToken'); const reason = require('../models/reason'); const mouseoverText = require('../models/mouseoverText'); -const buildingMaterial = require('../models/buildingMaterial'); -const buildingProject = require('../models/buildingProject'); -const buildingInventoryType = require('../models/buildingInventoryType'); +const buildingMaterial = require('../models/bmdashboard/buildingMaterial'); +const buildingProject = require('../models/bmdashboard/buildingProject'); +const buildingInventoryType = require('../models/bmdashboard/buildingInventoryType'); const userProfileRouter = require('../routes/userProfileRouter')(userProfile); const badgeRouter = require('../routes/badgeRouter')(badge); @@ -61,7 +61,6 @@ const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverTe // bm dashboard const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(buildingMaterial); -const bmProjectsRouter = require('../routes/bmdashboard/bmProjectsRouter')(); const bmProjectRouter = require('../routes/bmdashboard/bmProjectRouter')(buildingProject); module.exports = function (app) { @@ -96,6 +95,6 @@ module.exports = function (app) { app.use('/api', isEmailExistsRouter); // bm dashboard app.use('/api/bm', bmLoginRouter); - app.use('/api/bm', bmProjectsRouter); app.use('/api/bm', bmProjectRouter); + app.use('/api/bm', bmMaterialsRouter); }; From 55dd2e67cdf3b9fb91081ccb175003129c2b91d7 Mon Sep 17 00:00:00 2001 From: Aishwaryak01 Date: Sat, 11 Nov 2023 12:04:05 -0500 Subject: [PATCH 137/272] Create buildingTools.js Created model file for buildingTools.js which consists of schema to hold various attribute information related to tools. --- src/models/bmdashboard/buildingTools.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/models/bmdashboard/buildingTools.js diff --git a/src/models/bmdashboard/buildingTools.js b/src/models/bmdashboard/buildingTools.js new file mode 100644 index 000000000..94468de42 --- /dev/null +++ b/src/models/bmdashboard/buildingTools.js @@ -0,0 +1,19 @@ +const mongoose = require('mongoose'); + +const { Schema } = mongoose; + +const buildingTools = new Schema({ + inventoryItemId: { type: mongoose.SchemaTypes.ObjectId, ref: 'INVENTORY' }, // later ,INVENTORY needs to be changed as per inventory model + title: { type: String, required: true }, + image: { type: String, required: true }, + rentedOnDate: { type: Date, required: true }, + rentDuration: { type: Number, required: true }, // This value should be taken in number of days + total: {type: Number, required: true}, + availableCount:{type: Number, required: true}, + logInStatus:{Boolean}, + condition:{type: String, enum: ['Good', 'Needs Repair', 'Out of Order','Unused'], default: 'Condition'}, + userResponsible:{ type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + purchaseStatus:{type: String, enum: ['Rented', 'Purchased'], default: 'Status'}, +}); + +module.exports = mongoose.model('buildingTools', buildingTools, 'buildingTools'); \ No newline at end of file From bd537f79f38c980eea9ba1660e6b89aff577ece8 Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Mon, 13 Nov 2023 10:52:54 +0800 Subject: [PATCH 138/272] solve weekly summaries report page issue --- src/helpers/reporthelper.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/helpers/reporthelper.js b/src/helpers/reporthelper.js index c812ef03c..0c2a8104d 100644 --- a/src/helpers/reporthelper.js +++ b/src/helpers/reporthelper.js @@ -68,9 +68,6 @@ const reporthelper = function () { moment(pstEnd).format("YYYY-MM-DD"), ], }, - { - $in: ['$$timeentry.entryType', ['default', null]], - }, ], }, }, From 9512ea0b5241968f5721c8db526c207807f860b0 Mon Sep 17 00:00:00 2001 From: Carl Bebli Date: Mon, 13 Nov 2023 11:56:18 +0000 Subject: [PATCH 139/272] added new fields to the email options and edited the email body --- src/controllers/dashBoardController.js | 109 ++++++++++++------------- 1 file changed, 54 insertions(+), 55 deletions(-) diff --git a/src/controllers/dashBoardController.js b/src/controllers/dashBoardController.js index aacc915dd..68e88ae58 100644 --- a/src/controllers/dashBoardController.js +++ b/src/controllers/dashBoardController.js @@ -1,8 +1,8 @@ -const path = require('path'); -const fs = require('fs/promises'); -const mongoose = require('mongoose'); -const dashboardhelper = require('../helpers/dashboardhelper')(); -const emailSender = require('../utilities/emailSender'); +const path = require("path"); +const fs = require("fs/promises"); +const mongoose = require("mongoose"); +const dashboardhelper = require("../helpers/dashboardhelper")(); +const emailSender = require("../utilities/emailSender"); const dashboardcontroller = function () { const dashboarddata = function (req, res) { @@ -20,13 +20,13 @@ const dashboardcontroller = function () { const laborthismonth = dashboardhelper.laborthismonth( userId, req.params.fromDate, - req.params.toDate, + req.params.toDate ); laborthismonth.then((results) => { if (!results || results.length === 0) { const emptyresult = [ { - projectName: '', + projectName: "", timeSpent_hrs: 0, }, ]; @@ -42,7 +42,7 @@ const dashboardcontroller = function () { const laborthisweek = dashboardhelper.laborthisweek( userId, req.params.fromDate, - req.params.toDate, + req.params.toDate ); laborthisweek.then((results) => { res.send(results).status(200); @@ -63,7 +63,7 @@ const dashboardcontroller = function () { }); } }) - .catch(error => res.status(400).send(error)); + .catch((error) => res.status(400).send(error)); }; const orgData = function (req, res) { @@ -73,7 +73,7 @@ const dashboardcontroller = function () { .then((results) => { res.status(200).send(results[0]); }) - .catch(error => res.status(400).send(error)); + .catch((error) => res.status(400).send(error)); }; const getBugReportEmailBody = function ( @@ -85,7 +85,7 @@ const dashboardcontroller = function () { expected, actual, visual, - severity, + severity ) { const text = `New Bug Report From ${firstName} ${lastName}:

[Feature Name] Bug Title:

@@ -130,32 +130,32 @@ const dashboardcontroller = function () { expected, actual, visual, - severity, + severity ); try { emailSender( - 'onecommunityglobal@gmail.com', + "onecommunityglobal@gmail.com", `Bug Rport from ${firstName} ${lastName}`, emailBody, - email, + email ); - res.status(200).send('Success'); + res.status(200).send("Success"); } catch { - res.status(500).send('Failed'); + res.status(500).send("Failed"); } }; const suggestionData = { suggestion: [ - 'Identify and remedy poor client and/or user service experiences', - 'Identify bright spots and enhance positive service experiences', - 'Make fundamental changes to our programs and/or operations', - 'Inform the development of new programs/projects', - 'Identify where we are less inclusive or equitable across demographic groups', - 'Strengthen relationships with the people we serve', + "Identify and remedy poor client and/or user service experiences", + "Identify bright spots and enhance positive service experiences", + "Make fundamental changes to our programs and/or operations", + "Inform the development of new programs/projects", + "Identify where we are less inclusive or equitable across demographic groups", + "Strengthen relationships with the people we serve", "Understand people's needs and how we can help them achieve their goals", - 'Other', + "Other", ], field: [], }; @@ -164,54 +164,53 @@ const dashboardcontroller = function () { let fieldaaray = []; if (suggestionData.field.length) { fieldaaray = suggestionData.field.map( - item => `

${item}

-

${args[3][item]}

`, + (item) => `

${item}

+

${args[3][item]}

` ); } const text = `New Suggestion From ${args[3].firstName} ${ args[3].lastName - }: -

Suggestion Category:

+ } + : + ⚹ Suggestion Category:

${args[0]}

-

Suggestion:

+ ⚹ Suggestion:

${args[1]}

- ${fieldaaray.length > 0 ? fieldaaray : ''} -

Name of Suggester:

+ ${fieldaaray.length > 0 ? fieldaaray : ""} + ⚹ Name of Suggester:

${args[3].firstName} ${args[3].lastName}

-

Email of Suggester:

+ ⚹ Email of Suggester:

${args[4]}

-

Wants Feedback:

+ ⚹ Wants Feedback:

${args[2]}

-

Thank you,
- One Community

`; + Thank you,
+ One Community
`; return text; }; // send suggestion email const sendMakeSuggestion = async (req, res) => { - const { - suggestioncate, suggestion, confirm, email, ...rest -} = req.body; + const { suggestioncate, suggestion, confirm, email, ...rest } = req.body; const emailBody = await getsuggestionEmailBody( suggestioncate, suggestion, confirm, rest, - email, + email ); try { emailSender( - 'beblicarl.cb@gmail.com', - 'A new suggestion', + "onecommunityglobal@gmail.com", + "A new suggestion", emailBody, null, null, - email, + email ); - res.status(200).send('Success'); + res.status(200).send("Success"); } catch { - res.status(500).send('Failed'); + res.status(500).send("Failed"); } }; @@ -220,40 +219,40 @@ const dashboardcontroller = function () { if (suggestionData) { res.status(200).send(suggestionData); } else { - res.status(404).send('Suggestion data not found.'); + res.status(404).send("Suggestion data not found."); } } catch (error) { - console.error('Error getting suggestion data:', error); - res.status(500).send('Internal Server Error'); + console.error("Error getting suggestion data:", error); + res.status(500).send("Internal Server Error"); } }; const editSuggestionOption = async (req, res) => { try { if (req.body.suggestion) { - if (req.body.action === 'add') { + if (req.body.action === "add") { suggestionData.suggestion.unshift(req.body.newField); } - if (req.body.action === 'delete') { + if (req.body.action === "delete") { suggestionData.suggestion = suggestionData.suggestion.filter( - (item, index) => index + 1 !== +req.body.newField, + (item, index) => index + 1 !== +req.body.newField ); } } else { - if (req.body.action === 'add') { + if (req.body.action === "add") { suggestionData.field.unshift(req.body.newField); } - if (req.body.action === 'delete') { + if (req.body.action === "delete") { suggestionData.field = suggestionData.field.filter( - item => item !== req.body.newField, + (item) => item !== req.body.newField ); } } - res.status(200).send('success'); + res.status(200).send("success"); } catch (error) { - console.error('Error editing suggestion option:', error); - res.status(500).send('Internal Server Error'); + console.error("Error editing suggestion option:", error); + res.status(500).send("Internal Server Error"); } }; From db3a8703a27fce2f9b3d926f725d0c889bb7ee2b Mon Sep 17 00:00:00 2001 From: Carl Bebli Date: Mon, 13 Nov 2023 11:58:25 +0000 Subject: [PATCH 140/272] added new fields in the email options --- src/utilities/emailSender.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/utilities/emailSender.js b/src/utilities/emailSender.js index 98ca3e337..b4864add6 100644 --- a/src/utilities/emailSender.js +++ b/src/utilities/emailSender.js @@ -1,6 +1,6 @@ -const nodemailer = require("nodemailer"); -const { google } = require("googleapis"); -const logger = require("../startup/logger"); +const nodemailer = require('nodemailer'); +const { google } = require('googleapis'); +const logger = require('../startup/logger'); const closure = () => { const queue = []; @@ -12,9 +12,9 @@ const closure = () => { const REFRESH_TOKEN = process.env.REACT_APP_EMAIL_REFRESH_TOKEN; // Create the email envelope (transport) const transporter = nodemailer.createTransport({ - service: "gmail", + service: 'gmail', auth: { - type: "OAuth2", + type: 'OAuth2', user: CLIENT_EMAIL, clientId: CLIENT_ID, clientSecret: CLIENT_SECRET, @@ -24,7 +24,7 @@ const closure = () => { const OAuth2Client = new google.auth.OAuth2( CLIENT_ID, CLIENT_SECRET, - REDIRECT_URI + REDIRECT_URI, ); OAuth2Client.setCredentials({ refresh_token: REFRESH_TOKEN }); @@ -34,7 +34,9 @@ const closure = () => { if (!nextItem) return; - const { recipient, subject, message, cc, bcc, replyTo } = nextItem; + const { + recipient, subject, message, cc, bcc, replyTo, +} = nextItem; try { // Generate the accessToken on the fly @@ -69,7 +71,7 @@ const closure = () => { message, cc = null, bcc = null, - replyTo = null + replyTo = null, ) { if (process.env.sendEmail) { queue.push({ From 54aeac506b0cba57b56fe7999742e135de4642ec Mon Sep 17 00:00:00 2001 From: Oleksandr Riazantsev Date: Mon, 13 Nov 2023 14:36:42 -0500 Subject: [PATCH 141/272] merging development --- src/controllers/badgeController.js | 3 + .../bmdashboard/bmMaterialsController.js | 24 +++--- .../bmdashboard/bmProjectController.js | 79 +++++++++++++++++++ src/helpers/userHelper.js | 45 +++++++++-- src/models/bmdashboard/buildingProject.js | 15 ++++ src/models/inventoryItemMaterial.js | 6 +- src/routes/bmdashboard/bmMaterialsRouter.js | 4 +- src/routes/bmdashboard/bmProjectRouter.js | 16 ++++ src/startup/routes.js | 4 + src/utilities/escapeRegex.js | 2 +- 10 files changed, 172 insertions(+), 26 deletions(-) create mode 100644 src/controllers/bmdashboard/bmProjectController.js create mode 100644 src/models/bmdashboard/buildingProject.js create mode 100644 src/routes/bmdashboard/bmProjectRouter.js diff --git a/src/controllers/badgeController.js b/src/controllers/badgeController.js index 62bad6399..366c9323e 100644 --- a/src/controllers/badgeController.js +++ b/src/controllers/badgeController.js @@ -2,6 +2,7 @@ const mongoose = require('mongoose'); const UserProfile = require('../models/userProfile'); const { hasPermission } = require('../utilities/permissions'); const escapeRegex = require('../utilities/escapeRegex'); +const cache = require('../utilities/nodeCache')(); const badgeController = function (Badge) { const getAllBadges = async function (req, res) { @@ -47,6 +48,8 @@ const badgeController = function (Badge) { if (result) { record.badgeCollection = req.body.badgeCollection; + if (cache.hasCache(`user-${userToBeAssigned}`)) cache.removeCache(`user-${userToBeAssigned}`); + record.save() .then(results => res.status(201).send(results._id)) .catch(errors => res.status(500).send(errors)); diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index a31ed460e..fb6003e90 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -1,4 +1,4 @@ -const mongoose = require('mongoose') +const mongoose = require('mongoose'); const bmMaterialsController = function (ItemMaterial) { const bmMaterialsList = async function _matsList(req, res) { @@ -7,37 +7,37 @@ const bmMaterialsController = function (ItemMaterial) { .populate([ { path: 'project', - select: '_id projectName' + select: '_id projectName', }, { path: 'inventoryItemType', - select: '_id name uom totalStock totalAvailable' + select: '_id name uom totalStock totalAvailable', }, { path: 'usageRecord', populate: { path: 'createdBy', - select: '_id firstName lastName' - } + select: '_id firstName lastName', + }, }, { path: 'updateRecord', populate: { path: 'createdBy', - select: '_id firstName lastName' - } + select: '_id firstName lastName', + }, }, { path: 'purchaseRecord', populate: { path: 'createdBy', - select: '_id firstName lastName' - } - } + select: '_id firstName lastName', + }, + }, ]) .exec() .then(results => res.status(200).send(results)) - .catch(error => res.status(500).send(error)) + .catch(error => res.status(500).send(error)); } catch (err) { res.json(err); } @@ -45,4 +45,4 @@ const bmMaterialsController = function (ItemMaterial) { return { bmMaterialsList }; }; -module.exports = bmMaterialsController; \ No newline at end of file +module.exports = bmMaterialsController; diff --git a/src/controllers/bmdashboard/bmProjectController.js b/src/controllers/bmdashboard/bmProjectController.js new file mode 100644 index 000000000..929aba4ba --- /dev/null +++ b/src/controllers/bmdashboard/bmProjectController.js @@ -0,0 +1,79 @@ +// TODO: uncomment when executing auth checks +// const jwt = require('jsonwebtoken'); +// const config = require('../../config'); + +const bmMProjectController = function (BuildingProject) { + // TODO: uncomment when executing auth checks + // const { JWT_SECRET } = config; + + const fetchAllProjects = async (req, res) => { + //! Note: for easier testing this route currently returns all projects from the db + // TODO: uncomment the lines below to return only projects where field buildingManager === userid + // const token = req.headers.authorization; + // const { userid } = jwt.verify(token, JWT_SECRET); + try { + const projectData = await BuildingProject + // TODO: uncomment this line to filter by buildingManager field + // .find({ buildingManager: userid }) + .find() + .populate([ + { + path: 'buildingManager', + select: '_id firstName lastName email', + }, + { + path: 'team', + select: '_id firstName lastName email', + }, + ]) + .exec() + .then(result => result) + .catch(error => res.status(500).send(error)); + res.status(200).send(projectData); + } catch (err) { + res.json(err); + } + }; + + // fetches single project by project id + const fetchSingleProject = async (req, res) => { + //! Note: for easier testing this route currently returns the project without an auth check + // TODO: uncomment the lines below to check the user's ability to view the current project + // const token = req.headers.authorization; + // const { userid } = jwt.verify(token, JWT_SECRET); + const { projectId } = req.params; + try { + BuildingProject + .findById(projectId) + .populate([ + { + path: 'buildingManager', + select: '_id firstName lastName email', + }, + { + path: 'team', + select: '_id firstName lastName email', + }, + ]) + .exec() + .then(project => res.status(200).send(project)) + // TODO: uncomment this block to execute the auth check + // authenticate request by comparing userId param with buildingManager id field + // Note: _id has type object and must be converted to string + // .then((project) => { + // if (userid !== project.buildingManager._id.toString()) { + // return res.status(403).send({ + // message: 'You are not authorized to view this record.', + // }); + // } + // return res.status(200).send(project); + // }) + .catch(error => res.status(500).send(error)); + } catch (err) { + res.json(err); + } + }; + return { fetchAllProjects, fetchSingleProject }; +}; + +module.exports = bmMProjectController; diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index af416f1a7..c75dd7b45 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -87,8 +87,18 @@ const userHelper = function () { firstName, lastName, infringement, - totalInfringements + totalInfringements, + timeRemaining ) { + let final_paragraph = ''; + + if (timeRemaining == undefined) { + final_paragraph = '

Life happens and we understand that. That’s why we allow 5 of them before taking action. This action usually includes removal from our team though, so please let your direct supervisor know what happened and do your best to avoid future blue squares if you are getting close to 5 and wish to avoid termination. Each blue square drops off after a year.

'; + } else { + final_paragraph = `

Life happens and we understand that. Please make up the missed hours this following week though to avoid getting another blue square. So you know what’s needed, the missing/incomplete hours (${timeRemaining} hours) have been added to your current week and this new weekly total can be seen at the top of your dashboard.

+

Reminder also that each blue square is removed from your profile 1 year after it was issued.

`; + } + const text = `Dear ${firstName} ${lastName},

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

Date Assigned: ${infringement.date}

@@ -96,9 +106,10 @@ const userHelper = function () {

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

-

Life happens and we understand that. That’s why we allow 5 of them before taking action. This action usually includes removal from our team though, so please let your direct supervisor know what happened and do your best to avoid future blue squares if you are getting close to 5 and wish to avoid termination. Each blue square drops off after a year.

+ ${final_paragraph}

Thank you,
One Community

`; + return text; }; @@ -322,6 +333,8 @@ const userHelper = function () { for (let i = 0; i < users.length; i += 1) { const user = users[i]; + const person = await userProfile.findById(user._id); + const foundReason = await Reason.findOne({ date: currentUTCDate, userId: user._id, @@ -356,6 +369,9 @@ const userHelper = function () { const timeNotMet = timeSpent < weeklycommittedHours; let description; + const timeRemaining = weeklycommittedHours - timeSpent; + + const updateResult = await userProfile.findByIdAndUpdate( personId, { @@ -446,15 +462,28 @@ const userHelper = function () { { new: true } ); - emailSender( - status.email, - "New Infringement Assigned", - getInfringementEmailBody( + let emailBody = ''; + if (person.role == 'Core Team' && timeRemaining > 0) { + emailBody = getInfringementEmailBody( status.firstName, status.lastName, infringement, - status.infringements.length - ), + status.infringements.length, + timeRemaining, + ); + } else { + emailBody = getInfringementEmailBody( + status.firstName, + status.lastName, + infringement, + status.infringements.length, + ); + } + + emailSender( + status.email, + 'New Infringement Assigned', + emailBody, null, "onecommunityglobal@gmail.com" ); diff --git a/src/models/bmdashboard/buildingProject.js b/src/models/bmdashboard/buildingProject.js new file mode 100644 index 000000000..566bc124e --- /dev/null +++ b/src/models/bmdashboard/buildingProject.js @@ -0,0 +1,15 @@ +const mongoose = require('mongoose'); + +const { Schema } = mongoose; + +const buildingProject = new Schema({ + isActive: Boolean, + name: String, + template: String, // construction template (ie Earthbag Village) + location: String, // use lat/lng instead? + dateCreated: { type: Date, default: Date.now }, + buildingManager: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, // BM's id + team: [{ type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }], +}); + +module.exports = mongoose.model('buildingProject', buildingProject, 'buildingProjects'); diff --git a/src/models/inventoryItemMaterial.js b/src/models/inventoryItemMaterial.js index e6153af45..8460ecd6e 100644 --- a/src/models/inventoryItemMaterial.js +++ b/src/models/inventoryItemMaterial.js @@ -29,12 +29,12 @@ const InventoryItemMaterial = new Schema({ poId: { type: String, required: true }, sellerId: { type: String, required: true }, quantity: { type: Number, required: true }, // adds to stockBought - unitPrice: {type: Number, required: true}, + unitPrice: { type: Number, required: true }, currency: { type: String, required: true }, subtotal: { type: Number, required: true }, tax: { type: Number, required: true }, shipping: { type: Number, required: true }, - }] -}) + }], +}); module.exports = mongoose.model('inventoryItemMaterial', InventoryItemMaterial, 'inventoryMaterial'); diff --git a/src/routes/bmdashboard/bmMaterialsRouter.js b/src/routes/bmdashboard/bmMaterialsRouter.js index ab8a67388..1188acf9d 100644 --- a/src/routes/bmdashboard/bmMaterialsRouter.js +++ b/src/routes/bmdashboard/bmMaterialsRouter.js @@ -8,6 +8,6 @@ materialsRouter.route('/materials') .get(controller.bmMaterialsList); return materialsRouter; -} +}; -module.exports = routes; \ No newline at end of file +module.exports = routes; diff --git a/src/routes/bmdashboard/bmProjectRouter.js b/src/routes/bmdashboard/bmProjectRouter.js new file mode 100644 index 000000000..d60ea9b2b --- /dev/null +++ b/src/routes/bmdashboard/bmProjectRouter.js @@ -0,0 +1,16 @@ +const express = require('express'); + +const routes = function (buildingProject) { + const projectRouter = express.Router(); + const controller = require('../../controllers/bmdashboard/bmProjectController')(buildingProject); + +projectRouter.route('/projects') + .get(controller.fetchAllProjects); + +projectRouter.route('/project/:projectId') + .get(controller.fetchSingleProject); + + return projectRouter; +}; + +module.exports = routes; diff --git a/src/startup/routes.js b/src/startup/routes.js index 0f4c7308c..c7a7393c9 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -22,6 +22,8 @@ const reason = require('../models/reason'); const mouseoverText = require('../models/mouseoverText'); const inventoryItemMaterial = require('../models/inventoryItemMaterial'); const mapLocations = require('../models/mapLocation'); +const buildingProject = require('../models/bmdashboard/buildingProject'); + const userProfileRouter = require('../routes/userProfileRouter')(userProfile); const badgeRouter = require('../routes/badgeRouter')(badge); @@ -62,6 +64,7 @@ const mapLocationRouter = require('../routes/mapLocationsRouter')(mapLocations); // bm dashboard const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial); +const bmProjectRouter = require('../routes/bmdashboard/bmProjectRouter')(buildingProject); module.exports = function (app) { app.use('/api', forgotPwdRouter); @@ -97,4 +100,5 @@ module.exports = function (app) { // bm dashboard app.use('/api/bm', bmLoginRouter); app.use('/api/bm', bmMaterialsRouter); + app.use('/api/bm', bmProjectRouter); }; diff --git a/src/utilities/escapeRegex.js b/src/utilities/escapeRegex.js index 10fa2e61e..01a65ea50 100644 --- a/src/utilities/escapeRegex.js +++ b/src/utilities/escapeRegex.js @@ -1,6 +1,6 @@ const escapeRegex = function (text) { - return text.replace(/[[\]{}()*+?.\\^$|]/g, '\\$&'); + return `^${text.replace(/[[\]{}()*+?.\\^$|]/g, '\\$&')}&`; }; module.exports = escapeRegex; From 8009191ffa3dd7333bd0d84b8162e3d231bd8440 Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Tue, 14 Nov 2023 15:28:08 +0800 Subject: [PATCH 142/272] reduce redundant code --- src/controllers/projectController.js | 2 +- src/controllers/timeEntryController.js | 27 ++++++++++--------- src/helpers/dashboardhelper.js | 7 +++-- src/helpers/taskHelper.js | 2 +- src/helpers/userHelper.js | 36 +++++++++++++------------- 5 files changed, 36 insertions(+), 38 deletions(-) diff --git a/src/controllers/projectController.js b/src/controllers/projectController.js index dc92af354..a88378985 100644 --- a/src/controllers/projectController.js +++ b/src/controllers/projectController.js @@ -28,7 +28,7 @@ const projectController = function (Project) { // find if project has any time entries associated with it - timeentry.find({ projectId: record._id, entryType: [ 'default', 'project', null ] }, '_id') + timeentry.find({ projectId: record._id }, '_id') .then((timeentries) => { if (timeentries.length > 0) { res.status(400).send({ error: 'This project has associated time entries and cannot be deleted. Consider inactivaing it instead.' }); diff --git a/src/controllers/timeEntryController.js b/src/controllers/timeEntryController.js index aa7eff6ae..8adc6693d 100644 --- a/src/controllers/timeEntryController.js +++ b/src/controllers/timeEntryController.js @@ -236,7 +236,7 @@ const timeEntrycontroller = function (TimeEntry) { } const items = []; records.forEach((element) => { - if (element.entryType == 'default' || element.entryType == undefined) { + if (element.entryType === 'default' || element.entryType === undefined) { const timeentry = new TimeEntry(); timeentry.personId = element.personId; timeentry.projectId = element.projectId; @@ -265,7 +265,7 @@ const timeEntrycontroller = function (TimeEntry) { }; switch (req.body.entryType) { - case 'default': + default: if ( !mongoose.Types.ObjectId.isValid(req.body.personId) || !mongoose.Types.ObjectId.isValid(req.body.projectId) @@ -321,18 +321,18 @@ const timeEntrycontroller = function (TimeEntry) { res.status(400).send(error); }); - // Add this tangbile time entry to related task's hoursLogged - if ((timeentry.entryType === 'default') && timeentry.isTangible === true) { - try { - const currentTask = await task.findById(req.body.projectId); - currentTask.hoursLogged += (timeentry.totalSeconds / 3600); - await currentTask.save(); - } catch (error) { - throw new Error('Failed to find the task by id'); - } - } - // checking if logged in hours exceed estimated time after timeentry for a task if (timeentry.entryType === 'default') { + // Add this tangbile time entry to related task's hoursLogged + if (timeentry.isTangible === true) { + try { + const currentTask = await task.findById(req.body.projectId); + currentTask.hoursLogged += (timeentry.totalSeconds / 3600); + await currentTask.save(); + } catch (error) { + throw new Error('Failed to find the task by id'); + } + } + // checking if logged in hours exceed estimated time after timeentry for a task const record = await userProfile.findById(timeentry.personId.toString()); const currentTask = await task.findById(req.body.projectId); checkTaskOvertime(timeentry, record, currentTask); @@ -492,7 +492,6 @@ const timeEntrycontroller = function (TimeEntry) { const { projectId } = req.params; TimeEntry.find( { - entryType: ['default', null], projectId, dateOfWork: { $gte: fromDate, $lte: todate }, }, diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index 1c03c2f88..041b4e948 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -165,7 +165,6 @@ const dashboardhelper = function () { .tz('America/Los_Angeles') .endOf('week') .format('YYYY-MM-DD'); - const entryTypes = ['default', null]; return myTeam.aggregate([ { $match: { @@ -196,7 +195,7 @@ const dashboardhelper = function () { // leaderboard user roles hierarchy $or: [ { - role: { $in: ['Owner', 'Core Team'] }, + role: { $in: ['Owner', 'Core Team'] }, }, { $and: [ @@ -289,7 +288,7 @@ const dashboardhelper = function () { }, { $in: ['$$timeentry.entryType', ['default', null]], - } + }, ], }, }, @@ -445,7 +444,7 @@ const dashboardhelper = function () { $gte: pdtStart, $lte: pdtEnd, }, - eentryType: { $in: [ 'default', null ] }, + entryType: { $in: ['default', null] }, personId: userId, }); diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index 30bb220e9..b91020039 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -43,7 +43,7 @@ const taskHelper = function () { // dashboard tasks user roles hierarchy $or: [ { - role: { $in: ['Owner', 'Core Team'] }, + role: { $in: ['Owner', 'Core Team'] }, }, { $and: [ diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index 5824d5d73..be9e40bbc 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -578,31 +578,31 @@ const userHelper = function () { const missedHours = await userProfile.aggregate([ { $match: { - role: "Core Team", - isActive: true - } + role: 'Core Team', + isActive: true, + }, }, { $lookup: { - from: "timeEntries", - localField: "_id", - foreignField: "personId", + from: 'timeEntries', + localField: '_id', + foreignField: 'personId', pipeline: [ { $match: { $expr: { $and: [ - { $eq: ["$isTangible", true] }, - { $gte: ["$dateOfWork", startOfLastWeek] }, - { $lte: ["$dateOfWork", endOfLastWeek] }, - { $in: ['$entryType', 'default', null] } - ] - } - } - } + { $eq: ['$isTangible', true] }, + { $gte: ['$dateOfWork', startOfLastWeek] }, + { $lte: ['$dateOfWork', endOfLastWeek] }, + { $in: ['$entryType', 'default', null] }, + ], + }, + }, + }, ], - as: "timeEntries" - } + as: 'timeEntries', + }, }, { $project: { @@ -621,8 +621,8 @@ const userHelper = function () { { $sum: { $map: { - input: "$timeEntries", - in: "$$this.totalSeconds" + input: '$timeEntries', + in: '$$this.totalSeconds', } } }, From 9036fb629a2a816651ed988d61c7bc6626735c89 Mon Sep 17 00:00:00 2001 From: Eduardo Horta Date: Tue, 14 Nov 2023 13:48:59 -0300 Subject: [PATCH 143/272] Added .nvmrc file. Node v14. --- .nvmrc | 1 + 1 file changed, 1 insertion(+) create mode 100644 .nvmrc diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 000000000..518633e16 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +lts/fermium From 0fbbe6183f908f873b7c170747997954a42e4504 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Tue, 14 Nov 2023 15:22:25 -0800 Subject: [PATCH 144/272] update to routes, router, controller --- .../bmdashboard/bmMaterialsController.js | 92 ++++++++++--------- src/routes/bmdashboard/bmMaterialsRouter.js | 8 +- src/startup/routes.js | 7 +- 3 files changed, 56 insertions(+), 51 deletions(-) diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index d8bcfe7df..a2e87eec2 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -1,6 +1,9 @@ -// const mongoose = require('mongoose') +const mongoose = require('mongoose'); -const bmMaterialsController = function (ItemMaterial) { +// use in bmPurchaseMaterials auth check (see below) +// const buildingProject = require('../../models/bmdashboard/buildingProject'); + +const bmMaterialsController = function (ItemMaterial, BuildingMaterial) { const bmMaterialsList = async function _matsList(req, res) { try { ItemMaterial.find() @@ -43,57 +46,58 @@ const bmMaterialsController = function (ItemMaterial) { } }; - const bmAddMaterials = async function (req, res) { - // add permission check... - - const { material, requestor } = req.body; - const purchaseRecord = { - date: material.purchaseDate, - createdBy: requestor.requestorId, - poId: material.invoice, - sellerId: material.phone, - quantity: material.quantity, - unitPrice: material.unitPrice, - currency: material.currency, - subtotal: material.quantity, - tax: material.taxRate, - shipping: material.shippingFee, + const bmPurchaseMaterials = async function (req, res) { + const { + projectId, + matTypeId, + quantity, + requestor: { requestorId }, + } = req.body; + const newPurchaseRecord = { + quantity, + requestedBy: requestorId, }; - try { - const result = await ItemMaterial.findOneAndUpdate( - { project: material.projectId, inventoryItemType: material.material }, - { - $inc: { stockBought: material.quantity, stockAvailable: material.quantity }, - $push: { purchaseRecord }, - }, - { returnDocument: 'after', lean: true }, - ) - .exec(); - if (result) { - console.log(result); - res.status(201).send(result); - } else { - const itemMaterial = new ItemMaterial({ - inventoryItemType: material.material, - project: material.projectId, - stockBought: material.quantity, - stockAvailable: material.quantity, - usageRecord: [], - updateRecord: [], - purchaseRecord: [purchaseRecord], - }); - const newItemMaterial = await itemMaterial.save(); - res.status(201).send(newItemMaterial); + // check if requestor has permission to make purchase request + //! Note: this code is disabled until permissions are added + // TODO: uncomment this code to execute auth check + // const { buildingManager: bmId } = await buildingProject.findById(projectId, 'buildingManager').exec(); + // if (bmId !== requestorId) { + // res.status(403).send({ message: 'You are not authorized to edit this record.' }); + // return; + // } + + // check if the material is already being used in the project + // if no, add a new document to the collection + // if yes, update the existing document + const doc = await BuildingMaterial.findOne({ project: projectId, itemType: matTypeId }); + if (!doc) { + const newDoc = { + itemType: matTypeId, + project: projectId, + purchaseRecord: [newPurchaseRecord], + }; + BuildingMaterial + .create(newDoc) + .then(() => res.status(201).send()) + .catch(error => res.status(500).send(error)); + return; } + BuildingMaterial + .findOneAndUpdate( + { _id: mongoose.Types.ObjectId(doc._id) }, + { $push: { purchaseRecord: newPurchaseRecord } }, + ) + .exec() + .then(() => res.status(201).send()) + .catch(error => res.status(500).send(error)); } catch (error) { res.status(500).send(error); } }; - return { bmMaterialsList, - bmAddMaterials, + bmPurchaseMaterials, }; }; diff --git a/src/routes/bmdashboard/bmMaterialsRouter.js b/src/routes/bmdashboard/bmMaterialsRouter.js index 66dc6c985..da29c35d7 100644 --- a/src/routes/bmdashboard/bmMaterialsRouter.js +++ b/src/routes/bmdashboard/bmMaterialsRouter.js @@ -1,13 +1,11 @@ const express = require('express'); -const routes = function (itemMaterial, itemType) { +const routes = function (itemMaterial, buildingMaterial) { const materialsRouter = express.Router(); - const controller = require('../../controllers/bmdashboard/bmMaterialsController')(itemMaterial, itemType); - + const controller = require('../../controllers/bmdashboard/bmMaterialsController')(itemMaterial, buildingMaterial); materialsRouter.route('/materials') .get(controller.bmMaterialsList) - .post(controller.bmAddMaterials); - + .post(controller.bmPurchaseMaterials); return materialsRouter; }; diff --git a/src/startup/routes.js b/src/startup/routes.js index 2c8aced29..b1989698a 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -22,7 +22,8 @@ const reason = require('../models/reason'); const mouseoverText = require('../models/mouseoverText'); const inventoryItemMaterial = require('../models/inventoryItemMaterial'); const buildingProject = require('../models/bmdashboard/buildingProject'); - +const buildingInventoryType = require('../models/bmdashboard/buildingInventoryType'); +const buildingMaterial = require('../models/bmdashboard/buildingMaterial'); const userProfileRouter = require('../routes/userProfileRouter')(userProfile); const badgeRouter = require('../routes/badgeRouter')(badge); @@ -60,8 +61,9 @@ const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverTe // bm dashboard const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); -const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial, inventoryItemType); +const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial, buildingMaterial); const bmProjectRouter = require('../routes/bmdashboard/bmProjectRouter')(buildingProject); +const bmInventoryTypeRouter = require('../routes/bmdashboard/bmInventoryTypeRouter')(buildingInventoryType); module.exports = function (app) { app.use('/api', forgotPwdRouter); @@ -97,4 +99,5 @@ module.exports = function (app) { app.use('/api/bm', bmLoginRouter); app.use('/api/bm', bmMaterialsRouter); app.use('/api/bm', bmProjectRouter); + app.use('/api/bm', bmInventoryTypeRouter); }; From 9c0d47bbd82e22dc97d4463ad2f01bc7d58f0a19 Mon Sep 17 00:00:00 2001 From: Bhagyashree Birajdar Date: Tue, 14 Nov 2023 16:21:36 -0800 Subject: [PATCH 145/272] Remove console.log --- src/controllers/reasonSchedulingController.js | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/controllers/reasonSchedulingController.js b/src/controllers/reasonSchedulingController.js index 98dd152ff..050b9a42b 100644 --- a/src/controllers/reasonSchedulingController.js +++ b/src/controllers/reasonSchedulingController.js @@ -88,11 +88,10 @@ const postReason = async (req, res) => { //await newReason.save(); - console.log("Inside post sending email function."); - const savedData = await newReason.save(); + const savedData = await newReason.save(); if(savedData) { - console.log("Inside if."); + //Upon clicking the "Save" button in the Blue Square Reason Scheduler, an email will be automatically sent to the user and Jae. const subject = `Blue Square Reason for ${foundUser.firstName} ${foundUser.lastName} has been set`; @@ -105,15 +104,15 @@ const postReason = async (req, res) => {

Thank you,
One Community

`; - console.log("line before email sender") + - // 1 hardcoded email- emailSender('shreetesting4@gmail.com', subject, emailBody, null, null); + // 1 hardcoded email- emailSender('@gmail.com', subject, emailBody, null, null); // 2 user email - emailSender(`${foundUser.email}`, subject, emailBody, null, null); //3 - user email and hardcoded email ( After PR approval hardcode Jae's email) - // emailSender(`${foundUser.email},shreetesting4@gmail.com`, subject, emailBody, null, null); + // emailSender(`${foundUser.email},@gmail.com`, subject, emailBody, null, null); } return res.sendStatus(200); @@ -260,11 +259,11 @@ const patchReason = async (req, res) => { } foundReason.reason = reasonData.message; - console.log("patchReason----------"); + const savedData = await foundReason.save(); if(savedData) { - console.log(" Patch - Inside if."); + //Upon clicking the "Save" button in the Blue Square Reason Scheduler, an email will be automatically sent to the user and Jae. const subject = `Blue Square Reason for ${foundUser.firstName} ${foundUser.lastName} has been updated`; @@ -277,15 +276,15 @@ const patchReason = async (req, res) => {

Thank you,
One Community

`; - console.log("line before email sender") - // 1 hardcoded email- emailSender('shreetesting4@gmail.com', subject, emailBody, null, null); + + // 1 hardcoded email- emailSender('@gmail.com', subject, emailBody, null, null); // 2 user email - emailSender(`${foundUser.email}`, subject, emailBody, null, null); //3 - user email and hardcoded email ( After PR approval hardcode Jae's email) - // emailSender(`${foundUser.email},shreetesting4@gmail.com`, subject, emailBody, null, null); + // emailSender(`${foundUser.email},@gmail.com`, subject, emailBody, null, null); } From cec78db63afed949828395476c4d73f914e6133b Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Wed, 15 Nov 2023 17:04:41 -0800 Subject: [PATCH 146/272] add priority, brand fields to controller. update material schema. --- src/controllers/bmdashboard/bmMaterialsController.js | 4 ++++ src/models/bmdashboard/buildingMaterial.js | 12 +++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index a2e87eec2..a8090ebd9 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -51,10 +51,14 @@ const bmMaterialsController = function (ItemMaterial, BuildingMaterial) { projectId, matTypeId, quantity, + priority, + brand, requestor: { requestorId }, } = req.body; const newPurchaseRecord = { quantity, + priority, + brand, requestedBy: requestorId, }; try { diff --git a/src/models/bmdashboard/buildingMaterial.js b/src/models/bmdashboard/buildingMaterial.js index 714ba4ae7..4170443e0 100644 --- a/src/models/bmdashboard/buildingMaterial.js +++ b/src/models/bmdashboard/buildingMaterial.js @@ -13,15 +13,17 @@ const buildingMaterial = new Schema({ _id: false, // do not add _id field to subdocument date: { type: Date, default: Date.now() }, requestedBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - quantity: Number, - status: { type: String, default: 'Pending' }, // Pending, Rejected, Approved + quantity: { type: Number, required: true }, + priority: { type: String, enum: ['Low', 'Medium', 'High'], required: true }, + brand: String, + status: { type: String, default: 'Pending', enum: ['Approved', 'Pending', 'Rejected'] }, }], updateRecord: [{ _id: false, - date: Date, + date: { type: Date, required: true }, createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - quantityUsed: String, // '10 cubic yards' - quantityWasted: Number, + quantityUsed: { type: Number, required: true }, + quantityWasted: { type: Number, required: true }, }], }); From aec7cb8db3697737dbaa971ad65d3c45406ed78c Mon Sep 17 00:00:00 2001 From: Vishala Ramasamy Date: Wed, 15 Nov 2023 17:21:32 -0800 Subject: [PATCH 147/272] update materials completed --- src/controllers/bmdashboard/bmMaterialsController.js | 4 ++-- src/models/bmdashboard/buildingMaterial.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index c5403de21..502a2014a 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -75,7 +75,7 @@ const bmMaterialsController = function (ItemMaterial) { updateRecord: { date: req.body.date, createdBy: req.body.requestor.requestorId, - quantityUsed: quantityUsed + ' ' + material.itemType.unit, + quantityUsed: quantityUsed, quantityWasted: quantityWasted }, } @@ -117,7 +117,7 @@ const bmMaterialsController = function (ItemMaterial) { }, updateValue: { createdBy: req.body.requestor.requestorId, - quantityUsed: quantityUsed + ' ' + material.itemType.unit, + quantityUsed: quantityUsed, quantityWasted: quantityWasted, date: payload.date, }}); diff --git a/src/models/bmdashboard/buildingMaterial.js b/src/models/bmdashboard/buildingMaterial.js index c1d74b879..8e49219f2 100644 --- a/src/models/bmdashboard/buildingMaterial.js +++ b/src/models/bmdashboard/buildingMaterial.js @@ -16,7 +16,7 @@ const buildingMaterial = new Schema({ updateRecord: [{ date: Date, createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - quantityUsed: String, // '10 cubic yards' + quantityUsed: Number, quantityWasted: Number, }], }); From 89233e9869ff9273613e61a8fea8f6331002618f Mon Sep 17 00:00:00 2001 From: abdelmounaim lallouache Date: Wed, 15 Nov 2023 21:01:48 -0600 Subject: [PATCH 148/272] add setMapLocation --- .../profileInitialSetupController.js | 27 ++++++++++++++++++- src/routes/profileInitialSetupRouter.js | 6 +++-- src/startup/middleware.js | 2 +- src/startup/routes.js | 2 +- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/controllers/profileInitialSetupController.js b/src/controllers/profileInitialSetupController.js index b4230f1a4..21113c0fd 100644 --- a/src/controllers/profileInitialSetupController.js +++ b/src/controllers/profileInitialSetupController.js @@ -79,7 +79,8 @@ function informManagerMessage(user) { const profileInitialSetupController = function ( ProfileInitialSetupToken, userProfile, - Project + Project, + MapLocation ) { const { JWT_SECRET } = config; @@ -297,11 +298,35 @@ const profileInitialSetupController = function ( } }; + + const setMapLocation = async (req,res) => { + + const locationData = { + firstName: req.body.firstName, + lastName: req.body.lastName, + jobTitle: req.body.jobTitle, + location: req.body.location, + } + const location = new MapLocation(locationData); + + try { + const response = await location.save() + if (!response) { + throw new Error('Something went wrong during saving the location...') + } + res.status(200).send(response); + } catch (err) { + console.log(err.message) + res.status(500).json({ message: err.message || 'Something went wrong...' }); + } + } + return { getSetupToken, setUpNewUser, validateSetupToken, getTimeZoneAPIKeyByToken, + setMapLocation }; }; diff --git a/src/routes/profileInitialSetupRouter.js b/src/routes/profileInitialSetupRouter.js index a23c6a868..0e5b050c7 100644 --- a/src/routes/profileInitialSetupRouter.js +++ b/src/routes/profileInitialSetupRouter.js @@ -1,13 +1,15 @@ const express = require('express'); -const routes = function (ProfileInitialSetupToken, userProfile, Project) { +const routes = function (ProfileInitialSetupToken, userProfile, Project , mapLocations) { const ProfileInitialSetup = express.Router(); - const controller = require('../controllers/profileInitialSetupController')(ProfileInitialSetupToken, userProfile, Project); + const controller = require('../controllers/profileInitialSetupController')(ProfileInitialSetupToken, userProfile, Project , mapLocations); ProfileInitialSetup.route('/getInitialSetuptoken') .post(controller.getSetupToken); ProfileInitialSetup.route('/ProfileInitialSetup').post(controller.setUpNewUser) ProfileInitialSetup.route('/validateToken').post(controller.validateSetupToken) ProfileInitialSetup.route('/getTimeZoneAPIKeyByToken').post(controller.getTimeZoneAPIKeyByToken) + ProfileInitialSetup.route('/mapLocationsToken').post(controller.setMapLocation) + return ProfileInitialSetup; }; diff --git a/src/startup/middleware.js b/src/startup/middleware.js index 23ce1d4a6..16916c9f3 100644 --- a/src/startup/middleware.js +++ b/src/startup/middleware.js @@ -22,7 +22,7 @@ module.exports = function (app) { next(); return; } - if (req.originalUrl === '/api/ProfileInitialSetup' || req.originalUrl === '/api/validateToken' || req.originalUrl === '/api/getTimeZoneAPIKeyByToken' && req.method === 'POST' + if (req.originalUrl === '/api/ProfileInitialSetup' || req.originalUrl === '/api/validateToken' || req.originalUrl === '/api/getTimeZoneAPIKeyByToken' && req.method === 'POST' || req.originalUrl === '/api/mapLocationsToken' && req.method === 'POST' ) { next(); return; diff --git a/src/startup/routes.js b/src/startup/routes.js index 99e761f75..d4dcb3685 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -45,7 +45,7 @@ const popupBackupRouter = require('../routes/popupEditorBackupRouter')(popupBack const taskNotificationRouter = require('../routes/taskNotificationRouter')(taskNotification); const inventoryRouter = require('../routes/inventoryRouter')(inventoryItem, inventoryItemType); const timeZoneAPIRouter = require('../routes/timeZoneAPIRoutes')(); -const profileInitialSetupRouter = require('../routes/profileInitialSetupRouter')(profileInitialSetuptoken, userProfile, project); +const profileInitialSetupRouter = require('../routes/profileInitialSetupRouter')(profileInitialSetuptoken, userProfile, project , mapLocations); const isEmailExistsRouter = require('../routes/isEmailExistsRouter')(); From 7542d5c29e6f8657e59e77af12b7b4ee15391477 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Wed, 15 Nov 2023 20:25:45 -0800 Subject: [PATCH 149/272] update inv type schema --- src/models/bmdashboard/buildingInventoryType.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/models/bmdashboard/buildingInventoryType.js b/src/models/bmdashboard/buildingInventoryType.js index 71285fa24..8d2364c64 100644 --- a/src/models/bmdashboard/buildingInventoryType.js +++ b/src/models/bmdashboard/buildingInventoryType.js @@ -3,10 +3,10 @@ const mongoose = require('mongoose'); const { Schema } = mongoose; const buildingInventoryType = new Schema({ - category: String, // Consumable, Material, Tool, Equipment - name: String, - description: String, - unit: String, // unit of measurement + category: { type: String, enum: ['Consumable', 'Material', 'Tool', 'Equipment'], required: true }, + name: { type: String, required: true }, + description: { type: String, required: true }, + unit: { type: String, required: true }, // unit of measurement imageUrl: String, }); From 337fe08ef46f76e074b61bc67a9333ea52ef7b5b Mon Sep 17 00:00:00 2001 From: Bhagyashree Birajdar Date: Thu, 16 Nov 2023 09:41:23 -0800 Subject: [PATCH 150/272] update dependencies --- package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 3fcc98986..97de1f352 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5536,7 +5536,7 @@ "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" }, "lodash.merge": { "version": "4.6.2", From b9c52f0f75bbe6ce0b4291bf66eb765a8e69ed82 Mon Sep 17 00:00:00 2001 From: Bhagyashree Birajdar Date: Thu, 16 Nov 2023 11:59:44 -0800 Subject: [PATCH 151/272] Text Change --- src/controllers/reasonSchedulingController.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/reasonSchedulingController.js b/src/controllers/reasonSchedulingController.js index 050b9a42b..e310049c2 100644 --- a/src/controllers/reasonSchedulingController.js +++ b/src/controllers/reasonSchedulingController.js @@ -20,7 +20,7 @@ const postReason = async (req, res) => { if (moment.tz(reasonData.date, 'America/Los_Angeles').day() !== 0) { return res.status(400).json({ message: - 'The selected day must be a sunday so the code can work properly', + "You must choose the Sunday YOU'LL RETURN as your date. This is so your reason ends up as a note on that blue square.", errorCode: 0, }); } From 903da0c7f447ae8961ce879eb5cdf2bc067f1c64 Mon Sep 17 00:00:00 2001 From: Aishwaryak01 Date: Thu, 16 Nov 2023 15:09:48 -0500 Subject: [PATCH 152/272] Updated file buildingTool.js Updated file buildingTool.js for changes requested in PR --- .../bmdashboard/{buildingTools.js => buildingTool.js} | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) rename src/models/bmdashboard/{buildingTools.js => buildingTool.js} (64%) diff --git a/src/models/bmdashboard/buildingTools.js b/src/models/bmdashboard/buildingTool.js similarity index 64% rename from src/models/bmdashboard/buildingTools.js rename to src/models/bmdashboard/buildingTool.js index 94468de42..6cec3b5d0 100644 --- a/src/models/bmdashboard/buildingTools.js +++ b/src/models/bmdashboard/buildingTool.js @@ -3,17 +3,14 @@ const mongoose = require('mongoose'); const { Schema } = mongoose; const buildingTools = new Schema({ - inventoryItemId: { type: mongoose.SchemaTypes.ObjectId, ref: 'INVENTORY' }, // later ,INVENTORY needs to be changed as per inventory model + itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, title: { type: String, required: true }, - image: { type: String, required: true }, rentedOnDate: { type: Date, required: true }, rentDuration: { type: Number, required: true }, // This value should be taken in number of days - total: {type: Number, required: true}, - availableCount:{type: Number, required: true}, logInStatus:{Boolean}, - condition:{type: String, enum: ['Good', 'Needs Repair', 'Out of Order','Unused'], default: 'Condition'}, + condition:{type: String, enum: ['Good', 'Needs Repair', 'Out of Order','Unused'], default: 'Good'}, userResponsible:{ type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - purchaseStatus:{type: String, enum: ['Rented', 'Purchased'], default: 'Status'}, + purchaseStatus:{type: String, enum: ['Rented', 'Purchased'], default: 'Rented'}, }); module.exports = mongoose.model('buildingTools', buildingTools, 'buildingTools'); \ No newline at end of file From 6caba89ed9724434646185094dcea04bf65ef54a Mon Sep 17 00:00:00 2001 From: Olga Yudkin Date: Thu, 16 Nov 2023 15:17:40 -0500 Subject: [PATCH 153/272] initial commit --- package-lock.json | 16 +++++++-------- .../bmdashboard/bmToolController.js | 20 +++++++++++++++++++ src/routes/bmdashboard/bmToolsRouter.js | 14 +++++++++++++ src/startup/routes.js | 2 ++ 4 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 src/controllers/bmdashboard/bmToolController.js create mode 100644 src/routes/bmdashboard/bmToolsRouter.js diff --git a/package-lock.json b/package-lock.json index 3fcc98986..c9a26d709 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1568,7 +1568,7 @@ "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, "@types/mime": { @@ -4429,7 +4429,7 @@ "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, "fast-text-encoding": { @@ -4952,7 +4952,7 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true }, "indent-string": { @@ -5215,7 +5215,7 @@ "json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, "json5": { @@ -5536,7 +5536,7 @@ "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" }, "lodash.merge": { "version": "4.6.2", @@ -5929,7 +5929,7 @@ "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, "negotiator": { @@ -7887,7 +7887,7 @@ "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true }, "strip-final-newline": { @@ -7918,7 +7918,7 @@ "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, "through": { diff --git a/src/controllers/bmdashboard/bmToolController.js b/src/controllers/bmdashboard/bmToolController.js new file mode 100644 index 000000000..c3c389ddd --- /dev/null +++ b/src/controllers/bmdashboard/bmToolController.js @@ -0,0 +1,20 @@ +const bmToolController = (BuildingTool) => { + const fetchSingleTool = async (req, res) => { + const { toolId } = req.params; + try { + BuildingTool + .findById(toolId) + .populate([ + // TO DO + ]) + .exec() + .then(tool => res.status(200).send(tool)) + .catch(error => res.status(500).send(error)); + } catch (err) { + res.json(err); + } + }; + return fetchSingleTool; +}; + +module.exports = bmToolController; diff --git a/src/routes/bmdashboard/bmToolsRouter.js b/src/routes/bmdashboard/bmToolsRouter.js new file mode 100644 index 000000000..98dca3adf --- /dev/null +++ b/src/routes/bmdashboard/bmToolsRouter.js @@ -0,0 +1,14 @@ +const express = require('express'); + +const routes = function () { + const toolRouter = express.Router(); + const controller = require('../../controllers/bmdashboard/bmToolController')(); + + toolRouter.route('tools/:toolId') + .get(controller.fetchSingleTool); + + + return toolRouter; +}; + +module.exports = routes; diff --git a/src/startup/routes.js b/src/startup/routes.js index 799b854fe..12ba780ef 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -62,6 +62,7 @@ const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverTe const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial); const bmProjectRouter = require('../routes/bmdashboard/bmProjectRouter')(buildingProject); +const bmToolsRouter = require('../routes/bmdashboard/bmToolsRouter')(); module.exports = function (app) { app.use('/api', forgotPwdRouter); @@ -97,4 +98,5 @@ module.exports = function (app) { app.use('/api/bm', bmLoginRouter); app.use('/api/bm', bmMaterialsRouter); app.use('/api/bm', bmProjectRouter); + app.use('/api/bm', bmToolsRouter); }; From 2afd85d263f38a25be78ac7012eb1c2f6e9e6121 Mon Sep 17 00:00:00 2001 From: Bhagyashree Birajdar Date: Fri, 17 Nov 2023 08:27:12 -0800 Subject: [PATCH 154/272] Restore .gitattributes file to its original state --- .gitattributes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 6cf651ce7..d725bea56 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,6 @@ # https://warlord0blog.wordpress.com/2019/09/04/vscode-crlf-vs-lf-battle/ -# text=lf + text=lf *.css linguist-vendored eol=lf *.scss linguist-vendored eol=lf *.js linguist-vendored eol=lf From 9c648baa6b2e1ad99d327e44c6fc5f803a9318c8 Mon Sep 17 00:00:00 2001 From: Bhagyashree Birajdar Date: Fri, 17 Nov 2023 09:16:57 -0800 Subject: [PATCH 155/272] Remove extra spaces --- .gitattributes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index d725bea56..3b75a78dd 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,6 @@ # https://warlord0blog.wordpress.com/2019/09/04/vscode-crlf-vs-lf-battle/ - text=lf +text=lf *.css linguist-vendored eol=lf *.scss linguist-vendored eol=lf *.js linguist-vendored eol=lf From 2fa50925a76c266ac918d48e4e50c5579c8b0425 Mon Sep 17 00:00:00 2001 From: abdelmounaim lallouache Date: Fri, 17 Nov 2023 13:45:37 -0600 Subject: [PATCH 156/272] fix email sending for setup profile --- .../profileInitialSetupController.js | 27 ++++++++++++++----- src/utilities/emailSender.js | 10 ++++++- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/controllers/profileInitialSetupController.js b/src/controllers/profileInitialSetupController.js index 18cf7376c..3e51e5578 100644 --- a/src/controllers/profileInitialSetupController.js +++ b/src/controllers/profileInitialSetupController.js @@ -76,6 +76,23 @@ function informManagerMessage(user) { return message; } +const sendEmailWithAcknowledgment = (email, subject, message) => { + return new Promise((resolve, reject) => { + emailSender( + email, + subject, + message, + null, + null, + null, + (error,result) => { + if (result) resolve(result) + if (error) reject(result) + } + ); + }); +}; + const profileInitialSetupController = function ( ProfileInitialSetupToken, userProfile, @@ -114,15 +131,13 @@ const profileInitialSetupController = function ( const savedToken = await newToken.save(); const link = `${baseUrl}/ProfileInitialSetup/${savedToken.token}`; - emailSender( + const acknowledgment = await sendEmailWithAcknowledgment( email, "NEEDED: Complete your One Community profile setup", - sendLinkMessage(link), - null, - null + sendLinkMessage(link) ); - - res.status(200).send(link); + + res.status(200).send(acknowledgment); } } catch (error) { res.status(400).send(`Error: ${error}`); diff --git a/src/utilities/emailSender.js b/src/utilities/emailSender.js index b4864add6..b07f9a8c9 100644 --- a/src/utilities/emailSender.js +++ b/src/utilities/emailSender.js @@ -35,7 +35,7 @@ const closure = () => { if (!nextItem) return; const { - recipient, subject, message, cc, bcc, replyTo, + recipient, subject, message, cc, bcc, replyTo, acknowledgingReceipt } = nextItem; try { @@ -59,8 +59,14 @@ const closure = () => { }; const result = await transporter.sendMail(mailOptions); + if (typeof acknowledgingReceipt === 'function') { + acknowledgingReceipt(null,result); + } logger.logInfo(result); } catch (error) { + if (typeof acknowledgingReceipt === 'function') { + acknowledgingReceipt(error,null); + } logger.logException(error); } }, process.env.MAIL_QUEUE_INTERVAL || 1000); @@ -72,6 +78,7 @@ const closure = () => { cc = null, bcc = null, replyTo = null, + acknowledgingReceipt = null, ) { if (process.env.sendEmail) { queue.push({ @@ -81,6 +88,7 @@ const closure = () => { cc, bcc, replyTo, + acknowledgingReceipt }); } }; From a973d9aa876df747c81b536d289407e459a89f93 Mon Sep 17 00:00:00 2001 From: Vishala Ramasamy Date: Fri, 17 Nov 2023 16:02:49 -0800 Subject: [PATCH 157/272] added validations before adding to db --- .../bmdashboard/bmMaterialsController.js | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index 502a2014a..671cb0b24 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -89,7 +89,11 @@ const bmMaterialsController = function (ItemMaterial) { const bmPostMaterialUpdateBulk = function (req, res) { const materialUpdates= req.body; - const updateRecordsToBeAdded = materialUpdates.map(payload => { + let errorFlag = false; + const updateRecordsToBeAdded = []; + for(let i=0;i ItemMaterial.updateOne( { _id: updateItem.updateId }, { From a2bb72a83e5ac9946cec68f972ff03469650c229 Mon Sep 17 00:00:00 2001 From: abdelmounaim lallouache Date: Fri, 17 Nov 2023 20:08:10 -0600 Subject: [PATCH 158/272] update homeCountry,add profile picture --- .../profileInitialSetupController.js | 31 ++++++++++--------- src/routes/profileInitialSetupRouter.js | 1 - src/startup/middleware.js | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/controllers/profileInitialSetupController.js b/src/controllers/profileInitialSetupController.js index 21113c0fd..88902141d 100644 --- a/src/controllers/profileInitialSetupController.js +++ b/src/controllers/profileInitialSetupController.js @@ -213,6 +213,7 @@ const profileInitialSetupController = function ( newUser.collaborationPreference = req.body.collaborationPreference; newUser.timeZone = req.body.timeZone || "America/Los_Angeles"; newUser.location = req.body.location; + newUser.profilePic = req.body.profilePicture; newUser.permissions = { frontPermissions: [], backPermissions: [] @@ -247,7 +248,19 @@ const profileInitialSetupController = function ( const token = jwt.sign(jwtPayload, JWT_SECRET); + const locationData = { + firstName: req.body.firstName, + lastName: req.body.lastName, + jobTitle: req.body.jobTitle, + location: req.body.homeCountry, + } + res.send({ token }).status(200); + + const mapEntryResult = await setMapLocation(locationData) + if(mapEntryResult.type === "Error"){ + console.log(mapEntryResult.message) + } const NewUserCache = { permissions: savedUser.permissions, @@ -298,26 +311,15 @@ const profileInitialSetupController = function ( } }; - - const setMapLocation = async (req,res) => { + const setMapLocation = async (locationData) => { - const locationData = { - firstName: req.body.firstName, - lastName: req.body.lastName, - jobTitle: req.body.jobTitle, - location: req.body.location, - } const location = new MapLocation(locationData); try { const response = await location.save() - if (!response) { - throw new Error('Something went wrong during saving the location...') - } - res.status(200).send(response); + return response } catch (err) { - console.log(err.message) - res.status(500).json({ message: err.message || 'Something went wrong...' }); + return {type: "Error", message: err.message || 'An error occurred while saving the location'} } } @@ -326,7 +328,6 @@ const profileInitialSetupController = function ( setUpNewUser, validateSetupToken, getTimeZoneAPIKeyByToken, - setMapLocation }; }; diff --git a/src/routes/profileInitialSetupRouter.js b/src/routes/profileInitialSetupRouter.js index 0e5b050c7..9a87aa1a7 100644 --- a/src/routes/profileInitialSetupRouter.js +++ b/src/routes/profileInitialSetupRouter.js @@ -8,7 +8,6 @@ const routes = function (ProfileInitialSetupToken, userProfile, Project , mapLoc ProfileInitialSetup.route('/ProfileInitialSetup').post(controller.setUpNewUser) ProfileInitialSetup.route('/validateToken').post(controller.validateSetupToken) ProfileInitialSetup.route('/getTimeZoneAPIKeyByToken').post(controller.getTimeZoneAPIKeyByToken) - ProfileInitialSetup.route('/mapLocationsToken').post(controller.setMapLocation) return ProfileInitialSetup; diff --git a/src/startup/middleware.js b/src/startup/middleware.js index 16916c9f3..23ce1d4a6 100644 --- a/src/startup/middleware.js +++ b/src/startup/middleware.js @@ -22,7 +22,7 @@ module.exports = function (app) { next(); return; } - if (req.originalUrl === '/api/ProfileInitialSetup' || req.originalUrl === '/api/validateToken' || req.originalUrl === '/api/getTimeZoneAPIKeyByToken' && req.method === 'POST' || req.originalUrl === '/api/mapLocationsToken' && req.method === 'POST' + if (req.originalUrl === '/api/ProfileInitialSetup' || req.originalUrl === '/api/validateToken' || req.originalUrl === '/api/getTimeZoneAPIKeyByToken' && req.method === 'POST' ) { next(); return; From a418eaefcde0b3a65d2e4caae0aa7cd02258adcf Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Mon, 20 Nov 2023 11:45:18 +0800 Subject: [PATCH 159/272] fix permission issue --- src/controllers/timeEntryController.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/timeEntryController.js b/src/controllers/timeEntryController.js index 8adc6693d..011e466e2 100644 --- a/src/controllers/timeEntryController.js +++ b/src/controllers/timeEntryController.js @@ -110,7 +110,7 @@ const timeEntrycontroller = function (TimeEntry) { } if (!(await hasPermission(req.body.requestor, 'editTimeEntry') - || ((type === 'default' || type === 'person') && timeEntry.personId.toString() === req.body.requestor.requestorId.toString()))) { + || (type === 'default' && timeEntry.personId.toString() === req.body.requestor.requestorId.toString()))) { return res.status(403).send({ error: 'Unauthorized request' }); } From 14a1745f0b723da0d93a572611f1fc39c71b2e98 Mon Sep 17 00:00:00 2001 From: Olga Yudkin Date: Mon, 20 Nov 2023 15:08:36 -0500 Subject: [PATCH 160/272] remove duplictae conroller --- .../bmdashboard/bmToolController.js | 20 ------------------- 1 file changed, 20 deletions(-) delete mode 100644 src/controllers/bmdashboard/bmToolController.js diff --git a/src/controllers/bmdashboard/bmToolController.js b/src/controllers/bmdashboard/bmToolController.js deleted file mode 100644 index c3c389ddd..000000000 --- a/src/controllers/bmdashboard/bmToolController.js +++ /dev/null @@ -1,20 +0,0 @@ -const bmToolController = (BuildingTool) => { - const fetchSingleTool = async (req, res) => { - const { toolId } = req.params; - try { - BuildingTool - .findById(toolId) - .populate([ - // TO DO - ]) - .exec() - .then(tool => res.status(200).send(tool)) - .catch(error => res.status(500).send(error)); - } catch (err) { - res.json(err); - } - }; - return fetchSingleTool; -}; - -module.exports = bmToolController; From 10b371eceb0cfdd62fd7a0c69713b136334ea681 Mon Sep 17 00:00:00 2001 From: Olga Yudkin Date: Mon, 20 Nov 2023 15:44:14 -0500 Subject: [PATCH 161/272] updated buildingtool controller and schema --- src/controllers/bmdashboard/bmToolsController.js | 8 ++++++++ src/models/bmdashboard/buildingTool.js | 10 +++++----- src/routes/bmdashboard/bmToolsRouter.js | 4 ++-- src/startup/routes.js | 4 ++-- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/controllers/bmdashboard/bmToolsController.js b/src/controllers/bmdashboard/bmToolsController.js index 9bb17b2cf..09a820a3e 100644 --- a/src/controllers/bmdashboard/bmToolsController.js +++ b/src/controllers/bmdashboard/bmToolsController.js @@ -6,6 +6,14 @@ const bmToolsController = (BuildingTool) => { .findById(toolId) .populate([ // TO DO + { + path: 'itemType', + select: '', + }, + { + path: 'userResponsible', + select: '_id firstName lastName', + }, ]) .exec() .then(tool => res.status(200).send(tool)) diff --git a/src/models/bmdashboard/buildingTool.js b/src/models/bmdashboard/buildingTool.js index 6cec3b5d0..671eba630 100644 --- a/src/models/bmdashboard/buildingTool.js +++ b/src/models/bmdashboard/buildingTool.js @@ -7,10 +7,10 @@ const buildingTools = new Schema({ title: { type: String, required: true }, rentedOnDate: { type: Date, required: true }, rentDuration: { type: Number, required: true }, // This value should be taken in number of days - logInStatus:{Boolean}, - condition:{type: String, enum: ['Good', 'Needs Repair', 'Out of Order','Unused'], default: 'Good'}, - userResponsible:{ type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - purchaseStatus:{type: String, enum: ['Rented', 'Purchased'], default: 'Rented'}, + logInStatus: { type: Boolean }, + condition: { type: String, enum: ['Good', 'Needs Repair', 'Out of Order', 'Unused'], default: 'Good' }, + userResponsible: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + purchaseStatus: { type: String, enum: ['Rented', 'Purchased'], default: 'Rented' }, }); -module.exports = mongoose.model('buildingTools', buildingTools, 'buildingTools'); \ No newline at end of file +module.exports = mongoose.model('buildingTools', buildingTools, 'buildingTools'); diff --git a/src/routes/bmdashboard/bmToolsRouter.js b/src/routes/bmdashboard/bmToolsRouter.js index 58af3f273..6112f3502 100644 --- a/src/routes/bmdashboard/bmToolsRouter.js +++ b/src/routes/bmdashboard/bmToolsRouter.js @@ -1,8 +1,8 @@ const express = require('express'); -const routes = function () { +const routes = function (BuildingTool) { const toolRouter = express.Router(); - const controller = require('../../controllers/bmdashboard/bmToolsController')(); + const controller = require('../../controllers/bmdashboard/bmToolsController')(BuildingTool); toolRouter.route('tools/:toolId') .get(controller.fetchSingleTool); diff --git a/src/startup/routes.js b/src/startup/routes.js index 12ba780ef..e4924bdba 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -22,7 +22,7 @@ const reason = require('../models/reason'); const mouseoverText = require('../models/mouseoverText'); const inventoryItemMaterial = require('../models/inventoryItemMaterial'); const buildingProject = require('../models/bmdashboard/buildingProject'); - +const buildingTools = require('../models/bmdashboard/buildingTool'); const userProfileRouter = require('../routes/userProfileRouter')(userProfile); const badgeRouter = require('../routes/badgeRouter')(badge); @@ -62,7 +62,7 @@ const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverTe const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial); const bmProjectRouter = require('../routes/bmdashboard/bmProjectRouter')(buildingProject); -const bmToolsRouter = require('../routes/bmdashboard/bmToolsRouter')(); +const bmToolsRouter = require('../routes/bmdashboard/bmToolsRouter')(buildingTool); module.exports = function (app) { app.use('/api', forgotPwdRouter); From 9338492de79cde0b1d161caa0bdeefb7914d86f6 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Mon, 20 Nov 2023 12:49:17 -0800 Subject: [PATCH 162/272] add team, hours fields to team sub-doc in project schema --- src/models/bmdashboard/buildingProject.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/models/bmdashboard/buildingProject.js b/src/models/bmdashboard/buildingProject.js index 566bc124e..df2b51e96 100644 --- a/src/models/bmdashboard/buildingProject.js +++ b/src/models/bmdashboard/buildingProject.js @@ -8,8 +8,12 @@ const buildingProject = new Schema({ template: String, // construction template (ie Earthbag Village) location: String, // use lat/lng instead? dateCreated: { type: Date, default: Date.now }, - buildingManager: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, // BM's id - team: [{ type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }], + buildingManager: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + members: [{ + user: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + team: { type: mongoose.SchemaTypes.ObjectId, ref: 'teams' }, + hours: { type: Number, default: 0 }, // tracked via the Member Check-In Page timer + }], }); module.exports = mongoose.model('buildingProject', buildingProject, 'buildingProjects'); From 507c61fed22ddeab9b436b16ca3122a161f98a41 Mon Sep 17 00:00:00 2001 From: Olga Yudkin Date: Wed, 22 Nov 2023 12:15:01 -0500 Subject: [PATCH 163/272] updated buildingtool schema and controller --- src/controllers/bmdashboard/bmToolsController.js | 2 -- src/models/bmdashboard/buildingTool.js | 4 ++-- src/startup/routes.js | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/controllers/bmdashboard/bmToolsController.js b/src/controllers/bmdashboard/bmToolsController.js index 09a820a3e..e1b2f58c7 100644 --- a/src/controllers/bmdashboard/bmToolsController.js +++ b/src/controllers/bmdashboard/bmToolsController.js @@ -5,10 +5,8 @@ const bmToolsController = (BuildingTool) => { BuildingTool .findById(toolId) .populate([ - // TO DO { path: 'itemType', - select: '', }, { path: 'userResponsible', diff --git a/src/models/bmdashboard/buildingTool.js b/src/models/bmdashboard/buildingTool.js index 671eba630..9877cc2f7 100644 --- a/src/models/bmdashboard/buildingTool.js +++ b/src/models/bmdashboard/buildingTool.js @@ -2,7 +2,7 @@ const mongoose = require('mongoose'); const { Schema } = mongoose; -const buildingTools = new Schema({ +const buildingTool = new Schema({ itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, title: { type: String, required: true }, rentedOnDate: { type: Date, required: true }, @@ -13,4 +13,4 @@ const buildingTools = new Schema({ purchaseStatus: { type: String, enum: ['Rented', 'Purchased'], default: 'Rented' }, }); -module.exports = mongoose.model('buildingTools', buildingTools, 'buildingTools'); +module.exports = mongoose.model('buildingTool', buildingTool, 'buildingTools'); diff --git a/src/startup/routes.js b/src/startup/routes.js index e4924bdba..5cdf15b6a 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -22,7 +22,7 @@ const reason = require('../models/reason'); const mouseoverText = require('../models/mouseoverText'); const inventoryItemMaterial = require('../models/inventoryItemMaterial'); const buildingProject = require('../models/bmdashboard/buildingProject'); -const buildingTools = require('../models/bmdashboard/buildingTool'); +const buildingTool = require('../models/bmdashboard/buildingTool'); const userProfileRouter = require('../routes/userProfileRouter')(userProfile); const badgeRouter = require('../routes/badgeRouter')(badge); From 565522521c7d7fe5bd99ce27b827008fa9538fca Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Wed, 22 Nov 2023 17:26:22 -0800 Subject: [PATCH 164/272] build aggregate operator, add sorted fields to return array. add teams array field to buildingProject schema. --- .../bmdashboard/bmProjectController.js | 72 ++++++++++++++----- src/models/bmdashboard/buildingProject.js | 2 +- 2 files changed, 56 insertions(+), 18 deletions(-) diff --git a/src/controllers/bmdashboard/bmProjectController.js b/src/controllers/bmdashboard/bmProjectController.js index 929aba4ba..8ca62ea77 100644 --- a/src/controllers/bmdashboard/bmProjectController.js +++ b/src/controllers/bmdashboard/bmProjectController.js @@ -1,3 +1,4 @@ +/* eslint-disable prefer-destructuring */ // TODO: uncomment when executing auth checks // const jwt = require('jsonwebtoken'); // const config = require('../../config'); @@ -12,26 +13,63 @@ const bmMProjectController = function (BuildingProject) { // const token = req.headers.authorization; // const { userid } = jwt.verify(token, JWT_SECRET); try { - const projectData = await BuildingProject - // TODO: uncomment this line to filter by buildingManager field - // .find({ buildingManager: userid }) - .find() - .populate([ - { - path: 'buildingManager', - select: '_id firstName lastName email', + BuildingProject.aggregate([ + { + $match: { isActive: true }, + }, + { + $lookup: { + from: 'userProfiles', + let: { id: '$buildingManager' }, + pipeline: [ + { $match: { $expr: { $eq: ['$_id', '$$id'] } } }, + { $project: { firstName: 1, lastName: 1, email: 1 } }, + ], + as: 'buildingManager', }, - { - path: 'team', - select: '_id firstName lastName email', + }, + { $unwind: '$buildingManager' }, + { + $lookup: { + from: 'buildingMaterials', + let: { id: '$_id' }, + pipeline: [ + { $match: { $expr: { $eq: ['$project', '$$id'] } } }, + { $project: { updateRecord: 0, project: 0 } }, + ], + as: 'materials', }, - ]) - .exec() - .then(result => result) - .catch(error => res.status(500).send(error)); - res.status(200).send(projectData); + }, + { + $project: { + name: 1, + isActive: 1, + template: 1, + location: 1, + dateCreated: 1, + buildingManager: 1, + teams: 1, + members: 1, + materials: 1, + hoursWorked: { $sum: '$members.hours' }, + // cost values can be calculated once a process for purchasing inventory is created + totalMaterialsCost: { $sum: 1500 }, + totalEquipmentCost: { $sum: 3000 }, + }, + }, + ]) + .then((results) => { + results.forEach((proj) => { + proj.mostMaterialWaste = proj.materials.sort((a, b) => b.stockWasted - a.stockWasted)[0]; + proj.leastMaterialAvailable = proj.materials.sort((a, b) => a.stockAvailable - b.stockAvailable)[0]; + proj.mostMaterialBought = proj.materials.sort((a, b) => b.stockBought - a.stockBought)[0]; + proj.teamCount = proj.teams.length; + }); + res.status(200).send(results); + }) + .catch(error => res.status(500).send(error)); } catch (err) { - res.json(err); + res.status(500).send(err); } }; diff --git a/src/models/bmdashboard/buildingProject.js b/src/models/bmdashboard/buildingProject.js index df2b51e96..3ca4bf993 100644 --- a/src/models/bmdashboard/buildingProject.js +++ b/src/models/bmdashboard/buildingProject.js @@ -9,9 +9,9 @@ const buildingProject = new Schema({ location: String, // use lat/lng instead? dateCreated: { type: Date, default: Date.now }, buildingManager: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + teams: [{ type: mongoose.SchemaTypes.ObjectId, ref: 'teams' }], // teams assigned to the project members: [{ user: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - team: { type: mongoose.SchemaTypes.ObjectId, ref: 'teams' }, hours: { type: Number, default: 0 }, // tracked via the Member Check-In Page timer }], }); From 403ca7445abc832068ea0bcc6adca4d36e9fc0aa Mon Sep 17 00:00:00 2001 From: tsunami776 <43768723+tsunami776@users.noreply.github.com> Date: Wed, 22 Nov 2023 21:17:26 -0600 Subject: [PATCH 165/272] Fix model, controller and route for AI prompt --- src/controllers/dashBoardController.js | 16 ++++++++-------- ...dashBoardData.js => weeklySummaryAIPrompt.js} | 4 ++-- src/routes/dashboardRouter.js | 4 ++-- src/startup/routes.js | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) rename src/models/{dashBoardData.js => weeklySummaryAIPrompt.js} (51%) diff --git a/src/controllers/dashBoardController.js b/src/controllers/dashBoardController.js index 66e559a6c..0159783d2 100644 --- a/src/controllers/dashBoardController.js +++ b/src/controllers/dashBoardController.js @@ -3,7 +3,7 @@ const fs = require("fs/promises"); const mongoose = require("mongoose"); const dashboardhelper = require("../helpers/dashboardhelper")(); const emailSender = require("../utilities/emailSender"); -const DashboardData = require('../models/dashBoardData'); +const AIPrompt = require('../models/weeklySummaryAIPrompt'); const dashboardcontroller = function () { const dashboarddata = function (req, res) { @@ -16,17 +16,17 @@ const dashboardcontroller = function () { }); }; - const updateDashboardData = function (req, res) { + const updateAIPrompt = function (req, res) { if (req.body.requestor.role === 'Owner') { - DashboardData.findOneAndUpdate({ _id: 'ai-prompt' }, { ...req.body, aIPromptText: req.body.aIPromptText }) + AIPrompt.findOneAndUpdate({ _id: 'ai-prompt' }, { ...req.body, aIPromptText: req.body.aIPromptText }) .then(() => { res.status(200).send('Successfully saved AI prompt.'); }).catch(error => res.status(500).send(error)); } }; - const getDashBoardData = function (req, res) { - DashboardData.findById({ _id: 'ai-prompt' }) + const getAIPrompt = function (req, res) { + AIPrompt.findById({ _id: 'ai-prompt' }) .then((result) => { if (result) { // If the GPT prompt exists, send it back. @@ -37,7 +37,7 @@ const dashboardcontroller = function () { _id: 'ai-prompt', aIPromptText: "Please edit the following summary of my week's work. Make sure it is professionally written in 3rd person format.\nWrite it as only one paragraph. It must be only one paragraph. Keep it less than 500 words. Start the paragraph with 'This week'.\nMake sure the paragraph contains no links or URLs and write it in a tone that is matter-of-fact and without embellishment.\nDo not add flowery language, keep it simple and factual. Do not add a final summary sentence. Apply all this to the following:" }; - DashboardData.create(defaultPrompt) + AIPrompt.create(defaultPrompt) .then((newResult) => { res.status(200).send(newResult); }) @@ -292,8 +292,8 @@ const dashboardcontroller = function () { return { dashboarddata, - getDashBoardData, - updateDashboardData, + getAIPrompt, + updateAIPrompt, monthlydata, weeklydata, leaderboarddata, diff --git a/src/models/dashBoardData.js b/src/models/weeklySummaryAIPrompt.js similarity index 51% rename from src/models/dashBoardData.js rename to src/models/weeklySummaryAIPrompt.js index 2ae3a5482..a55db4a97 100644 --- a/src/models/dashBoardData.js +++ b/src/models/weeklySummaryAIPrompt.js @@ -2,9 +2,9 @@ const mongoose = require('mongoose'); const { Schema } = mongoose; -const DashboardData = new Schema({ +const WeeklySummaryAIPrompt = new Schema({ _id: { type: mongoose.Schema.Types.String }, aIPromptText: { type: String }, }); -module.exports = mongoose.model('dashboardData', DashboardData, 'dashboard'); +module.exports = mongoose.model('weeklySummaryAIPrompt', WeeklySummaryAIPrompt, 'weeklySummaryAIPrompt'); diff --git a/src/routes/dashboardRouter.js b/src/routes/dashboardRouter.js index 7b55fcb89..fc54a43a1 100644 --- a/src/routes/dashboardRouter.js +++ b/src/routes/dashboardRouter.js @@ -6,8 +6,8 @@ const route = function () { const Dashboardrouter = express.Router(); Dashboardrouter.route('/dashboard/aiPrompt') - .get(controller.getDashBoardData) - .put(controller.updateDashboardData); + .get(controller.getAIPrompt) + .put(controller.updateAIPrompt); Dashboardrouter.route('/dashboard/:userId') .get(controller.dashboarddata); diff --git a/src/startup/routes.js b/src/startup/routes.js index afe9d81f9..667185982 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -17,7 +17,7 @@ const role = require('../models/role'); const rolePreset = require('../models/rolePreset'); const ownerMessage = require('../models/ownerMessage'); const ownerStandardMessage = require('../models/ownerStandardMessage'); -const dashboardData = require('../models/dashBoardData'); +const weeklySummaryAIPrompt = require('../models/weeklySummaryAIPrompt'); const profileInitialSetuptoken = require('../models/profileInitialSetupToken'); const reason = require('../models/reason'); const mouseoverText = require('../models/mouseoverText'); @@ -27,7 +27,7 @@ const buildingProject = require('../models/bmdashboard/buildingProject'); const userProfileRouter = require('../routes/userProfileRouter')(userProfile); const badgeRouter = require('../routes/badgeRouter')(badge); -const dashboardRouter = require('../routes/dashboardRouter')(dashboardData); +const dashboardRouter = require('../routes/dashboardRouter')(weeklySummaryAIPrompt); const timeEntryRouter = require('../routes/timeentryRouter')(timeEntry); const projectRouter = require('../routes/projectRouter')(project); const informationRouter = require('../routes/informationRouter')(information); From 2f35809bccfbc0c20974b3b518d8d7dc4d5a3318 Mon Sep 17 00:00:00 2001 From: Carl Bebli Date: Tue, 28 Nov 2023 09:18:38 +0000 Subject: [PATCH 166/272] added a line break to the email body --- src/controllers/dashBoardController.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/controllers/dashBoardController.js b/src/controllers/dashBoardController.js index 68e88ae58..b1b62f9ae 100644 --- a/src/controllers/dashBoardController.js +++ b/src/controllers/dashBoardController.js @@ -172,6 +172,8 @@ const dashboardcontroller = function () { args[3].lastName } : +
+
⚹ Suggestion Category:

${args[0]}

⚹ Suggestion: @@ -206,7 +208,8 @@ const dashboardcontroller = function () { emailBody, null, null, - email + email, + null ); res.status(200).send("Success"); } catch { From 83b031f76123cac63bd1e563e08306c80e2f65dc Mon Sep 17 00:00:00 2001 From: Carl Bebli Date: Tue, 28 Nov 2023 09:21:41 +0000 Subject: [PATCH 167/272] added a line break to the email body --- src/controllers/dashBoardController.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/controllers/dashBoardController.js b/src/controllers/dashBoardController.js index 68e88ae58..b1b62f9ae 100644 --- a/src/controllers/dashBoardController.js +++ b/src/controllers/dashBoardController.js @@ -172,6 +172,8 @@ const dashboardcontroller = function () { args[3].lastName } : +
+
⚹ Suggestion Category:

${args[0]}

⚹ Suggestion: @@ -206,7 +208,8 @@ const dashboardcontroller = function () { emailBody, null, null, - email + email, + null ); res.status(200).send("Success"); } catch { From 50f96f6459ddaebd63f4d66aac2133a7853df1dc Mon Sep 17 00:00:00 2001 From: Carl Bebli Date: Tue, 28 Nov 2023 13:42:03 +0000 Subject: [PATCH 168/272] bluesquare replyto improvement --- src/helpers/userHelper.js | 635 ++++++++++++++++++++++---------------- 1 file changed, 361 insertions(+), 274 deletions(-) diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index c75dd7b45..8bf04eb5f 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -13,7 +13,7 @@ const emailSender = require("../utilities/emailSender"); const logger = require("../startup/logger"); const hasPermission = require("../utilities/permissions"); const Reason = require("../models/reason"); -const token = require("../models/profileInitialSetupToken") +const token = require("../models/profileInitialSetupToken"); const userHelper = function () { const getTeamMembers = function (user) { @@ -57,7 +57,7 @@ const userHelper = function () { if (picParts.length < 2) { return { result: false, - errors: "Invalid image" + errors: "Invalid image", }; } @@ -79,7 +79,7 @@ const userHelper = function () { return { result, - errors + errors, }; }; @@ -90,10 +90,11 @@ const userHelper = function () { totalInfringements, timeRemaining ) { - let final_paragraph = ''; + let final_paragraph = ""; if (timeRemaining == undefined) { - final_paragraph = '

Life happens and we understand that. That’s why we allow 5 of them before taking action. This action usually includes removal from our team though, so please let your direct supervisor know what happened and do your best to avoid future blue squares if you are getting close to 5 and wish to avoid termination. Each blue square drops off after a year.

'; + final_paragraph = + "

Life happens and we understand that. That’s why we allow 5 of them before taking action. This action usually includes removal from our team though, so please let your direct supervisor know what happened and do your best to avoid future blue squares if you are getting close to 5 and wish to avoid termination. Each blue square drops off after a year.

"; } else { final_paragraph = `

Life happens and we understand that. Please make up the missed hours this following week though to avoid getting another blue square. So you know what’s needed, the missing/incomplete hours (${timeRemaining} hours) have been added to your current week and this new weekly total can be seen at the top of your dashboard.

Reminder also that each blue square is removed from your profile 1 year after it was issued.

`; @@ -104,8 +105,8 @@ const userHelper = function () {

Date Assigned: ${infringement.date}

Description: ${infringement.description}

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

+ .localeData() + .ordinal(totalInfringements)} blue square of 5.

${final_paragraph}

Thank you,
One Community

`; @@ -124,9 +125,7 @@ const userHelper = function () { * @return {void} */ const emailWeeklySummariesForAllUsers = async (weekIndex = 1) => { - const currentFormattedDate = moment() - .tz("America/Los_Angeles") - .format(); + const currentFormattedDate = moment().tz("America/Los_Angeles").format(); logger.logInfo( `Job for emailing all users' weekly summaries starting at ${currentFormattedDate}` @@ -145,7 +144,11 @@ const userHelper = function () { const weeklySummaryNotRequiredMessage = '
Weekly Summary: Not required for this user
'; - results.sort((a, b) => `${a.firstName} ${a.lastName}`.localeCompare(`${b.firstName} ${b.lastname}`)); + results.sort((a, b) => + `${a.firstName} ${a.lastName}`.localeCompare( + `${b.firstName} ${b.lastname}` + ) + ); for (let i = 0; i < results.length; i += 1) { const result = results[i]; @@ -157,7 +160,7 @@ const userHelper = function () { mediaUrl, weeklySummariesCount, weeklycommittedHours, - weeklySummaryOption + weeklySummaryOption, } = result; if (email !== undefined && email !== null) { @@ -169,7 +172,9 @@ const userHelper = function () { // hence totalSeconds[0] should be used const hoursLogged = result.totalSeconds[0] / 3600 || 0; - const mediaUrlLink = mediaUrl ? `${mediaUrl}` : 'Not provided!'; + const mediaUrlLink = mediaUrl + ? `${mediaUrl}` + : "Not provided!"; let weeklySummaryMessage = weeklySummaryNotProvidedMessage; const colorStyle = (() => { @@ -192,16 +197,16 @@ const userHelper = function () {
Weekly Summary (for the week ending on ${moment(dueDate) - .tz("America/Los_Angeles") - .format("YYYY-MMM-DD")}): + .tz("America/Los_Angeles") + .format("YYYY-MMM-DD")}):
${summary}
`; } else if ( - weeklySummaryOption === 'Not Required' - || (!weeklySummaryOption && result.weeklySummaryNotReq) + weeklySummaryOption === "Not Required" || + (!weeklySummaryOption && result.weeklySummaryNotReq) ) { weeklySummaryMessage = weeklySummaryNotRequiredMessage; } @@ -213,21 +218,26 @@ const userHelper = function () { Name: ${firstName} ${lastName}

- Media URL: ${mediaUrlLink || 'Not provided!'} + Media URL: ${ + mediaUrlLink || 'Not provided!' + }

- ${weeklySummariesCount === 8 - ? `

Total Valid Weekly Summaries: ${weeklySummariesCount}

` - : `

Total Valid Weekly Summaries: ${weeklySummariesCount || - "No valid submissions yet!"}

` + ${ + weeklySummariesCount === 8 + ? `

Total Valid Weekly Summaries: ${weeklySummariesCount}

` + : `

Total Valid Weekly Summaries: ${ + weeklySummariesCount || "No valid submissions yet!" + }

` } - ${hoursLogged >= weeklycommittedHours - - ? `

Hours logged: ${hoursLogged.toFixed(2)} / ${weeklycommittedHours}

` - - : `

Hours logged: ${hoursLogged.toFixed( - 2 - )} / ${weeklycommittedHours}

` + ${ + hoursLogged >= weeklycommittedHours + ? `

Hours logged: ${hoursLogged.toFixed( + 2 + )} / ${weeklycommittedHours}

` + : `

Hours logged: ${hoursLogged.toFixed( + 2 + )} / ${weeklycommittedHours}

` } ${weeklySummaryMessage} `; @@ -254,7 +264,9 @@ const userHelper = function () { "onecommunityglobal@gmail.com, sangam.pravah@gmail.com, onecommunityhospitality@gmail.com", "Weekly Summaries for all active users...", emailBody, - null + null, + null, + emailString ); } catch (err) { logger.logException(err); @@ -275,18 +287,16 @@ const userHelper = function () { weeklySummaries: { $each: [ { - dueDate: moment() - .tz("America/Los_Angeles") - .endOf("week"), - summary: "" - } + dueDate: moment().tz("America/Los_Angeles").endOf("week"), + summary: "", + }, ], $position: 0, - $slice: 4 - } - } + $slice: 4, + }, + }, }) - .catch(error => logger.logException(error)); + .catch((error) => logger.logException(error)); }; /** @@ -297,18 +307,14 @@ const userHelper = function () { */ const assignBlueSquareForTimeNotMet = async () => { try { - const currentFormattedDate = moment() - .tz("America/Los_Angeles") - .format(); + const currentFormattedDate = moment().tz("America/Los_Angeles").format(); const currentUTCDate = moment .tz("America/Los_Angeles") .startOf("day") .toISOString(); logger.logInfo( - - `Job for assigning blue square for commitment not met starting at ${currentFormattedDate}`, - + `Job for assigning blue square for commitment not met starting at ${currentFormattedDate}` ); const pdtStartOfLastWeek = moment() @@ -321,7 +327,6 @@ const userHelper = function () { .endOf("week") .subtract(1, "week"); - const users = await userProfile.find( { isActive: true }, "_id weeklycommittedHours weeklySummaries missedHours" @@ -344,8 +349,10 @@ const userHelper = function () { let hasWeeklySummary = false; - - if (Array.isArray(user.weeklySummaries) && user.weeklySummaries.length) { + if ( + Array.isArray(user.weeklySummaries) && + user.weeklySummaries.length + ) { const { summary } = user.weeklySummaries[0]; if (summary) { hasWeeklySummary = true; @@ -371,31 +378,28 @@ const userHelper = function () { const timeRemaining = weeklycommittedHours - timeSpent; - const updateResult = await userProfile.findByIdAndUpdate( personId, { $inc: { - totalTangibleHrs: timeSpent || 0 + totalTangibleHrs: timeSpent || 0, }, $max: { - personalBestMaxHrs: timeSpent || 0 + personalBestMaxHrs: timeSpent || 0, }, $push: { - savedTangibleHrs: { $each: [timeSpent || 0], $slice: -200 } + savedTangibleHrs: { $each: [timeSpent || 0], $slice: -200 }, }, $set: { - lastWeekTangibleHrs: timeSpent || 0 - } + lastWeekTangibleHrs: timeSpent || 0, + }, }, { new: true } ); if ( - - updateResult?.weeklySummaryOption === 'Not Required' - || updateResult?.weeklySummaryNotReq - + updateResult?.weeklySummaryOption === "Not Required" || + updateResult?.weeklySummaryNotReq ) { hasWeeklySummary = true; } @@ -419,8 +423,8 @@ const userHelper = function () { personId, { $push: { - oldInfringements: { $each: oldInfringements, $slice: -10 } - } + oldInfringements: { $each: oldInfringements, $slice: -10 }, + }, }, { new: true } ); @@ -431,11 +435,15 @@ const userHelper = function () { description = foundReason.reason; } else { if (timeNotMet && !hasWeeklySummary) { - description = `System auto-assigned infringement for two reasons: not meeting weekly volunteer time commitment as well as not submitting a weekly summary. For the hours portion, you logged ${timeSpent.toFixed(2)} hours against committed effort of ${weeklycommittedHours} hours in the week starting ${pdtStartOfLastWeek.format( + description = `System auto-assigned infringement for two reasons: not meeting weekly volunteer time commitment as well as not submitting a weekly summary. For the hours portion, you logged ${timeSpent.toFixed( + 2 + )} hours against committed effort of ${weeklycommittedHours} hours in the week starting ${pdtStartOfLastWeek.format( "dddd YYYY-MM-DD" )} and ending ${pdtEndOfLastWeek.format("dddd YYYY-MM-DD")}.`; } else if (timeNotMet) { - description = `System auto-assigned infringement for not meeting weekly volunteer time commitment. You logged ${timeSpent.toFixed(2)} hours against committed effort of ${weeklycommittedHours} hours in the week starting ${pdtStartOfLastWeek.format( + description = `System auto-assigned infringement for not meeting weekly volunteer time commitment. You logged ${timeSpent.toFixed( + 2 + )} hours against committed effort of ${weeklycommittedHours} hours in the week starting ${pdtStartOfLastWeek.format( "dddd YYYY-MM-DD" )} and ending ${pdtEndOfLastWeek.format("dddd YYYY-MM-DD")}.`; } else { @@ -446,46 +454,46 @@ const userHelper = function () { } const infringement = { - date: moment() - .utc() - .format("YYYY-MM-DD"), - description + date: moment().utc().format("YYYY-MM-DD"), + description, }; const status = await userProfile.findByIdAndUpdate( personId, { $push: { - infringements: infringement - } + infringements: infringement, + }, }, { new: true } ); - let emailBody = ''; - if (person.role == 'Core Team' && timeRemaining > 0) { + let emailBody = ""; + if (person.role == "Core Team" && timeRemaining > 0) { emailBody = getInfringementEmailBody( status.firstName, status.lastName, infringement, status.infringements.length, - timeRemaining, + timeRemaining ); } else { emailBody = getInfringementEmailBody( status.firstName, status.lastName, infringement, - status.infringements.length, + status.infringements.length ); } emailSender( status.email, - 'New Infringement Assigned', + "New Infringement Assigned", emailBody, null, - "onecommunityglobal@gmail.com" + "onecommunityglobal@gmail.com", + null, + status.email ); const categories = await dashboardHelper.laborThisWeekByCategory( @@ -520,15 +528,15 @@ const userHelper = function () { await userProfile.findOneAndUpdate( { _id: personId, - "categoryTangibleHrs.category": { $ne: elem._id } + "categoryTangibleHrs.category": { $ne: elem._id }, }, { $addToSet: { categoryTangibleHrs: { category: elem._id, - hrs: elem.timeSpent_hrs - } - } + hrs: elem.timeSpent_hrs, + }, + }, } ); } @@ -545,8 +553,10 @@ const userHelper = function () { for (let i = 0; i < inactiveUsers.length; i += 1) { const user = inactiveUsers[i]; - await processWeeklySummariesByUserId(mongoose.Types.ObjectId(user._id), false); - + await processWeeklySummariesByUserId( + mongoose.Types.ObjectId(user._id), + false + ); } } catch (err) { logger.logException(err); @@ -555,9 +565,7 @@ const userHelper = function () { const applyMissedHourForCoreTeam = async () => { try { - const currentDate = moment() - .tz("America/Los_Angeles") - .format(); + const currentDate = moment().tz("America/Los_Angeles").format(); logger.logInfo( `Job for applying missed hours for Core Team members starting at ${currentDate}` @@ -579,8 +587,8 @@ const userHelper = function () { { $match: { role: "Core Team", - isActive: true - } + isActive: true, + }, }, { $lookup: { @@ -594,14 +602,14 @@ const userHelper = function () { $and: [ { $eq: ["$isTangible", true] }, { $gte: ["$dateOfWork", startOfLastWeek] }, - { $lte: ["$dateOfWork", endOfLastWeek] } - ] - } - } - } + { $lte: ["$dateOfWork", endOfLastWeek] }, + ], + }, + }, + }, ], - as: "timeEntries" - } + as: "timeEntries", + }, }, { $project: { @@ -611,9 +619,10 @@ const userHelper = function () { { $subtract: [ { - - $sum: [{ $ifNull: ['$missedHours', 0] }, '$weeklycommittedHours'], - + $sum: [ + { $ifNull: ["$missedHours", 0] }, + "$weeklycommittedHours", + ], }, { $divide: [ @@ -621,30 +630,30 @@ const userHelper = function () { $sum: { $map: { input: "$timeEntries", - in: "$$this.totalSeconds" - } - } + in: "$$this.totalSeconds", + }, + }, }, - 3600 - ] - } - ] + 3600, + ], + }, + ], }, - 0 - ] - } - } - } + 0, + ], + }, + }, + }, ]); const bulkOps = []; - missedHours.forEach(obj => { + missedHours.forEach((obj) => { bulkOps.push({ updateOne: { filter: { _id: obj._id }, - update: { missedHours: obj.missedHours } - } + update: { missedHours: obj.missedHours }, + }, }); }); @@ -655,17 +664,13 @@ const userHelper = function () { }; const deleteBlueSquareAfterYear = async () => { - const currentFormattedDate = moment() - .tz("America/Los_Angeles") - .format(); + const currentFormattedDate = moment().tz("America/Los_Angeles").format(); logger.logInfo( `Job for deleting blue squares older than 1 year starting at ${currentFormattedDate}` ); - const cutOffDate = moment() - .subtract(1, "year") - .format("YYYY-MM-DD"); + const cutOffDate = moment().subtract(1, "year").format("YYYY-MM-DD"); try { const results = await userProfile.updateMany( @@ -674,10 +679,10 @@ const userHelper = function () { $pull: { infringements: { date: { - $lte: cutOffDate - } - } - } + $lte: cutOffDate, + }, + }, + }, } ); @@ -688,9 +693,7 @@ const userHelper = function () { }; const reActivateUser = async () => { - const currentFormattedDate = moment() - .tz("America/Los_Angeles") - .format(); + const currentFormattedDate = moment().tz("America/Los_Angeles").format(); logger.logInfo( `Job for activating users based on scheduled re-activation date starting at ${currentFormattedDate}` @@ -708,11 +711,11 @@ const userHelper = function () { user._id, { $set: { - isActive: true + isActive: true, }, $unset: { - endDate: user.endDate - } + endDate: user.endDate, + }, }, { new: true } ); @@ -724,8 +727,12 @@ const userHelper = function () { const id = user._id; const person = await userProfile.findById(id); - const endDate = moment(person.endDate).format('YYYY-MM-DD'); - logger.logInfo(`User with id: ${user._id} was re-acticated at ${moment().format()}.`); + const endDate = moment(person.endDate).format("YYYY-MM-DD"); + logger.logInfo( + `User with id: ${ + user._id + } was re-acticated at ${moment().format()}.` + ); const subject = `IMPORTANT:${person.firstName} ${person.lastName} has been RE-activated in the Highest Good Network`; @@ -739,9 +746,14 @@ const userHelper = function () {

The HGN A.I. (and One Community)

`; - - emailSender('onecommunityglobal@gmail.com', subject, emailBody, null, null); - + emailSender( + "onecommunityglobal@gmail.com", + subject, + emailBody, + null, + null, + person.email + ); } } } catch (err) { @@ -749,24 +761,38 @@ const userHelper = function () { } }; - - const notifyInfringements = function (original, current, firstName, lastName, emailAddress) { - + const notifyInfringements = function ( + original, + current, + firstName, + lastName, + emailAddress + ) { if (!current) return; const newOriginal = original.toObject(); const newCurrent = current.toObject(); const totalInfringements = newCurrent.length; let newInfringements = []; - newInfringements = _.differenceWith(newCurrent, newOriginal, (arrVal, othVal) => arrVal._id.equals(othVal._id)); + newInfringements = _.differenceWith( + newCurrent, + newOriginal, + (arrVal, othVal) => arrVal._id.equals(othVal._id) + ); newInfringements.forEach((element) => { emailSender( emailAddress, - 'New Infringement Assigned', - getInfringementEmailBody(firstName, lastName, element, totalInfringements), + "New Infringement Assigned", + getInfringementEmailBody( + firstName, + lastName, + element, + totalInfringements + ), null, - "onecommunityglobal@gmail.com" + "onecommunityglobal@gmail.com", + emailAddress ); }); }; @@ -778,10 +804,10 @@ const userHelper = function () { $set: { "badgeCollection.$.badge": newBadgeId, "badgeCollection.$.lastModified": Date.now().toString(), - "badgeCollection.$.count": 1 - } + "badgeCollection.$.count": 1, + }, }, - err => { + (err) => { if (err) { throw new Error(err); } @@ -796,9 +822,9 @@ const userHelper = function () { { $inc: { "badgeCollection.$.count": 1 }, $set: { "badgeCollection.$.lastModified": Date.now().toString() }, - $push: { "badgeCollection.$.earnedDate": earnedDateBadge() } + $push: { "badgeCollection.$.earnedDate": earnedDateBadge() }, }, - err => { + (err) => { if (err) { console.log(err); } @@ -812,17 +838,21 @@ const userHelper = function () { count = 1, featured = false ) { - console.log('Adding Badge'); + console.log("Adding Badge"); userProfile.findByIdAndUpdate( personId, { $push: { badgeCollection: { - badge: badgeId, count, earnedDate: [earnedDateBadge()], featured, lastModified: Date.now().toString(), + badge: badgeId, + count, + earnedDate: [earnedDateBadge()], + featured, + lastModified: Date.now().toString(), }, }, }, - err => { + (err) => { if (err) { throw new Error(err); } @@ -835,10 +865,10 @@ const userHelper = function () { personId, { $pull: { - badgeCollection: { badge: badgeId } - } + badgeCollection: { badge: badgeId }, + }, }, - err => { + (err) => { if (err) { throw new Error(err); } @@ -855,10 +885,10 @@ const userHelper = function () { { $set: { "badgeCollection.$.count": count, - "badgeCollection.$.lastModified": Date.now().toString() - } + "badgeCollection.$.lastModified": Date.now().toString(), + }, }, - err => { + (err) => { if (err) { throw new Error(err); } @@ -869,8 +899,13 @@ const userHelper = function () { // remove the last badge you earned on this streak(not including 1) - const removePrevHrBadge = async function (personId, user, badgeCollection, hrs, weeks) { - + const removePrevHrBadge = async function ( + personId, + user, + badgeCollection, + hrs, + weeks + ) { // Check each Streak Greater than One to check if it works if (weeks < 3) { return; @@ -882,30 +917,29 @@ const userHelper = function () { $match: { type: "X Hours for X Week Streak", weeks: { $gt: 1, $lt: weeks }, - totalHrs: hrs - } + totalHrs: hrs, + }, }, { $sort: { weeks: -1, totalHrs: -1 } }, { $group: { _id: "$weeks", badges: { - $push: { _id: "$_id", hrs: "$totalHrs", weeks: "$weeks" } - } - } - } + $push: { _id: "$_id", hrs: "$totalHrs", weeks: "$weeks" }, + }, + }, + }, ]) - .then(results => { - results.forEach(streak => { - streak.badges.every(bdge => { + .then((results) => { + results.forEach((streak) => { + streak.badges.every((bdge) => { for (let i = 0; i < badgeCollection.length; i += 1) { if ( - - badgeCollection[i].badge?.type === 'X Hours for X Week Streak' - && badgeCollection[i].badge?.weeks === bdge.weeks - && bdge.hrs === hrs - && !removed - + badgeCollection[i].badge?.type === + "X Hours for X Week Streak" && + badgeCollection[i].badge?.weeks === bdge.weeks && + bdge.hrs === hrs && + !removed ) { changeBadgeCount( personId, @@ -924,15 +958,24 @@ const userHelper = function () { // 'No Infringement Streak', - const checkNoInfringementStreak = async function (personId, user, badgeCollection) { + const checkNoInfringementStreak = async function ( + personId, + user, + badgeCollection + ) { let badgeOfType; for (let i = 0; i < badgeCollection.length; i += 1) { - if (badgeCollection[i].badge?.type === 'No Infringement Streak') { - if (badgeOfType && badgeOfType.months <= badgeCollection[i].badge.months) { + if (badgeCollection[i].badge?.type === "No Infringement Streak") { + if ( + badgeOfType && + badgeOfType.months <= badgeCollection[i].badge.months + ) { removeDupBadge(personId, badgeOfType._id); badgeOfType = badgeCollection[i].badge; - } else if (badgeOfType && badgeOfType.months > badgeCollection[i].badge.months) { - + } else if ( + badgeOfType && + badgeOfType.months > badgeCollection[i].badge.months + ) { removeDupBadge(personId, badgeCollection[i].badge._id); } else if (!badgeOfType) { badgeOfType = badgeCollection[i].badge; @@ -942,28 +985,29 @@ const userHelper = function () { await badge .find({ type: "No Infringement Streak" }) .sort({ months: -1 }) - .then(results => { + .then((results) => { if (!Array.isArray(results) || !results.length) { return; } - results.every(elem => { + results.every((elem) => { // Cannot account for time paused yet if (elem.months <= 12) { - - if (moment().diff(moment(user.createdDate), 'months', true) >= elem.months) { - + if ( + moment().diff(moment(user.createdDate), "months", true) >= + elem.months + ) { if ( user.infringements.length === 0 || Math.abs( moment().diff( - - moment(user.infringements[user.infringements?.length - 1].date), - 'months', - true, - ), - + moment( + user.infringements[user.infringements?.length - 1].date + ), + "months", + true + ) ) >= elem.months ) { if (badgeOfType) { @@ -981,21 +1025,23 @@ const userHelper = function () { } } } else if (user?.infringements?.length === 0) { - - if (moment().diff(moment(user.createdDate), 'months', true) >= elem.months) { - + if ( + moment().diff(moment(user.createdDate), "months", true) >= + elem.months + ) { if ( user.oldInfringements.length === 0 || Math.abs( moment().diff( - - moment(user.oldInfringements[user.oldInfringements?.length - 1].date), - 'months', - true, - ), - ) - >= elem.months - 12 - + moment( + user.oldInfringements[user.oldInfringements?.length - 1] + .date + ), + "months", + true + ) + ) >= + elem.months - 12 ) { if (badgeOfType) { if (badgeOfType._id.toString() !== elem._id.toString()) { @@ -1024,10 +1070,10 @@ const userHelper = function () { badgeCollection ) { const badgesOfType = badgeCollection - .map(obj => obj.badge) - .filter(badge => badge.type === 'Minimum Hours Multiple') + .map((obj) => obj.badge) + .filter((badge) => badge.type === "Minimum Hours Multiple"); await badge - .find({ type: 'Minimum Hours Multiple' }) + .find({ type: "Minimum Hours Multiple" }) .sort({ multiple: -1 }) .then((results) => { if (!Array.isArray(results) || !results.length) { @@ -1046,13 +1092,13 @@ const userHelper = function () { ); return theBadge ? increaseBadgeCount( - personId, - mongoose.Types.ObjectId(theBadge._id) - ) + personId, + mongoose.Types.ObjectId(theBadge._id) + ) : addBadge(personId, mongoose.Types.ObjectId(elem._id)); } } - }) + }); }; // 'Personal Max', @@ -1065,7 +1111,7 @@ const userHelper = function () { } } } - await badge.findOne({ type: "Personal Max" }).then(results => { + await badge.findOne({ type: "Personal Max" }).then((results) => { if ( user.lastWeekTangibleHrs && user.lastWeekTangibleHrs >= 1 && @@ -1078,9 +1124,11 @@ const userHelper = function () { user.personalBestMaxHrs ); } else { - - addBadge(personId, mongoose.Types.ObjectId(results._id), user.personalBestMaxHrs); - + addBadge( + personId, + mongoose.Types.ObjectId(results._id), + user.personalBestMaxHrs + ); } } }); @@ -1090,13 +1138,13 @@ const userHelper = function () { const checkMostHrsWeek = async function (personId, user, badgeCollection) { if ( - user.weeklycommittedHours > 0 - && user.lastWeekTangibleHrs > user.weeklycommittedHours + user.weeklycommittedHours > 0 && + user.lastWeekTangibleHrs > user.weeklycommittedHours ) { const badgeOfType = badgeCollection - .filter(object => object.badge.type === 'Most Hrs in Week') - .map(object => object.badge); - await badge.findOne({ type: 'Most Hrs in Week' }).then((results) => { + .filter((object) => object.badge.type === "Most Hrs in Week") + .map((object) => object.badge); + await badge.findOne({ type: "Most Hrs in Week" }).then((results) => { userProfile .aggregate([ { $match: { isActive: true } }, @@ -1105,7 +1153,6 @@ const userHelper = function () { .then((userResults) => { if (badgeOfType.length > 1) { removeDupBadge(user._id, badgeOfType[0]._id); - } if ( @@ -1138,8 +1185,8 @@ const userHelper = function () { await badge .find({ type: "X Hours for X Week Streak", weeks: 1 }) .sort({ totalHrs: -1 }) - .then(results => { - results.every(elem => { + .then((results) => { + results.every((elem) => { if (elem.totalHrs <= user.lastWeekTangibleHrs) { let theBadge; for (let i = 0; i < badgesOfType.length; i += 1) { @@ -1167,24 +1214,26 @@ const userHelper = function () { $group: { _id: "$weeks", badges: { - $push: { _id: "$_id", hrs: "$totalHrs", weeks: "$weeks" } - } - } - } + $push: { _id: "$_id", hrs: "$totalHrs", weeks: "$weeks" }, + }, + }, + }, ]) - .then(results => { + .then((results) => { let lastHr = -1; - results.forEach(streak => { - streak.badges.every(bdge => { + results.forEach((streak) => { + streak.badges.every((bdge) => { let badgeOfType; for (let i = 0; i < badgeCollection.length; i += 1) { if ( - - badgeCollection[i].badge?.type === 'X Hours for X Week Streak' - && badgeCollection[i].badge?.weeks === bdge.weeks + badgeCollection[i].badge?.type === + "X Hours for X Week Streak" && + badgeCollection[i].badge?.weeks === bdge.weeks ) { - if (badgeOfType && badgeOfType.totalHrs <= badgeCollection[i].badge.totalHrs) { - + if ( + badgeOfType && + badgeOfType.totalHrs <= badgeCollection[i].badge.totalHrs + ) { removeDupBadge(personId, badgeOfType._id); badgeOfType = badgeCollection[i].badge; } else if ( @@ -1217,7 +1266,13 @@ const userHelper = function () { mongoose.Types.ObjectId(bdge._id) ); - removePrevHrBadge(personId, user, badgeCollection, bdge.hrs, bdge.weeks); + removePrevHrBadge( + personId, + user, + badgeCollection, + bdge.hrs, + bdge.weeks + ); } else if (!badgeOfType) { addBadge(personId, mongoose.Types.ObjectId(bdge._id)); removePrevHrBadge( @@ -1228,9 +1283,17 @@ const userHelper = function () { bdge.weeks ); } else if (badgeOfType && badgeOfType.totalHrs === bdge.hrs) { - increaseBadgeCount(personId, mongoose.Types.ObjectId(badgeOfType._id)); - removePrevHrBadge(personId, user, badgeCollection, bdge.hrs, bdge.weeks); - + increaseBadgeCount( + personId, + mongoose.Types.ObjectId(badgeOfType._id) + ); + removePrevHrBadge( + personId, + user, + badgeCollection, + bdge.hrs, + bdge.weeks + ); } return false; } @@ -1243,16 +1306,25 @@ const userHelper = function () { // 'Lead a team of X+' - - const checkLeadTeamOfXplus = async function (personId, user, badgeCollection) { - const leaderRoles = ['Mentor', 'Manager', 'Administrator', 'Owner', 'Core Team']; - const approvedRoles = ['Mentor', 'Manager']; + const checkLeadTeamOfXplus = async function ( + personId, + user, + badgeCollection + ) { + const leaderRoles = [ + "Mentor", + "Manager", + "Administrator", + "Owner", + "Core Team", + ]; + const approvedRoles = ["Mentor", "Manager"]; if (!approvedRoles.includes(user.role)) return; let teamMembers; await getTeamMembers({ - _id: personId - }).then(results => { + _id: personId, + }).then((results) => { if (results) { teamMembers = results.myteam; } else { @@ -1271,13 +1343,17 @@ const userHelper = function () { }); let badgeOfType; for (let i = 0; i < badgeCollection.length; i += 1) { - - if (badgeCollection[i].badge?.type === 'Lead a team of X+') { - if (badgeOfType && badgeOfType.people <= badgeCollection[i].badge.people) { + if (badgeCollection[i].badge?.type === "Lead a team of X+") { + if ( + badgeOfType && + badgeOfType.people <= badgeCollection[i].badge.people + ) { removeDupBadge(personId, badgeOfType._id); badgeOfType = badgeCollection[i].badge; - } else if (badgeOfType && badgeOfType.people > badgeCollection[i].badge.people) { - + } else if ( + badgeOfType && + badgeOfType.people > badgeCollection[i].badge.people + ) { removeDupBadge(personId, badgeCollection[i].badge._id); } else if (!badgeOfType) { badgeOfType = badgeCollection[i].badge; @@ -1287,7 +1363,7 @@ const userHelper = function () { await badge .find({ type: "Lead a team of X+" }) .sort({ people: -1 }) - .then(results => { + .then((results) => { if (!Array.isArray(results) || !results.length) { return; } @@ -1295,16 +1371,14 @@ const userHelper = function () { if (teamMembers && teamMembers.length >= badge.people) { if (badgeOfType) { if ( - badgeOfType._id.toString() !== badge._id.toString() - && badgeOfType.people < badge.people - + badgeOfType._id.toString() !== badge._id.toString() && + badgeOfType.people < badge.people ) { replaceBadge( personId, mongoose.Types.ObjectId(badgeOfType._id), - mongoose.Types.ObjectId(badge._id), - + mongoose.Types.ObjectId(badge._id) ); } return false; @@ -1327,19 +1401,18 @@ const userHelper = function () { "education", "society", "economics", - "stewardship" + "stewardship", ]; const badgesOfType = badgeCollection - .filter(object => object.badge.type === "Total Hrs in Category") - .map(object => object.badge); + .filter((object) => object.badge.type === "Total Hrs in Category") + .map((object) => object.badge); - categories.forEach(async category => { + categories.forEach(async (category) => { const categoryHrs = Object.keys(hoursByCategory).find( - elem => elem === category + (elem) => elem === category ); - let badgeOfType; for (let i = 0; i < badgeCollection.length; i += 1) { if ( @@ -1365,16 +1438,16 @@ const userHelper = function () { const newCatg = category.charAt(0).toUpperCase() + category.slice(1); - - await badge.find({ type: 'Total Hrs in Category', category: newCatg }) + await badge + .find({ type: "Total Hrs in Category", category: newCatg }) .sort({ totalHrs: -1 }) - .then(results => { + .then((results) => { if (!Array.isArray(results) || !results.length || !categoryHrs) { return; } - results.every(elem => { + results.every((elem) => { if ( hoursByCategory[categoryHrs] >= 100 && hoursByCategory[categoryHrs] >= elem.totalHrs @@ -1415,9 +1488,9 @@ const userHelper = function () { const awardNewBadges = async () => { console.log("Awarding"); try { - - const users = await userProfile.find({ isActive: true }).populate('badgeCollection.badge'); - + const users = await userProfile + .find({ isActive: true }) + .populate("badgeCollection.badge"); for (let i = 0; i < users.length; i += 1) { const user = users[i]; @@ -1439,20 +1512,25 @@ const userHelper = function () { const getTangibleHoursReportedThisWeekByUserId = function (personId) { const userId = mongoose.Types.ObjectId(personId); - const pdtstart = moment().tz('America/Los_Angeles').startOf('week').format('YYYY-MM-DD'); - const pdtend = moment().tz('America/Los_Angeles').endOf('week').format('YYYY-MM-DD'); - + const pdtstart = moment() + .tz("America/Los_Angeles") + .startOf("week") + .format("YYYY-MM-DD"); + const pdtend = moment() + .tz("America/Los_Angeles") + .endOf("week") + .format("YYYY-MM-DD"); return timeEntries .find( { personId: userId, dateOfWork: { $gte: pdtstart, $lte: pdtend }, - isTangible: true + isTangible: true, }, "totalSeconds" ) - .then(results => { + .then((results) => { const totalTangibleWeeklySeconds = results.reduce( (acc, { totalSeconds }) => acc + totalSeconds, 0 @@ -1475,15 +1553,19 @@ const userHelper = function () { await userProfile.findByIdAndUpdate( user._id, user.set({ - isActive: false + isActive: false, }), { new: true } ); const id = user._id; const person = await userProfile.findById(id); - const lastDay = moment(person.endDate).format('YYYY-MM-DD'); - logger.logInfo(`User with id: ${user._id} was de-acticated at ${moment().format()}.`); + const lastDay = moment(person.endDate).format("YYYY-MM-DD"); + logger.logInfo( + `User with id: ${ + user._id + } was de-acticated at ${moment().format()}.` + ); const subject = `IMPORTANT:${person.firstName} ${person.lastName} has been deactivated in the Highest Good Network`; @@ -1497,8 +1579,14 @@ const userHelper = function () {

The HGN A.I. (and One Community)

`; - - emailSender('onecommunityglobal@gmail.com', subject, emailBody, null, null); + emailSender( + "onecommunityglobal@gmail.com", + subject, + emailBody, + null, + null, + person.email + ); } } } catch (err) { @@ -1514,8 +1602,7 @@ const userHelper = function () { } catch (error) { logger.logException(err); } - } - + }; return { getUserName, @@ -1531,7 +1618,7 @@ const userHelper = function () { emailWeeklySummariesForAllUsers, awardNewBadges, getTangibleHoursReportedThisWeekByUserId, - deleteExpiredTokens + deleteExpiredTokens, }; }; From 67b764a89a3fcebb233f9f2cb6d623d69ce9abec Mon Sep 17 00:00:00 2001 From: wang9hu Date: Tue, 28 Nov 2023 17:47:57 -0800 Subject: [PATCH 169/272] fix some response send result before set status code, add empty string for teamCode in the team model, make team controller check team name for duplicates when post new team --- src/controllers/dashBoardController.js | 96 +++++++++++++------------- src/controllers/logincontroller.js | 4 +- src/controllers/teamController.js | 24 ++++--- src/models/team.js | 2 +- 4 files changed, 67 insertions(+), 59 deletions(-) diff --git a/src/controllers/dashBoardController.js b/src/controllers/dashBoardController.js index b1b62f9ae..1cf730a5a 100644 --- a/src/controllers/dashBoardController.js +++ b/src/controllers/dashBoardController.js @@ -1,8 +1,8 @@ -const path = require("path"); -const fs = require("fs/promises"); -const mongoose = require("mongoose"); -const dashboardhelper = require("../helpers/dashboardhelper")(); -const emailSender = require("../utilities/emailSender"); +const path = require('path'); +const fs = require('fs/promises'); +const mongoose = require('mongoose'); +const dashboardhelper = require('../helpers/dashboardhelper')(); +const emailSender = require('../utilities/emailSender'); const dashboardcontroller = function () { const dashboarddata = function (req, res) { @@ -11,7 +11,7 @@ const dashboardcontroller = function () { const snapshot = dashboardhelper.personaldetails(userId); snapshot.then((results) => { - res.send(results).status(200); + res.status(200).send(results); }); }; @@ -20,13 +20,13 @@ const dashboardcontroller = function () { const laborthismonth = dashboardhelper.laborthismonth( userId, req.params.fromDate, - req.params.toDate + req.params.toDate, ); laborthismonth.then((results) => { if (!results || results.length === 0) { const emptyresult = [ { - projectName: "", + projectName: '', timeSpent_hrs: 0, }, ]; @@ -42,10 +42,10 @@ const dashboardcontroller = function () { const laborthisweek = dashboardhelper.laborthisweek( userId, req.params.fromDate, - req.params.toDate + req.params.toDate, ); laborthisweek.then((results) => { - res.send(results).status(200); + res.status(200).send(results); }); }; @@ -63,7 +63,7 @@ const dashboardcontroller = function () { }); } }) - .catch((error) => res.status(400).send(error)); + .catch(error => res.status(400).send(error)); }; const orgData = function (req, res) { @@ -73,7 +73,7 @@ const dashboardcontroller = function () { .then((results) => { res.status(200).send(results[0]); }) - .catch((error) => res.status(400).send(error)); + .catch(error => res.status(400).send(error)); }; const getBugReportEmailBody = function ( @@ -85,7 +85,7 @@ const dashboardcontroller = function () { expected, actual, visual, - severity + severity, ) { const text = `New Bug Report From ${firstName} ${lastName}:

[Feature Name] Bug Title:

@@ -130,32 +130,32 @@ const dashboardcontroller = function () { expected, actual, visual, - severity + severity, ); try { emailSender( - "onecommunityglobal@gmail.com", + 'onecommunityglobal@gmail.com', `Bug Rport from ${firstName} ${lastName}`, emailBody, - email + email, ); - res.status(200).send("Success"); + res.status(200).send('Success'); } catch { - res.status(500).send("Failed"); + res.status(500).send('Failed'); } }; const suggestionData = { suggestion: [ - "Identify and remedy poor client and/or user service experiences", - "Identify bright spots and enhance positive service experiences", - "Make fundamental changes to our programs and/or operations", - "Inform the development of new programs/projects", - "Identify where we are less inclusive or equitable across demographic groups", - "Strengthen relationships with the people we serve", + 'Identify and remedy poor client and/or user service experiences', + 'Identify bright spots and enhance positive service experiences', + 'Make fundamental changes to our programs and/or operations', + 'Inform the development of new programs/projects', + 'Identify where we are less inclusive or equitable across demographic groups', + 'Strengthen relationships with the people we serve', "Understand people's needs and how we can help them achieve their goals", - "Other", + 'Other', ], field: [], }; @@ -164,8 +164,8 @@ const dashboardcontroller = function () { let fieldaaray = []; if (suggestionData.field.length) { fieldaaray = suggestionData.field.map( - (item) => `

${item}

-

${args[3][item]}

` + item => `

${item}

+

${args[3][item]}

`, ); } const text = `New Suggestion From ${args[3].firstName} ${ @@ -178,7 +178,7 @@ const dashboardcontroller = function () {

${args[0]}

⚹ Suggestion:

${args[1]}

- ${fieldaaray.length > 0 ? fieldaaray : ""} + ${fieldaaray.length > 0 ? fieldaaray : ''} ⚹ Name of Suggester:

${args[3].firstName} ${args[3].lastName}

⚹ Email of Suggester: @@ -193,27 +193,29 @@ const dashboardcontroller = function () { // send suggestion email const sendMakeSuggestion = async (req, res) => { - const { suggestioncate, suggestion, confirm, email, ...rest } = req.body; + const { + suggestioncate, suggestion, confirm, email, ...rest +} = req.body; const emailBody = await getsuggestionEmailBody( suggestioncate, suggestion, confirm, rest, - email + email, ); try { emailSender( - "onecommunityglobal@gmail.com", - "A new suggestion", + 'onecommunityglobal@gmail.com', + 'A new suggestion', emailBody, null, null, email, - null + null, ); - res.status(200).send("Success"); + res.status(200).send('Success'); } catch { - res.status(500).send("Failed"); + res.status(500).send('Failed'); } }; @@ -222,40 +224,40 @@ const dashboardcontroller = function () { if (suggestionData) { res.status(200).send(suggestionData); } else { - res.status(404).send("Suggestion data not found."); + res.status(404).send('Suggestion data not found.'); } } catch (error) { - console.error("Error getting suggestion data:", error); - res.status(500).send("Internal Server Error"); + console.error('Error getting suggestion data:', error); + res.status(500).send('Internal Server Error'); } }; const editSuggestionOption = async (req, res) => { try { if (req.body.suggestion) { - if (req.body.action === "add") { + if (req.body.action === 'add') { suggestionData.suggestion.unshift(req.body.newField); } - if (req.body.action === "delete") { + if (req.body.action === 'delete') { suggestionData.suggestion = suggestionData.suggestion.filter( - (item, index) => index + 1 !== +req.body.newField + (item, index) => index + 1 !== +req.body.newField, ); } } else { - if (req.body.action === "add") { + if (req.body.action === 'add') { suggestionData.field.unshift(req.body.newField); } - if (req.body.action === "delete") { + if (req.body.action === 'delete') { suggestionData.field = suggestionData.field.filter( - (item) => item !== req.body.newField + item => item !== req.body.newField, ); } } - res.status(200).send("success"); + res.status(200).send('success'); } catch (error) { - console.error("Error editing suggestion option:", error); - res.status(500).send("Internal Server Error"); + console.error('Error editing suggestion option:', error); + res.status(500).send('Internal Server Error'); } }; diff --git a/src/controllers/logincontroller.js b/src/controllers/logincontroller.js index cdeae9b37..b6da4cf8b 100644 --- a/src/controllers/logincontroller.js +++ b/src/controllers/logincontroller.js @@ -43,7 +43,7 @@ const logincontroller = function () { new: true, userId: user._id, }; - res.send(result).status(200); + res.status(200).send(result); } else if (isPasswordMatch && !isNewUser) { const jwtPayload = { userid: user._id, @@ -57,7 +57,7 @@ const logincontroller = function () { const token = jwt.sign(jwtPayload, JWT_SECRET); - res.send({ token }).status(200); + res.status(200).send({ token }); } else { res.status(403).send({ message: 'Invalid password.', diff --git a/src/controllers/teamController.js b/src/controllers/teamController.js index b204875a5..86733daf4 100644 --- a/src/controllers/teamController.js +++ b/src/controllers/teamController.js @@ -7,32 +7,38 @@ const teamcontroller = function (Team) { const getAllTeams = function (req, res) { Team.find({}) .sort({ teamName: 1 }) - .then(results => res.send(results).status(200)) - .catch(error => res.send(error).status(404)); + .then(results => res.status(200).send(results)) + .catch(error => res.status(404).send(error)); }; const getTeamById = function (req, res) { const { teamId } = req.params; Team.findById(teamId) - .then(results => res.send(results).status(200)) - .catch(error => res.send(error).status(404)); + .then(results => res.status(200).send(results)) + .catch(error => res.status(404).send(error)); }; const postTeam = async function (req, res) { if (!await hasPermission(req.body.requestor, 'postTeam')) { res.status(403).send({ error: 'You are not authorized to create teams.' }); return; } + + if (await Team.exists({ teamName: req.body.teamName })) { + res.status(403).send({ error: `Team Name "${req.body.teamName}" already exists` }); + return; + } + const team = new Team(); team.teamName = req.body.teamName; - team.isACtive = req.body.isActive; + team.isACtive = true; team.createdDatetime = Date.now(); team.modifiedDatetime = Date.now(); team .save() - .then(results => res.send(results).status(200)) - .catch(error => res.send(error).status(404)); + .then(results => res.status(200).send(results)) + .catch(error => res.status(404).send(error)); }; const deleteTeam = async function (req, res) { if (!await hasPermission(req.body.requestor, 'deleteTeam')) { @@ -49,7 +55,7 @@ const teamcontroller = function (Team) { const deleteteam = record.remove(); Promise.all([removeteamfromprofile, deleteteam]) - .then(res.status(200).send({ message: ' Team successfully deleted and user profiles updated' })) + .then(res.status(200).send({ message: 'Team successfully deleted and user profiles updated' })) .catch((errors) => { res.status(400).send(errors); }); @@ -87,7 +93,7 @@ const teamcontroller = function (Team) { record .save() - .then(results => res.status(201).send(results._id)) + .then(results => res.status(200).send(results._id)) .catch(errors => res.status(400).send(errors)); }); }; diff --git a/src/models/team.js b/src/models/team.js index 00fbaf8e3..1df50b95a 100644 --- a/src/models/team.js +++ b/src/models/team.js @@ -18,7 +18,7 @@ const team = new Schema({ default: '', validate: { validator(v) { - const teamCoderegex = /^([a-zA-Z]-[a-zA-Z]{3}|[a-zA-Z]{5})$/; + const teamCoderegex = /^([a-zA-Z]-[a-zA-Z]{3}|[a-zA-Z]{5})$|^$/; return teamCoderegex.test(v); }, message: From 03acb2fe39661754b1b29f29e2b036c34f0c7c72 Mon Sep 17 00:00:00 2001 From: Olga Yudkin Date: Thu, 30 Nov 2023 12:05:17 -0500 Subject: [PATCH 170/272] updates --- src/controllers/bmdashboard/bmToolsController.js | 1 + src/routes/bmdashboard/bmToolsRouter.js | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/bmdashboard/bmToolsController.js b/src/controllers/bmdashboard/bmToolsController.js index e1b2f58c7..c54ac7b24 100644 --- a/src/controllers/bmdashboard/bmToolsController.js +++ b/src/controllers/bmdashboard/bmToolsController.js @@ -7,6 +7,7 @@ const bmToolsController = (BuildingTool) => { .populate([ { path: 'itemType', + select: '_id name description unit imageURL', }, { path: 'userResponsible', diff --git a/src/routes/bmdashboard/bmToolsRouter.js b/src/routes/bmdashboard/bmToolsRouter.js index 6112f3502..32ea64f20 100644 --- a/src/routes/bmdashboard/bmToolsRouter.js +++ b/src/routes/bmdashboard/bmToolsRouter.js @@ -4,10 +4,9 @@ const routes = function (BuildingTool) { const toolRouter = express.Router(); const controller = require('../../controllers/bmdashboard/bmToolsController')(BuildingTool); - toolRouter.route('tools/:toolId') + toolRouter.route('/tools/:toolId') .get(controller.fetchSingleTool); - return toolRouter; }; From b3e7dd1e063df76ed893178a7d340116636858c5 Mon Sep 17 00:00:00 2001 From: kaikane lacno <114305309+lacnoskillz@users.noreply.github.com> Date: Thu, 30 Nov 2023 14:49:02 -0600 Subject: [PATCH 171/272] Update pull_request_template.md --- .github/pull_request_template.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index c6fee8ab4..4816bd1e2 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -17,9 +17,10 @@ To test this backend PR you need to checkout the #XXX frontend PR. ## How to test: 1. check into current branch 2. do `npm install` and `...` to run this PR locally -3. log as admin user -4. go to dashboard→ Tasks→ task→… -5. verify function “A” (feel free to include screenshot here) +3. Clear site data/cache +4. log as admin user +5. go to dashboard→ Tasks→ task→… +6. verify function “A” (feel free to include screenshot here) ## Screenshots or videos of changes: From d71867ed9574a36efecc0ca073bf55328c166ef0 Mon Sep 17 00:00:00 2001 From: Vishala Ramasamy Date: Thu, 30 Nov 2023 13:35:10 -0800 Subject: [PATCH 172/272] update material changes --- .../bmdashboard/bmMaterialsController.js | 4 ++-- .../bmdashboard/buildingInventoryType.js | 8 +++---- src/models/bmdashboard/buildingMaterial.js | 22 +++++++++++-------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index 671cb0b24..b9c6438b4 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -88,7 +88,7 @@ const bmMaterialsController = function (ItemMaterial) { }; const bmPostMaterialUpdateBulk = function (req, res) { - const materialUpdates= req.body; + const materialUpdates= req.body.upadateMaterials; let errorFlag = false; const updateRecordsToBeAdded = []; for(let i=0;i Date: Thu, 30 Nov 2023 16:49:51 -0800 Subject: [PATCH 173/272] resolved conflicts --- src/controllers/dashBoardController.js | 28 -------------------------- 1 file changed, 28 deletions(-) diff --git a/src/controllers/dashBoardController.js b/src/controllers/dashBoardController.js index 6739043f3..b8294b93e 100644 --- a/src/controllers/dashBoardController.js +++ b/src/controllers/dashBoardController.js @@ -168,18 +168,6 @@ const dashboardcontroller = function () {

${args[3][item]}

`, ); } -<<<<<<< HEAD - const text = `New Suggestion: -

Suggestion Category:

-

${args[0]}

-

Suggestion:

-

${args[1]}

- ${fieldaaray.length > 0 ? fieldaaray : ''} -

Wants Feedback:

-

${args[2]}

-

Thank you,
- One Community

`; -======= const text = `New Suggestion From ${args[3].firstName} ${ args[3].lastName } @@ -197,33 +185,18 @@ const dashboardcontroller = function () {

${args[2]}

Thank you,
One Community
`; ->>>>>>> development return text; }; // send suggestion email const sendMakeSuggestion = async (req, res) => { -<<<<<<< HEAD - const { - suggestioncate, suggestion, confirm, ...rest -} = req.body; -======= const { suggestioncate, suggestion, confirm, email, ...rest } = req.body; ->>>>>>> development const emailBody = await getsuggestionEmailBody( suggestioncate, suggestion, confirm, rest, -<<<<<<< HEAD - ); - try { - emailSender( - 'onecommunityglobal@gmail.com', - 'A new suggestion', - emailBody, -======= email ); try { @@ -234,7 +207,6 @@ const dashboardcontroller = function () { null, null, email ->>>>>>> development ); res.status(200).send('Success'); } catch { From a9058c03c6166d0227f901cf54b5bca5f31b2b25 Mon Sep 17 00:00:00 2001 From: Vishala Ramasamy Date: Thu, 30 Nov 2023 18:04:38 -0800 Subject: [PATCH 174/272] resolved conflicts --- src/controllers/dashBoardController.js | 33 +- src/helpers/userHelper.js | 782 ++++++++++++++----------- src/startup/routes.js | 15 +- 3 files changed, 477 insertions(+), 353 deletions(-) diff --git a/src/controllers/dashBoardController.js b/src/controllers/dashBoardController.js index b8294b93e..30bddc871 100644 --- a/src/controllers/dashBoardController.js +++ b/src/controllers/dashBoardController.js @@ -1,8 +1,8 @@ -const path = require("path"); -const fs = require("fs/promises"); -const mongoose = require("mongoose"); -const dashboardhelper = require("../helpers/dashboardhelper")(); -const emailSender = require("../utilities/emailSender"); +const path = require('path'); +const fs = require('fs/promises'); +const mongoose = require('mongoose'); +const dashboardhelper = require('../helpers/dashboardhelper')(); +const emailSender = require('../utilities/emailSender'); const dashboardcontroller = function () { const dashboarddata = function (req, res) { @@ -11,7 +11,7 @@ const dashboardcontroller = function () { const snapshot = dashboardhelper.personaldetails(userId); snapshot.then((results) => { - res.send(results).status(200); + res.status(200).send(results); }); }; @@ -45,7 +45,7 @@ const dashboardcontroller = function () { req.params.toDate, ); laborthisweek.then((results) => { - res.send(results).status(200); + res.status(200).send(results); }); }; @@ -172,11 +172,13 @@ const dashboardcontroller = function () { args[3].lastName }
: +
+
⚹ Suggestion Category:

${args[0]}

⚹ Suggestion:

${args[1]}

- ${fieldaaray.length > 0 ? fieldaaray : ""} + ${fieldaaray.length > 0 ? fieldaaray : ''} ⚹ Name of Suggester:

${args[3].firstName} ${args[3].lastName}

⚹ Email of Suggester: @@ -191,22 +193,25 @@ const dashboardcontroller = function () { // send suggestion email const sendMakeSuggestion = async (req, res) => { - const { suggestioncate, suggestion, confirm, email, ...rest } = req.body; + const { + suggestioncate, suggestion, confirm, email, ...rest +} = req.body; const emailBody = await getsuggestionEmailBody( suggestioncate, suggestion, confirm, rest, - email + email, ); try { emailSender( - "onecommunityglobal@gmail.com", - "A new suggestion", + 'onecommunityglobal@gmail.com', + 'A new suggestion', emailBody, null, null, - email + email, + null ); res.status(200).send('Success'); } catch { @@ -269,4 +274,4 @@ const dashboardcontroller = function () { }; }; -module.exports = dashboardcontroller; +module.exports = dashboardcontroller; \ No newline at end of file diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index ab6dcea9f..f639a4d37 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -1,28 +1,28 @@ /* eslint-disable no-continue */ /* eslint-disable no-await-in-loop */ -const mongoose = require('mongoose'); -const moment = require('moment-timezone'); -const _ = require('lodash'); -const userProfile = require('../models/userProfile'); -const timeEntries = require('../models/timeentry'); -const badge = require('../models/badge'); -const myTeam = require('./helperModels/myTeam'); -const dashboardHelper = require('./dashboardhelper')(); -const reportHelper = require('./reporthelper')(); -const emailSender = require('../utilities/emailSender'); -const logger = require('../startup/logger'); -const hasPermission = require('../utilities/permissions'); -const Reason = require('../models/reason'); -const token = require('../models/profileInitialSetupToken'); +const mongoose = require("mongoose"); +const moment = require("moment-timezone"); +const _ = require("lodash"); +const userProfile = require("../models/userProfile"); +const timeEntries = require("../models/timeentry"); +const badge = require("../models/badge"); +const myTeam = require("./helperModels/myTeam"); +const dashboardHelper = require("./dashboardhelper")(); +const reportHelper = require("./reporthelper")(); +const emailSender = require("../utilities/emailSender"); +const logger = require("../startup/logger"); +const hasPermission = require("../utilities/permissions"); +const Reason = require("../models/reason"); +const token = require("../models/profileInitialSetupToken"); const userHelper = function () { const getTeamMembers = function (user) { const userId = mongoose.Types.ObjectId(user._id); // var teamid = userdetails.teamId; return myTeam.findById(userId).select({ - 'myTeam._id': 0, - 'myTeam.role': 0, - 'myTeam.fullName': 0, + "myTeam._id": 0, + "myTeam.role": 0, + "myTeam.fullName": 0, _id: 0, }); }; @@ -46,33 +46,34 @@ const userHelper = function () { const getUserName = async function (userId) { const userid = mongoose.Types.ObjectId(userId); - return userProfile.findById(userid, 'firstName lastName'); + return userProfile.findById(userid, "firstName lastName"); }; const validateProfilePic = function (profilePic) { - const picParts = profilePic.split('base64'); + const picParts = profilePic.split("base64"); let result = true; const errors = []; if (picParts.length < 2) { return { result: false, - errors: 'Invalid image', + errors: "Invalid image", }; } // validate size const imageSize = picParts[1].length; - const sizeInBytes = (4 * Math.ceil(imageSize / 3) * 0.5624896334383812) / 1024; + const sizeInBytes = + (4 * Math.ceil(imageSize / 3) * 0.5624896334383812) / 1024; if (sizeInBytes > 50) { - errors.push('Image size should not exceed 50KB'); + errors.push("Image size should not exceed 50KB"); result = false; } - const imageType = picParts[0].split('/')[1]; - if (imageType !== 'jpeg;' && imageType !== 'png;') { - errors.push('Image type shoud be either jpeg or png.'); + const imageType = picParts[0].split("/")[1]; + if (imageType !== "jpeg;" && imageType !== "png;") { + errors.push("Image type shoud be either jpeg or png."); result = false; } @@ -89,10 +90,11 @@ const userHelper = function () { totalInfringements, timeRemaining ) { - let final_paragraph = ''; + let final_paragraph = ""; if (timeRemaining == undefined) { - final_paragraph = '

Life happens and we understand that. That’s why we allow 5 of them before taking action. This action usually includes removal from our team though, so please let your direct supervisor know what happened and do your best to avoid future blue squares if you are getting close to 5 and wish to avoid termination. Each blue square drops off after a year.

'; + final_paragraph = + "

Life happens and we understand that. That’s why we allow 5 of them before taking action. This action usually includes removal from our team though, so please let your direct supervisor know what happened and do your best to avoid future blue squares if you are getting close to 5 and wish to avoid termination. Each blue square drops off after a year.

"; } else { final_paragraph = `

Life happens and we understand that. Please make up the missed hours this following week though to avoid getting another blue square. So you know what’s needed, the missing/incomplete hours (${timeRemaining} hours) have been added to your current week and this new weekly total can be seen at the top of your dashboard.

Reminder also that each blue square is removed from your profile 1 year after it was issued.

`; @@ -103,8 +105,8 @@ const userHelper = function () {

Date Assigned: ${infringement.date}

Description: ${infringement.description}

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

+ .localeData() + .ordinal(totalInfringements)}
blue square of 5.

${final_paragraph}

Thank you,
One Community

`; @@ -123,12 +125,10 @@ const userHelper = function () { * @return {void} */ const emailWeeklySummariesForAllUsers = async (weekIndex = 1) => { - const currentFormattedDate = moment() - .tz('America/Los_Angeles') - .format(); + const currentFormattedDate = moment().tz("America/Los_Angeles").format(); logger.logInfo( - `Job for emailing all users' weekly summaries starting at ${currentFormattedDate}`, + `Job for emailing all users' weekly summaries starting at ${currentFormattedDate}` ); const emails = []; @@ -136,13 +136,19 @@ const userHelper = function () { try { const results = await reportHelper.weeklySummaries(weekIndex, weekIndex); - let emailBody = '

Weekly Summaries for all active users:

'; + let emailBody = "

Weekly Summaries for all active users:

"; - const weeklySummaryNotProvidedMessage = '
Weekly Summary: Not provided!
'; + const weeklySummaryNotProvidedMessage = + '
Weekly Summary: Not provided!
'; - const weeklySummaryNotRequiredMessage = '
Weekly Summary: Not required for this user
'; + const weeklySummaryNotRequiredMessage = + '
Weekly Summary: Not required for this user
'; - results.sort((a, b) => `${a.firstName} ${a.lastName}`.localeCompare(`${b.firstName} ${b.lastname}`)); + results.sort((a, b) => + `${a.firstName} ${a.lastName}`.localeCompare( + `${b.firstName} ${b.lastname}` + ) + ); for (let i = 0; i < results.length; i += 1) { const result = results[i]; @@ -166,19 +172,21 @@ const userHelper = function () { // hence totalSeconds[0] should be used const hoursLogged = result.totalSeconds[0] / 3600 || 0; - const mediaUrlLink = mediaUrl ? `${mediaUrl}` : 'Not provided!'; + const mediaUrlLink = mediaUrl + ? `${mediaUrl}` + : "Not provided!"; let weeklySummaryMessage = weeklySummaryNotProvidedMessage; const colorStyle = (() => { switch (weeklySummaryOption) { - case 'Team': + case "Team": return 'style="color: magenta;"'; - case 'Not Required': + case "Not Required": return 'style="color: green"'; - case 'Required': - return ''; + case "Required": + return ""; default: - return result.weeklySummaryNotReq ? 'style="color: green"' : ''; + return result.weeklySummaryNotReq ? 'style="color: green"' : ""; } })(); // weeklySummaries array should only have one item if any, hence weeklySummaries[0] needs be used to access it. @@ -189,16 +197,16 @@ const userHelper = function () {
Weekly Summary (for the week ending on ${moment(dueDate) - .tz('America/Los_Angeles') - .format('YYYY-MMM-DD')}): + .tz("America/Los_Angeles") + .format("YYYY-MMM-DD")}):
${summary}
`; } else if ( - weeklySummaryOption === 'Not Required' - || (!weeklySummaryOption && result.weeklySummaryNotReq) + weeklySummaryOption === "Not Required" || + (!weeklySummaryOption && result.weeklySummaryNotReq) ) { weeklySummaryMessage = weeklySummaryNotRequiredMessage; } @@ -210,21 +218,26 @@ const userHelper = function () { Name: ${firstName} ${lastName}

- Media URL: ${mediaUrlLink || 'Not provided!'} + Media URL: ${ + mediaUrlLink || 'Not provided!' + }

- ${weeklySummariesCount === 8 - ? `

Total Valid Weekly Summaries: ${weeklySummariesCount}

` - : `

Total Valid Weekly Summaries: ${weeklySummariesCount - || 'No valid submissions yet!'}

` + ${ + weeklySummariesCount === 8 + ? `

Total Valid Weekly Summaries: ${weeklySummariesCount}

` + : `

Total Valid Weekly Summaries: ${ + weeklySummariesCount || "No valid submissions yet!" + }

` } - ${hoursLogged >= weeklycommittedHours - - ? `

Hours logged: ${hoursLogged.toFixed(2)} / ${weeklycommittedHours}

` - - : `

Hours logged: ${hoursLogged.toFixed( - 2, - )} / ${weeklycommittedHours}

` + ${ + hoursLogged >= weeklycommittedHours + ? `

Hours logged: ${hoursLogged.toFixed( + 2 + )} / ${weeklycommittedHours}

` + : `

Hours logged: ${hoursLogged.toFixed( + 2 + )} / ${weeklycommittedHours}

` } ${weeklySummaryMessage} `; @@ -233,8 +246,10 @@ const userHelper = function () { // Necessary because our version of node is outdated // and doesn't have String.prototype.replaceAll let emailString = [...new Set(emails)].toString(); - while (emailString.includes(',')) emailString = emailString.replace(',', '\n'); - while (emailString.includes('\n')) emailString = emailString.replace('\n', ', '); + while (emailString.includes(",")) + emailString = emailString.replace(",", "\n"); + while (emailString.includes("\n")) + emailString = emailString.replace("\n", ", "); emailBody += `\n
@@ -246,10 +261,12 @@ const userHelper = function () { `; emailSender( - 'onecommunityglobal@gmail.com, sangam.pravah@gmail.com, onecommunityhospitality@gmail.com', - 'Weekly Summaries for all active users...', + "onecommunityglobal@gmail.com, sangam.pravah@gmail.com, onecommunityhospitality@gmail.com", + "Weekly Summaries for all active users...", emailBody, null, + null, + emailString ); } catch (err) { logger.logException(err); @@ -270,10 +287,8 @@ const userHelper = function () { weeklySummaries: { $each: [ { - dueDate: moment() - .tz('America/Los_Angeles') - .endOf('week'), - summary: '', + dueDate: moment().tz("America/Los_Angeles").endOf("week"), + summary: "", }, ], $position: 0, @@ -281,7 +296,7 @@ const userHelper = function () { }, }, }) - .catch(error => logger.logException(error)); + .catch((error) => logger.logException(error)); }; /** @@ -292,39 +307,34 @@ const userHelper = function () { */ const assignBlueSquareForTimeNotMet = async () => { try { - const currentFormattedDate = moment() - .tz('America/Los_Angeles') - .format(); + const currentFormattedDate = moment().tz("America/Los_Angeles").format(); const currentUTCDate = moment - .tz('America/Los_Angeles') - .startOf('day') + .tz("America/Los_Angeles") + .startOf("day") .toISOString(); logger.logInfo( - - `Job for assigning blue square for commitment not met starting at ${currentFormattedDate}`, - + `Job for assigning blue square for commitment not met starting at ${currentFormattedDate}` ); const pdtStartOfLastWeek = moment() - .tz('America/Los_Angeles') - .startOf('week') - .subtract(1, 'week'); + .tz("America/Los_Angeles") + .startOf("week") + .subtract(1, "week"); const pdtEndOfLastWeek = moment() - .tz('America/Los_Angeles') - .endOf('week') - .subtract(1, 'week'); - + .tz("America/Los_Angeles") + .endOf("week") + .subtract(1, "week"); const users = await userProfile.find( { isActive: true }, - '_id weeklycommittedHours weeklySummaries missedHours', + "_id weeklycommittedHours weeklySummaries missedHours" ); - // this part is supposed to be a for, so it'll be slower when sending emails, so the emails will not be - // targeted as spam - // There's no need to put Promise.all here + //this part is supposed to be a for, so it'll be slower when sending emails, so the emails will not be + //targeted as spam + //There's no need to put Promise.all here for (let i = 0; i < users.length; i += 1) { const user = users[i]; @@ -339,8 +349,10 @@ const userHelper = function () { let hasWeeklySummary = false; - - if (Array.isArray(user.weeklySummaries) && user.weeklySummaries.length) { + if ( + Array.isArray(user.weeklySummaries) && + user.weeklySummaries.length + ) { const { summary } = user.weeklySummaries[0]; if (summary) { hasWeeklySummary = true; @@ -353,19 +365,19 @@ const userHelper = function () { const results = await dashboardHelper.laborthisweek( personId, pdtStartOfLastWeek, - pdtEndOfLastWeek, + pdtEndOfLastWeek ); const { timeSpent_hrs: timeSpent } = results[0]; - const weeklycommittedHours = user.weeklycommittedHours + (user.missedHours ?? 0); + const weeklycommittedHours = + user.weeklycommittedHours + (user.missedHours ?? 0); const timeNotMet = timeSpent < weeklycommittedHours; let description; const timeRemaining = weeklycommittedHours - timeSpent; - const updateResult = await userProfile.findByIdAndUpdate( personId, { @@ -382,25 +394,23 @@ const userHelper = function () { lastWeekTangibleHrs: timeSpent || 0, }, }, - { new: true }, + { new: true } ); if ( - - updateResult?.weeklySummaryOption === 'Not Required' - || updateResult?.weeklySummaryNotReq - + updateResult?.weeklySummaryOption === "Not Required" || + updateResult?.weeklySummaryNotReq ) { hasWeeklySummary = true; } - const cutOffDate = moment().subtract(1, 'year'); + const cutOffDate = moment().subtract(1, "year"); const oldInfringements = []; for (let k = 0; k < updateResult?.infringements.length; k += 1) { if ( - updateResult?.infringements - && moment(updateResult?.infringements[k].date).diff(cutOffDate) >= 0 + updateResult?.infringements && + moment(updateResult?.infringements[k].date).diff(cutOffDate) >= 0 ) { oldInfringements.push(updateResult.infringements[k]); } else { @@ -416,31 +426,35 @@ const userHelper = function () { oldInfringements: { $each: oldInfringements, $slice: -10 }, }, }, - { new: true }, + { new: true } ); } if (timeNotMet || !hasWeeklySummary) { if (foundReason) { description = foundReason.reason; - } else if (timeNotMet && !hasWeeklySummary) { - description = `System auto-assigned infringement for two reasons: not meeting weekly volunteer time commitment as well as not submitting a weekly summary. For the hours portion, you logged ${timeSpent.toFixed(2)} hours against committed effort of ${weeklycommittedHours} hours in the week starting ${pdtStartOfLastWeek.format( - 'dddd YYYY-MM-DD', - )} and ending ${pdtEndOfLastWeek.format('dddd YYYY-MM-DD')}.`; + } else { + if (timeNotMet && !hasWeeklySummary) { + description = `System auto-assigned infringement for two reasons: not meeting weekly volunteer time commitment as well as not submitting a weekly summary. For the hours portion, you logged ${timeSpent.toFixed( + 2 + )} hours against committed effort of ${weeklycommittedHours} hours in the week starting ${pdtStartOfLastWeek.format( + "dddd YYYY-MM-DD" + )} and ending ${pdtEndOfLastWeek.format("dddd YYYY-MM-DD")}.`; } else if (timeNotMet) { - description = `System auto-assigned infringement for not meeting weekly volunteer time commitment. You logged ${timeSpent.toFixed(2)} hours against committed effort of ${weeklycommittedHours} hours in the week starting ${pdtStartOfLastWeek.format( - 'dddd YYYY-MM-DD', - )} and ending ${pdtEndOfLastWeek.format('dddd YYYY-MM-DD')}.`; + description = `System auto-assigned infringement for not meeting weekly volunteer time commitment. You logged ${timeSpent.toFixed( + 2 + )} hours against committed effort of ${weeklycommittedHours} hours in the week starting ${pdtStartOfLastWeek.format( + "dddd YYYY-MM-DD" + )} and ending ${pdtEndOfLastWeek.format("dddd YYYY-MM-DD")}.`; } else { description = `System auto-assigned infringement for not submitting a weekly summary for the week starting ${pdtStartOfLastWeek.format( - 'dddd YYYY-MM-DD', - )} and ending ${pdtEndOfLastWeek.format('dddd YYYY-MM-DD')}.`; + "dddd YYYY-MM-DD" + )} and ending ${pdtEndOfLastWeek.format("dddd YYYY-MM-DD")}.`; } + } const infringement = { - date: moment() - .utc() - .format('YYYY-MM-DD'), + date: moment().utc().format("YYYY-MM-DD"), description, }; @@ -451,45 +465,47 @@ const userHelper = function () { infringements: infringement, }, }, - { new: true }, + { new: true } ); - let emailBody = ''; - if (person.role == 'Core Team' && timeRemaining > 0) { + let emailBody = ""; + if (person.role == "Core Team" && timeRemaining > 0) { emailBody = getInfringementEmailBody( status.firstName, status.lastName, infringement, status.infringements.length, - timeRemaining, + timeRemaining ); } else { emailBody = getInfringementEmailBody( status.firstName, status.lastName, infringement, - status.infringements.length, + status.infringements.length ); } emailSender( status.email, - 'New Infringement Assigned', + "New Infringement Assigned", emailBody, null, - 'onecommunityglobal@gmail.com', + "onecommunityglobal@gmail.com", + null, + status.email ); const categories = await dashboardHelper.laborThisWeekByCategory( personId, pdtStartOfLastWeek, - pdtEndOfLastWeek, + pdtEndOfLastWeek ); if (Array.isArray(categories) && categories.length > 0) { await userProfile.findOneAndUpdate( { _id: personId, categoryTangibleHrs: { $exists: false } }, - { $set: { categoryTangibleHrs: [] } }, + { $set: { categoryTangibleHrs: [] } } ); } else { continue; @@ -499,20 +515,20 @@ const userHelper = function () { const elem = categories[j]; if (elem._id == null) { - elem._id = 'Other'; + elem._id = "Other"; } const updateResult2 = await userProfile.findOneAndUpdate( - { _id: personId, 'categoryTangibleHrs.category': elem._id }, - { $inc: { 'categoryTangibleHrs.$.hrs': elem.timeSpent_hrs } }, - { new: true }, + { _id: personId, "categoryTangibleHrs.category": elem._id }, + { $inc: { "categoryTangibleHrs.$.hrs": elem.timeSpent_hrs } }, + { new: true } ); if (!updateResult2) { await userProfile.findOneAndUpdate( { _id: personId, - 'categoryTangibleHrs.category': { $ne: elem._id }, + "categoryTangibleHrs.category": { $ne: elem._id }, }, { $addToSet: { @@ -521,7 +537,7 @@ const userHelper = function () { hrs: elem.timeSpent_hrs, }, }, - }, + } ); } } @@ -533,11 +549,14 @@ const userHelper = function () { // processWeeklySummaries for nonActive users try { - const inactiveUsers = await userProfile.find({ isActive: false }, '_id'); + const inactiveUsers = await userProfile.find({ isActive: false }, "_id"); for (let i = 0; i < inactiveUsers.length; i += 1) { const user = inactiveUsers[i]; - await processWeeklySummariesByUserId(mongoose.Types.ObjectId(user._id), false); + await processWeeklySummariesByUserId( + mongoose.Types.ObjectId(user._id), + false + ); } } catch (err) { logger.logException(err); @@ -546,52 +565,50 @@ const userHelper = function () { const applyMissedHourForCoreTeam = async () => { try { - const currentDate = moment() - .tz('America/Los_Angeles') - .format(); + const currentDate = moment().tz("America/Los_Angeles").format(); logger.logInfo( - `Job for applying missed hours for Core Team members starting at ${currentDate}`, + `Job for applying missed hours for Core Team members starting at ${currentDate}` ); const startOfLastWeek = moment() - .tz('America/Los_Angeles') - .startOf('week') - .subtract(1, 'week') - .format('YYYY-MM-DD'); + .tz("America/Los_Angeles") + .startOf("week") + .subtract(1, "week") + .format("YYYY-MM-DD"); const endOfLastWeek = moment() - .tz('America/Los_Angeles') - .endOf('week') - .subtract(1, 'week') - .format('YYYY-MM-DD'); + .tz("America/Los_Angeles") + .endOf("week") + .subtract(1, "week") + .format("YYYY-MM-DD"); const missedHours = await userProfile.aggregate([ { $match: { - role: 'Core Team', + role: "Core Team", isActive: true, }, }, { $lookup: { - from: 'timeEntries', - localField: '_id', - foreignField: 'personId', + from: "timeEntries", + localField: "_id", + foreignField: "personId", pipeline: [ { $match: { $expr: { $and: [ - { $eq: ['$isTangible', true] }, - { $gte: ['$dateOfWork', startOfLastWeek] }, - { $lte: ['$dateOfWork', endOfLastWeek] }, + { $eq: ["$isTangible", true] }, + { $gte: ["$dateOfWork", startOfLastWeek] }, + { $lte: ["$dateOfWork", endOfLastWeek] }, ], }, }, }, ], - as: 'timeEntries', + as: "timeEntries", }, }, { @@ -602,17 +619,18 @@ const userHelper = function () { { $subtract: [ { - - $sum: [{ $ifNull: ['$missedHours', 0] }, '$weeklycommittedHours'], - + $sum: [ + { $ifNull: ["$missedHours", 0] }, + "$weeklycommittedHours", + ], }, { $divide: [ { $sum: { $map: { - input: '$timeEntries', - in: '$$this.totalSeconds', + input: "$timeEntries", + in: "$$this.totalSeconds", }, }, }, @@ -646,17 +664,13 @@ const userHelper = function () { }; const deleteBlueSquareAfterYear = async () => { - const currentFormattedDate = moment() - .tz('America/Los_Angeles') - .format(); + const currentFormattedDate = moment().tz("America/Los_Angeles").format(); logger.logInfo( - `Job for deleting blue squares older than 1 year starting at ${currentFormattedDate}`, + `Job for deleting blue squares older than 1 year starting at ${currentFormattedDate}` ); - const cutOffDate = moment() - .subtract(1, 'year') - .format('YYYY-MM-DD'); + const cutOffDate = moment().subtract(1, "year").format("YYYY-MM-DD"); try { const results = await userProfile.updateMany( @@ -669,7 +683,7 @@ const userHelper = function () { }, }, }, - }, + } ); logger.logInfo(results); @@ -679,18 +693,16 @@ const userHelper = function () { }; const reActivateUser = async () => { - const currentFormattedDate = moment() - .tz('America/Los_Angeles') - .format(); + const currentFormattedDate = moment().tz("America/Los_Angeles").format(); logger.logInfo( - `Job for activating users based on scheduled re-activation date starting at ${currentFormattedDate}`, + `Job for activating users based on scheduled re-activation date starting at ${currentFormattedDate}` ); try { const users = await userProfile.find( { isActive: false, reactivationDate: { $exists: true } }, - '_id isActive reactivationDate', + "_id isActive reactivationDate" ); for (let i = 0; i < users.length; i += 1) { const user = users[i]; @@ -705,18 +717,22 @@ const userHelper = function () { endDate: user.endDate, }, }, - { new: true }, + { new: true } ); logger.logInfo( `User with id: ${user._id} was re-acticated at ${moment() - .tz('America/Los_Angeles') - .format()}.`, + .tz("America/Los_Angeles") + .format()}.` ); const id = user._id; const person = await userProfile.findById(id); - const endDate = moment(person.endDate).format('YYYY-MM-DD'); - logger.logInfo(`User with id: ${user._id} was re-acticated at ${moment().format()}.`); + const endDate = moment(person.endDate).format("YYYY-MM-DD"); + logger.logInfo( + `User with id: ${ + user._id + } was re-acticated at ${moment().format()}.` + ); const subject = `IMPORTANT:${person.firstName} ${person.lastName} has been RE-activated in the Highest Good Network`; @@ -730,8 +746,14 @@ const userHelper = function () {

The HGN A.I. (and One Community)

`; - - emailSender('onecommunityglobal@gmail.com', subject, emailBody, null, null); + emailSender( + "onecommunityglobal@gmail.com", + subject, + emailBody, + null, + null, + person.email + ); } } } catch (err) { @@ -739,59 +761,74 @@ const userHelper = function () { } }; - - const notifyInfringements = function (original, current, firstName, lastName, emailAddress) { + const notifyInfringements = function ( + original, + current, + firstName, + lastName, + emailAddress + ) { if (!current) return; const newOriginal = original.toObject(); const newCurrent = current.toObject(); const totalInfringements = newCurrent.length; let newInfringements = []; - newInfringements = _.differenceWith(newCurrent, newOriginal, (arrVal, othVal) => arrVal._id.equals(othVal._id)); + newInfringements = _.differenceWith( + newCurrent, + newOriginal, + (arrVal, othVal) => arrVal._id.equals(othVal._id) + ); newInfringements.forEach((element) => { emailSender( emailAddress, - 'New Infringement Assigned', - getInfringementEmailBody(firstName, lastName, element, totalInfringements), + "New Infringement Assigned", + getInfringementEmailBody( + firstName, + lastName, + element, + totalInfringements + ), null, - 'onecommunityglobal@gmail.com', + "onecommunityglobal@gmail.com", + emailAddress ); }); }; const replaceBadge = async function (personId, oldBadgeId, newBadgeId) { userProfile.updateOne( - { _id: personId, 'badgeCollection.badge': oldBadgeId }, + { _id: personId, "badgeCollection.badge": oldBadgeId }, { $set: { - 'badgeCollection.$.badge': newBadgeId, - 'badgeCollection.$.lastModified': Date.now().toString(), - 'badgeCollection.$.count': 1, + "badgeCollection.$.badge": newBadgeId, + "badgeCollection.$.lastModified": Date.now().toString(), + "badgeCollection.$.count": 1, }, }, (err) => { if (err) { throw new Error(err); } - }, + } ); }; const increaseBadgeCount = async function (personId, badgeId) { - console.log('Increase Badge Count', personId, badgeId); + console.log("Increase Badge Count", personId, badgeId); userProfile.updateOne( - { _id: personId, 'badgeCollection.badge': badgeId }, + { _id: personId, "badgeCollection.badge": badgeId }, { - $inc: { 'badgeCollection.$.count': 1 }, - $set: { 'badgeCollection.$.lastModified': Date.now().toString() }, - $push: { 'badgeCollection.$.earnedDate': earnedDateBadge() }, + $inc: { "badgeCollection.$.count": 1 }, + $set: { "badgeCollection.$.lastModified": Date.now().toString() }, + $push: { "badgeCollection.$.earnedDate": earnedDateBadge() }, }, (err) => { if (err) { console.log(err); } - }, + } ); }; @@ -799,15 +836,19 @@ const userHelper = function () { personId, badgeId, count = 1, - featured = false, + featured = false ) { - console.log('Adding Badge'); + console.log("Adding Badge"); userProfile.findByIdAndUpdate( personId, { $push: { badgeCollection: { - badge: badgeId, count, earnedDate: [earnedDateBadge()], featured, lastModified: Date.now().toString(), + badge: badgeId, + count, + earnedDate: [earnedDateBadge()], + featured, + lastModified: Date.now().toString(), }, }, }, @@ -815,7 +856,7 @@ const userHelper = function () { if (err) { throw new Error(err); } - }, + } ); }; @@ -831,7 +872,7 @@ const userHelper = function () { if (err) { throw new Error(err); } - }, + } ); }; @@ -840,25 +881,31 @@ const userHelper = function () { removeDupBadge(personId, badgeId); } else if (count) { userProfile.updateOne( - { _id: personId, 'badgeCollection.badge': badgeId }, + { _id: personId, "badgeCollection.badge": badgeId }, { $set: { - 'badgeCollection.$.count': count, - 'badgeCollection.$.lastModified': Date.now().toString(), + "badgeCollection.$.count": count, + "badgeCollection.$.lastModified": Date.now().toString(), }, }, (err) => { if (err) { throw new Error(err); } - }, + } ); } }; // remove the last badge you earned on this streak(not including 1) - const removePrevHrBadge = async function (personId, user, badgeCollection, hrs, weeks) { + const removePrevHrBadge = async function ( + personId, + user, + badgeCollection, + hrs, + weeks + ) { // Check each Streak Greater than One to check if it works if (weeks < 3) { return; @@ -868,7 +915,7 @@ const userHelper = function () { .aggregate([ { $match: { - type: 'X Hours for X Week Streak', + type: "X Hours for X Week Streak", weeks: { $gt: 1, $lt: weeks }, totalHrs: hrs, }, @@ -876,9 +923,9 @@ const userHelper = function () { { $sort: { weeks: -1, totalHrs: -1 } }, { $group: { - _id: '$weeks', + _id: "$weeks", badges: { - $push: { _id: '$_id', hrs: '$totalHrs', weeks: '$weeks' }, + $push: { _id: "$_id", hrs: "$totalHrs", weeks: "$weeks" }, }, }, }, @@ -888,17 +935,16 @@ const userHelper = function () { streak.badges.every((bdge) => { for (let i = 0; i < badgeCollection.length; i += 1) { if ( - - badgeCollection[i].badge?.type === 'X Hours for X Week Streak' - && badgeCollection[i].badge?.weeks === bdge.weeks - && bdge.hrs === hrs - && !removed - + badgeCollection[i].badge?.type === + "X Hours for X Week Streak" && + badgeCollection[i].badge?.weeks === bdge.weeks && + bdge.hrs === hrs && + !removed ) { changeBadgeCount( personId, badgeCollection[i].badge._id, - badgeCollection[i].badge.count - 1, + badgeCollection[i].badge.count - 1 ); removed = true; return false; @@ -912,14 +958,24 @@ const userHelper = function () { // 'No Infringement Streak', - const checkNoInfringementStreak = async function (personId, user, badgeCollection) { + const checkNoInfringementStreak = async function ( + personId, + user, + badgeCollection + ) { let badgeOfType; for (let i = 0; i < badgeCollection.length; i += 1) { - if (badgeCollection[i].badge?.type === 'No Infringement Streak') { - if (badgeOfType && badgeOfType.months <= badgeCollection[i].badge.months) { + if (badgeCollection[i].badge?.type === "No Infringement Streak") { + if ( + badgeOfType && + badgeOfType.months <= badgeCollection[i].badge.months + ) { removeDupBadge(personId, badgeOfType._id); badgeOfType = badgeCollection[i].badge; - } else if (badgeOfType && badgeOfType.months > badgeCollection[i].badge.months) { + } else if ( + badgeOfType && + badgeOfType.months > badgeCollection[i].badge.months + ) { removeDupBadge(personId, badgeCollection[i].badge._id); } else if (!badgeOfType) { badgeOfType = badgeCollection[i].badge; @@ -927,7 +983,7 @@ const userHelper = function () { } } await badge - .find({ type: 'No Infringement Streak' }) + .find({ type: "No Infringement Streak" }) .sort({ months: -1 }) .then((results) => { if (!Array.isArray(results) || !results.length) { @@ -938,17 +994,20 @@ const userHelper = function () { // Cannot account for time paused yet if (elem.months <= 12) { - if (moment().diff(moment(user.createdDate), 'months', true) >= elem.months) { + if ( + moment().diff(moment(user.createdDate), "months", true) >= + elem.months + ) { if ( - user.infringements.length === 0 - || Math.abs( + user.infringements.length === 0 || + Math.abs( moment().diff( - - moment(user.infringements[user.infringements?.length - 1].date), - 'months', - true, - ), - + moment( + user.infringements[user.infringements?.length - 1].date + ), + "months", + true + ) ) >= elem.months ) { if (badgeOfType) { @@ -956,7 +1015,7 @@ const userHelper = function () { replaceBadge( personId, mongoose.Types.ObjectId(badgeOfType._id), - mongoose.Types.ObjectId(elem._id), + mongoose.Types.ObjectId(elem._id) ); } return false; @@ -966,26 +1025,30 @@ const userHelper = function () { } } } else if (user?.infringements?.length === 0) { - if (moment().diff(moment(user.createdDate), 'months', true) >= elem.months) { + if ( + moment().diff(moment(user.createdDate), "months", true) >= + elem.months + ) { if ( - user.oldInfringements.length === 0 - || Math.abs( + user.oldInfringements.length === 0 || + Math.abs( moment().diff( - - moment(user.oldInfringements[user.oldInfringements?.length - 1].date), - 'months', - true, - ), - ) - >= elem.months - 12 - + moment( + user.oldInfringements[user.oldInfringements?.length - 1] + .date + ), + "months", + true + ) + ) >= + elem.months - 12 ) { if (badgeOfType) { if (badgeOfType._id.toString() !== elem._id.toString()) { replaceBadge( personId, mongoose.Types.ObjectId(badgeOfType._id), - mongoose.Types.ObjectId(elem._id), + mongoose.Types.ObjectId(elem._id) ); } return false; @@ -1004,13 +1067,13 @@ const userHelper = function () { const checkMinHoursMultiple = async function ( personId, user, - badgeCollection, + badgeCollection ) { const badgesOfType = badgeCollection - .map(obj => obj.badge) - .filter(badge => badge.type === 'Minimum Hours Multiple'); + .map((obj) => obj.badge) + .filter((badge) => badge.type === "Minimum Hours Multiple"); await badge - .find({ type: 'Minimum Hours Multiple' }) + .find({ type: "Minimum Hours Multiple" }) .sort({ multiple: -1 }) .then((results) => { if (!Array.isArray(results) || !results.length) { @@ -1021,17 +1084,17 @@ const userHelper = function () { const elem = results[i]; // making variable elem accessible for below code if ( - user.lastWeekTangibleHrs / user.weeklycommittedHours - >= elem.multiple + user.lastWeekTangibleHrs / user.weeklycommittedHours >= + elem.multiple ) { const theBadge = badgesOfType.find( - badge => badge._id.toString() === elem._id.toString(), + (badge) => badge._id.toString() === elem._id.toString() ); return theBadge ? increaseBadgeCount( - personId, - mongoose.Types.ObjectId(theBadge._id), - ) + personId, + mongoose.Types.ObjectId(theBadge._id) + ) : addBadge(personId, mongoose.Types.ObjectId(elem._id)); } } @@ -1042,26 +1105,30 @@ const userHelper = function () { const checkPersonalMax = async function (personId, user, badgeCollection) { let badgeOfType; for (let i = 0; i < badgeCollection.length; i += 1) { - if (badgeCollection[i].badge?.type === 'Personal Max') { + if (badgeCollection[i].badge?.type === "Personal Max") { if (badgeOfType) { removeDupBadge(personId, badgeOfType._id); } } } - await badge.findOne({ type: 'Personal Max' }).then((results) => { + await badge.findOne({ type: "Personal Max" }).then((results) => { if ( - user.lastWeekTangibleHrs - && user.lastWeekTangibleHrs >= 1 - && user.lastWeekTangibleHrs === user.personalBestMaxHrs + user.lastWeekTangibleHrs && + user.lastWeekTangibleHrs >= 1 && + user.lastWeekTangibleHrs === user.personalBestMaxHrs ) { if (badgeOfType) { changeBadgeCount( personId, mongoose.Types.ObjectId(badgeOfType._id), - user.personalBestMaxHrs, + user.personalBestMaxHrs ); } else { - addBadge(personId, mongoose.Types.ObjectId(results._id), user.personalBestMaxHrs); + addBadge( + personId, + mongoose.Types.ObjectId(results._id), + user.personalBestMaxHrs + ); } } }); @@ -1071,17 +1138,17 @@ const userHelper = function () { const checkMostHrsWeek = async function (personId, user, badgeCollection) { if ( - user.weeklycommittedHours > 0 - && user.lastWeekTangibleHrs > user.weeklycommittedHours + user.weeklycommittedHours > 0 && + user.lastWeekTangibleHrs > user.weeklycommittedHours ) { const badgeOfType = badgeCollection - .filter(object => object.badge.type === 'Most Hrs in Week') - .map(object => object.badge); - await badge.findOne({ type: 'Most Hrs in Week' }).then((results) => { + .filter((object) => object.badge.type === "Most Hrs in Week") + .map((object) => object.badge); + await badge.findOne({ type: "Most Hrs in Week" }).then((results) => { userProfile .aggregate([ { $match: { isActive: true } }, - { $group: { _id: 1, maxHours: { $max: '$lastWeekTangibleHrs' } } }, + { $group: { _id: 1, maxHours: { $max: "$lastWeekTangibleHrs" } } }, ]) .then((userResults) => { if (badgeOfType.length > 1) { @@ -1089,13 +1156,13 @@ const userHelper = function () { } if ( - user.lastWeekTangibleHrs - && user.lastWeekTangibleHrs >= userResults[0].maxHours + user.lastWeekTangibleHrs && + user.lastWeekTangibleHrs >= userResults[0].maxHours ) { if (badgeOfType.length) { increaseBadgeCount( personId, - mongoose.Types.ObjectId(badgeOfType[0]._id), + mongoose.Types.ObjectId(badgeOfType[0]._id) ); } else { addBadge(personId, mongoose.Types.ObjectId(results._id)); @@ -1111,12 +1178,12 @@ const userHelper = function () { // Handle Increasing the 1 week streak badges const badgesOfType = []; for (let i = 0; i < badgeCollection.length; i += 1) { - if (badgeCollection[i].badge?.type === 'X Hours for X Week Streak') { + if (badgeCollection[i].badge?.type === "X Hours for X Week Streak") { badgesOfType.push(badgeCollection[i].badge); } } await badge - .find({ type: 'X Hours for X Week Streak', weeks: 1 }) + .find({ type: "X Hours for X Week Streak", weeks: 1 }) .sort({ totalHrs: -1 }) .then((results) => { results.every((elem) => { @@ -1141,13 +1208,13 @@ const userHelper = function () { // Check each Streak Greater than One to check if it works await badge .aggregate([ - { $match: { type: 'X Hours for X Week Streak', weeks: { $gt: 1 } } }, + { $match: { type: "X Hours for X Week Streak", weeks: { $gt: 1 } } }, { $sort: { weeks: -1, totalHrs: -1 } }, { $group: { - _id: '$weeks', + _id: "$weeks", badges: { - $push: { _id: '$_id', hrs: '$totalHrs', weeks: '$weeks' }, + $push: { _id: "$_id", hrs: "$totalHrs", weeks: "$weeks" }, }, }, }, @@ -1159,16 +1226,19 @@ const userHelper = function () { let badgeOfType; for (let i = 0; i < badgeCollection.length; i += 1) { if ( - - badgeCollection[i].badge?.type === 'X Hours for X Week Streak' - && badgeCollection[i].badge?.weeks === bdge.weeks + badgeCollection[i].badge?.type === + "X Hours for X Week Streak" && + badgeCollection[i].badge?.weeks === bdge.weeks ) { - if (badgeOfType && badgeOfType.totalHrs <= badgeCollection[i].badge.totalHrs) { + if ( + badgeOfType && + badgeOfType.totalHrs <= badgeCollection[i].badge.totalHrs + ) { removeDupBadge(personId, badgeOfType._id); badgeOfType = badgeCollection[i].badge; } else if ( - badgeOfType - && badgeOfType.totalHrs > badgeCollection[i].badge.totalHrs + badgeOfType && + badgeOfType.totalHrs > badgeCollection[i].badge.totalHrs ) { removeDupBadge(personId, badgeCollection[i].badge._id); } else if (!badgeOfType) { @@ -1193,10 +1263,16 @@ const userHelper = function () { replaceBadge( personId, mongoose.Types.ObjectId(badgeOfType._id), - mongoose.Types.ObjectId(bdge._id), + mongoose.Types.ObjectId(bdge._id) ); - removePrevHrBadge(personId, user, badgeCollection, bdge.hrs, bdge.weeks); + removePrevHrBadge( + personId, + user, + badgeCollection, + bdge.hrs, + bdge.weeks + ); } else if (!badgeOfType) { addBadge(personId, mongoose.Types.ObjectId(bdge._id)); removePrevHrBadge( @@ -1204,11 +1280,20 @@ const userHelper = function () { user, badgeCollection, bdge.hrs, - bdge.weeks, + bdge.weeks ); } else if (badgeOfType && badgeOfType.totalHrs === bdge.hrs) { - increaseBadgeCount(personId, mongoose.Types.ObjectId(badgeOfType._id)); - removePrevHrBadge(personId, user, badgeCollection, bdge.hrs, bdge.weeks); + increaseBadgeCount( + personId, + mongoose.Types.ObjectId(badgeOfType._id) + ); + removePrevHrBadge( + personId, + user, + badgeCollection, + bdge.hrs, + bdge.weeks + ); } return false; } @@ -1221,10 +1306,19 @@ const userHelper = function () { // 'Lead a team of X+' - - const checkLeadTeamOfXplus = async function (personId, user, badgeCollection) { - const leaderRoles = ['Mentor', 'Manager', 'Administrator', 'Owner', 'Core Team']; - const approvedRoles = ['Mentor', 'Manager']; + const checkLeadTeamOfXplus = async function ( + personId, + user, + badgeCollection + ) { + const leaderRoles = [ + "Mentor", + "Manager", + "Administrator", + "Owner", + "Core Team", + ]; + const approvedRoles = ["Mentor", "Manager"]; if (!approvedRoles.includes(user.role)) return; let teamMembers; @@ -1249,11 +1343,17 @@ const userHelper = function () { }); let badgeOfType; for (let i = 0; i < badgeCollection.length; i += 1) { - if (badgeCollection[i].badge?.type === 'Lead a team of X+') { - if (badgeOfType && badgeOfType.people <= badgeCollection[i].badge.people) { + if (badgeCollection[i].badge?.type === "Lead a team of X+") { + if ( + badgeOfType && + badgeOfType.people <= badgeCollection[i].badge.people + ) { removeDupBadge(personId, badgeOfType._id); badgeOfType = badgeCollection[i].badge; - } else if (badgeOfType && badgeOfType.people > badgeCollection[i].badge.people) { + } else if ( + badgeOfType && + badgeOfType.people > badgeCollection[i].badge.people + ) { removeDupBadge(personId, badgeCollection[i].badge._id); } else if (!badgeOfType) { badgeOfType = badgeCollection[i].badge; @@ -1261,7 +1361,7 @@ const userHelper = function () { } } await badge - .find({ type: 'Lead a team of X+' }) + .find({ type: "Lead a team of X+" }) .sort({ people: -1 }) .then((results) => { if (!Array.isArray(results) || !results.length) { @@ -1271,16 +1371,14 @@ const userHelper = function () { if (teamMembers && teamMembers.length >= badge.people) { if (badgeOfType) { if ( - badgeOfType._id.toString() !== badge._id.toString() - && badgeOfType.people < badge.people - + badgeOfType._id.toString() !== badge._id.toString() && + badgeOfType.people < badge.people ) { replaceBadge( personId, mongoose.Types.ObjectId(badgeOfType._id), - mongoose.Types.ObjectId(badge._id), - + mongoose.Types.ObjectId(badge._id) ); } return false; @@ -1297,40 +1395,39 @@ const userHelper = function () { const checkTotalHrsInCat = async function (personId, user, badgeCollection) { const hoursByCategory = user.hoursByCategory || {}; const categories = [ - 'food', - 'energy', - 'housing', - 'education', - 'society', - 'economics', - 'stewardship', + "food", + "energy", + "housing", + "education", + "society", + "economics", + "stewardship", ]; const badgesOfType = badgeCollection - .filter(object => object.badge.type === 'Total Hrs in Category') - .map(object => object.badge); + .filter((object) => object.badge.type === "Total Hrs in Category") + .map((object) => object.badge); categories.forEach(async (category) => { const categoryHrs = Object.keys(hoursByCategory).find( - elem => elem === category, + (elem) => elem === category ); - let badgeOfType; for (let i = 0; i < badgeCollection.length; i += 1) { if ( - badgeCollection[i].badge?.type === 'Total Hrs in Category' - && badgeCollection[i].badge?.category === category + badgeCollection[i].badge?.type === "Total Hrs in Category" && + badgeCollection[i].badge?.category === category ) { if ( - badgeOfType - && badgeOfType.totalHrs <= badgeCollection[i].badge.totalHrs + badgeOfType && + badgeOfType.totalHrs <= badgeCollection[i].badge.totalHrs ) { removeDupBadge(personId, badgeOfType._id); badgeOfType = badgeCollection[i].badge; } else if ( - badgeOfType - && badgeOfType.totalHrs > badgeCollection[i].badge.totalHrs + badgeOfType && + badgeOfType.totalHrs > badgeCollection[i].badge.totalHrs ) { removeDupBadge(personId, badgeCollection[i].badge._id); } else if (!badgeOfType) { @@ -1341,8 +1438,8 @@ const userHelper = function () { const newCatg = category.charAt(0).toUpperCase() + category.slice(1); - - await badge.find({ type: 'Total Hrs in Category', category: newCatg }) + await badge + .find({ type: "Total Hrs in Category", category: newCatg }) .sort({ totalHrs: -1 }) .then((results) => { @@ -1352,8 +1449,8 @@ const userHelper = function () { results.every((elem) => { if ( - hoursByCategory[categoryHrs] >= 100 - && hoursByCategory[categoryHrs] >= elem.totalHrs + hoursByCategory[categoryHrs] >= 100 && + hoursByCategory[categoryHrs] >= elem.totalHrs ) { let theBadge; for (let i = 0; i < badgesOfType.length; i += 1) { @@ -1368,13 +1465,13 @@ const userHelper = function () { } if (badgeOfType) { if ( - badgeOfType._id.toString() !== elem._id.toString() - && badgeOfType.totalHrs < elem.totalHrs + badgeOfType._id.toString() !== elem._id.toString() && + badgeOfType.totalHrs < elem.totalHrs ) { replaceBadge( personId, mongoose.Types.ObjectId(badgeOfType._id), - mongoose.Types.ObjectId(elem._id), + mongoose.Types.ObjectId(elem._id) ); } return false; @@ -1389,10 +1486,11 @@ const userHelper = function () { }; const awardNewBadges = async () => { - console.log('Awarding'); + console.log("Awarding"); try { - const users = await userProfile.find({ isActive: true }).populate('badgeCollection.badge'); - + const users = await userProfile + .find({ isActive: true }) + .populate("badgeCollection.badge"); for (let i = 0; i < users.length; i += 1) { const user = users[i]; @@ -1414,9 +1512,14 @@ const userHelper = function () { const getTangibleHoursReportedThisWeekByUserId = function (personId) { const userId = mongoose.Types.ObjectId(personId); - const pdtstart = moment().tz('America/Los_Angeles').startOf('week').format('YYYY-MM-DD'); - const pdtend = moment().tz('America/Los_Angeles').endOf('week').format('YYYY-MM-DD'); - + const pdtstart = moment() + .tz("America/Los_Angeles") + .startOf("week") + .format("YYYY-MM-DD"); + const pdtend = moment() + .tz("America/Los_Angeles") + .endOf("week") + .format("YYYY-MM-DD"); return timeEntries .find( @@ -1425,12 +1528,12 @@ const userHelper = function () { dateOfWork: { $gte: pdtstart, $lte: pdtend }, isTangible: true, }, - 'totalSeconds', + "totalSeconds" ) .then((results) => { const totalTangibleWeeklySeconds = results.reduce( (acc, { totalSeconds }) => acc + totalSeconds, - 0, + 0 ); return (totalTangibleWeeklySeconds / 3600).toFixed(2); }); @@ -1440,25 +1543,29 @@ const userHelper = function () { try { const users = await userProfile.find( { isActive: true, endDate: { $exists: true } }, - '_id isActive endDate', + "_id isActive endDate" ); for (let i = 0; i < users.length; i += 1) { const user = users[i]; const { endDate } = user; endDate.setHours(endDate.getHours() + 7); - if (moment().isAfter(moment(endDate).add(1, 'days'))) { + if (moment().isAfter(moment(endDate).add(1, "days"))) { await userProfile.findByIdAndUpdate( user._id, user.set({ isActive: false, }), - { new: true }, + { new: true } ); const id = user._id; const person = await userProfile.findById(id); - const lastDay = moment(person.endDate).format('YYYY-MM-DD'); - logger.logInfo(`User with id: ${user._id} was de-acticated at ${moment().format()}.`); + const lastDay = moment(person.endDate).format("YYYY-MM-DD"); + logger.logInfo( + `User with id: ${ + user._id + } was de-acticated at ${moment().format()}.` + ); const subject = `IMPORTANT:${person.firstName} ${person.lastName} has been deactivated in the Highest Good Network`; @@ -1472,8 +1579,14 @@ const userHelper = function () {

The HGN A.I. (and One Community)

`; - - emailSender('onecommunityglobal@gmail.com', subject, emailBody, null, null); + emailSender( + "onecommunityglobal@gmail.com", + subject, + emailBody, + null, + null, + person.email + ); } } } catch (err) { @@ -1491,7 +1604,6 @@ const userHelper = function () { } }; - return { getUserName, getTeamMembers, @@ -1510,4 +1622,4 @@ const userHelper = function () { }; }; -module.exports = userHelper; +module.exports = userHelper; \ No newline at end of file diff --git a/src/startup/routes.js b/src/startup/routes.js index 1713d6a67..8b8cf98f4 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -20,9 +20,11 @@ const ownerStandardMessage = require('../models/ownerStandardMessage'); const profileInitialSetuptoken = require('../models/profileInitialSetupToken'); const reason = require('../models/reason'); const mouseoverText = require('../models/mouseoverText'); -const buildingMaterial = require('../models/bmdashboard/buildingMaterial'); +const inventoryItemMaterial = require('../models/inventoryItemMaterial'); +const mapLocations = require('../models/mapLocation'); const buildingProject = require('../models/bmdashboard/buildingProject'); const buildingInventoryType = require('../models/bmdashboard/buildingInventoryType'); +const buildingMaterial = require('../models/bmdashboard/buildingMaterial'); const userProfileRouter = require('../routes/userProfileRouter')(userProfile); const badgeRouter = require('../routes/badgeRouter')(badge); @@ -58,10 +60,13 @@ const ownerStandardMessageRouter = require('../routes/ownerStandardMessageRouter const reasonRouter = require('../routes/reasonRouter')(reason, userProfile); const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverText); +const mapLocationRouter = require('../routes/mapLocationsRouter')(mapLocations); + // bm dashboard const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); -const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(buildingMaterial); +const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial, buildingMaterial); const bmProjectRouter = require('../routes/bmdashboard/bmProjectRouter')(buildingProject); +const bmInventoryTypeRouter = require('../routes/bmdashboard/bmInventoryTypeRouter')(buildingInventoryType); module.exports = function (app) { app.use('/api', forgotPwdRouter); @@ -93,8 +98,10 @@ module.exports = function (app) { app.use('/api', informationRouter); app.use('/api', mouseoverTextRouter); app.use('/api', isEmailExistsRouter); + app.use('/api', mapLocationRouter); // bm dashboard app.use('/api/bm', bmLoginRouter); - app.use('/api/bm', bmProjectRouter); app.use('/api/bm', bmMaterialsRouter); -}; + app.use('/api/bm', bmProjectRouter); + app.use('/api/bm', bmInventoryTypeRouter); +}; \ No newline at end of file From c1294d44413f8b67abbadbb0ac8ab1e953ab967d Mon Sep 17 00:00:00 2001 From: lacnoskillz Date: Fri, 1 Dec 2023 12:14:46 -0600 Subject: [PATCH 175/272] remake branch without package-lock.json modifications --- .../bmdashboard/bmInventoryTypeController.js | 53 +++++++++++++++---- .../bmdashboard/bmInventoryTypeRouter.js | 5 ++ 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/controllers/bmdashboard/bmInventoryTypeController.js b/src/controllers/bmdashboard/bmInventoryTypeController.js index b9ced243e..f7e964f86 100644 --- a/src/controllers/bmdashboard/bmInventoryTypeController.js +++ b/src/controllers/bmdashboard/bmInventoryTypeController.js @@ -1,19 +1,54 @@ const bmInventoryTypeController = function (InvType) { const fetchMaterialTypes = async (req, res) => { try { - InvType - .find() - .exec() - .then(result => res.status(200).send(result)) - .catch(error => res.status(500).send(error)); - } catch (err) { - res.json(err); + const result = await InvType.find().exec(); + res.status(200).send(result); + } catch (error) { + res.status(500).send(error); } }; + const fetchSingleInventoryType = async (req, res) => { + const { invtypeId } = req.params; + try { + const result = await InvType.findById(invtypeId).exec(); + res.status(200).send(result); + } catch (error) { + res.status(500).send(error); + } + }; + + const updateNameAndUnit = async (req, res) => { + try { + const { invtypeId } = req.params; + const { name, unit } = req.body; + + const updateData = {}; - return { - fetchMaterialTypes, + if (name) { + updateData.name = name; + } + + if (unit) { + updateData.unit = unit; + } + + const updatedInvType = await InvType.findByIdAndUpdate( + invtypeId, + updateData, + { new: true, runValidators: true }, + ); + + if (!updatedInvType) { + return res.status(404).json({ error: 'invType Material not found check Id' }); + } + + res.status(200).json(updatedInvType); + } catch (error) { + res.status(500).send(error); + } }; + + return { fetchMaterialTypes, fetchSingleInventoryType, updateNameAndUnit }; }; module.exports = bmInventoryTypeController; diff --git a/src/routes/bmdashboard/bmInventoryTypeRouter.js b/src/routes/bmdashboard/bmInventoryTypeRouter.js index ceae439dc..e62e71c07 100644 --- a/src/routes/bmdashboard/bmInventoryTypeRouter.js +++ b/src/routes/bmdashboard/bmInventoryTypeRouter.js @@ -4,9 +4,14 @@ const routes = function (invType) { const inventoryTypeRouter = express.Router(); const controller = require('../../controllers/bmdashboard/bmInventoryTypeController')(invType); + // Route for fetching all material types inventoryTypeRouter.route('/invtypes/materials') .get(controller.fetchMaterialTypes); + // Combined routes for getting a single inventory type and updating its name and unit of measurement + inventoryTypeRouter.route('/invtypes/material/:invtypeId') + .get(controller.fetchSingleInventoryType) + .put(controller.updateNameAndUnit); return inventoryTypeRouter; }; From 28badf296ee9d88dd2c50b0d0b9c9e9e858cc2fe Mon Sep 17 00:00:00 2001 From: lacnoskillz Date: Fri, 1 Dec 2023 12:34:55 -0600 Subject: [PATCH 176/272] changed fetchMaterialTypes back to how it was before --- .../bmdashboard/bmInventoryTypeController.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/controllers/bmdashboard/bmInventoryTypeController.js b/src/controllers/bmdashboard/bmInventoryTypeController.js index f7e964f86..5460f529c 100644 --- a/src/controllers/bmdashboard/bmInventoryTypeController.js +++ b/src/controllers/bmdashboard/bmInventoryTypeController.js @@ -1,10 +1,13 @@ const bmInventoryTypeController = function (InvType) { const fetchMaterialTypes = async (req, res) => { try { - const result = await InvType.find().exec(); - res.status(200).send(result); - } catch (error) { - res.status(500).send(error); + InvType + .find() + .exec() + .then(result => res.status(200).send(result)) + .catch(error => res.status(500).send(error)); + } catch (err) { + res.json(err); } }; const fetchSingleInventoryType = async (req, res) => { From 40e044a474dd2ca6be9a517ac4963ebb0d09acf6 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Fri, 1 Dec 2023 12:17:24 -0800 Subject: [PATCH 177/272] update fetchAllProjects func to populate itemType field --- src/controllers/bmdashboard/bmProjectController.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/controllers/bmdashboard/bmProjectController.js b/src/controllers/bmdashboard/bmProjectController.js index 8ca62ea77..b6b3e4e18 100644 --- a/src/controllers/bmdashboard/bmProjectController.js +++ b/src/controllers/bmdashboard/bmProjectController.js @@ -36,6 +36,17 @@ const bmMProjectController = function (BuildingProject) { pipeline: [ { $match: { $expr: { $eq: ['$project', '$$id'] } } }, { $project: { updateRecord: 0, project: 0 } }, + { + $lookup: { + from: 'buildingInventoryTypes', + localField: 'itemType', + foreignField: '_id', + as: 'itemType', + }, + }, + { + $unwind: '$itemType', + }, ], as: 'materials', }, @@ -63,7 +74,6 @@ const bmMProjectController = function (BuildingProject) { proj.mostMaterialWaste = proj.materials.sort((a, b) => b.stockWasted - a.stockWasted)[0]; proj.leastMaterialAvailable = proj.materials.sort((a, b) => a.stockAvailable - b.stockAvailable)[0]; proj.mostMaterialBought = proj.materials.sort((a, b) => b.stockBought - a.stockBought)[0]; - proj.teamCount = proj.teams.length; }); res.status(200).send(results); }) From be6b67f1074864b7eb440c45d992fe4d056eabc3 Mon Sep 17 00:00:00 2001 From: Olga Yudkin Date: Fri, 1 Dec 2023 15:25:44 -0500 Subject: [PATCH 178/272] renamed tool router and controller and fixed syntax error --- .../bmdashboard/bmToolController.js | 27 +++++++++++++++++++ .../bmdashboard/bmToolsController.js | 27 ------------------- .../{bmToolsRouter.js => bmToolRouter.js} | 2 +- src/startup/routes.js | 4 +-- 4 files changed, 30 insertions(+), 30 deletions(-) create mode 100644 src/controllers/bmdashboard/bmToolController.js delete mode 100644 src/controllers/bmdashboard/bmToolsController.js rename src/routes/bmdashboard/{bmToolsRouter.js => bmToolRouter.js} (90%) diff --git a/src/controllers/bmdashboard/bmToolController.js b/src/controllers/bmdashboard/bmToolController.js new file mode 100644 index 000000000..2b29101f3 --- /dev/null +++ b/src/controllers/bmdashboard/bmToolController.js @@ -0,0 +1,27 @@ +const bmToolController = (BuildingTool) => { + const fetchSingleTool = async (req, res) => { + const { toolId } = req.params; + try { + BuildingTool + .findById(toolId) + // .populate([ + // { + // path: 'itemType', + // select: '_id name description unit imageURL', + // }, + // { + // path: 'userResponsible', + // select: '_id firstName lastName', + // }, + // ]) + .exec() + .then(tool => res.status(200).send(tool)) + .catch(error => res.status(500).send(error)); + } catch (err) { + res.json(err); + } + }; + return { fetchSingleTool }; +}; + +module.exports = bmToolController; diff --git a/src/controllers/bmdashboard/bmToolsController.js b/src/controllers/bmdashboard/bmToolsController.js deleted file mode 100644 index c54ac7b24..000000000 --- a/src/controllers/bmdashboard/bmToolsController.js +++ /dev/null @@ -1,27 +0,0 @@ -const bmToolsController = (BuildingTool) => { - const fetchSingleTool = async (req, res) => { - const { toolId } = req.params; - try { - BuildingTool - .findById(toolId) - .populate([ - { - path: 'itemType', - select: '_id name description unit imageURL', - }, - { - path: 'userResponsible', - select: '_id firstName lastName', - }, - ]) - .exec() - .then(tool => res.status(200).send(tool)) - .catch(error => res.status(500).send(error)); - } catch (err) { - res.json(err); - } - }; - return fetchSingleTool; -}; - -module.exports = bmToolsController; diff --git a/src/routes/bmdashboard/bmToolsRouter.js b/src/routes/bmdashboard/bmToolRouter.js similarity index 90% rename from src/routes/bmdashboard/bmToolsRouter.js rename to src/routes/bmdashboard/bmToolRouter.js index 32ea64f20..a1a30ea40 100644 --- a/src/routes/bmdashboard/bmToolsRouter.js +++ b/src/routes/bmdashboard/bmToolRouter.js @@ -2,7 +2,7 @@ const express = require('express'); const routes = function (BuildingTool) { const toolRouter = express.Router(); - const controller = require('../../controllers/bmdashboard/bmToolsController')(BuildingTool); + const controller = require('../../controllers/bmdashboard/bmToolController')(BuildingTool); toolRouter.route('/tools/:toolId') .get(controller.fetchSingleTool); diff --git a/src/startup/routes.js b/src/startup/routes.js index 5cdf15b6a..6cd7d3771 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -62,7 +62,7 @@ const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverTe const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial); const bmProjectRouter = require('../routes/bmdashboard/bmProjectRouter')(buildingProject); -const bmToolsRouter = require('../routes/bmdashboard/bmToolsRouter')(buildingTool); +const bmToolRouter = require('../routes/bmdashboard/bmToolRouter')(buildingTool); module.exports = function (app) { app.use('/api', forgotPwdRouter); @@ -98,5 +98,5 @@ module.exports = function (app) { app.use('/api/bm', bmLoginRouter); app.use('/api/bm', bmMaterialsRouter); app.use('/api/bm', bmProjectRouter); - app.use('/api/bm', bmToolsRouter); + app.use('/api/bm', bmToolRouter); }; From f67d2b46f3604ce625dfaeff447d5ae338749310 Mon Sep 17 00:00:00 2001 From: Oleksandr Riazantsev Date: Fri, 1 Dec 2023 17:15:06 -0500 Subject: [PATCH 179/272] Cron job - change main locations --- src/cronjobs/userProfileJobs.js | 2 +- src/helpers/userHelper.js | 104 ++++++++++++++++++++++++++------ 2 files changed, 85 insertions(+), 21 deletions(-) diff --git a/src/cronjobs/userProfileJobs.js b/src/cronjobs/userProfileJobs.js index f3903c057..1e4c6392a 100644 --- a/src/cronjobs/userProfileJobs.js +++ b/src/cronjobs/userProfileJobs.js @@ -18,12 +18,12 @@ const userProfileJobs = () => { await userhelper.awardNewBadges(); await userhelper.reActivateUser(); await userhelper.deActivateUser(); + await userhelper.oneTimeLocationUpdate(); }, null, false, 'America/Los_Angeles', ); - allUserProfileJobs.start(); }; module.exports = userProfileJobs; diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index 8bf04eb5f..1e349245c 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -105,8 +105,8 @@ const userHelper = function () {

Date Assigned: ${infringement.date}

Description: ${infringement.description}

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

+ .localeData() + .ordinal(totalInfringements)} blue square of 5.

${final_paragraph}

Thank you,
One Community

`; @@ -197,8 +197,8 @@ const userHelper = function () {
Weekly Summary (for the week ending on ${moment(dueDate) - .tz("America/Los_Angeles") - .format("YYYY-MMM-DD")}): + .tz("America/Los_Angeles") + .format("YYYY-MMM-DD")}):
${summary} @@ -220,24 +220,24 @@ const userHelper = function () { Media URL: ${ mediaUrlLink || 'Not provided!' - } + }

${ weeklySummariesCount === 8 - ? `

Total Valid Weekly Summaries: ${weeklySummariesCount}

` - : `

Total Valid Weekly Summaries: ${ + ? `

Total Valid Weekly Summaries: ${weeklySummariesCount}

` + : `

Total Valid Weekly Summaries: ${ weeklySummariesCount || "No valid submissions yet!" - }

` + }

` } ${ hoursLogged >= weeklycommittedHours - ? `

Hours logged: ${hoursLogged.toFixed( - 2 - )} / ${weeklycommittedHours}

` - : `

Hours logged: ${hoursLogged.toFixed( - 2 - )} / ${weeklycommittedHours}

` + ? `

Hours logged: ${hoursLogged.toFixed( + 2 + )} / ${weeklycommittedHours}

` + : `

Hours logged: ${hoursLogged.toFixed( + 2 + )} / ${weeklycommittedHours}

` } ${weeklySummaryMessage}
`; @@ -298,6 +298,69 @@ const userHelper = function () { }) .catch((error) => logger.logException(error)); }; + async function wait(ms) { + return new Promise((r) => setTimeout(r, ms)); + } + const oneTimeLocationUpdate = async () => { + const users = await userProfile.find({}, '_id'); + + for (let i = 0; i < users.length; i += 1) { + const user = users[i]; + const person = await userProfile.findById(user._id); + if (!person.location.coords && !person.location.country && !person.location.city && !person.location.userProvided) { + const personLoc = person.location || ''; + let location; + if (personLoc) { + try { + const res = await fetch(`https://api.opencagedata.com/geocode/v1/json?key=d093a5e0eee34aea8043f4e6edb0e9f7&q=${encodeURIComponent(personLoc)}&pretty=1&limit=1`); + if (!res) { + throw new Error(); + } else { + const data = await res.json(); + location = { + userProvided: personLoc || '', + coords: { + lat: data.results[0].geometry.lat || '', + lng: data.results[0].geometry.lng || '', + }, + country: data.results[0].components.country || '', + city: data.results[0].components.city || '', + }; + } + } catch (err) { + console.log(err); + location = { + userProvided: personLoc, + coords: { + lat: 'err', + lng: '', + }, + country: '', + city: '', + } + } + } else { + location = { + userProvided: personLoc || '', + coords: { + lat: '', + lng: '', + }, + country: '', + city: '', + }; + } + await userProfile.findOneAndUpdate({ _id: user._id }, { + $set: { + location, + }, + }); + } + + await wait(2000); + } + }; + /** * This function is called by a cron job to do 3 things to all active users: @@ -936,7 +999,7 @@ const userHelper = function () { for (let i = 0; i < badgeCollection.length; i += 1) { if ( badgeCollection[i].badge?.type === - "X Hours for X Week Streak" && + "X Hours for X Week Streak" && badgeCollection[i].badge?.weeks === bdge.weeks && bdge.hrs === hrs && !removed @@ -1041,7 +1104,7 @@ const userHelper = function () { true ) ) >= - elem.months - 12 + elem.months - 12 ) { if (badgeOfType) { if (badgeOfType._id.toString() !== elem._id.toString()) { @@ -1092,9 +1155,9 @@ const userHelper = function () { ); return theBadge ? increaseBadgeCount( - personId, - mongoose.Types.ObjectId(theBadge._id) - ) + personId, + mongoose.Types.ObjectId(theBadge._id) + ) : addBadge(personId, mongoose.Types.ObjectId(elem._id)); } } @@ -1227,7 +1290,7 @@ const userHelper = function () { for (let i = 0; i < badgeCollection.length; i += 1) { if ( badgeCollection[i].badge?.type === - "X Hours for X Week Streak" && + "X Hours for X Week Streak" && badgeCollection[i].badge?.weeks === bdge.weeks ) { if ( @@ -1619,6 +1682,7 @@ const userHelper = function () { awardNewBadges, getTangibleHoursReportedThisWeekByUserId, deleteExpiredTokens, + oneTimeLocationUpdate, }; }; From 37dbad95613343a6f7dc0b7c58d29f53521f0a60 Mon Sep 17 00:00:00 2001 From: Nathan Hoffman Date: Fri, 1 Dec 2023 17:12:06 -0800 Subject: [PATCH 180/272] Fix end anchor symbol in escapeRegex --- src/utilities/escapeRegex.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utilities/escapeRegex.js b/src/utilities/escapeRegex.js index 01a65ea50..cf7563e26 100644 --- a/src/utilities/escapeRegex.js +++ b/src/utilities/escapeRegex.js @@ -1,6 +1,6 @@ const escapeRegex = function (text) { - return `^${text.replace(/[[\]{}()*+?.\\^$|]/g, '\\$&')}&`; + return `^${text.replace(/[[\]{}()*+?.\\^$|]/g, '\\$&')}$`; }; module.exports = escapeRegex; From 051cd4bc1bc1b920e52183b8f1b752f3ec1b268d Mon Sep 17 00:00:00 2001 From: One Community Date: Sat, 2 Dec 2023 00:19:36 -0800 Subject: [PATCH 181/272] Revert "Cron job - change main locations" --- src/cronjobs/userProfileJobs.js | 2 +- src/helpers/userHelper.js | 104 ++++++-------------------------- 2 files changed, 21 insertions(+), 85 deletions(-) diff --git a/src/cronjobs/userProfileJobs.js b/src/cronjobs/userProfileJobs.js index 1e4c6392a..f3903c057 100644 --- a/src/cronjobs/userProfileJobs.js +++ b/src/cronjobs/userProfileJobs.js @@ -18,12 +18,12 @@ const userProfileJobs = () => { await userhelper.awardNewBadges(); await userhelper.reActivateUser(); await userhelper.deActivateUser(); - await userhelper.oneTimeLocationUpdate(); }, null, false, 'America/Los_Angeles', ); + allUserProfileJobs.start(); }; module.exports = userProfileJobs; diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index 1e349245c..8bf04eb5f 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -105,8 +105,8 @@ const userHelper = function () {

Date Assigned: ${infringement.date}

Description: ${infringement.description}

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

+ .localeData() + .ordinal(totalInfringements)} blue square of 5.

${final_paragraph}

Thank you,
One Community

`; @@ -197,8 +197,8 @@ const userHelper = function () {
Weekly Summary (for the week ending on ${moment(dueDate) - .tz("America/Los_Angeles") - .format("YYYY-MMM-DD")}): + .tz("America/Los_Angeles") + .format("YYYY-MMM-DD")}):
${summary} @@ -220,24 +220,24 @@ const userHelper = function () { Media URL: ${ mediaUrlLink || 'Not provided!' - } + }

${ weeklySummariesCount === 8 - ? `

Total Valid Weekly Summaries: ${weeklySummariesCount}

` - : `

Total Valid Weekly Summaries: ${ + ? `

Total Valid Weekly Summaries: ${weeklySummariesCount}

` + : `

Total Valid Weekly Summaries: ${ weeklySummariesCount || "No valid submissions yet!" - }

` + }

` } ${ hoursLogged >= weeklycommittedHours - ? `

Hours logged: ${hoursLogged.toFixed( - 2 - )} / ${weeklycommittedHours}

` - : `

Hours logged: ${hoursLogged.toFixed( - 2 - )} / ${weeklycommittedHours}

` + ? `

Hours logged: ${hoursLogged.toFixed( + 2 + )} / ${weeklycommittedHours}

` + : `

Hours logged: ${hoursLogged.toFixed( + 2 + )} / ${weeklycommittedHours}

` } ${weeklySummaryMessage}
`; @@ -298,69 +298,6 @@ const userHelper = function () { }) .catch((error) => logger.logException(error)); }; - async function wait(ms) { - return new Promise((r) => setTimeout(r, ms)); - } - const oneTimeLocationUpdate = async () => { - const users = await userProfile.find({}, '_id'); - - for (let i = 0; i < users.length; i += 1) { - const user = users[i]; - const person = await userProfile.findById(user._id); - if (!person.location.coords && !person.location.country && !person.location.city && !person.location.userProvided) { - const personLoc = person.location || ''; - let location; - if (personLoc) { - try { - const res = await fetch(`https://api.opencagedata.com/geocode/v1/json?key=d093a5e0eee34aea8043f4e6edb0e9f7&q=${encodeURIComponent(personLoc)}&pretty=1&limit=1`); - if (!res) { - throw new Error(); - } else { - const data = await res.json(); - location = { - userProvided: personLoc || '', - coords: { - lat: data.results[0].geometry.lat || '', - lng: data.results[0].geometry.lng || '', - }, - country: data.results[0].components.country || '', - city: data.results[0].components.city || '', - }; - } - } catch (err) { - console.log(err); - location = { - userProvided: personLoc, - coords: { - lat: 'err', - lng: '', - }, - country: '', - city: '', - } - } - } else { - location = { - userProvided: personLoc || '', - coords: { - lat: '', - lng: '', - }, - country: '', - city: '', - }; - } - await userProfile.findOneAndUpdate({ _id: user._id }, { - $set: { - location, - }, - }); - } - - await wait(2000); - } - }; - /** * This function is called by a cron job to do 3 things to all active users: @@ -999,7 +936,7 @@ const userHelper = function () { for (let i = 0; i < badgeCollection.length; i += 1) { if ( badgeCollection[i].badge?.type === - "X Hours for X Week Streak" && + "X Hours for X Week Streak" && badgeCollection[i].badge?.weeks === bdge.weeks && bdge.hrs === hrs && !removed @@ -1104,7 +1041,7 @@ const userHelper = function () { true ) ) >= - elem.months - 12 + elem.months - 12 ) { if (badgeOfType) { if (badgeOfType._id.toString() !== elem._id.toString()) { @@ -1155,9 +1092,9 @@ const userHelper = function () { ); return theBadge ? increaseBadgeCount( - personId, - mongoose.Types.ObjectId(theBadge._id) - ) + personId, + mongoose.Types.ObjectId(theBadge._id) + ) : addBadge(personId, mongoose.Types.ObjectId(elem._id)); } } @@ -1290,7 +1227,7 @@ const userHelper = function () { for (let i = 0; i < badgeCollection.length; i += 1) { if ( badgeCollection[i].badge?.type === - "X Hours for X Week Streak" && + "X Hours for X Week Streak" && badgeCollection[i].badge?.weeks === bdge.weeks ) { if ( @@ -1682,7 +1619,6 @@ const userHelper = function () { awardNewBadges, getTangibleHoursReportedThisWeekByUserId, deleteExpiredTokens, - oneTimeLocationUpdate, }; }; From 081c1bba112e3c603d582ef6642dc1dae6b7889b Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Tue, 5 Dec 2023 11:38:48 -0800 Subject: [PATCH 182/272] add records subdocuments --- src/models/bmdashboard/buildingTool.js | 38 ++++++++++++++++++++------ 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/models/bmdashboard/buildingTool.js b/src/models/bmdashboard/buildingTool.js index 6cec3b5d0..95be0c4d5 100644 --- a/src/models/bmdashboard/buildingTool.js +++ b/src/models/bmdashboard/buildingTool.js @@ -2,15 +2,35 @@ const mongoose = require('mongoose'); const { Schema } = mongoose; -const buildingTools = new Schema({ +const buildingTool = new Schema({ itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, - title: { type: String, required: true }, - rentedOnDate: { type: Date, required: true }, - rentDuration: { type: Number, required: true }, // This value should be taken in number of days - logInStatus:{Boolean}, - condition:{type: String, enum: ['Good', 'Needs Repair', 'Out of Order','Unused'], default: 'Good'}, - userResponsible:{ type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - purchaseStatus:{type: String, enum: ['Rented', 'Purchased'], default: 'Rented'}, + code: { type: Number, required: true }, // add function to create code for on-site tool tracking + purchaseStatus: { type: String, enum: ['Rental', 'Purchase'], required: true }, + // add discriminator based on rental or purchase so these fields are required if tool is rented + rentedOnDate: Date, + rentalDue: Date, + userResponsible: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + purchaseRecord: [{ // track purchase/rental requests + _id: false, // do not add _id field to subdocument + date: { type: Date, default: Date.now() }, + requestedBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + priority: { type: String, enum: ['Low', 'Medium', 'High'], required: true }, + brand: String, + status: { type: String, default: 'Pending', enum: ['Approved', 'Pending', 'Rejected'] }, + }], + updateRecord: [{ // track tool condition updates + _id: false, + date: { type: Date, default: Date.now() }, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + condition: { type: String, enum: ['Good', 'Needs Repair', 'Out of Order'] }, + }], + logRecord: [{ // track tool daily check in/out and use + _id: false, + date: { type: Date, default: Date.now() }, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + responsibleUser: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + type: { type: String, enum: ['Check In', 'Check Out'] }, // default = opposite of current log status? + }], }); -module.exports = mongoose.model('buildingTools', buildingTools, 'buildingTools'); \ No newline at end of file +module.exports = mongoose.model('buildingTool', buildingTool, 'buildingTools'); From 35b1b6c36220b8af1a83194b7923cf7f301f2a5d Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Wed, 6 Dec 2023 08:44:49 -0800 Subject: [PATCH 183/272] add new model template --- src/models/bmdashboard/buildingReusable.js | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/models/bmdashboard/buildingReusable.js diff --git a/src/models/bmdashboard/buildingReusable.js b/src/models/bmdashboard/buildingReusable.js new file mode 100644 index 000000000..1d0503010 --- /dev/null +++ b/src/models/bmdashboard/buildingReusable.js @@ -0,0 +1,29 @@ +const mongoose = require('mongoose'); + +const { Schema } = mongoose; + +const buildingReusable = new Schema({ + itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, + project: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingProject' }, + stockBought: { type: Number, default: 0 }, + stockDestroyed: { type: Number, default: 0 }, + stockAvailable: { type: Number, default: 0 }, + purchaseRecord: [{ + _id: false, // do not add _id field to subdocument + date: { type: Date, default: Date.now() }, + requestedBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + quantity: { type: Number, required: true }, + priority: { type: String, enum: ['Low', 'Medium', 'High'], required: true }, + brand: String, + status: { type: String, default: 'Pending', enum: ['Approved', 'Pending', 'Rejected'] }, + }], + updateRecord: [{ + _id: false, + date: { type: Date, required: true }, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + quantityUsed: { type: Number, required: true }, + quantityDestroyed: { type: Number, required: true }, + }], +}); + +module.exports = mongoose.model('buildingReusable', buildingReusable, 'buildingReusables'); From 0976b730a58bb2f6c0a21d13d15e45df3861c672 Mon Sep 17 00:00:00 2001 From: Vishala Ramasamy Date: Wed, 6 Dec 2023 09:43:10 -0800 Subject: [PATCH 184/272] removed mongo-round package --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 32d23ee6a..1c6b8a5d4 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,6 @@ "lodash": "^4.17.21", "moment": "^2.29.4", "moment-timezone": "^0.5.35", - "mongo-round": "^1.0.0", "mongodb": "^3.7.3", "mongoose": "^5.13.15", "mongoose-validator": "^2.1.0", From 0a30abbaa285dff8ca19f219a92077beb40183a2 Mon Sep 17 00:00:00 2001 From: Shiwani Rajagopalan Date: Wed, 6 Dec 2023 17:16:44 -0500 Subject: [PATCH 185/272] added timeOffFrom and timeOffTill fields to mongoDB --- src/controllers/reasonSchedulingController.js | 188 ++++++---- src/helpers/dashboardhelper.js | 339 +++++++++--------- src/models/userProfile.js | 104 +++--- 3 files changed, 348 insertions(+), 283 deletions(-) diff --git a/src/controllers/reasonSchedulingController.js b/src/controllers/reasonSchedulingController.js index e310049c2..89b312bc2 100644 --- a/src/controllers/reasonSchedulingController.js +++ b/src/controllers/reasonSchedulingController.js @@ -1,23 +1,19 @@ - -const moment = require('moment-timezone'); -const UserModel = require('../models/userProfile'); -const ReasonModel = require('../models/reason'); +const moment = require("moment-timezone"); +const UserModel = require("../models/userProfile"); +const ReasonModel = require("../models/reason"); const emailSender = require("../utilities/emailSender"); - const postReason = async (req, res) => { try { const { userId, requestor, reasonData } = req.body; const newDate = moment - .tz(reasonData.date, 'America/Los_Angeles') - .startOf('day'); - const currentDate = moment - .tz('America/Los_Angeles') - .startOf('day'); + .tz(reasonData.date, "America/Los_Angeles") + .startOf("day"); + const currentDate = moment.tz("America/Los_Angeles").startOf("day"); // error case 0 - if (moment.tz(reasonData.date, 'America/Los_Angeles').day() !== 0) { + if (moment.tz(reasonData.date, "America/Los_Angeles").day() !== 0) { return res.status(400).json({ message: "You must choose the Sunday YOU'LL RETURN as your date. This is so your reason ends up as a note on that blue square.", @@ -27,19 +23,19 @@ const postReason = async (req, res) => { if (newDate.isBefore(currentDate)) { return res.status(400).json({ - message: 'You should select a date that is yet to come', + message: "You should select a date that is yet to come", errorCode: 7, }); } if (!reasonData.message) { return res.status(400).json({ - message: 'You must provide a reason.', + message: "You must provide a reason.", errorCode: 6, }); } - //Commented this condition to make reason scheduler available to all the users. + //Commented this condition to make reason scheduler available to all the users. // error case 1 // if (requestor.role !== 'Owner' && requestor.role !== 'Administrator') { // return res.status(403).json({ @@ -54,15 +50,61 @@ const postReason = async (req, res) => { // error case 2 if (!foundUser) { return res.status(404).json({ - message: 'User not found', + message: "User not found", errorCode: 2, }); } + // new changes + + if ( + foundUser.hasOwnProperty("timeOffFrom") && + foundUser.hasOwnProperty("timeOffTill") + ) { + if (currentDate >= foundUser.timeOffTill) { + await UserModel.findOneAndUpdate( + { + _id: userId, + }, + { + $set: { + timeOffFrom: currentDate, + timeOffTill: newDate, + }, + } + ); + } else { + await UserModel.findOneAndUpdate( + { + _id: userId, + }, + { + $set: { + timeOffTill: newDate, + }, + } + ); + } + } else { + await UserModel.findOneAndUpdate( + { + _id: userId, + }, + { + $set: { + timeOffFrom: currentDate, + timeOffTill: newDate, + }, + } + ); + } + + // + const foundReason = await ReasonModel.findOne({ date: moment - .tz(reasonData.date, 'America/Los_Angeles') - .startOf('day') + .tz(reasonData.date, "America/Los_Angeles") + .startOf("day") .toISOString(), userId, }); @@ -70,14 +112,14 @@ const postReason = async (req, res) => { // error case 3 if (foundReason) { return res.status(403).json({ - message: 'The reason must be unique to the date', + message: "The reason must be unique to the date", errorCode: 3, }); } const savingDate = moment - .tz(reasonData.date, 'America/Los_Angeles') - .startOf('day') + .tz(reasonData.date, "America/Los_Angeles") + .startOf("day") .toISOString(); const newReason = new ReasonModel({ @@ -86,16 +128,13 @@ const postReason = async (req, res) => { userId, }); - //await newReason.save(); - const savedData = await newReason.save(); - if(savedData) - { - + const savedData = await newReason.save(); + if (savedData) { //Upon clicking the "Save" button in the Blue Square Reason Scheduler, an email will be automatically sent to the user and Jae. - const subject = `Blue Square Reason for ${foundUser.firstName} ${foundUser.lastName} has been set`; + const subject = `Blue Square Reason for ${foundUser.firstName} ${foundUser.lastName} has been set`; - const emailBody = `

Hi !

+ const emailBody = `

Hi !

This email is to let you know that ${foundUser.firstName} ${foundUser.lastName} has set their Blue Square Reason.

@@ -104,23 +143,21 @@ const postReason = async (req, res) => {

Thank you,
One Community

`; - - - // 1 hardcoded email- emailSender('@gmail.com', subject, emailBody, null, null); - // 2 user email - - emailSender(`${foundUser.email}`, subject, emailBody, null, null); + // 1 hardcoded email- emailSender('@gmail.com', subject, emailBody, null, null); - //3 - user email and hardcoded email ( After PR approval hardcode Jae's email) - // emailSender(`${foundUser.email},@gmail.com`, subject, emailBody, null, null); - } - - return res.sendStatus(200); + // 2 user email - + emailSender(`${foundUser.email}`, subject, emailBody, null, null); + //3 - user email and hardcoded email ( After PR approval hardcode Jae's email) + // emailSender(`${foundUser.email},@gmail.com`, subject, emailBody, null, null); + } + + return res.sendStatus(200); } catch (error) { console.log(error); return res.status(400).json({ - errMessage: 'Something went wrong', + errMessage: "Something went wrong", }); } }; @@ -143,7 +180,7 @@ const getAllReasons = async (req, res) => { // error case 2 if (!foundUser) { return res.status(404).json({ - message: 'User not found', + message: "User not found", }); } @@ -157,7 +194,7 @@ const getAllReasons = async (req, res) => { } catch (error) { console.log(error); return res.status(400).json({ - errMessage: 'Something went wrong while fetching the user', + errMessage: "Something went wrong while fetching the user", }); } }; @@ -181,24 +218,24 @@ const getSingleReason = async (req, res) => { // error case 2 if (!foundUser) { return res.status(404).json({ - message: 'User not found', + message: "User not found", errorCode: 2, }); } const foundReason = await ReasonModel.findOne({ date: moment - .tz(queryDate, 'America/Los_Angeles') - .startOf('day') + .tz(queryDate, "America/Los_Angeles") + .startOf("day") .toISOString(), userId, }); if (!foundReason) { return res.status(200).json({ - reason: '', - date: '', - userId: '', + reason: "", + date: "", + userId: "", isSet: false, }); } @@ -207,7 +244,7 @@ const getSingleReason = async (req, res) => { } catch (error) { console.log(error); return res.status(400).json({ - message: 'Something went wrong while fetching single reason', + message: "Something went wrong while fetching single reason", }); } }; @@ -228,7 +265,7 @@ const patchReason = async (req, res) => { if (!reasonData.message) { return res.status(400).json({ - message: 'You must provide a reason.', + message: "You must provide a reason.", errorCode: 6, }); } @@ -238,36 +275,34 @@ const patchReason = async (req, res) => { // error case 2 if (!foundUser) { return res.status(404).json({ - message: 'User not found', + message: "User not found", errorCode: 2, }); } const foundReason = await ReasonModel.findOne({ date: moment - .tz(reasonData.date, 'America/Los_Angeles') - .startOf('day') + .tz(reasonData.date, "America/Los_Angeles") + .startOf("day") .toISOString(), userId, }); // error case 4 if (!foundReason) { return res.status(404).json({ - message: 'Reason not found', + message: "Reason not found", errorCode: 4, }); } foundReason.reason = reasonData.message; - + const savedData = await foundReason.save(); - if(savedData) - { - + if (savedData) { //Upon clicking the "Save" button in the Blue Square Reason Scheduler, an email will be automatically sent to the user and Jae. - const subject = `Blue Square Reason for ${foundUser.firstName} ${foundUser.lastName} has been updated`; + const subject = `Blue Square Reason for ${foundUser.firstName} ${foundUser.lastName} has been updated`; - const emailBody = `

Hi !

+ const emailBody = `

Hi !

This email is to let you know that ${foundUser.firstName} ${foundUser.lastName} has updated their Blue Square Reason.

@@ -276,25 +311,22 @@ const patchReason = async (req, res) => {

Thank you,
One Community

`; - - - // 1 hardcoded email- emailSender('@gmail.com', subject, emailBody, null, null); - // 2 user email - - emailSender(`${foundUser.email}`, subject, emailBody, null, null); + // 1 hardcoded email- emailSender('@gmail.com', subject, emailBody, null, null); - //3 - user email and hardcoded email ( After PR approval hardcode Jae's email) - // emailSender(`${foundUser.email},@gmail.com`, subject, emailBody, null, null); - - - } + // 2 user email - + emailSender(`${foundUser.email}`, subject, emailBody, null, null); + + //3 - user email and hardcoded email ( After PR approval hardcode Jae's email) + // emailSender(`${foundUser.email},@gmail.com`, subject, emailBody, null, null); + } return res.status(200).json({ - message: 'Reason Updated!', + message: "Reason Updated!", }); } catch (error) { return res.status(400).json({ - message: 'something went wrong while patching the reason', + message: "something went wrong while patching the reason", }); } }; @@ -305,10 +337,10 @@ const deleteReason = async (req, res) => { const { userId } = req.params; //error case 1 - if (requestor.role !== 'Owner' && requestor.role !== 'Administrator') { + if (requestor.role !== "Owner" && requestor.role !== "Administrator") { return res.status(403).json({ message: - 'You must be an Owner or Administrator to schedule a reason for a Blue Square', + "You must be an Owner or Administrator to schedule a reason for a Blue Square", errorCode: 1, }); } @@ -318,21 +350,21 @@ const deleteReason = async (req, res) => { // error case 2 if (!foundUser) { return res.status(404).json({ - message: 'User not found', + message: "User not found", errorCode: 2, }); } const foundReason = await ReasonModel.findOne({ date: moment - .tz(reasonData.date, 'America/Los_Angeles') - .startOf('day') + .tz(reasonData.date, "America/Los_Angeles") + .startOf("day") .toISOString(), }); if (!foundReason) { return res.status(404).json({ - message: 'Reason not found', + message: "Reason not found", errorCode: 4, }); } @@ -340,13 +372,13 @@ const deleteReason = async (req, res) => { foundReason.remove((err) => { if (err) { return res.status(500).json({ - message: 'Error while deleting document', + message: "Error while deleting document", errorCode: 5, }); } return res.status(200).json({ - message: 'Document deleted', + message: "Document deleted", }); }); } catch (error) {} diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index 34d464583..64c867f71 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -1,26 +1,26 @@ -const moment = require('moment-timezone'); -const mongoose = require('mongoose'); -const userProfile = require('../models/userProfile'); -const timeentry = require('../models/timeentry'); -const myTeam = require('../helpers/helperModels/myTeam'); +const moment = require("moment-timezone"); +const mongoose = require("mongoose"); +const userProfile = require("../models/userProfile"); +const timeentry = require("../models/timeentry"); +const myTeam = require("../helpers/helperModels/myTeam"); const dashboardhelper = function () { const personaldetails = function (userId) { return userProfile.findById( userId, - '_id firstName lastName role profilePic badgeCollection', + "_id firstName lastName role profilePic badgeCollection" ); }; const getOrgData = async function () { const pdtstart = moment() - .tz('America/Los_Angeles') - .startOf('week') - .format('YYYY-MM-DD'); + .tz("America/Los_Angeles") + .startOf("week") + .format("YYYY-MM-DD"); const pdtend = moment() - .tz('America/Los_Angeles') - .endOf('week') - .format('YYYY-MM-DD'); + .tz("America/Los_Angeles") + .endOf("week") + .format("YYYY-MM-DD"); /** * Previous aggregate pipeline had two issues: @@ -39,35 +39,35 @@ const dashboardhelper = function () { $gte: 1, }, role: { - $ne: 'Mentor', + $ne: "Mentor", }, }, }, { $lookup: { - from: 'timeEntries', - localField: '_id', - foreignField: 'personId', - as: 'timeEntryData', + from: "timeEntries", + localField: "_id", + foreignField: "personId", + as: "timeEntryData", }, }, { $project: { - personId: '$_id', + personId: "$_id", name: 1, weeklycommittedHours: 1, role: 1, timeEntryData: { $filter: { - input: '$timeEntryData', - as: 'timeentry', + input: "$timeEntryData", + as: "timeentry", cond: { $and: [ { - $gte: ['$$timeentry.dateOfWork', pdtstart], + $gte: ["$$timeentry.dateOfWork", pdtstart], }, { - $lte: ['$$timeentry.dateOfWork', pdtend], + $lte: ["$$timeentry.dateOfWork", pdtend], }, ], }, @@ -77,7 +77,7 @@ const dashboardhelper = function () { }, { $unwind: { - path: '$timeEntryData', + path: "$timeEntryData", preserveNullAndEmptyArrays: true, }, }, @@ -88,27 +88,27 @@ const dashboardhelper = function () { totalSeconds: { $cond: [ { - $gte: ['$timeEntryData.totalSeconds', 0], + $gte: ["$timeEntryData.totalSeconds", 0], }, - '$timeEntryData.totalSeconds', + "$timeEntryData.totalSeconds", 0, ], }, tangibletime: { $cond: [ { - $eq: ['$timeEntryData.isTangible', true], + $eq: ["$timeEntryData.isTangible", true], }, - '$timeEntryData.totalSeconds', + "$timeEntryData.totalSeconds", 0, ], }, intangibletime: { $cond: [ { - $eq: ['$timeEntryData.isTangible', false], + $eq: ["$timeEntryData.isTangible", false], }, - '$timeEntryData.totalSeconds', + "$timeEntryData.totalSeconds", 0, ], }, @@ -117,17 +117,17 @@ const dashboardhelper = function () { { $group: { _id: { - personId: '$personId', - weeklycommittedHours: '$weeklycommittedHours', + personId: "$personId", + weeklycommittedHours: "$weeklycommittedHours", }, time_hrs: { - $sum: { $divide: ['$totalSeconds', 3600] }, + $sum: { $divide: ["$totalSeconds", 3600] }, }, tangibletime_hrs: { - $sum: { $divide: ['$tangibletime', 3600] }, + $sum: { $divide: ["$tangibletime", 3600] }, }, intangibletime_hrs: { - $sum: { $divide: ['$intangibletime', 3600] }, + $sum: { $divide: ["$intangibletime", 3600] }, }, }, }, @@ -135,15 +135,15 @@ const dashboardhelper = function () { $group: { _id: 0, memberCount: { $sum: 1 }, - totalweeklycommittedHours: { $sum: '$_id.weeklycommittedHours' }, + totalweeklycommittedHours: { $sum: "$_id.weeklycommittedHours" }, totaltime_hrs: { - $sum: '$time_hrs', + $sum: "$time_hrs", }, totaltangibletime_hrs: { - $sum: '$tangibletime_hrs', + $sum: "$tangibletime_hrs", }, totalintangibletime_hrs: { - $sum: '$intangibletime_hrs', + $sum: "$intangibletime_hrs", }, }, }, @@ -155,13 +155,13 @@ const dashboardhelper = function () { const getLeaderboard = function (userId) { const userid = mongoose.Types.ObjectId(userId); const pdtstart = moment() - .tz('America/Los_Angeles') - .startOf('week') - .format('YYYY-MM-DD'); + .tz("America/Los_Angeles") + .startOf("week") + .format("YYYY-MM-DD"); const pdtend = moment() - .tz('America/Los_Angeles') - .endOf('week') - .format('YYYY-MM-DD'); + .tz("America/Los_Angeles") + .endOf("week") + .format("YYYY-MM-DD"); return myTeam.aggregate([ { $match: { @@ -169,22 +169,22 @@ const dashboardhelper = function () { }, }, { - $unwind: '$myteam', + $unwind: "$myteam", }, { $project: { _id: 0, role: 1, - personId: '$myteam._id', - name: '$myteam.fullName', + personId: "$myteam._id", + name: "$myteam.fullName", }, }, { $lookup: { - from: 'userProfiles', - localField: 'personId', - foreignField: '_id', - as: 'persondata', + from: "userProfiles", + localField: "personId", + foreignField: "_id", + as: "persondata", }, }, { @@ -192,31 +192,37 @@ const dashboardhelper = function () { // leaderboard user roles hierarchy $or: [ { - role: { $in: ['Owner', 'Core Team'] }, + role: { $in: ["Owner", "Core Team"] }, }, { $and: [ { - role: 'Administrator', + role: "Administrator", }, - { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, - ] + { "persondata.0.role": { $nin: ["Owner", "Administrator"] } }, + ], }, { $and: [ { - role: { $in: ['Manager', 'Mentor'] }, + role: { $in: ["Manager", "Mentor"] }, }, { - 'persondata.0.role': { - $nin: ['Manager', 'Mentor', 'Core Team', 'Administrator', 'Owner'], + "persondata.0.role": { + $nin: [ + "Manager", + "Mentor", + "Core Team", + "Administrator", + "Owner", + ], }, }, ], }, - { 'persondata.0._id': userId }, - { 'persondata.0.role': 'Volunteer' }, - { 'persondata.0.isVisible': true }, + { "persondata.0._id": userId }, + { "persondata.0.role": "Volunteer" }, + { "persondata.0.isVisible": true }, ], }, }, @@ -225,31 +231,31 @@ const dashboardhelper = function () { personId: 1, name: 1, role: { - $arrayElemAt: ['$persondata.role', 0], + $arrayElemAt: ["$persondata.role", 0], }, isVisible: { - $arrayElemAt: ['$persondata.isVisible', 0], + $arrayElemAt: ["$persondata.isVisible", 0], }, hasSummary: { $ne: [ { $arrayElemAt: [ { - $arrayElemAt: ['$persondata.weeklySummaries.summary', 0], + $arrayElemAt: ["$persondata.weeklySummaries.summary", 0], }, 0, ], }, - '', + "", ], }, weeklycommittedHours: { $sum: [ { - $arrayElemAt: ['$persondata.weeklycommittedHours', 0], + $arrayElemAt: ["$persondata.weeklycommittedHours", 0], }, { - $ifNull: [{ $arrayElemAt: ['$persondata.missedHours', 0] }, 0], + $ifNull: [{ $arrayElemAt: ["$persondata.missedHours", 0] }, 0], }, ], }, @@ -257,10 +263,10 @@ const dashboardhelper = function () { }, { $lookup: { - from: 'timeEntries', - localField: 'personId', - foreignField: 'personId', - as: 'timeEntryData', + from: "timeEntries", + localField: "personId", + foreignField: "personId", + as: "timeEntryData", }, }, { @@ -273,15 +279,15 @@ const dashboardhelper = function () { weeklycommittedHours: 1, timeEntryData: { $filter: { - input: '$timeEntryData', - as: 'timeentry', + input: "$timeEntryData", + as: "timeentry", cond: { $and: [ { - $gte: ['$$timeentry.dateOfWork', pdtstart], + $gte: ["$$timeentry.dateOfWork", pdtstart], }, { - $lte: ['$$timeentry.dateOfWork', pdtend], + $lte: ["$$timeentry.dateOfWork", pdtend], }, ], }, @@ -291,7 +297,7 @@ const dashboardhelper = function () { }, { $unwind: { - path: '$timeEntryData', + path: "$timeEntryData", preserveNullAndEmptyArrays: true, }, }, @@ -306,18 +312,18 @@ const dashboardhelper = function () { totalSeconds: { $cond: [ { - $gte: ['$timeEntryData.totalSeconds', 0], + $gte: ["$timeEntryData.totalSeconds", 0], }, - '$timeEntryData.totalSeconds', + "$timeEntryData.totalSeconds", 0, ], }, isTangible: { $cond: [ { - $gte: ['$timeEntryData.totalSeconds', 0], + $gte: ["$timeEntryData.totalSeconds", 0], }, - '$timeEntryData.isTangible', + "$timeEntryData.isTangible", false, ], }, @@ -328,18 +334,18 @@ const dashboardhelper = function () { tangibletime: { $cond: [ { - $eq: ['$isTangible', true], + $eq: ["$isTangible", true], }, - '$totalSeconds', + "$totalSeconds", 0, ], }, intangibletime: { $cond: [ { - $eq: ['$isTangible', false], + $eq: ["$isTangible", false], }, - '$totalSeconds', + "$totalSeconds", 0, ], }, @@ -348,58 +354,65 @@ const dashboardhelper = function () { { $group: { _id: { - personId: '$personId', - weeklycommittedHours: '$weeklycommittedHours', - name: '$name', - role: '$role', - isVisible: '$isVisible', - hasSummary: '$hasSummary', + personId: "$personId", + weeklycommittedHours: "$weeklycommittedHours", + name: "$name", + role: "$role", + isVisible: "$isVisible", + hasSummary: "$hasSummary", }, totalSeconds: { - $sum: '$totalSeconds', + $sum: "$totalSeconds", }, tangibletime: { - $sum: '$tangibletime', + $sum: "$tangibletime", }, intangibletime: { - $sum: '$intangibletime', + $sum: "$intangibletime", }, }, }, { $project: { _id: 0, - personId: '$_id.personId', - name: '$_id.name', - role: '$_id.role', - isVisible: '$_id.isVisible', - hasSummary: '$_id.hasSummary', - weeklycommittedHours: '$_id.weeklycommittedHours', + personId: "$_id.personId", + name: "$_id.name", + role: "$_id.role", + isVisible: "$_id.isVisible", + hasSummary: "$_id.hasSummary", + weeklycommittedHours: "$_id.weeklycommittedHours", totaltime_hrs: { - $divide: ['$totalSeconds', 3600], + $divide: ["$totalSeconds", 3600], }, totaltangibletime_hrs: { - $divide: ['$tangibletime', 3600], + $divide: ["$tangibletime", 3600], }, totalintangibletime_hrs: { - $divide: ['$intangibletime', 3600], + $divide: ["$intangibletime", 3600], }, percentagespentintangible: { $cond: [ { - $eq: ['$totalSeconds', 0], + $eq: ["$totalSeconds", 0], }, 0, { $multiply: [ { - $divide: ['$tangibletime', '$totalSeconds'], + $divide: ["$tangibletime", "$totalSeconds"], }, 100, ], }, ], }, + timeOffFrom: { + $ifNull: ["$persondata.timeOffFrom", null], + }, + timeOffTill: { + $ifNull: ["$persondata.timeOffTill", null], + }, + currentDate: { $toDate: new Date() }, }, }, { @@ -420,14 +433,14 @@ const dashboardhelper = function () { const getUserLaborData = async function (userId) { try { const pdtStart = moment() - .tz('America/Los_Angeles') - .startOf('week') - .format('YYYY-MM-DD'); + .tz("America/Los_Angeles") + .startOf("week") + .format("YYYY-MM-DD"); const pdtEnd = moment() - .tz('America/Los_Angeles') - .endOf('week') - .format('YYYY-MM-DD'); + .tz("America/Los_Angeles") + .endOf("week") + .format("YYYY-MM-DD"); const user = await userProfile.findById({ _id: userId, @@ -457,7 +470,7 @@ const dashboardhelper = function () { personId: userId, role: user.role, isVisible: user.isVisible, - hasSummary: user.weeklySummaries[0].summary !== '', + hasSummary: user.weeklySummaries[0].summary !== "", weeklycommittedHours: user.weeklycommittedHours, name: `${user.firstName} ${user.lastName}`, totaltime_hrs: (tangibleSeconds + intangibleSeconds) / 3600, @@ -470,8 +483,8 @@ const dashboardhelper = function () { } catch (err) { return [ { - personId: 'error', - name: 'Error Error', + personId: "error", + name: "Error Error", totaltime_hrs: 0, totaltangibletime_hrs: 0, totalintangibletime_hrs: 0, @@ -482,8 +495,8 @@ const dashboardhelper = function () { }; const laborthismonth = function (userId, startDate, endDate) { - const fromdate = moment(startDate).format('YYYY-MM-DD'); - const todate = moment(endDate).format('YYYY-MM-DD'); + const fromdate = moment(startDate).format("YYYY-MM-DD"); + const todate = moment(endDate).format("YYYY-MM-DD"); return timeentry.aggregate([ { @@ -499,19 +512,19 @@ const dashboardhelper = function () { { $group: { _id: { - projectId: '$projectId', + projectId: "$projectId", }, labor: { - $sum: '$totalSeconds', + $sum: "$totalSeconds", }, }, }, { $lookup: { - from: 'projects', - localField: '_id.projectId', - foreignField: '_id', - as: 'project', + from: "projects", + localField: "_id.projectId", + foreignField: "_id", + as: "project", }, }, { @@ -520,13 +533,13 @@ const dashboardhelper = function () { projectName: { $ifNull: [ { - $arrayElemAt: ['$project.projectName', 0], + $arrayElemAt: ["$project.projectName", 0], }, - 'Undefined', + "Undefined", ], }, timeSpent_hrs: { - $divide: ['$labor', 3600], + $divide: ["$labor", 3600], }, }, }, @@ -534,8 +547,8 @@ const dashboardhelper = function () { }; const laborthisweek = function (userId, startDate, endDate) { - const fromdate = moment(startDate).format('YYYY-MM-DD'); - const todate = moment(endDate).format('YYYY-MM-DD'); + const fromdate = moment(startDate).format("YYYY-MM-DD"); + const todate = moment(endDate).format("YYYY-MM-DD"); return userProfile.aggregate([ { @@ -551,10 +564,10 @@ const dashboardhelper = function () { }, { $lookup: { - from: 'timeEntries', - localField: '_id', - foreignField: 'personId', - as: 'timeEntryData', + from: "timeEntries", + localField: "_id", + foreignField: "personId", + as: "timeEntryData", }, }, { @@ -562,18 +575,18 @@ const dashboardhelper = function () { weeklycommittedHours: 1, timeEntryData: { $filter: { - input: '$timeEntryData', - as: 'timeentry', + input: "$timeEntryData", + as: "timeentry", cond: { $and: [ { - $eq: ['$$timeentry.isTangible', true], + $eq: ["$$timeentry.isTangible", true], }, { - $gte: ['$$timeentry.dateOfWork', fromdate], + $gte: ["$$timeentry.dateOfWork", fromdate], }, { - $lte: ['$$timeentry.dateOfWork', todate], + $lte: ["$$timeentry.dateOfWork", todate], }, ], }, @@ -583,27 +596,27 @@ const dashboardhelper = function () { }, { $unwind: { - path: '$timeEntryData', + path: "$timeEntryData", preserveNullAndEmptyArrays: true, }, }, { $group: { _id: { - _id: '$_id', - weeklycommittedHours: '$weeklycommittedHours', + _id: "$_id", + weeklycommittedHours: "$weeklycommittedHours", }, effort: { - $sum: '$timeEntryData.totalSeconds', + $sum: "$timeEntryData.totalSeconds", }, }, }, { $project: { _id: 0, - weeklycommittedHours: '$_id.weeklycommittedHours', + weeklycommittedHours: "$_id.weeklycommittedHours", timeSpent_hrs: { - $divide: ['$effort', 3600], + $divide: ["$effort", 3600], }, }, }, @@ -611,8 +624,8 @@ const dashboardhelper = function () { }; const laborThisWeekByCategory = function (userId, startDate, endDate) { - const fromdate = moment(startDate).format('YYYY-MM-DD'); - const todate = moment(endDate).format('YYYY-MM-DD'); + const fromdate = moment(startDate).format("YYYY-MM-DD"); + const todate = moment(endDate).format("YYYY-MM-DD"); return userProfile.aggregate([ { @@ -628,10 +641,10 @@ const dashboardhelper = function () { }, { $lookup: { - from: 'timeEntries', - localField: '_id', - foreignField: 'personId', - as: 'timeEntryData', + from: "timeEntries", + localField: "_id", + foreignField: "personId", + as: "timeEntryData", }, }, { @@ -639,18 +652,18 @@ const dashboardhelper = function () { weeklycommittedHours: 1, timeEntryData: { $filter: { - input: '$timeEntryData', - as: 'timeentry', + input: "$timeEntryData", + as: "timeentry", cond: { $and: [ { - $eq: ['$$timeentry.isTangible', true], + $eq: ["$$timeentry.isTangible", true], }, { - $gte: ['$$timeentry.dateOfWork', fromdate], + $gte: ["$$timeentry.dateOfWork", fromdate], }, { - $lte: ['$$timeentry.dateOfWork', todate], + $lte: ["$$timeentry.dateOfWork", todate], }, ], }, @@ -660,37 +673,37 @@ const dashboardhelper = function () { }, { $unwind: { - path: '$timeEntryData', + path: "$timeEntryData", preserveNullAndEmptyArrays: true, }, }, { $group: { - _id: '$timeEntryData.projectId', + _id: "$timeEntryData.projectId", effort: { - $sum: '$timeEntryData.totalSeconds', + $sum: "$timeEntryData.totalSeconds", }, }, }, { $lookup: { - from: 'projects', - localField: '_id', - foreignField: '_id', - as: 'project', + from: "projects", + localField: "_id", + foreignField: "_id", + as: "project", }, }, { $unwind: { - path: '$project', + path: "$project", preserveNullAndEmptyArrays: true, }, }, { $group: { - _id: '$project.category', + _id: "$project.category", effort: { - $sum: '$effort', + $sum: "$effort", }, }, }, @@ -698,7 +711,7 @@ const dashboardhelper = function () { $project: { _id: 1, timeSpent_hrs: { - $divide: ['$effort', 3600], + $divide: ["$effort", 3600], }, }, }, diff --git a/src/models/userProfile.js b/src/models/userProfile.js index e3f8d4a48..762b61c02 100644 --- a/src/models/userProfile.js +++ b/src/models/userProfile.js @@ -1,9 +1,9 @@ -const mongoose = require('mongoose'); -const moment = require('moment-timezone'); +const mongoose = require("mongoose"); +const moment = require("moment-timezone"); const { Schema } = mongoose; -const validate = require('mongoose-validator'); -const bcrypt = require('bcryptjs'); +const validate = require("mongoose-validator"); +const bcrypt = require("bcryptjs"); const SALT_ROUNDS = 10; const nextDay = new Date(); @@ -15,11 +15,12 @@ const userProfileSchema = new Schema({ required: true, validate: { validator(v) { - const passwordregex = /(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/; + const passwordregex = + /(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/; return passwordregex.test(v); }, message: - '{VALUE} is not a valid password!password should be at least 8 charcaters long with uppercase, lowercase and number/special char.', + "{VALUE} is not a valid password!password should be at least 8 charcaters long with uppercase, lowercase and number/special char.", }, }, isActive: { type: Boolean, required: true, default: true }, @@ -47,7 +48,9 @@ const userProfileSchema = new Schema({ type: String, required: true, unique: true, - validate: [validate({ validator: 'isEmail', message: 'Email address is invalid' })], + validate: [ + validate({ validator: "isEmail", message: "Email address is invalid" }), + ], }, weeklycommittedHours: { type: Number, default: 10 }, weeklycommittedHoursHistory: [ @@ -60,13 +63,15 @@ const userProfileSchema = new Schema({ createdDate: { type: Date, required: true, default: nextDay }, lastModifiedDate: { type: Date, required: true, default: Date.now() }, reactivationDate: { type: Date }, - personalLinks: [{ _id: Schema.Types.ObjectId, Name: String, Link: { type: String } }], + personalLinks: [ + { _id: Schema.Types.ObjectId, Name: String, Link: { type: String } }, + ], adminLinks: [{ _id: Schema.Types.ObjectId, Name: String, Link: String }], - teams: [{ type: mongoose.SchemaTypes.ObjectId, ref: 'team' }], - projects: [{ type: mongoose.SchemaTypes.ObjectId, ref: 'project' }], + teams: [{ type: mongoose.SchemaTypes.ObjectId, ref: "team" }], + projects: [{ type: mongoose.SchemaTypes.ObjectId, ref: "project" }], badgeCollection: [ { - badge: { type: mongoose.SchemaTypes.ObjectId, ref: 'badge' }, + badge: { type: mongoose.SchemaTypes.ObjectId, ref: "badge" }, count: { type: Number, default: 0 }, earnedDate: { type: Array, default: [] }, lastModified: { type: Date, required: true, default: Date.now() }, @@ -79,20 +84,25 @@ const userProfileSchema = new Schema({ ], profilePic: { type: String }, infringements: [ - { date: { type: String, required: true }, description: { type: String, required: true } }, + { + date: { type: String, required: true }, + description: { type: String, required: true }, + }, ], location: { - userProvided: { type: String, default: '' }, + userProvided: { type: String, default: "" }, coords: { - lat: { type: Number, default: '' }, - lng: { type: Number, default: '' }, + lat: { type: Number, default: "" }, + lng: { type: Number, default: "" }, }, - country: { type: String, default: '' }, - city: { type: String, default: '' } - + country: { type: String, default: "" }, + city: { type: String, default: "" }, }, oldInfringements: [ - { date: { type: String, required: true }, description: { type: String, required: true } }, + { + date: { type: String, required: true }, + description: { type: String, required: true }, + }, ], privacySettings: { blueSquares: { type: Boolean, default: true }, @@ -104,7 +114,7 @@ const userProfileSchema = new Schema({ dueDate: { type: Date, required: true, - default: moment().tz('America/Los_Angeles').endOf('week'), + default: moment().tz("America/Los_Angeles").endOf("week"), }, summary: { type: String }, uploadDate: { type: Date }, @@ -134,17 +144,17 @@ const userProfileSchema = new Schema({ category: { type: String, enum: [ - 'Food', - 'Energy', - 'Housing', - 'Education', - 'Society', - 'Economics', - 'Stewardship', - 'Other', - 'Unspecified', + "Food", + "Energy", + "Housing", + "Education", + "Society", + "Economics", + "Stewardship", + "Other", + "Unspecified", ], - default: 'Other', + default: "Other", }, hrs: { type: Number, default: 0 }, }, @@ -152,48 +162,58 @@ const userProfileSchema = new Schema({ savedTangibleHrs: [Number], timeEntryEditHistory: [ { - date: { type: Date, required: true, default: moment().tz('America/Los_Angeles').toDate() }, + date: { + type: Date, + required: true, + default: moment().tz("America/Los_Angeles").toDate(), + }, initialSeconds: { type: Number, required: true }, newSeconds: { type: Number, required: true }, }, ], weeklySummaryNotReq: { type: Boolean, default: false }, - timeZone: { type: String, required: true, default: 'America/Los_Angeles' }, + timeZone: { type: String, required: true, default: "America/Los_Angeles" }, isVisible: { type: Boolean, default: false }, weeklySummaryOption: { type: String }, - bioPosted: { type: String, default: 'default' }, + bioPosted: { type: String, default: "default" }, isFirstTimelog: { type: Boolean, default: true }, teamCode: { type: String, - default: '', + default: "", validate: { validator(v) { const teamCoderegex = /^([a-zA-Z]-[a-zA-Z]{3}|[a-zA-Z]{5})$|^$/; return teamCoderegex.test(v); }, - message: - 'Please enter a code in the format of A-AAA or AAAAA', + message: "Please enter a code in the format of A-AAA or AAAAA", }, }, infoCollections: [ { areaName: { type: String }, areaContent: { type: String }, - }], + }, + ], + timeOffFrom: { type: Date, default: undefined }, + timeOffTill: { type: Date, default: undefined }, }); -userProfileSchema.pre('save', function (next) { +userProfileSchema.pre("save", function (next) { const user = this; - if (!user.isModified('password')) return next(); + if (!user.isModified("password")) return next(); return bcrypt .genSalt(SALT_ROUNDS) - .then(result => bcrypt.hash(user.password, result)) + .then((result) => bcrypt.hash(user.password, result)) .then((hash) => { user.password = hash; return next(); }) - .catch(error => next(error)); + .catch((error) => next(error)); }); -module.exports = mongoose.model('userProfile', userProfileSchema, 'userProfiles'); +module.exports = mongoose.model( + "userProfile", + userProfileSchema, + "userProfiles" +); From 9e5ae9875eb5422b5d6ec260d5617ab314f905a4 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Wed, 6 Dec 2023 20:01:06 -0800 Subject: [PATCH 186/272] experimenting with discriminators --- .../bmdashboard/bmMaterialsController.js | 12 ++++- src/models/bmdashboard/buildingMaterial.js | 49 +++++++++++++++++-- 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index a8090ebd9..c3dcd8c69 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -47,6 +47,8 @@ const bmMaterialsController = function (ItemMaterial, BuildingMaterial) { }; const bmPurchaseMaterials = async function (req, res) { + console.log(BuildingMaterial); + console.log(req.body); const { projectId, matTypeId, @@ -83,7 +85,10 @@ const bmMaterialsController = function (ItemMaterial, BuildingMaterial) { }; BuildingMaterial .create(newDoc) - .then(() => res.status(201).send()) + .then((result) => { + console.log('result new: ', result); + res.status(201).send(); + }) .catch(error => res.status(500).send(error)); return; } @@ -93,7 +98,10 @@ const bmMaterialsController = function (ItemMaterial, BuildingMaterial) { { $push: { purchaseRecord: newPurchaseRecord } }, ) .exec() - .then(() => res.status(201).send()) + .then((result) => { + console.log('result old: ', result); + res.status(201).send(); + }) .catch(error => res.status(500).send(error)); } catch (error) { res.status(500).send(error); diff --git a/src/models/bmdashboard/buildingMaterial.js b/src/models/bmdashboard/buildingMaterial.js index 4170443e0..d9a6be194 100644 --- a/src/models/bmdashboard/buildingMaterial.js +++ b/src/models/bmdashboard/buildingMaterial.js @@ -2,7 +2,14 @@ const mongoose = require('mongoose'); const { Schema } = mongoose; -const buildingMaterial = new Schema({ +const inventoryBaseSchema = new Schema({ + testField1: { type: String, default: 'hello world' }, + testField2: { type: Number, default: 101 }, +}); + +const InvBase = mongoose.model('InvBase', inventoryBaseSchema); + +const buildingMaterial = InvBase.discriminator('buildingMaterial', new Schema({ itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, project: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingProject' }, stockBought: { type: Number, default: 0 }, // total amount of item bought for use in the project @@ -25,6 +32,42 @@ const buildingMaterial = new Schema({ quantityUsed: { type: Number, required: true }, quantityWasted: { type: Number, required: true }, }], -}); +})); + +// common fields +const eventDefinition = { time: Date } +// specific fields +const ClickedLinkEventDefinition = {...eventDefinition, url: String} + +// completely separate models and collections on db level +const eventSchema = new mongoose.Schema(eventDefinition, options); +const Event = mongoose.model('Event', eventSchema); + +const ClickedLinkEvent = new mongoose.Schema(ClickedLinkEventDefinition , options); + +// const buildingMaterial = new Schema({ +// itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, +// project: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingProject' }, +// stockBought: { type: Number, default: 0 }, // total amount of item bought for use in the project +// stockUsed: { type: Number, default: 0 }, // total amount of item used successfully in the project +// stockWasted: { type: Number, default: 0 }, // total amount of item wasted/ruined/lost in the project +// stockAvailable: { type: Number, default: 0 }, // bought - (used + wasted) +// purchaseRecord: [{ +// _id: false, // do not add _id field to subdocument +// date: { type: Date, default: Date.now() }, +// requestedBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, +// quantity: { type: Number, required: true }, +// priority: { type: String, enum: ['Low', 'Medium', 'High'], required: true }, +// brand: String, +// status: { type: String, default: 'Pending', enum: ['Approved', 'Pending', 'Rejected'] }, +// }], +// updateRecord: [{ +// _id: false, +// date: { type: Date, required: true }, +// createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, +// quantityUsed: { type: Number, required: true }, +// quantityWasted: { type: Number, required: true }, +// }], +// }); -module.exports = mongoose.model('buildingMaterial', buildingMaterial, 'buildingMaterials'); +module.exports = buildingMaterial; From d54cc867e1efe980f5bfcc955ddfff34d5414802 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Thu, 7 Dec 2023 16:57:12 -0800 Subject: [PATCH 187/272] add baseInvSchema file, update material and reusable schemas with discriminators --- .../bmdashboard/bmMaterialsController.js | 14 +--- src/models/bmdashboard/baseInvSchema.js | 23 +++++++ src/models/bmdashboard/buildingMaterial.js | 66 +++---------------- src/models/bmdashboard/buildingReusable.js | 22 ++----- 4 files changed, 41 insertions(+), 84 deletions(-) create mode 100644 src/models/bmdashboard/baseInvSchema.js diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index c3dcd8c69..c79cbb56c 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -47,8 +47,6 @@ const bmMaterialsController = function (ItemMaterial, BuildingMaterial) { }; const bmPurchaseMaterials = async function (req, res) { - console.log(BuildingMaterial); - console.log(req.body); const { projectId, matTypeId, @@ -60,7 +58,7 @@ const bmMaterialsController = function (ItemMaterial, BuildingMaterial) { const newPurchaseRecord = { quantity, priority, - brand, + brandPref: brand, requestedBy: requestorId, }; try { @@ -85,10 +83,7 @@ const bmMaterialsController = function (ItemMaterial, BuildingMaterial) { }; BuildingMaterial .create(newDoc) - .then((result) => { - console.log('result new: ', result); - res.status(201).send(); - }) + .then(() => res.status(201).send()) .catch(error => res.status(500).send(error)); return; } @@ -98,10 +93,7 @@ const bmMaterialsController = function (ItemMaterial, BuildingMaterial) { { $push: { purchaseRecord: newPurchaseRecord } }, ) .exec() - .then((result) => { - console.log('result old: ', result); - res.status(201).send(); - }) + .then(() => res.status(201).send()) .catch(error => res.status(500).send(error)); } catch (error) { res.status(500).send(error); diff --git a/src/models/bmdashboard/baseInvSchema.js b/src/models/bmdashboard/baseInvSchema.js new file mode 100644 index 000000000..7eff943e7 --- /dev/null +++ b/src/models/bmdashboard/baseInvSchema.js @@ -0,0 +1,23 @@ +const mongoose = require('mongoose'); + +// base schema for all categories of inventory (Consumable, Material, Reusable, Tool, Equipment) +// this schema is extended by the individual schemas for each inventory type +// all documents derived from this schema are saved to the collection 'buildingInventoryItems' + +const baseInvSchema = mongoose.Schema({ + itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, + project: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingProject' }, + purchaseRecord: [{ + _id: false, // do not add _id field to subdocument + date: { type: Date, default: Date.now() }, + requestedBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + quantity: { type: Number, required: true }, + priority: { type: String, enum: ['Low', 'Medium', 'High'], required: true }, + brandPref: String, + status: { type: String, default: 'Pending', enum: ['Approved', 'Pending', 'Rejected'] }, + }], +}); + +const baseInv = mongoose.model('buildingInventory', baseInvSchema, 'buildingInventoryItems'); + +module.exports = baseInv; diff --git a/src/models/bmdashboard/buildingMaterial.js b/src/models/bmdashboard/buildingMaterial.js index d9a6be194..caf61e4c0 100644 --- a/src/models/bmdashboard/buildingMaterial.js +++ b/src/models/bmdashboard/buildingMaterial.js @@ -1,73 +1,23 @@ const mongoose = require('mongoose'); -const { Schema } = mongoose; +const baseInv = require('./baseInvSchema'); -const inventoryBaseSchema = new Schema({ - testField1: { type: String, default: 'hello world' }, - testField2: { type: Number, default: 101 }, -}); +// inherits all properties of baseInv schema using discriminator +// each document derived from this schema includes key field { __t: "buildingMaterial" } -const InvBase = mongoose.model('InvBase', inventoryBaseSchema); - -const buildingMaterial = InvBase.discriminator('buildingMaterial', new Schema({ - itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, - project: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingProject' }, +const buildingMaterial = baseInv.discriminator('buildingMaterial', new mongoose.Schema({ stockBought: { type: Number, default: 0 }, // total amount of item bought for use in the project - stockUsed: { type: Number, default: 0 }, // total amount of item used successfully in the project - stockWasted: { type: Number, default: 0 }, // total amount of item wasted/ruined/lost in the project - stockAvailable: { type: Number, default: 0 }, // bought - (used + wasted) - purchaseRecord: [{ - _id: false, // do not add _id field to subdocument - date: { type: Date, default: Date.now() }, - requestedBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - quantity: { type: Number, required: true }, - priority: { type: String, enum: ['Low', 'Medium', 'High'], required: true }, - brand: String, - status: { type: String, default: 'Pending', enum: ['Approved', 'Pending', 'Rejected'] }, - }], + stockUsed: { type: Number, default: 0 }, // stock that has been used up and cannot be reused + stockWasted: { type: Number, default: 0 }, // ruined or destroyed stock + stockAvailable: { type: Number, default: 0 }, // available = bought - (used + wasted/destroyed) updateRecord: [{ _id: false, date: { type: Date, required: true }, createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, quantityUsed: { type: Number, required: true }, quantityWasted: { type: Number, required: true }, + test: { type: String, default: 'testing this field' }, }], })); -// common fields -const eventDefinition = { time: Date } -// specific fields -const ClickedLinkEventDefinition = {...eventDefinition, url: String} - -// completely separate models and collections on db level -const eventSchema = new mongoose.Schema(eventDefinition, options); -const Event = mongoose.model('Event', eventSchema); - -const ClickedLinkEvent = new mongoose.Schema(ClickedLinkEventDefinition , options); - -// const buildingMaterial = new Schema({ -// itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, -// project: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingProject' }, -// stockBought: { type: Number, default: 0 }, // total amount of item bought for use in the project -// stockUsed: { type: Number, default: 0 }, // total amount of item used successfully in the project -// stockWasted: { type: Number, default: 0 }, // total amount of item wasted/ruined/lost in the project -// stockAvailable: { type: Number, default: 0 }, // bought - (used + wasted) -// purchaseRecord: [{ -// _id: false, // do not add _id field to subdocument -// date: { type: Date, default: Date.now() }, -// requestedBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, -// quantity: { type: Number, required: true }, -// priority: { type: String, enum: ['Low', 'Medium', 'High'], required: true }, -// brand: String, -// status: { type: String, default: 'Pending', enum: ['Approved', 'Pending', 'Rejected'] }, -// }], -// updateRecord: [{ -// _id: false, -// date: { type: Date, required: true }, -// createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, -// quantityUsed: { type: Number, required: true }, -// quantityWasted: { type: Number, required: true }, -// }], -// }); - module.exports = buildingMaterial; diff --git a/src/models/bmdashboard/buildingReusable.js b/src/models/bmdashboard/buildingReusable.js index 1d0503010..1f2ceaa48 100644 --- a/src/models/bmdashboard/buildingReusable.js +++ b/src/models/bmdashboard/buildingReusable.js @@ -1,22 +1,14 @@ const mongoose = require('mongoose'); -const { Schema } = mongoose; +const baseInv = require('./baseInvSchema'); -const buildingReusable = new Schema({ - itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, - project: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingProject' }, +// inherits all properties of baseInv schema using discriminator +// each document derived from this schema includes key field { __t: "buildingReusable" } + +const buildingReusable = baseInv.discriminator('buildingReusable', new mongoose.Schema({ stockBought: { type: Number, default: 0 }, stockDestroyed: { type: Number, default: 0 }, stockAvailable: { type: Number, default: 0 }, - purchaseRecord: [{ - _id: false, // do not add _id field to subdocument - date: { type: Date, default: Date.now() }, - requestedBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - quantity: { type: Number, required: true }, - priority: { type: String, enum: ['Low', 'Medium', 'High'], required: true }, - brand: String, - status: { type: String, default: 'Pending', enum: ['Approved', 'Pending', 'Rejected'] }, - }], updateRecord: [{ _id: false, date: { type: Date, required: true }, @@ -24,6 +16,6 @@ const buildingReusable = new Schema({ quantityUsed: { type: Number, required: true }, quantityDestroyed: { type: Number, required: true }, }], -}); +})); -module.exports = mongoose.model('buildingReusable', buildingReusable, 'buildingReusables'); +module.exports = buildingReusable; From e799a5ed88bdd7bdf710fb6898babb5249ffef2e Mon Sep 17 00:00:00 2001 From: Shengwei Peng Date: Fri, 8 Dec 2023 12:56:53 -0500 Subject: [PATCH 188/272] Fix: Assigned badges have no earned date - Modified earned date format function in userHelper.js - Added data validation for earned date and badge count mismatch in badgeController.js - Added fillEarnedDateToMatchCount function to resolve earned date and badge count mismatch in badgeController.js - Refactored data validation for duplicate badge id in badgeController.js - Added data validation for badge count should greater than 0 in badgeController.js - Added formatDate function to format date to MMM-DD-YY in badgeController.js --- src/controllers/badgeController.js | 205 ++++++++++++++++++++--------- src/helpers/userHelper.js | 34 +++-- 2 files changed, 167 insertions(+), 72 deletions(-) diff --git a/src/controllers/badgeController.js b/src/controllers/badgeController.js index 366c9323e..a438df505 100644 --- a/src/controllers/badgeController.js +++ b/src/controllers/badgeController.js @@ -3,10 +3,11 @@ const UserProfile = require('../models/userProfile'); const { hasPermission } = require('../utilities/permissions'); const escapeRegex = require('../utilities/escapeRegex'); const cache = require('../utilities/nodeCache')(); +// const userHelper = require('../helpers/userHelper'); const badgeController = function (Badge) { const getAllBadges = async function (req, res) { - if (!await hasPermission(req.body.requestor, 'seeBadges')) { + if (!(await hasPermission(req.body.requestor, 'seeBadges'))) { res.status(403).send('You are not authorized to view all badge data.'); return; } @@ -14,10 +15,11 @@ const badgeController = function (Badge) { Badge.find( {}, 'badgeName type multiple weeks months totalHrs people imageUrl category project ranking description showReport', - ).populate({ - path: 'project', - select: '_id projectName', - }) + ) + .populate({ + path: 'project', + select: '_id projectName', + }) .sort({ ranking: 1, badgeName: 1, @@ -26,8 +28,51 @@ const badgeController = function (Badge) { .catch(error => res.status(404).send(error)); }; + /** + * Updated Date: 12/06/2023 + * Updated By: Shengwei + * Function added: + * - Added data validation for earned date and badge count mismatch. + * - Added fillEarnedDateToMatchCount function to resolve earned date and badge count mismatch. + * - Refactored data validation for duplicate badge id. + * - Added data validation for badge count should greater than 0. + * - Added formatDate function to format date to MMM-DD-YY. + */ + + const formatDate = () => { + const currentDate = new Date(Date.now()); + const monthNames = [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec', + ]; + + const month = monthNames[currentDate.getMonth()]; + const day = currentDate.getDate(); + const year = currentDate.getFullYear().toString().slice(-2); // Get last two digits of the year + + return `${month}-${day}-${year}`; + }; + + const fillEarnedDateToMatchCount = (earnedDate, count) => { + const result = [...earnedDate]; + while (result.length < count) { + result.push(formatDate()); + } + return result; + }; + const assignBadges = async function (req, res) { - if (!await hasPermission(req.body.requestor, 'assignBadges')) { + if (!(await hasPermission(req.body.requestor, 'assignBadges'))) { res.status(403).send('You are not authorized to assign badges.'); return; } @@ -39,63 +84,90 @@ const badgeController = function (Badge) { res.status(400).send('Can not find the user to be assigned.'); return; } - const grouped = req.body.badgeCollection.reduce((groupd, item) => { - const propertyValue = item.badge; - groupd[propertyValue] = (groupd[propertyValue] || 0) + 1; - return groupd; - }, {}); - const result = Object.keys(grouped).every(bdge => grouped[bdge] <= 1); - if (result) { - record.badgeCollection = req.body.badgeCollection; - - if (cache.hasCache(`user-${userToBeAssigned}`)) cache.removeCache(`user-${userToBeAssigned}`); - - record.save() - .then(results => res.status(201).send(results._id)) - .catch(errors => res.status(500).send(errors)); - } else { - res.status(500).send('Duplicate badges sent in.'); + const badgeCounts = {}; + // This line is using the forEach function to group badges in the badgeCollection + // array in the request body. + // Validation: No duplicate badge id; + try { + req.body.badgeCollection.forEach((element) => { + if (badgeCounts[element.badge]) { + res.status(500).send('Duplicate badges sent in.'); + return; + } + badgeCounts[element.badge] = element.count; + // Validation: count should be greater than 0 + if (element.count < 1) { + throw new Error('Badge count should be greater than 0.'); + } + if (element.count !== element.earnedDate.length) { + element.earnedDate = fillEarnedDateToMatchCount( + element.earnedDate, + element.count, + ); + } + }); + } catch (err) { + res.status(500).send('Internal Err: Badge Collection.'); + return; } + record.badgeCollection = req.body.badgeCollection; + + if (cache.hasCache(`user-${userToBeAssigned}`)) { cache.removeCache(`user-${userToBeAssigned}`); } + // Save Updated User Profile + record + .save() + .then(results => res.status(201).send(results._id)) + .catch(errors => res.status(500).send(errors)); }); }; const postBadge = async function (req, res) { - if (!await hasPermission(req.body.requestor, 'createBadges')) { - res.status(403).send({ error: 'You are not authorized to create new badges.' }); + if (!(await hasPermission(req.body.requestor, 'createBadges'))) { + res + .status(403) + .send({ error: 'You are not authorized to create new badges.' }); return; } - Badge.find({ badgeName: { $regex: escapeRegex(req.body.badgeName), $options: 'i' } }) - .then((result) => { - if (result.length > 0) { - res.status(400).send({ error: `Another badge with name ${result[0].badgeName} already exists. Sorry, but badge names should be like snowflakes, no two should be the same. Please choose a different name for this badge so it can be proudly unique.` }); - return; - } - const badge = new Badge(); - - badge.badgeName = req.body.badgeName; - badge.category = req.body.category; - badge.type = req.body.type; - badge.multiple = req.body.multiple; - badge.totalHrs = req.body.totalHrs; - badge.weeks = req.body.weeks; - badge.months = req.body.months; - badge.people = req.body.people; - badge.project = req.body.project; - badge.imageUrl = req.body.imageUrl; - badge.ranking = req.body.ranking; - badge.description = req.body.description; - badge.showReport = req.body.showReport; - - badge.save() - .then(results => res.status(201).send(results)) - .catch(errors => res.status(500).send(errors)); - }); + Badge.find({ + badgeName: { $regex: escapeRegex(req.body.badgeName), $options: 'i' }, + }).then((result) => { + if (result.length > 0) { + res + .status(400) + .send({ + error: `Another badge with name ${result[0].badgeName} already exists. Sorry, but badge names should be like snowflakes, no two should be the same. Please choose a different name for this badge so it can be proudly unique.`, + }); + return; + } + const badge = new Badge(); + + badge.badgeName = req.body.badgeName; + badge.category = req.body.category; + badge.type = req.body.type; + badge.multiple = req.body.multiple; + badge.totalHrs = req.body.totalHrs; + badge.weeks = req.body.weeks; + badge.months = req.body.months; + badge.people = req.body.people; + badge.project = req.body.project; + badge.imageUrl = req.body.imageUrl; + badge.ranking = req.body.ranking; + badge.description = req.body.description; + badge.showReport = req.body.showReport; + + badge + .save() + .then(results => res.status(201).send(results)) + .catch(errors => res.status(500).send(errors)); + }); }; const deleteBadge = async function (req, res) { - if (!await hasPermission(req.body.requestor, 'deleteBadges')) { - res.status(403).send({ error: 'You are not authorized to delete badges.' }); + if (!(await hasPermission(req.body.requestor, 'deleteBadges'))) { + res + .status(403) + .send({ error: 'You are not authorized to delete badges.' }); return; } const { badgeId } = req.params; @@ -104,19 +176,33 @@ const badgeController = function (Badge) { res.status(400).send({ error: 'No valid records found' }); return; } - const removeBadgeFromProfile = UserProfile.updateMany({}, { $pull: { badgeCollection: { badge: record._id } } }).exec(); + const removeBadgeFromProfile = UserProfile.updateMany( + {}, + { $pull: { badgeCollection: { badge: record._id } } }, + ).exec(); const deleteRecord = record.remove(); Promise.all([removeBadgeFromProfile, deleteRecord]) - .then(res.status(200).send({ message: 'Badge successfully deleted and user profiles updated' })) - .catch((errors) => { res.status(500).send(errors); }); - }) - .catch((error) => { res.status(500).send(error); }); + .then( + res + .status(200) + .send({ + message: 'Badge successfully deleted and user profiles updated', + }), + ) + .catch((errors) => { + res.status(500).send(errors); + }); + }).catch((error) => { + res.status(500).send(error); + }); }; const putBadge = async function (req, res) { - if (!await hasPermission(req.body.requestor, 'updateBadges')) { - res.status(403).send({ error: 'You are not authorized to update badges.' }); + if (!(await hasPermission(req.body.requestor, 'updateBadges'))) { + res + .status(403) + .send({ error: 'You are not authorized to update badges.' }); return; } const { badgeId } = req.params; @@ -129,7 +215,6 @@ const badgeController = function (Badge) { // store onto Azure and return url } - const data = { badgeName: req.body.name || req.body.badgeName, description: req.body.description, diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index f639a4d37..b25328e28 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -27,21 +27,31 @@ const userHelper = function () { }); }; + // Updated By: Shengwei + // Updated Date: 12/08/2023 + // Update format to "MMM-DD-YY" from "YYYY-MMM-DD" (Confirmed with Jae) const earnedDateBadge = () => { - const today = new Date(); - const yyyy = today.getFullYear(); - // Add 1 beacuse the month start at zero - let mm = today.getMonth() + 1; - let dd = today.getDate(); - - // eslint-disable-next-line no-unused-expressions - mm = mm < 10 ? `0${mm}` : mm; - // eslint-disable-next-line no-unused-expressions - dd = dd < 10 ? `0${dd}` : dd; + const currentDate = new Date(Date.now()); + const monthNames = [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec', + ]; - const formatedDate = `${yyyy}-${mm}-${dd}`; + const month = monthNames[currentDate.getMonth()]; + const day = currentDate.getDate(); + const year = currentDate.getFullYear().toString().slice(-2); // Get last two digits of the year - return formatedDate; + return `${month}-${day}-${year}`; }; const getUserName = async function (userId) { From 07835ede44e255d2e8705608a89ce16a61728fb6 Mon Sep 17 00:00:00 2001 From: Shengwei Peng Date: Fri, 8 Dec 2023 13:11:35 -0500 Subject: [PATCH 189/272] Update: Modified date format function - Update fromatDate in badgeController using moment timezone library - Update earnedDateBadge in userHelper using moment timezone library --- src/controllers/badgeController.js | 22 ++-------------------- src/helpers/userHelper.js | 22 ++-------------------- 2 files changed, 4 insertions(+), 40 deletions(-) diff --git a/src/controllers/badgeController.js b/src/controllers/badgeController.js index a438df505..89c47ba79 100644 --- a/src/controllers/badgeController.js +++ b/src/controllers/badgeController.js @@ -41,28 +41,10 @@ const badgeController = function (Badge) { const formatDate = () => { const currentDate = new Date(Date.now()); - const monthNames = [ - 'Jan', - 'Feb', - 'Mar', - 'Apr', - 'May', - 'Jun', - 'Jul', - 'Aug', - 'Sep', - 'Oct', - 'Nov', - 'Dec', - ]; - - const month = monthNames[currentDate.getMonth()]; - const day = currentDate.getDate(); - const year = currentDate.getFullYear().toString().slice(-2); // Get last two digits of the year - - return `${month}-${day}-${year}`; + return moment(currentDate).tz('America/Los_Angeles').format(); }; + const fillEarnedDateToMatchCount = (earnedDate, count) => { const result = [...earnedDate]; while (result.length < count) { diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index b25328e28..c9d5ca1bf 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -15,6 +15,7 @@ const hasPermission = require("../utilities/permissions"); const Reason = require("../models/reason"); const token = require("../models/profileInitialSetupToken"); + const userHelper = function () { const getTeamMembers = function (user) { const userId = mongoose.Types.ObjectId(user._id); @@ -32,26 +33,7 @@ const userHelper = function () { // Update format to "MMM-DD-YY" from "YYYY-MMM-DD" (Confirmed with Jae) const earnedDateBadge = () => { const currentDate = new Date(Date.now()); - const monthNames = [ - 'Jan', - 'Feb', - 'Mar', - 'Apr', - 'May', - 'Jun', - 'Jul', - 'Aug', - 'Sep', - 'Oct', - 'Nov', - 'Dec', - ]; - - const month = monthNames[currentDate.getMonth()]; - const day = currentDate.getDate(); - const year = currentDate.getFullYear().toString().slice(-2); // Get last two digits of the year - - return `${month}-${day}-${year}`; + return moment(currentDate).tz('America/Los_Angeles').format(); }; const getUserName = async function (userId) { From 1e08bdbf405f756e40fb36fb93f949bb8ea9b8b8 Mon Sep 17 00:00:00 2001 From: Shengwei Peng Date: Fri, 8 Dec 2023 13:35:59 -0500 Subject: [PATCH 190/272] Fix: Added format MMM-DD-YY for moment format function --- src/controllers/badgeController.js | 4 ++-- src/helpers/userHelper.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/controllers/badgeController.js b/src/controllers/badgeController.js index 89c47ba79..4c92bd9a5 100644 --- a/src/controllers/badgeController.js +++ b/src/controllers/badgeController.js @@ -1,9 +1,9 @@ +const moment = require('moment-timezone'); const mongoose = require('mongoose'); const UserProfile = require('../models/userProfile'); const { hasPermission } = require('../utilities/permissions'); const escapeRegex = require('../utilities/escapeRegex'); const cache = require('../utilities/nodeCache')(); -// const userHelper = require('../helpers/userHelper'); const badgeController = function (Badge) { const getAllBadges = async function (req, res) { @@ -41,7 +41,7 @@ const badgeController = function (Badge) { const formatDate = () => { const currentDate = new Date(Date.now()); - return moment(currentDate).tz('America/Los_Angeles').format(); + return moment(currentDate).tz('America/Los_Angeles').format('MMM-DD-YY'); }; diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index c9d5ca1bf..fa0115271 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -33,7 +33,7 @@ const userHelper = function () { // Update format to "MMM-DD-YY" from "YYYY-MMM-DD" (Confirmed with Jae) const earnedDateBadge = () => { const currentDate = new Date(Date.now()); - return moment(currentDate).tz('America/Los_Angeles').format(); + return moment(currentDate).tz('America/Los_Angeles').format('MMM-DD-YY'); }; const getUserName = async function (userId) { From a63f976b36e4df494356409759803e4bc817e6f8 Mon Sep 17 00:00:00 2001 From: Shengwei Peng Date: Fri, 8 Dec 2023 15:02:00 -0500 Subject: [PATCH 191/272] Added a logger for the function responsible for filling mismatched badge earned dates --- src/controllers/badgeController.js | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/controllers/badgeController.js b/src/controllers/badgeController.js index 4c92bd9a5..11ee56ea4 100644 --- a/src/controllers/badgeController.js +++ b/src/controllers/badgeController.js @@ -4,6 +4,7 @@ const UserProfile = require('../models/userProfile'); const { hasPermission } = require('../utilities/permissions'); const escapeRegex = require('../utilities/escapeRegex'); const cache = require('../utilities/nodeCache')(); +const logger = require('../startup/logger'); const badgeController = function (Badge) { const getAllBadges = async function (req, res) { @@ -44,7 +45,6 @@ const badgeController = function (Badge) { return moment(currentDate).tz('America/Los_Angeles').format('MMM-DD-YY'); }; - const fillEarnedDateToMatchCount = (earnedDate, count) => { const result = [...earnedDate]; while (result.length < count) { @@ -86,6 +86,12 @@ const badgeController = function (Badge) { element.earnedDate, element.count, ); + element.lastModified = Date.now(); + logger.logInfo( + `Badge count and earned dates mismatched found. ${Date.now()} was generated for user ${userToBeAssigned}. Badge record ID ${ + element._id + }; Badge Type ID ${element.badge}`, + ); } }); } catch (err) { @@ -94,7 +100,9 @@ const badgeController = function (Badge) { } record.badgeCollection = req.body.badgeCollection; - if (cache.hasCache(`user-${userToBeAssigned}`)) { cache.removeCache(`user-${userToBeAssigned}`); } + if (cache.hasCache(`user-${userToBeAssigned}`)) { + cache.removeCache(`user-${userToBeAssigned}`); + } // Save Updated User Profile record .save() @@ -115,11 +123,9 @@ const badgeController = function (Badge) { badgeName: { $regex: escapeRegex(req.body.badgeName), $options: 'i' }, }).then((result) => { if (result.length > 0) { - res - .status(400) - .send({ - error: `Another badge with name ${result[0].badgeName} already exists. Sorry, but badge names should be like snowflakes, no two should be the same. Please choose a different name for this badge so it can be proudly unique.`, - }); + res.status(400).send({ + error: `Another badge with name ${result[0].badgeName} already exists. Sorry, but badge names should be like snowflakes, no two should be the same. Please choose a different name for this badge so it can be proudly unique.`, + }); return; } const badge = new Badge(); @@ -166,11 +172,9 @@ const badgeController = function (Badge) { Promise.all([removeBadgeFromProfile, deleteRecord]) .then( - res - .status(200) - .send({ - message: 'Badge successfully deleted and user profiles updated', - }), + res.status(200).send({ + message: 'Badge successfully deleted and user profiles updated', + }), ) .catch((errors) => { res.status(500).send(errors); From b2608a817416abce1293a6780704ff3543888514 Mon Sep 17 00:00:00 2001 From: Nathan Hoffman Date: Fri, 8 Dec 2023 14:41:38 -0800 Subject: [PATCH 192/272] Update minimum permissions --- src/utilities/createInitialPermissions.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/utilities/createInitialPermissions.js b/src/utilities/createInitialPermissions.js index 9cdf7f9e0..86a79b94c 100644 --- a/src/utilities/createInitialPermissions.js +++ b/src/utilities/createInitialPermissions.js @@ -6,6 +6,9 @@ const permissionsRoles = [ { roleName: 'Administrator', permissions: [ + // Reports + 'getWeeklySummaries', + 'getReports', // Doesn't do anything on back-end. // Badges 'seeBadges', 'assignBadges', @@ -65,8 +68,7 @@ const permissionsRoles = [ // General 'getUserProfiles', 'getProjectMembers', - 'getWeeklySummaries', - // 'getReportsPage',? + 'getTimeZoneAPIKey', 'checkLeadTeamOfXplus', ], @@ -97,6 +99,7 @@ const permissionsRoles = [ 'getAllInvType', 'postInvType', 'getWeeklySummaries', + 'getReports', 'getTimeZoneAPIKey', 'checkLeadTeamOfXplus', ], @@ -124,7 +127,6 @@ const permissionsRoles = [ 'putInvType', 'getAllInvType', 'postInvType', - 'getWeeklySummaries', 'getTimeZoneAPIKey', 'checkLeadTeamOfXplus', ], @@ -151,7 +153,6 @@ const permissionsRoles = [ 'putInvType', 'getAllInvType', 'postInvType', - 'getWeeklySummaries', 'getTimeZoneAPIKey', 'checkLeadTeamOfXplus', ], @@ -212,6 +213,7 @@ const permissionsRoles = [ 'getAllInvType', 'postInvType', 'getWeeklySummaries', + 'getReports', 'getTimeZoneAPIKey', 'checkLeadTeamOfXplus', 'editTeamCode', From 778217620b5fb6c11e3522f671e35cdd45d758ef Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Fri, 8 Dec 2023 14:47:04 -0800 Subject: [PATCH 193/272] add single inventory file to hold base and extended schemas --- .../bmdashboard/buildingInventoryItem.js | 94 +++++++++++++++++++ src/startup/routes.js | 2 +- 2 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 src/models/bmdashboard/buildingInventoryItem.js diff --git a/src/models/bmdashboard/buildingInventoryItem.js b/src/models/bmdashboard/buildingInventoryItem.js new file mode 100644 index 000000000..db5c3012c --- /dev/null +++ b/src/models/bmdashboard/buildingInventoryItem.js @@ -0,0 +1,94 @@ +const mongoose = require('mongoose'); + +//---------------------- +// BASE INVENTORY SCHEMA +//---------------------- + +// base schema for all categories of inventory (Consumable, Material, Reusable, Tool, Equipment) +// this schema is extended by the individual schemas for each inventory type +// all documents derived from this schema are saved to the collection 'buildingInventoryItems' + +const baseInvSchema = mongoose.Schema({ + itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, + project: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingProject' }, + purchaseRecord: [{ + _id: false, // do not add _id field to subdocument + date: { type: Date, default: Date.now() }, + requestedBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + quantity: { type: Number, required: true }, + priority: { type: String, enum: ['Low', 'Medium', 'High'], required: true }, + brandPref: String, + status: { type: String, default: 'Pending', enum: ['Approved', 'Pending', 'Rejected'] }, + }], +}); + +const baseInv = mongoose.model('buildingInventory', baseInvSchema, 'buildingInventoryItems'); + +//----------------- +// MATERIALS SCHEMA +//----------------- + +// inherits all properties of baseInv schema using discriminator +// each document derived from this schema includes key field { __t: "material" } +// ex: sand, stone, bricks, lumber, insulation + +const buildingMaterial = baseInv.discriminator('material', new mongoose.Schema({ + stockBought: { type: Number, default: 0 }, // total amount of item bought for use in the project + stockUsed: { type: Number, default: 0 }, // stock that has been used up and cannot be reused + stockWasted: { type: Number, default: 0 }, // ruined or destroyed stock + stockAvailable: { type: Number, default: 0 }, // available = bought - (used + wasted/destroyed) + updateRecord: [{ + _id: false, + date: { type: Date, required: true }, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + quantityUsed: { type: Number, required: true }, + quantityWasted: { type: Number, required: true }, + }], +})); + +//----------------- +// REUSABLES SCHEMA +//----------------- + +// inherits all properties of baseInv schema using discriminator +// each document derived from this schema includes key field { __t: "reusable" } +// ex: hammers, screwdrivers, mallets, brushes, gloves + +const buildingReusable = baseInv.discriminator('reusable', new mongoose.Schema({ + stockBought: { type: Number, default: 0 }, + stockDestroyed: { type: Number, default: 0 }, + stockAvailable: { type: Number, default: 0 }, + updateRecord: [{ + _id: false, + date: { type: Date, required: true }, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + quantityUsed: { type: Number, required: true }, + quantityDestroyed: { type: Number, required: true }, + }], +})); + +//----------------- +// CONSUMABLES SCHEMA +//----------------- + +// inherits all properties of baseInv schema using discriminator +// each document derived from this schema includes key field { __t: "consumable" } +// ex: screws, nails, staples + +//------------- +// TOOLS SCHEMA +//------------- + +// inherits all properties of baseInv schema using discriminator +// each document derived from this schema includes key field { __t: "tool" } +// ex: power drills, wheelbarrows, shovels + +// const buildingTool = baseInv.discriminator('tool', new mongoose.Schema({ + +// })); + + +module.exports = { + buildingMaterial, + buildingReusable, +}; diff --git a/src/startup/routes.js b/src/startup/routes.js index 2d95ea639..5f77a413d 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -24,7 +24,7 @@ const inventoryItemMaterial = require('../models/inventoryItemMaterial'); const mapLocations = require('../models/mapLocation'); const buildingProject = require('../models/bmdashboard/buildingProject'); const buildingInventoryType = require('../models/bmdashboard/buildingInventoryType'); -const buildingMaterial = require('../models/bmdashboard/buildingMaterial'); +const { buildingMaterial } = require('../models/bmdashboard/buildingInventoryItem'); const userProfileRouter = require('../routes/userProfileRouter')(userProfile); const badgeRouter = require('../routes/badgeRouter')(badge); From 5dd37d817997961c79b5db65a059d39b771116a4 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Sat, 9 Dec 2023 14:55:41 -0800 Subject: [PATCH 194/272] add building tool inv to schema file --- .../bmdashboard/buildingInventoryItem.js | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/models/bmdashboard/buildingInventoryItem.js b/src/models/bmdashboard/buildingInventoryItem.js index db5c3012c..0d357ae7a 100644 --- a/src/models/bmdashboard/buildingInventoryItem.js +++ b/src/models/bmdashboard/buildingInventoryItem.js @@ -83,9 +83,35 @@ const buildingReusable = baseInv.discriminator('reusable', new mongoose.Schema({ // each document derived from this schema includes key field { __t: "tool" } // ex: power drills, wheelbarrows, shovels -// const buildingTool = baseInv.discriminator('tool', new mongoose.Schema({ - -// })); +const buildingTool = baseInv.discriminator('tool', new mongoose.Schema({ + code: { type: Number, required: true }, // add function to create code for on-site tool tracking + purchaseStatus: { type: String, enum: ['Rental', 'Purchase'], required: true }, + // add discriminator based on rental or purchase so these fields are required if tool is rented + rentedOnDate: Date, + rentalDue: Date, + userResponsible: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + purchaseRecord: [{ // track purchase/rental requests + _id: false, // do not add _id field to subdocument + date: { type: Date, default: Date.now() }, + requestedBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + priority: { type: String, enum: ['Low', 'Medium', 'High'], required: true }, + brand: String, + status: { type: String, default: 'Pending', enum: ['Approved', 'Pending', 'Rejected'] }, + }], + updateRecord: [{ // track tool condition updates + _id: false, + date: { type: Date, default: Date.now() }, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + condition: { type: String, enum: ['Good', 'Needs Repair', 'Out of Order'] }, + }], + logRecord: [{ // track tool daily check in/out and use + _id: false, + date: { type: Date, default: Date.now() }, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + responsibleUser: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + type: { type: String, enum: ['Check In', 'Check Out'] }, // default = opposite of current log status? + }], +})); module.exports = { From 6f36edd374fe2e4052a79a36649cfc67b5302394 Mon Sep 17 00:00:00 2001 From: Shengwei Peng Date: Sun, 10 Dec 2023 00:16:26 -0500 Subject: [PATCH 195/272] Update error handling in badge assginment feature --- src/controllers/badgeController.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/controllers/badgeController.js b/src/controllers/badgeController.js index 11ee56ea4..5dd2113a6 100644 --- a/src/controllers/badgeController.js +++ b/src/controllers/badgeController.js @@ -73,8 +73,9 @@ const badgeController = function (Badge) { try { req.body.badgeCollection.forEach((element) => { if (badgeCounts[element.badge]) { - res.status(500).send('Duplicate badges sent in.'); - return; + throw new Error('Duplicate badges sent in.'); + // res.status(500).send('Duplicate badges sent in.'); + // return; } badgeCounts[element.badge] = element.count; // Validation: count should be greater than 0 @@ -95,7 +96,7 @@ const badgeController = function (Badge) { } }); } catch (err) { - res.status(500).send('Internal Err: Badge Collection.'); + res.status(500).send(`Internal Error: Badge Collection. ${ err.message}`); return; } record.badgeCollection = req.body.badgeCollection; @@ -107,7 +108,10 @@ const badgeController = function (Badge) { record .save() .then(results => res.status(201).send(results._id)) - .catch(errors => res.status(500).send(errors)); + .catch((err) => { + logger.logException(err); + res.status(500).send('Internal Error: Unable to save the record.'); + }); }); }; From 4a9deec48787963f3993f3a8faeb232280623d15 Mon Sep 17 00:00:00 2001 From: wang9hu Date: Sat, 9 Dec 2023 23:53:58 -0800 Subject: [PATCH 196/272] integrate ownerMessage and ownerStandardMessage, simplify route and controller logic --- src/controllers/ownerMessageController.js | 88 +++++++++++------------ src/models/ownerMessage.js | 3 +- src/routes/ownerMessageRouter.js | 11 ++- src/startup/routes.js | 6 +- 4 files changed, 52 insertions(+), 56 deletions(-) diff --git a/src/controllers/ownerMessageController.js b/src/controllers/ownerMessageController.js index b4a00431b..f09a32030 100644 --- a/src/controllers/ownerMessageController.js +++ b/src/controllers/ownerMessageController.js @@ -1,63 +1,61 @@ const ownerMessageController = function (OwnerMessage) { - const postOwnerMessage = function (req, res) { - if (req.body.requestor.role !== 'Owner') { - res.status(403).send('You are not authorized to create messages!'); + const getOwnerMessage = async function (req, res) { + try { + const results = await OwnerMessage.find({}); + if (results.length === 0) { // first time initialization + const ownerMessage = new OwnerMessage(); + await ownerMessage.save(); + res.status(200).send({ ownerMessage }); + } else { + res.status(200).send({ ownerMessage: results[0] }); + } + } catch (error) { + res.status(404).send(error); } - const ownerMessage = new OwnerMessage(); - ownerMessage.message = req.body.newMessage; - ownerMessage.save().then(() => res.status(201).json({ - _serverMessage: 'Message succesfuly created!', - ownerMessage, - })).catch(err => res.status(500).send({ err })); - }; - - const getOwnerMessage = function (req, res) { - OwnerMessage.find() - .then(results => res.status(200).send(results)) - .catch(error => res.status(404).send(error)); }; - const deleteOwnerMessage = function (req, res) { + const updateOwnerMessage = async function (req, res) { if (req.body.requestor.role !== 'Owner') { - res.status(403).send('You are not authorized to delete messages!'); + res.status(403).send('You are not authorized to create messages!'); + } + const { standardMessage, message } = req.body; + try { + const results = await OwnerMessage.find({}); + const ownerMessage = results[0]; + if (standardMessage) { + ownerMessage.standardMessage = standardMessage; + } else { + ownerMessage.message = message; + } + await ownerMessage.save(); + res.status(201).send({ + _serverMessage: 'Update successfully!', + ownerMessage: { standardMessage, message }, + }); + } catch (error) { + res.status(500).send(error); } - OwnerMessage.deleteMany({}) - .then((result) => { - result - .then(res.status(200).send({ _serverMessage: 'Message deleted!' })) - .catch((error) => { - res.status(400).send(error); - }); - }) - .catch((error) => { - res.status(400).send(error); - }); }; - const updateOwnerMessage = function (req, res) { + const deleteOwnerMessage = async function (req, res) { if (req.body.requestor.role !== 'Owner') { - res.status(403).send('You are not authorized to update messages!'); + res.status(403).send('You are not authorized to delete messages!'); + } + try { + const results = await OwnerMessage.find({}); + const ownerMessage = results[0]; + ownerMessage.message = ''; + await ownerMessage.save(); + res.status(200).send({ _serverMessage: 'Delete successfully!', ownerMessage }); + } catch (error) { + res.status(500).send(error); } - const { id } = req.params; - - return OwnerMessage.findById(id, (error, ownerMessage) => { - if (error || ownerMessage === null) { - res.status(400).send('No ownerMessage found'); - return; - } - - ownerMessage.message = req.body.newMessage; - ownerMessage.save() - .then(results => res.status(201).send(results)) - .catch(errors => res.status(400).send(errors)); - }); }; return { - postOwnerMessage, getOwnerMessage, - deleteOwnerMessage, updateOwnerMessage, + deleteOwnerMessage, }; }; diff --git a/src/models/ownerMessage.js b/src/models/ownerMessage.js index be953c3a3..a6314c929 100644 --- a/src/models/ownerMessage.js +++ b/src/models/ownerMessage.js @@ -3,7 +3,8 @@ const mongoose = require('mongoose'); const { Schema } = mongoose; const OwnerMessage = new Schema({ - message: { type: String }, + message: { type: String, default: '' }, + standardMessage: { type: String, default: '' }, }); module.exports = mongoose.model('ownerMessage', OwnerMessage, 'ownerMessage'); diff --git a/src/routes/ownerMessageRouter.js b/src/routes/ownerMessageRouter.js index e436deed8..6f5716fe9 100644 --- a/src/routes/ownerMessageRouter.js +++ b/src/routes/ownerMessageRouter.js @@ -5,14 +5,11 @@ const routes = function (ownerMessage) { const OwnerMessageRouter = express.Router(); OwnerMessageRouter.route('/ownerMessage') - .post(controller.postOwnerMessage) - .get(controller.getOwnerMessage) - .delete(controller.deleteOwnerMessage); + .get(controller.getOwnerMessage) + .put(controller.updateOwnerMessage) + .delete(controller.deleteOwnerMessage); - OwnerMessageRouter.route('/ownerMessage/:id') - .put(controller.updateOwnerMessage); - -return OwnerMessageRouter; + return OwnerMessageRouter; }; module.exports = routes; diff --git a/src/startup/routes.js b/src/startup/routes.js index 2d95ea639..e7c91dab0 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -16,7 +16,7 @@ const inventoryItemType = require('../models/inventoryItemType'); const role = require('../models/role'); const rolePreset = require('../models/rolePreset'); const ownerMessage = require('../models/ownerMessage'); -const ownerStandardMessage = require('../models/ownerStandardMessage'); +// const ownerStandardMessage = require('../models/ownerStandardMessage'); const profileInitialSetuptoken = require('../models/profileInitialSetupToken'); const reason = require('../models/reason'); const mouseoverText = require('../models/mouseoverText'); @@ -55,7 +55,7 @@ const taskEditSuggestionRouter = require('../routes/taskEditSuggestionRouter')(t const roleRouter = require('../routes/roleRouter')(role); const rolePresetRouter = require('../routes/rolePresetRouter')(rolePreset); const ownerMessageRouter = require('../routes/ownerMessageRouter')(ownerMessage); -const ownerStandardMessageRouter = require('../routes/ownerStandardMessageRouter')(ownerStandardMessage); +// const ownerStandardMessageRouter = require('../routes/ownerStandardMessageRouter')(ownerStandardMessage); const reasonRouter = require('../routes/reasonRouter')(reason, userProfile); const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverText); @@ -92,7 +92,7 @@ module.exports = function (app) { app.use('/api', roleRouter); app.use('/api', rolePresetRouter); app.use('/api', ownerMessageRouter); - app.use('/api', ownerStandardMessageRouter); + // app.use('/api', ownerStandardMessageRouter); app.use('/api', profileInitialSetupRouter); app.use('/api', reasonRouter); app.use('/api', informationRouter); From 1128f8937e0ae2acf8e237a45a947813f87a0abb Mon Sep 17 00:00:00 2001 From: wang9hu Date: Sun, 10 Dec 2023 14:28:16 -0800 Subject: [PATCH 197/272] remove unused files and codes related to ownerStandardMessage --- .../ownerStandardMessageController.js | 64 ------------------- src/models/ownerStandardMessage.js | 9 --- src/routes/ownerStandardMessageRouter.js | 18 ------ src/startup/routes.js | 3 - 4 files changed, 94 deletions(-) delete mode 100644 src/controllers/ownerStandardMessageController.js delete mode 100644 src/models/ownerStandardMessage.js delete mode 100644 src/routes/ownerStandardMessageRouter.js diff --git a/src/controllers/ownerStandardMessageController.js b/src/controllers/ownerStandardMessageController.js deleted file mode 100644 index efd933888..000000000 --- a/src/controllers/ownerStandardMessageController.js +++ /dev/null @@ -1,64 +0,0 @@ -const ownerStandardMessageController = function (OwnerStandardMessage) { - const postOwnerStandardMessage = function (req, res) { - if (req.body.requestor.role !== 'Owner') { - res.status(403).send('You are not authorized to create messages!'); - } - const ownerStandardMessage = new OwnerStandardMessage(); - ownerStandardMessage.message = req.body.newStandardMessage; - ownerStandardMessage.save().then(() => res.status(201).json({ - _serverMessage: 'Message succesfuly created!', - ownerStandardMessage, - })).catch(err => res.status(500).send({ err })); - }; - - const getOwnerStandardMessage = function (req, res) { - OwnerStandardMessage.find() - .then(results => res.status(200).send(results)) - .catch(error => res.status(404).send(error)); - }; - - const deleteOwnerStandardMessage = function (req, res) { - if (req.body.requestor.role !== 'Owner') { - res.status(403).send('You are not authorized to delete messages!'); - } - OwnerStandardMessage.deleteMany({}) - .then((result) => { - result - .then(res.status(200).send({ _serverMessage: 'Standard Message deleted!' })) - .catch((error) => { - res.status(400).send(error); - }); - }) - .catch((error) => { - res.status(400).send(error); - }); - }; - - const updateOwnerStandardMessage = function (req, res) { - if (req.body.requestor.role !== 'Owner') { - res.status(403).send('You are not authorized to update messages!'); - } - const { id } = req.params; - - return OwnerStandardMessage.findById(id, (error, ownerStandardMessage) => { - if (error || ownerStandardMessage === null) { - res.status(400).send('No ownerStandardMessage found'); - return; - } - - ownerStandardMessage.message = req.body.newStandardMessage; - ownerStandardMessage.save() - .then(results => res.status(201).send(results)) - .catch(errors => res.status(400).send(errors)); - }); - }; - - return { - postOwnerStandardMessage, - getOwnerStandardMessage, - deleteOwnerStandardMessage, - updateOwnerStandardMessage, - }; -}; - -module.exports = ownerStandardMessageController; diff --git a/src/models/ownerStandardMessage.js b/src/models/ownerStandardMessage.js deleted file mode 100644 index d344a773f..000000000 --- a/src/models/ownerStandardMessage.js +++ /dev/null @@ -1,9 +0,0 @@ -const mongoose = require('mongoose'); - -const { Schema } = mongoose; - -const OwnerStandardMessage = new Schema({ - message: { type: String }, -}); - -module.exports = mongoose.model('ownerStandardMessage', OwnerStandardMessage, 'ownerStandardMessage'); diff --git a/src/routes/ownerStandardMessageRouter.js b/src/routes/ownerStandardMessageRouter.js deleted file mode 100644 index 08e629c3d..000000000 --- a/src/routes/ownerStandardMessageRouter.js +++ /dev/null @@ -1,18 +0,0 @@ -const express = require('express'); - -const routes = function (ownerStandardMessage) { - const controller = require('../controllers/ownerStandardMessageController')(ownerStandardMessage); - const OwnerStandardMessageRouter = express.Router(); - - OwnerStandardMessageRouter.route('/ownerStandardMessage') - .post(controller.postOwnerStandardMessage) - .get(controller.getOwnerStandardMessage) - .delete(controller.deleteOwnerStandardMessage); - - OwnerStandardMessageRouter.route('/ownerStandardMessage/:id') - .put(controller.updateOwnerStandardMessage); - -return OwnerStandardMessageRouter; -}; - -module.exports = routes; diff --git a/src/startup/routes.js b/src/startup/routes.js index e7c91dab0..ff5d01b2b 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -16,7 +16,6 @@ const inventoryItemType = require('../models/inventoryItemType'); const role = require('../models/role'); const rolePreset = require('../models/rolePreset'); const ownerMessage = require('../models/ownerMessage'); -// const ownerStandardMessage = require('../models/ownerStandardMessage'); const profileInitialSetuptoken = require('../models/profileInitialSetupToken'); const reason = require('../models/reason'); const mouseoverText = require('../models/mouseoverText'); @@ -55,7 +54,6 @@ const taskEditSuggestionRouter = require('../routes/taskEditSuggestionRouter')(t const roleRouter = require('../routes/roleRouter')(role); const rolePresetRouter = require('../routes/rolePresetRouter')(rolePreset); const ownerMessageRouter = require('../routes/ownerMessageRouter')(ownerMessage); -// const ownerStandardMessageRouter = require('../routes/ownerStandardMessageRouter')(ownerStandardMessage); const reasonRouter = require('../routes/reasonRouter')(reason, userProfile); const mouseoverTextRouter = require('../routes/mouseoverTextRouter')(mouseoverText); @@ -92,7 +90,6 @@ module.exports = function (app) { app.use('/api', roleRouter); app.use('/api', rolePresetRouter); app.use('/api', ownerMessageRouter); - // app.use('/api', ownerStandardMessageRouter); app.use('/api', profileInitialSetupRouter); app.use('/api', reasonRouter); app.use('/api', informationRouter); From 7895974de7e6d864000daba5810319c316b5274a Mon Sep 17 00:00:00 2001 From: wantingxu Date: Sun, 10 Dec 2023 21:09:27 -0800 Subject: [PATCH 198/272] add teamcode --- src/controllers/userProfileController.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index a8c0cf230..1a3dd504f 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -241,6 +241,7 @@ const userProfileController = function (UserProfile) { ); const canEditTeamCode = req.body.requestor.role === 'Owner' + || req.body.requestor.role === 'Administrator' || req.body.requestor.permissions?.frontPermissions.includes('editTeamCode'); if (!isRequestorAuthorized) { @@ -575,6 +576,7 @@ const userProfileController = function (UserProfile) { if (key === 'teamCode') { const canEditTeamCode = req.body.requestor.role === 'Owner' + || req.body.requestor.role === 'Administrator' || req.body.requestor.permissions?.frontPermissions.includes('editTeamCode'); if (!canEditTeamCode) { From 4cef847de5eb3711b72dd94838f54dee69325a2b Mon Sep 17 00:00:00 2001 From: wang9hu Date: Sun, 10 Dec 2023 21:23:20 -0800 Subject: [PATCH 199/272] make update standard message to empty message --- src/controllers/ownerMessageController.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/controllers/ownerMessageController.js b/src/controllers/ownerMessageController.js index f09a32030..1b2c30205 100644 --- a/src/controllers/ownerMessageController.js +++ b/src/controllers/ownerMessageController.js @@ -18,16 +18,18 @@ const ownerMessageController = function (OwnerMessage) { if (req.body.requestor.role !== 'Owner') { res.status(403).send('You are not authorized to create messages!'); } - const { standardMessage, message } = req.body; + const { isStandard, newMessage } = req.body; try { const results = await OwnerMessage.find({}); const ownerMessage = results[0]; - if (standardMessage) { - ownerMessage.standardMessage = standardMessage; + if (isStandard) { + ownerMessage.standardMessage = newMessage; + ownerMessage.message = ''; } else { - ownerMessage.message = message; + ownerMessage.message = newMessage; } await ownerMessage.save(); + const { standardMessage, message } = ownerMessage; res.status(201).send({ _serverMessage: 'Update successfully!', ownerMessage: { standardMessage, message }, From acefbbb69d072699f1e556e3b294684770b7617c Mon Sep 17 00:00:00 2001 From: Vishala Ramasamy Date: Mon, 11 Dec 2023 18:08:12 -0800 Subject: [PATCH 200/272] Leaderboard api fix --- src/helpers/dashboardhelper.js | 603 +++++++++++++++++++-------------- 1 file changed, 355 insertions(+), 248 deletions(-) diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index fe2007281..59b1d7f51 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -3,6 +3,7 @@ const mongoose = require('mongoose'); const userProfile = require('../models/userProfile'); const timeentry = require('../models/timeentry'); const myTeam = require('../helpers/helperModels/myTeam'); +const team = require('../models/team'); const dashboardhelper = function () { const personaldetails = function (userId) { @@ -152,8 +153,13 @@ const dashboardhelper = function () { return output; }; - const getLeaderboard = function (userId) { + const getLeaderboard = async function (userId) { const userid = mongoose.Types.ObjectId(userId); + const userById = await userProfile.findOne({ _id: userid , isActive:true}, {role:1}) + .then((res)=>{ return res; }).catch((e)=>{}); + + if(userById==null) return null; + const userRole = userById.role; const pdtstart = moment() .tz('America/Los_Angeles') .startOf('week') @@ -162,254 +168,355 @@ const dashboardhelper = function () { .tz('America/Los_Angeles') .endOf('week') .format('YYYY-MM-DD'); - return myTeam.aggregate([ - { - $match: { - _id: userid, - }, - }, - { - $unwind: '$myteam', - }, - { - $project: { - _id: 0, - role: 1, - personId: '$myteam._id', - name: '$myteam.fullName', - }, - }, - { - $lookup: { - from: 'userProfiles', - localField: 'personId', - foreignField: '_id', - as: 'persondata', - }, - }, - { - $match: { - // leaderboard user roles hierarchy - $or: [ - { - role: { $in: ['Owner', 'Core Team'] }, - }, - { - $and: [ - { - role: 'Administrator', - }, - { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, - ], - }, - { - $and: [ - { - role: { $in: ['Manager', 'Mentor'] }, - }, - { - 'persondata.0.role': { - $nin: ['Manager', 'Mentor', 'Core Team', 'Administrator', 'Owner'], - }, - }, - ], - }, - { 'persondata.0._id': userId }, - { 'persondata.0.role': 'Volunteer' }, - { 'persondata.0.isVisible': true }, - ], - }, - }, - { - $project: { - personId: 1, - name: 1, - role: { - $arrayElemAt: ['$persondata.role', 0], - }, - isVisible: { - $arrayElemAt: ['$persondata.isVisible', 0], - }, - hasSummary: { - $ne: [ - { - $arrayElemAt: [ - { - $arrayElemAt: ['$persondata.weeklySummaries.summary', 0], - }, - 0, - ], - }, - '', - ], - }, - weeklycommittedHours: { - $sum: [ - { - $arrayElemAt: ['$persondata.weeklycommittedHours', 0], - }, - { - $ifNull: [{ $arrayElemAt: ['$persondata.missedHours', 0] }, 0], - }, - ], - }, - }, - }, - { - $lookup: { - from: 'timeEntries', - localField: 'personId', - foreignField: 'personId', - as: 'timeEntryData', - }, - }, - { - $project: { - personId: 1, - name: 1, - role: 1, - isVisible: 1, - hasSummary: 1, - weeklycommittedHours: 1, - timeEntryData: { - $filter: { - input: '$timeEntryData', - as: 'timeentry', - cond: { - $and: [ - { - $gte: ['$$timeentry.dateOfWork', pdtstart], - }, - { - $lte: ['$$timeentry.dateOfWork', pdtend], - }, - ], - }, - }, - }, - }, - }, - { - $unwind: { - path: '$timeEntryData', - preserveNullAndEmptyArrays: true, - }, - }, - { - $project: { - personId: 1, - name: 1, - role: 1, - isVisible: 1, - hasSummary: 1, - weeklycommittedHours: 1, - totalSeconds: { - $cond: [ - { - $gte: ['$timeEntryData.totalSeconds', 0], - }, - '$timeEntryData.totalSeconds', - 0, - ], - }, - isTangible: { - $cond: [ - { - $gte: ['$timeEntryData.totalSeconds', 0], - }, - '$timeEntryData.isTangible', - false, - ], - }, - }, - }, - { - $addFields: { - tangibletime: { - $cond: [ - { - $eq: ['$isTangible', true], - }, - '$totalSeconds', - 0, - ], - }, - intangibletime: { - $cond: [ - { - $eq: ['$isTangible', false], - }, - '$totalSeconds', - 0, - ], - }, - }, - }, - { - $group: { - _id: { - personId: '$personId', - weeklycommittedHours: '$weeklycommittedHours', - name: '$name', - role: '$role', - isVisible: '$isVisible', - hasSummary: '$hasSummary', - }, - totalSeconds: { - $sum: '$totalSeconds', - }, - tangibletime: { - $sum: '$tangibletime', - }, - intangibletime: { - $sum: '$intangibletime', - }, - }, - }, - { - $project: { - _id: 0, - personId: '$_id.personId', - name: '$_id.name', - role: '$_id.role', - isVisible: '$_id.isVisible', - hasSummary: '$_id.hasSummary', - weeklycommittedHours: '$_id.weeklycommittedHours', - totaltime_hrs: { - $divide: ['$totalSeconds', 3600], - }, - totaltangibletime_hrs: { - $divide: ['$tangibletime', 3600], - }, - totalintangibletime_hrs: { - $divide: ['$intangibletime', 3600], - }, - percentagespentintangible: { - $cond: [ - { - $eq: ['$totalSeconds', 0], - }, - 0, - { - $multiply: [ - { - $divide: ['$tangibletime', '$totalSeconds'], - }, - 100, - ], - }, - ], - }, - }, - }, - { - $sort: { - totaltangibletime_hrs: -1, - name: 1, - role: 1, - }, + + let teamMemberIds = [userid] + let teamMembers = []; + if(userRole!='Administrator' && userRole!='Owner' && userRole!='Core Team') //Manager , Mentor , Volunteer ... , Show only team members + { + + const teamsResult = await team.find( { "members.userId": { $in: [userid] } }, {members:1} ) + .then((res)=>{ return res; }).catch((e)=>{}) + + teamsResult.map((_myTeam)=>{ + _myTeam.members.map((teamMember)=> { + if(!teamMember.userId.equals(userid)) + teamMemberIds.push( teamMember.userId ); + } ) + }) + + teamMembers = await userProfile.find({ _id: { $in: teamMemberIds } , isActive:true }, + {role:1,firstName:1,lastName:1,isVisible:1,weeklycommittedHours:1,weeklySummaries:1}) + .then((res)=>{ return res; }).catch((e)=>{}) + + } + else { + if(userRole == 'Administrator'){ //All users except Owner and Core Team + const excludedRoles = ['Core Team', 'Owner']; + teamMembers = await userProfile.find({ isActive:true , role: { $nin: excludedRoles } }, + {role:1,firstName:1,lastName:1,isVisible:1,weeklycommittedHours:1,weeklySummaries:1}) + .then((res)=>{ return res; }).catch((e)=>{}) + } + else{ //'Core Team', 'Owner' //All users + teamMembers = await userProfile.find({ isActive:true}, + {role:1,firstName:1,lastName:1,isVisible:1,weeklycommittedHours:1,weeklySummaries:1}) + .then((res)=>{ return res; }).catch((e)=>{}) + } + + + } + + teamMemberIds = teamMembers.map(member => member._id); + + const timeEntries = await timeentry.find({ + dateOfWork: { + $gte: pdtstart, + $lte: pdtend, }, - ]); + personId: { $in: teamMemberIds } + }); + + let timeEntryByPerson = {} + timeEntries.map((timeEntry)=>{ + + let personIdStr = timeEntry.personId.toString(); + + if(timeEntryByPerson[personIdStr]==null) + timeEntryByPerson[personIdStr] = {tangibleSeconds:0,intangibleSeconds:0,totalSeconds:0}; + + if (timeEntry.isTangible === true) { + timeEntryByPerson[personIdStr].tangibleSeconds += timeEntry.totalSeconds; + } else { + timeEntryByPerson[personIdStr].intangibleSeconds += timeEntry.totalSeconds; + } + + timeEntryByPerson[personIdStr].totalSeconds += timeEntry.totalSeconds; + }) + + let leaderBoardData = []; + teamMembers.map((teamMember)=>{ + let obj = { + personId : teamMember._id, + role : teamMember.role, + name : teamMember.firstName + ' ' + teamMember.lastName, + isVisible : teamMember.isVisible, + hasSummary : teamMember.weeklySummaries?.length > 0 ? teamMember.weeklySummaries[0].summary!='' : false, + weeklycommittedHours : teamMember.weeklycommittedHours, + totaltangibletime_hrs : ((timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / 3600) || 0), + totalintangibletime_hrs : ((timeEntryByPerson[teamMember._id.toString()]?.intangibleSeconds / 3600) || 0), + totaltime_hrs : ((timeEntryByPerson[teamMember._id.toString()]?.totalSeconds / 3600) || 0), + percentagespentintangible : + (timeEntryByPerson[teamMember._id.toString()] && timeEntryByPerson[teamMember._id.toString()]?.totalSeconds !=0 && timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds !=0) ? + (timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / timeEntryByPerson[teamMember._id.toString()]?.totalSeconds) * 100 + : + 0 + } + leaderBoardData.push(obj); + }) + + let sortedLBData = leaderBoardData.sort((a, b) => { + // Sort by totaltangibletime_hrs in descending order + if (b.totaltangibletime_hrs !== a.totaltangibletime_hrs) { + return b.totaltangibletime_hrs - a.totaltangibletime_hrs; + } + + // Then sort by name in ascending order + if (a.name !== b.name) { + return a.name.localeCompare(b.name); + } + + // Finally, sort by role in ascending order + return a.role.localeCompare(b.role); + }); + return sortedLBData; + + // return myTeam.aggregate([ + // { + // $match: { + // _id: userid, + // }, + // }, + // { + // $unwind: '$myteam', + // }, + // { + // $project: { + // _id: 0, + // role: 1, + // personId: '$myteam._id', + // name: '$myteam.fullName', + // }, + // }, + // { + // $lookup: { + // from: 'userProfiles', + // localField: 'personId', + // foreignField: '_id', + // as: 'persondata', + // }, + // }, + // { + // $match: { + // // leaderboard user roles hierarchy + // $or: [ + // { + // role: { $in: ['Owner', 'Core Team'] }, + // }, + // { + // $and: [ + // { + // role: 'Administrator', + // }, + // { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, + // ], + // }, + // { + // $and: [ + // { + // role: { $in: ['Manager', 'Mentor'] }, + // }, + // { + // 'persondata.0.role': { + // $nin: ['Manager', 'Mentor', 'Core Team', 'Administrator', 'Owner'], + // }, + // }, + // ], + // }, + // { 'persondata.0._id': userId }, + // { 'persondata.0.role': 'Volunteer' }, + // { 'persondata.0.isVisible': true }, + // ], + // }, + // }, + // { + // $project: { + // personId: 1, + // name: 1, + // role: { + // $arrayElemAt: ['$persondata.role', 0], + // }, + // isVisible: { + // $arrayElemAt: ['$persondata.isVisible', 0], + // }, + // hasSummary: { + // $ne: [ + // { + // $arrayElemAt: [ + // { + // $arrayElemAt: ['$persondata.weeklySummaries.summary', 0], + // }, + // 0, + // ], + // }, + // '', + // ], + // }, + // weeklycommittedHours: { + // $sum: [ + // { + // $arrayElemAt: ['$persondata.weeklycommittedHours', 0], + // }, + // { + // $ifNull: [{ $arrayElemAt: ['$persondata.missedHours', 0] }, 0], + // }, + // ], + // }, + // }, + // }, + // { + // $lookup: { + // from: 'timeEntries', + // localField: 'personId', + // foreignField: 'personId', + // as: 'timeEntryData', + // }, + // }, + // { + // $project: { + // personId: 1, + // name: 1, + // role: 1, + // isVisible: 1, + // hasSummary: 1, + // weeklycommittedHours: 1, + // timeEntryData: { + // $filter: { + // input: '$timeEntryData', + // as: 'timeentry', + // cond: { + // $and: [ + // { + // $gte: ['$$timeentry.dateOfWork', pdtstart], + // }, + // { + // $lte: ['$$timeentry.dateOfWork', pdtend], + // }, + // ], + // }, + // }, + // }, + // }, + // }, + // { + // $unwind: { + // path: '$timeEntryData', + // preserveNullAndEmptyArrays: true, + // }, + // }, + // { + // $project: { + // personId: 1, + // name: 1, + // role: 1, + // isVisible: 1, + // hasSummary: 1, + // weeklycommittedHours: 1, + // totalSeconds: { + // $cond: [ + // { + // $gte: ['$timeEntryData.totalSeconds', 0], + // }, + // '$timeEntryData.totalSeconds', + // 0, + // ], + // }, + // isTangible: { + // $cond: [ + // { + // $gte: ['$timeEntryData.totalSeconds', 0], + // }, + // '$timeEntryData.isTangible', + // false, + // ], + // }, + // }, + // }, + // { + // $addFields: { + // tangibletime: { + // $cond: [ + // { + // $eq: ['$isTangible', true], + // }, + // '$totalSeconds', + // 0, + // ], + // }, + // intangibletime: { + // $cond: [ + // { + // $eq: ['$isTangible', false], + // }, + // '$totalSeconds', + // 0, + // ], + // }, + // }, + // }, + // { + // $group: { + // _id: { + // personId: '$personId', + // weeklycommittedHours: '$weeklycommittedHours', + // name: '$name', + // role: '$role', + // isVisible: '$isVisible', + // hasSummary: '$hasSummary', + // }, + // totalSeconds: { + // $sum: '$totalSeconds', + // }, + // tangibletime: { + // $sum: '$tangibletime', + // }, + // intangibletime: { + // $sum: '$intangibletime', + // }, + // }, + // }, + // { + // $project: { + // _id: 0, + // personId: '$_id.personId', + // name: '$_id.name', + // role: '$_id.role', + // isVisible: '$_id.isVisible', + // hasSummary: '$_id.hasSummary', + // weeklycommittedHours: '$_id.weeklycommittedHours', + // totaltime_hrs: { + // $divide: ['$totalSeconds', 3600], + // }, + // totaltangibletime_hrs: { + // $divide: ['$tangibletime', 3600], + // }, + // totalintangibletime_hrs: { + // $divide: ['$intangibletime', 3600], + // }, + // percentagespentintangible: { + // $cond: [ + // { + // $eq: ['$totalSeconds', 0], + // }, + // 0, + // { + // $multiply: [ + // { + // $divide: ['$tangibletime', '$totalSeconds'], + // }, + // 100, + // ], + // }, + // ], + // }, + // }, + // }, + // { + // $sort: { + // totaltangibletime_hrs: -1, + // name: 1, + // role: 1, + // }, + // }, + // ]); }; /** From 2a1ef65af84d0d89eea2d6fb2fcc83fd0cf98810 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Tue, 12 Dec 2023 08:51:56 -0800 Subject: [PATCH 201/272] add tool and equipment discriminators --- .../bmdashboard/buildingInventoryItem.js | 88 +++++++++++++------ 1 file changed, 61 insertions(+), 27 deletions(-) diff --git a/src/models/bmdashboard/buildingInventoryItem.js b/src/models/bmdashboard/buildingInventoryItem.js index 0d357ae7a..845243331 100644 --- a/src/models/bmdashboard/buildingInventoryItem.js +++ b/src/models/bmdashboard/buildingInventoryItem.js @@ -1,8 +1,8 @@ const mongoose = require('mongoose'); -//---------------------- -// BASE INVENTORY SCHEMA -//---------------------- +//----------------------- +// BASE INVENTORY SCHEMAS +//----------------------- // base schema for all categories of inventory (Consumable, Material, Reusable, Tool, Equipment) // this schema is extended by the individual schemas for each inventory type @@ -46,6 +46,28 @@ const buildingMaterial = baseInv.discriminator('material', new mongoose.Schema({ }], })); +//----------------- +// CONSUMABLES SCHEMA +//----------------- + +// inherits all properties of baseInv schema using discriminator +// each document derived from this schema includes key field { __t: "consumable" } +// ex: screws, nails, staples + +const buildingConsumable = baseInv.discriminator('consumable', new mongoose.Schema({ + stockBought: { type: Number, default: 0 }, // total amount of item bought for use in the project + stockUsed: { type: Number, default: 0 }, // stock that has been used up and cannot be reused + stockWasted: { type: Number, default: 0 }, // ruined or destroyed stock + stockAvailable: { type: Number, default: 0 }, // available = bought - (used + wasted/destroyed) + updateRecord: [{ + _id: false, + date: { type: Date, required: true }, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + quantityUsed: { type: Number, required: true }, + quantityWasted: { type: Number, required: true }, + }], +})); + //----------------- // REUSABLES SCHEMA //----------------- @@ -67,54 +89,66 @@ const buildingReusable = baseInv.discriminator('reusable', new mongoose.Schema({ }], })); -//----------------- -// CONSUMABLES SCHEMA -//----------------- - -// inherits all properties of baseInv schema using discriminator -// each document derived from this schema includes key field { __t: "consumable" } -// ex: screws, nails, staples - //------------- -// TOOLS SCHEMA +// TOOL SCHEMAS //------------- // inherits all properties of baseInv schema using discriminator // each document derived from this schema includes key field { __t: "tool" } -// ex: power drills, wheelbarrows, shovels +// ex: power drills, wheelbarrows, shovels, jackhammers + +// Base Tool Schema: const buildingTool = baseInv.discriminator('tool', new mongoose.Schema({ code: { type: Number, required: true }, // add function to create code for on-site tool tracking purchaseStatus: { type: String, enum: ['Rental', 'Purchase'], required: true }, - // add discriminator based on rental or purchase so these fields are required if tool is rented - rentedOnDate: Date, - rentalDue: Date, - userResponsible: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - purchaseRecord: [{ // track purchase/rental requests - _id: false, // do not add _id field to subdocument - date: { type: Date, default: Date.now() }, - requestedBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - priority: { type: String, enum: ['Low', 'Medium', 'High'], required: true }, - brand: String, - status: { type: String, default: 'Pending', enum: ['Approved', 'Pending', 'Rejected'] }, - }], + imgUrl: String, updateRecord: [{ // track tool condition updates _id: false, date: { type: Date, default: Date.now() }, createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, condition: { type: String, enum: ['Good', 'Needs Repair', 'Out of Order'] }, }], - logRecord: [{ // track tool daily check in/out and use + logRecord: [{ // track tool daily check in/out and responsible user _id: false, date: { type: Date, default: Date.now() }, createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, responsibleUser: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - type: { type: String, enum: ['Check In', 'Check Out'] }, // default = opposite of current log status? + type: { type: String, enum: ['Check In', 'Check Out'] }, }], })); +// Rented Tool Schema: +// inherits all properties of buildingTool schema using discriminator +// each document derived from this schema includes key field { __t: "tool_rental" } + +// const buildingToolRental = buildingTool.discriminator('tool_rental', new mongoose.Schema({ +// rentedOnDate: { type: Date, required: true }, +// rentalDueDate: { type: Date, required: true }, +// })); + +//------------------ +// EQUIPMENT SCHEMAS +//------------------ + +// inherits all properties of baseInv schema using discriminator +// each document derived from this schema includes key field { __t: "equipment" } +// items in this category are assumed to be rented +// ex: tractors, excavators, bulldozers + +const buildingEquipment = baseInv.discriminator('equipment', new mongoose.Schema({ + isTracked: { type: Boolean, required: true }, + assetTracker: String, + // add rental record? +})); + +// add purchase varient instead of rental varient? module.exports = { buildingMaterial, + buildingConsumable, buildingReusable, + buildingTool, + // buildingToolRental, + buildingEquipment, }; From ef31db0d43ac6f8c2c6f79b6b9d859502776547a Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Tue, 12 Dec 2023 10:12:45 -0800 Subject: [PATCH 202/272] delete redundant files. add basic equipment schema --- src/models/bmdashboard/baseInvSchema.js | 23 ----------- .../bmdashboard/buildingInventoryItem.js | 41 ++++++++++++------- src/models/bmdashboard/buildingReusable.js | 21 ---------- 3 files changed, 26 insertions(+), 59 deletions(-) delete mode 100644 src/models/bmdashboard/baseInvSchema.js delete mode 100644 src/models/bmdashboard/buildingReusable.js diff --git a/src/models/bmdashboard/baseInvSchema.js b/src/models/bmdashboard/baseInvSchema.js deleted file mode 100644 index 7eff943e7..000000000 --- a/src/models/bmdashboard/baseInvSchema.js +++ /dev/null @@ -1,23 +0,0 @@ -const mongoose = require('mongoose'); - -// base schema for all categories of inventory (Consumable, Material, Reusable, Tool, Equipment) -// this schema is extended by the individual schemas for each inventory type -// all documents derived from this schema are saved to the collection 'buildingInventoryItems' - -const baseInvSchema = mongoose.Schema({ - itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, - project: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingProject' }, - purchaseRecord: [{ - _id: false, // do not add _id field to subdocument - date: { type: Date, default: Date.now() }, - requestedBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - quantity: { type: Number, required: true }, - priority: { type: String, enum: ['Low', 'Medium', 'High'], required: true }, - brandPref: String, - status: { type: String, default: 'Pending', enum: ['Approved', 'Pending', 'Rejected'] }, - }], -}); - -const baseInv = mongoose.model('buildingInventory', baseInvSchema, 'buildingInventoryItems'); - -module.exports = baseInv; diff --git a/src/models/bmdashboard/buildingInventoryItem.js b/src/models/bmdashboard/buildingInventoryItem.js index 845243331..ed9c52ebc 100644 --- a/src/models/bmdashboard/buildingInventoryItem.js +++ b/src/models/bmdashboard/buildingInventoryItem.js @@ -15,7 +15,7 @@ const baseInvSchema = mongoose.Schema({ _id: false, // do not add _id field to subdocument date: { type: Date, default: Date.now() }, requestedBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - quantity: { type: Number, required: true }, + quantity: { type: Number, required: true, default: 1 }, // default 1 for tool or equipment purchases priority: { type: String, enum: ['Low', 'Medium', 'High'], required: true }, brandPref: String, status: { type: String, default: 'Pending', enum: ['Approved', 'Pending', 'Rejected'] }, @@ -100,8 +100,11 @@ const buildingReusable = baseInv.discriminator('reusable', new mongoose.Schema({ // Base Tool Schema: const buildingTool = baseInv.discriminator('tool', new mongoose.Schema({ - code: { type: Number, required: true }, // add function to create code for on-site tool tracking + code: { type: Number, required: true }, // TODO: add function to create simple numeric code for on-site tool tracking purchaseStatus: { type: String, enum: ['Rental', 'Purchase'], required: true }, + // rental fields are required if purchaseStatus = "Rental" (hopefully correct syntax) + rentedOnDate: { type: Date, required: () => this.purchaseStatus === 'Rental' }, + rentalDueDate: { type: Date, required: () => this.purchaseStatus === 'Rental' }, imgUrl: String, updateRecord: [{ // track tool condition updates _id: false, @@ -118,15 +121,6 @@ const buildingTool = baseInv.discriminator('tool', new mongoose.Schema({ }], })); -// Rented Tool Schema: -// inherits all properties of buildingTool schema using discriminator -// each document derived from this schema includes key field { __t: "tool_rental" } - -// const buildingToolRental = buildingTool.discriminator('tool_rental', new mongoose.Schema({ -// rentedOnDate: { type: Date, required: true }, -// rentalDueDate: { type: Date, required: true }, -// })); - //------------------ // EQUIPMENT SCHEMAS //------------------ @@ -137,9 +131,27 @@ const buildingTool = baseInv.discriminator('tool', new mongoose.Schema({ // ex: tractors, excavators, bulldozers const buildingEquipment = baseInv.discriminator('equipment', new mongoose.Schema({ - isTracked: { type: Boolean, required: true }, - assetTracker: String, - // add rental record? + isTracked: { type: Boolean, required: true }, // has asset tracker + assetTracker: { type: String, required: () => this.isTracked }, // required if isTracked = true (syntax?) + code: { type: Number, required: true }, // TODO: add function to create simple numeric code for on-site tool tracking + purchaseStatus: { type: String, enum: ['Rental', 'Purchase'], required: true }, + // rental fields are required if purchaseStatus = "Rental" (hopefully correct syntax) + rentedOnDate: { type: Date, required: () => this.purchaseStatus === 'Rental' }, + rentalDueDate: { type: Date, required: () => this.purchaseStatus === 'Rental' }, + imgUrl: String, + updateRecord: [{ // track equipment condition updates + _id: false, + date: { type: Date, default: Date.now() }, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + condition: { type: String, enum: ['Good', 'Needs Repair', 'Out of Order'] }, + }], + logRecord: [{ // track tool daily check in/out and responsible user + _id: false, + date: { type: Date, default: Date.now() }, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + responsibleUser: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + type: { type: String, enum: ['Check In', 'Check Out'] }, + }], })); // add purchase varient instead of rental varient? @@ -149,6 +161,5 @@ module.exports = { buildingConsumable, buildingReusable, buildingTool, - // buildingToolRental, buildingEquipment, }; diff --git a/src/models/bmdashboard/buildingReusable.js b/src/models/bmdashboard/buildingReusable.js deleted file mode 100644 index 1f2ceaa48..000000000 --- a/src/models/bmdashboard/buildingReusable.js +++ /dev/null @@ -1,21 +0,0 @@ -const mongoose = require('mongoose'); - -const baseInv = require('./baseInvSchema'); - -// inherits all properties of baseInv schema using discriminator -// each document derived from this schema includes key field { __t: "buildingReusable" } - -const buildingReusable = baseInv.discriminator('buildingReusable', new mongoose.Schema({ - stockBought: { type: Number, default: 0 }, - stockDestroyed: { type: Number, default: 0 }, - stockAvailable: { type: Number, default: 0 }, - updateRecord: [{ - _id: false, - date: { type: Date, required: true }, - createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - quantityUsed: { type: Number, required: true }, - quantityDestroyed: { type: Number, required: true }, - }], -})); - -module.exports = buildingReusable; From 6cc5807680d68381b3446d49eaca951f51b33ea3 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Tue, 12 Dec 2023 12:03:57 -0800 Subject: [PATCH 203/272] experimenting with new schema varient --- .../bmdashboard/buildingInventoryItem.js | 217 ++++++++++++------ 1 file changed, 146 insertions(+), 71 deletions(-) diff --git a/src/models/bmdashboard/buildingInventoryItem.js b/src/models/bmdashboard/buildingInventoryItem.js index ed9c52ebc..a9559a45d 100644 --- a/src/models/bmdashboard/buildingInventoryItem.js +++ b/src/models/bmdashboard/buildingInventoryItem.js @@ -8,9 +8,28 @@ const mongoose = require('mongoose'); // this schema is extended by the individual schemas for each inventory type // all documents derived from this schema are saved to the collection 'buildingInventoryItems' -const baseInvSchema = mongoose.Schema({ +// const baseInvSchema = mongoose.Schema({ +// itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, +// project: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingProject' }, +// purchaseRecord: [{ +// _id: false, // do not add _id field to subdocument +// date: { type: Date, default: Date.now() }, +// requestedBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, +// quantity: { type: Number, required: true, default: 1 }, // default 1 for tool or equipment purchases +// priority: { type: String, enum: ['Low', 'Medium', 'High'], required: true }, +// brandPref: String, +// status: { type: String, default: 'Pending', enum: ['Approved', 'Pending', 'Rejected'] }, +// }], +// }); + +// const baseInv = mongoose.model('buildingInventory', baseInvSchema, 'buildingInventoryItems'); + +const baseSchemaForMaterialReusableConsumable = mongoose.Schema({ itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, project: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingProject' }, + stockBought: { type: Number, default: 0 }, // total amount of item bought for use in the project + // TODO: can stockAvailable default be a function? + stockAvailable: { type: Number, default: 0 }, // available = bought - (used + wasted/destroyed) purchaseRecord: [{ _id: false, // do not add _id field to subdocument date: { type: Date, default: Date.now() }, @@ -20,9 +39,41 @@ const baseInvSchema = mongoose.Schema({ brandPref: String, status: { type: String, default: 'Pending', enum: ['Approved', 'Pending', 'Rejected'] }, }], + updateRecord: [{ + _id: false, + date: { type: Date, required: true }, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + quantityUsed: { type: Number, required: true }, + quantityWasted: { type: Number, required: true }, + }], }); -const baseInv = mongoose.model('buildingInventory', baseInvSchema, 'buildingInventoryItems'); +const baseInvSmallItems = mongoose.model('buildingInvSmallItems', baseSchemaForMaterialReusableConsumable, 'buildingInventoryItems'); + +const baseSchemaForToolEquipment = mongoose.Schema({ + itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, + project: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingProject' }, + purchaseStatus: { type: String, enum: ['Rental', 'Purchase'], required: true }, + // rental fields are required if purchaseStatus = "Rental" (hopefully correct syntax) + rentedOnDate: { type: Date, required: () => this.purchaseStatus === 'Rental' }, + rentalDueDate: { type: Date, required: () => this.purchaseStatus === 'Rental' }, + imgUrl: String, + updateRecord: [{ // track tool condition updates + _id: false, + date: { type: Date, default: Date.now() }, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + condition: { type: String, enum: ['Good', 'Needs Repair', 'Out of Order'] }, + }], + logRecord: [{ // track tool daily check in/out and responsible user + _id: false, + date: { type: Date, default: Date.now() }, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + responsibleUser: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + type: { type: String, enum: ['Check In', 'Check Out'] }, + }], +}); + +const baseInvLargeItems = mongoose.model('buildingInvLargeItems', baseSchemaForToolEquipment, 'buildingInventoryItems'); //----------------- // MATERIALS SCHEMA @@ -32,18 +83,23 @@ const baseInv = mongoose.model('buildingInventory', baseInvSchema, 'buildingInve // each document derived from this schema includes key field { __t: "material" } // ex: sand, stone, bricks, lumber, insulation -const buildingMaterial = baseInv.discriminator('material', new mongoose.Schema({ - stockBought: { type: Number, default: 0 }, // total amount of item bought for use in the project +// const buildingMaterial = baseInv.discriminator('material', new mongoose.Schema({ +// stockBought: { type: Number, default: 0 }, // total amount of item bought for use in the project +// stockUsed: { type: Number, default: 0 }, // stock that has been used up and cannot be reused +// stockWasted: { type: Number, default: 0 }, // ruined or destroyed stock +// stockAvailable: { type: Number, default: 0 }, // available = bought - (used + wasted/destroyed) +// updateRecord: [{ +// _id: false, +// date: { type: Date, required: true }, +// createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, +// quantityUsed: { type: Number, required: true }, +// quantityWasted: { type: Number, required: true }, +// }], +// })); + +const buildingMaterial = baseInvSmallItems.discriminator('material', new mongoose.Schema({ stockUsed: { type: Number, default: 0 }, // stock that has been used up and cannot be reused stockWasted: { type: Number, default: 0 }, // ruined or destroyed stock - stockAvailable: { type: Number, default: 0 }, // available = bought - (used + wasted/destroyed) - updateRecord: [{ - _id: false, - date: { type: Date, required: true }, - createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - quantityUsed: { type: Number, required: true }, - quantityWasted: { type: Number, required: true }, - }], })); //----------------- @@ -54,18 +110,23 @@ const buildingMaterial = baseInv.discriminator('material', new mongoose.Schema({ // each document derived from this schema includes key field { __t: "consumable" } // ex: screws, nails, staples -const buildingConsumable = baseInv.discriminator('consumable', new mongoose.Schema({ - stockBought: { type: Number, default: 0 }, // total amount of item bought for use in the project +// const buildingConsumable = baseInv.discriminator('consumable', new mongoose.Schema({ +// stockBought: { type: Number, default: 0 }, // total amount of item bought for use in the project +// stockUsed: { type: Number, default: 0 }, // stock that has been used up and cannot be reused +// stockWasted: { type: Number, default: 0 }, // ruined or destroyed stock +// stockAvailable: { type: Number, default: 0 }, // available = bought - (used + wasted/destroyed) +// updateRecord: [{ +// _id: false, +// date: { type: Date, required: true }, +// createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, +// quantityUsed: { type: Number, required: true }, +// quantityWasted: { type: Number, required: true }, +// }], +// })); + +const buildingConsumable = baseInvSmallItems.discriminator('consumable', new mongoose.Schema({ stockUsed: { type: Number, default: 0 }, // stock that has been used up and cannot be reused stockWasted: { type: Number, default: 0 }, // ruined or destroyed stock - stockAvailable: { type: Number, default: 0 }, // available = bought - (used + wasted/destroyed) - updateRecord: [{ - _id: false, - date: { type: Date, required: true }, - createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - quantityUsed: { type: Number, required: true }, - quantityWasted: { type: Number, required: true }, - }], })); //----------------- @@ -76,17 +137,21 @@ const buildingConsumable = baseInv.discriminator('consumable', new mongoose.Sche // each document derived from this schema includes key field { __t: "reusable" } // ex: hammers, screwdrivers, mallets, brushes, gloves -const buildingReusable = baseInv.discriminator('reusable', new mongoose.Schema({ - stockBought: { type: Number, default: 0 }, +// const buildingReusable = baseInv.discriminator('reusable', new mongoose.Schema({ +// stockBought: { type: Number, default: 0 }, +// stockDestroyed: { type: Number, default: 0 }, +// stockAvailable: { type: Number, default: 0 }, +// updateRecord: [{ +// _id: false, +// date: { type: Date, required: true }, +// createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, +// quantityUsed: { type: Number, required: true }, +// quantityDestroyed: { type: Number, required: true }, +// }], +// })); + +const buildingReusable = baseInvSmallItems.discriminator('reusable', new mongoose.Schema({ stockDestroyed: { type: Number, default: 0 }, - stockAvailable: { type: Number, default: 0 }, - updateRecord: [{ - _id: false, - date: { type: Date, required: true }, - createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - quantityUsed: { type: Number, required: true }, - quantityDestroyed: { type: Number, required: true }, - }], })); //------------- @@ -99,28 +164,33 @@ const buildingReusable = baseInv.discriminator('reusable', new mongoose.Schema({ // Base Tool Schema: -const buildingTool = baseInv.discriminator('tool', new mongoose.Schema({ +// const buildingTool = baseInv.discriminator('tool', new mongoose.Schema({ +// code: { type: Number, required: true }, // TODO: add function to create simple numeric code for on-site tool tracking +// purchaseStatus: { type: String, enum: ['Rental', 'Purchase'], required: true }, +// // rental fields are required if purchaseStatus = "Rental" (hopefully correct syntax) +// rentedOnDate: { type: Date, required: () => this.purchaseStatus === 'Rental' }, +// rentalDueDate: { type: Date, required: () => this.purchaseStatus === 'Rental' }, +// imgUrl: String, +// updateRecord: [{ // track tool condition updates +// _id: false, +// date: { type: Date, default: Date.now() }, +// createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, +// condition: { type: String, enum: ['Good', 'Needs Repair', 'Out of Order'] }, +// }], +// logRecord: [{ // track tool daily check in/out and responsible user +// _id: false, +// date: { type: Date, default: Date.now() }, +// createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, +// responsibleUser: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, +// type: { type: String, enum: ['Check In', 'Check Out'] }, +// }], +// })); + +const buildingTool = baseInvLargeItems.discriminator('tool', new mongoose.Schema({ code: { type: Number, required: true }, // TODO: add function to create simple numeric code for on-site tool tracking - purchaseStatus: { type: String, enum: ['Rental', 'Purchase'], required: true }, - // rental fields are required if purchaseStatus = "Rental" (hopefully correct syntax) - rentedOnDate: { type: Date, required: () => this.purchaseStatus === 'Rental' }, - rentalDueDate: { type: Date, required: () => this.purchaseStatus === 'Rental' }, - imgUrl: String, - updateRecord: [{ // track tool condition updates - _id: false, - date: { type: Date, default: Date.now() }, - createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - condition: { type: String, enum: ['Good', 'Needs Repair', 'Out of Order'] }, - }], - logRecord: [{ // track tool daily check in/out and responsible user - _id: false, - date: { type: Date, default: Date.now() }, - createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - responsibleUser: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - type: { type: String, enum: ['Check In', 'Check Out'] }, - }], })); + //------------------ // EQUIPMENT SCHEMAS //------------------ @@ -130,28 +200,33 @@ const buildingTool = baseInv.discriminator('tool', new mongoose.Schema({ // items in this category are assumed to be rented // ex: tractors, excavators, bulldozers -const buildingEquipment = baseInv.discriminator('equipment', new mongoose.Schema({ +// const buildingEquipment = baseInv.discriminator('equipment', new mongoose.Schema({ +// isTracked: { type: Boolean, required: true }, // has asset tracker +// assetTracker: { type: String, required: () => this.isTracked }, // required if isTracked = true (syntax?) +// code: { type: Number, required: true }, // TODO: add function to create simple numeric code for on-site tool tracking +// purchaseStatus: { type: String, enum: ['Rental', 'Purchase'], required: true }, +// // rental fields are required if purchaseStatus = "Rental" (hopefully correct syntax) +// rentedOnDate: { type: Date, required: () => this.purchaseStatus === 'Rental' }, +// rentalDueDate: { type: Date, required: () => this.purchaseStatus === 'Rental' }, +// imgUrl: String, +// updateRecord: [{ // track equipment condition updates +// _id: false, +// date: { type: Date, default: Date.now() }, +// createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, +// condition: { type: String, enum: ['Good', 'Needs Repair', 'Out of Order'] }, +// }], +// logRecord: [{ // track tool daily check in/out and responsible user +// _id: false, +// date: { type: Date, default: Date.now() }, +// createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, +// responsibleUser: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, +// type: { type: String, enum: ['Check In', 'Check Out'] }, +// }], +// })); + +const buildingEquipment = baseInvLargeItems.discriminator('equipment', new mongoose.Schema({ isTracked: { type: Boolean, required: true }, // has asset tracker assetTracker: { type: String, required: () => this.isTracked }, // required if isTracked = true (syntax?) - code: { type: Number, required: true }, // TODO: add function to create simple numeric code for on-site tool tracking - purchaseStatus: { type: String, enum: ['Rental', 'Purchase'], required: true }, - // rental fields are required if purchaseStatus = "Rental" (hopefully correct syntax) - rentedOnDate: { type: Date, required: () => this.purchaseStatus === 'Rental' }, - rentalDueDate: { type: Date, required: () => this.purchaseStatus === 'Rental' }, - imgUrl: String, - updateRecord: [{ // track equipment condition updates - _id: false, - date: { type: Date, default: Date.now() }, - createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - condition: { type: String, enum: ['Good', 'Needs Repair', 'Out of Order'] }, - }], - logRecord: [{ // track tool daily check in/out and responsible user - _id: false, - date: { type: Date, default: Date.now() }, - createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - responsibleUser: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, - type: { type: String, enum: ['Check In', 'Check Out'] }, - }], })); // add purchase varient instead of rental varient? From f92d83360f7cca247068b393d576c2cf3baec0dc Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Tue, 12 Dec 2023 12:29:45 -0800 Subject: [PATCH 204/272] refactor file --- .../bmdashboard/buildingInventoryItem.js | 184 +++++------------- 1 file changed, 46 insertions(+), 138 deletions(-) diff --git a/src/models/bmdashboard/buildingInventoryItem.js b/src/models/bmdashboard/buildingInventoryItem.js index a9559a45d..5e8b24916 100644 --- a/src/models/bmdashboard/buildingInventoryItem.js +++ b/src/models/bmdashboard/buildingInventoryItem.js @@ -4,27 +4,13 @@ const mongoose = require('mongoose'); // BASE INVENTORY SCHEMAS //----------------------- -// base schema for all categories of inventory (Consumable, Material, Reusable, Tool, Equipment) -// this schema is extended by the individual schemas for each inventory type -// all documents derived from this schema are saved to the collection 'buildingInventoryItems' - -// const baseInvSchema = mongoose.Schema({ -// itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, -// project: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingProject' }, -// purchaseRecord: [{ -// _id: false, // do not add _id field to subdocument -// date: { type: Date, default: Date.now() }, -// requestedBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, -// quantity: { type: Number, required: true, default: 1 }, // default 1 for tool or equipment purchases -// priority: { type: String, enum: ['Low', 'Medium', 'High'], required: true }, -// brandPref: String, -// status: { type: String, default: 'Pending', enum: ['Approved', 'Pending', 'Rejected'] }, -// }], -// }); - -// const baseInv = mongoose.model('buildingInventory', baseInvSchema, 'buildingInventoryItems'); - -const baseSchemaForMaterialReusableConsumable = mongoose.Schema({ +// TODO: purchaseRecord subdocs may be changed to purchaseRequests. A new purchaseRecord subdoc may be added to track purchases and costs for the item. + +// SMALL ITEMS BASE +// base schema for Consumable, Material, Reusable +// documents stored in 'buildingInventoryItems' collection + +const smallItemBaseSchema = mongoose.Schema({ itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, project: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingProject' }, stockBought: { type: Number, default: 0 }, // total amount of item bought for use in the project @@ -48,16 +34,29 @@ const baseSchemaForMaterialReusableConsumable = mongoose.Schema({ }], }); -const baseInvSmallItems = mongoose.model('buildingInvSmallItems', baseSchemaForMaterialReusableConsumable, 'buildingInventoryItems'); +const smallItemBase = mongoose.model('smallItemBase', smallItemBaseSchema, 'buildingInventoryItems'); + +// LARGE ITEMS BASE +// base schema for Tool, Equipment +// documents stored in 'buildingInventoryItems' collection -const baseSchemaForToolEquipment = mongoose.Schema({ +const largeItemBaseSchema = mongoose.Schema({ itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, project: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingProject' }, purchaseStatus: { type: String, enum: ['Rental', 'Purchase'], required: true }, // rental fields are required if purchaseStatus = "Rental" (hopefully correct syntax) rentedOnDate: { type: Date, required: () => this.purchaseStatus === 'Rental' }, rentalDueDate: { type: Date, required: () => this.purchaseStatus === 'Rental' }, - imgUrl: String, + imageUrl: String, + purchaseRecord: [{ + _id: false, // do not add _id field to subdocument + date: { type: Date, default: Date.now() }, + requestedBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + priority: { type: String, enum: ['Low', 'Medium', 'High'], required: true }, + makeModelPref: String, + estTimeRequired: { type: Number, required: true }, // estimated time required on site + status: { type: String, default: 'Pending', enum: ['Approved', 'Pending', 'Rejected'] }, + }], updateRecord: [{ // track tool condition updates _id: false, date: { type: Date, default: Date.now() }, @@ -73,164 +72,73 @@ const baseSchemaForToolEquipment = mongoose.Schema({ }], }); -const baseInvLargeItems = mongoose.model('buildingInvLargeItems', baseSchemaForToolEquipment, 'buildingInventoryItems'); +const largeItemBase = mongoose.model('largeItemBase', largeItemBaseSchema, 'buildingInventoryItems'); //----------------- // MATERIALS SCHEMA //----------------- -// inherits all properties of baseInv schema using discriminator +// inherits all properties of smallItemBaseSchema // each document derived from this schema includes key field { __t: "material" } // ex: sand, stone, bricks, lumber, insulation -// const buildingMaterial = baseInv.discriminator('material', new mongoose.Schema({ -// stockBought: { type: Number, default: 0 }, // total amount of item bought for use in the project -// stockUsed: { type: Number, default: 0 }, // stock that has been used up and cannot be reused -// stockWasted: { type: Number, default: 0 }, // ruined or destroyed stock -// stockAvailable: { type: Number, default: 0 }, // available = bought - (used + wasted/destroyed) -// updateRecord: [{ -// _id: false, -// date: { type: Date, required: true }, -// createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, -// quantityUsed: { type: Number, required: true }, -// quantityWasted: { type: Number, required: true }, -// }], -// })); - -const buildingMaterial = baseInvSmallItems.discriminator('material', new mongoose.Schema({ +const buildingMaterial = smallItemBase.discriminator('material', new mongoose.Schema({ stockUsed: { type: Number, default: 0 }, // stock that has been used up and cannot be reused stockWasted: { type: Number, default: 0 }, // ruined or destroyed stock })); -//----------------- -// CONSUMABLES SCHEMA -//----------------- +//------------------ +// CONSUMABLE SCHEMA +//------------------ -// inherits all properties of baseInv schema using discriminator +// inherits all properties of smallItemBaseSchema // each document derived from this schema includes key field { __t: "consumable" } // ex: screws, nails, staples -// const buildingConsumable = baseInv.discriminator('consumable', new mongoose.Schema({ -// stockBought: { type: Number, default: 0 }, // total amount of item bought for use in the project -// stockUsed: { type: Number, default: 0 }, // stock that has been used up and cannot be reused -// stockWasted: { type: Number, default: 0 }, // ruined or destroyed stock -// stockAvailable: { type: Number, default: 0 }, // available = bought - (used + wasted/destroyed) -// updateRecord: [{ -// _id: false, -// date: { type: Date, required: true }, -// createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, -// quantityUsed: { type: Number, required: true }, -// quantityWasted: { type: Number, required: true }, -// }], -// })); - -const buildingConsumable = baseInvSmallItems.discriminator('consumable', new mongoose.Schema({ +const buildingConsumable = smallItemBase.discriminator('consumable', new mongoose.Schema({ stockUsed: { type: Number, default: 0 }, // stock that has been used up and cannot be reused stockWasted: { type: Number, default: 0 }, // ruined or destroyed stock })); -//----------------- -// REUSABLES SCHEMA -//----------------- +//---------------- +// REUSABLE SCHEMA +//---------------- -// inherits all properties of baseInv schema using discriminator +// inherits all properties of smallItemBaseSchema // each document derived from this schema includes key field { __t: "reusable" } // ex: hammers, screwdrivers, mallets, brushes, gloves -// const buildingReusable = baseInv.discriminator('reusable', new mongoose.Schema({ -// stockBought: { type: Number, default: 0 }, -// stockDestroyed: { type: Number, default: 0 }, -// stockAvailable: { type: Number, default: 0 }, -// updateRecord: [{ -// _id: false, -// date: { type: Date, required: true }, -// createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, -// quantityUsed: { type: Number, required: true }, -// quantityDestroyed: { type: Number, required: true }, -// }], -// })); - -const buildingReusable = baseInvSmallItems.discriminator('reusable', new mongoose.Schema({ +const buildingReusable = smallItemBase.discriminator('reusable', new mongoose.Schema({ stockDestroyed: { type: Number, default: 0 }, })); -//------------- -// TOOL SCHEMAS -//------------- +//------------ +// TOOL SCHEMA +//------------ -// inherits all properties of baseInv schema using discriminator +// inherits all properties of largeItemBaseSchema // each document derived from this schema includes key field { __t: "tool" } // ex: power drills, wheelbarrows, shovels, jackhammers -// Base Tool Schema: - -// const buildingTool = baseInv.discriminator('tool', new mongoose.Schema({ -// code: { type: Number, required: true }, // TODO: add function to create simple numeric code for on-site tool tracking -// purchaseStatus: { type: String, enum: ['Rental', 'Purchase'], required: true }, -// // rental fields are required if purchaseStatus = "Rental" (hopefully correct syntax) -// rentedOnDate: { type: Date, required: () => this.purchaseStatus === 'Rental' }, -// rentalDueDate: { type: Date, required: () => this.purchaseStatus === 'Rental' }, -// imgUrl: String, -// updateRecord: [{ // track tool condition updates -// _id: false, -// date: { type: Date, default: Date.now() }, -// createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, -// condition: { type: String, enum: ['Good', 'Needs Repair', 'Out of Order'] }, -// }], -// logRecord: [{ // track tool daily check in/out and responsible user -// _id: false, -// date: { type: Date, default: Date.now() }, -// createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, -// responsibleUser: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, -// type: { type: String, enum: ['Check In', 'Check Out'] }, -// }], -// })); - -const buildingTool = baseInvLargeItems.discriminator('tool', new mongoose.Schema({ +const buildingTool = largeItemBase.discriminator('tool', new mongoose.Schema({ code: { type: Number, required: true }, // TODO: add function to create simple numeric code for on-site tool tracking })); -//------------------ -// EQUIPMENT SCHEMAS -//------------------ +//----------------- +// EQUIPMENT SCHEMA +//----------------- -// inherits all properties of baseInv schema using discriminator +// inherits all properties of largeItemBaseSchema // each document derived from this schema includes key field { __t: "equipment" } // items in this category are assumed to be rented // ex: tractors, excavators, bulldozers -// const buildingEquipment = baseInv.discriminator('equipment', new mongoose.Schema({ -// isTracked: { type: Boolean, required: true }, // has asset tracker -// assetTracker: { type: String, required: () => this.isTracked }, // required if isTracked = true (syntax?) -// code: { type: Number, required: true }, // TODO: add function to create simple numeric code for on-site tool tracking -// purchaseStatus: { type: String, enum: ['Rental', 'Purchase'], required: true }, -// // rental fields are required if purchaseStatus = "Rental" (hopefully correct syntax) -// rentedOnDate: { type: Date, required: () => this.purchaseStatus === 'Rental' }, -// rentalDueDate: { type: Date, required: () => this.purchaseStatus === 'Rental' }, -// imgUrl: String, -// updateRecord: [{ // track equipment condition updates -// _id: false, -// date: { type: Date, default: Date.now() }, -// createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, -// condition: { type: String, enum: ['Good', 'Needs Repair', 'Out of Order'] }, -// }], -// logRecord: [{ // track tool daily check in/out and responsible user -// _id: false, -// date: { type: Date, default: Date.now() }, -// createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, -// responsibleUser: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, -// type: { type: String, enum: ['Check In', 'Check Out'] }, -// }], -// })); - -const buildingEquipment = baseInvLargeItems.discriminator('equipment', new mongoose.Schema({ +const buildingEquipment = largeItemBase.discriminator('equipment', new mongoose.Schema({ isTracked: { type: Boolean, required: true }, // has asset tracker assetTracker: { type: String, required: () => this.isTracked }, // required if isTracked = true (syntax?) })); -// add purchase varient instead of rental varient? - module.exports = { buildingMaterial, buildingConsumable, From bae46b1c69333910a54d0d914a5faaec6ed31246 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Tue, 12 Dec 2023 12:43:52 -0800 Subject: [PATCH 205/272] undo changes to current material routes to avoid breaking things --- .../bmdashboard/bmMaterialsController.js | 2 +- src/models/bmdashboard/buildingMaterial.js | 30 +++++++++++-------- src/startup/routes.js | 2 +- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index 2c79bd9b9..911ca0b55 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -48,7 +48,7 @@ const bmMaterialsController = function (ItemMaterial,BuildingMaterial) { const newPurchaseRecord = { quantity, priority, - brandPref: brand, + brand, requestedBy: requestorId, }; try { diff --git a/src/models/bmdashboard/buildingMaterial.js b/src/models/bmdashboard/buildingMaterial.js index caf61e4c0..bc86884ed 100644 --- a/src/models/bmdashboard/buildingMaterial.js +++ b/src/models/bmdashboard/buildingMaterial.js @@ -1,23 +1,29 @@ const mongoose = require('mongoose'); -const baseInv = require('./baseInvSchema'); +const { Schema } = mongoose; -// inherits all properties of baseInv schema using discriminator -// each document derived from this schema includes key field { __t: "buildingMaterial" } - -const buildingMaterial = baseInv.discriminator('buildingMaterial', new mongoose.Schema({ +const buildingMaterial = new Schema({ + itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, + project: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingProject' }, stockBought: { type: Number, default: 0 }, // total amount of item bought for use in the project - stockUsed: { type: Number, default: 0 }, // stock that has been used up and cannot be reused - stockWasted: { type: Number, default: 0 }, // ruined or destroyed stock - stockAvailable: { type: Number, default: 0 }, // available = bought - (used + wasted/destroyed) + stockUsed: { type: Number, default: 0 }, // total amount of item used successfully in the project + stockWasted: { type: Number, default: 0 }, // total amount of item wasted/ruined/lost in the project + stockAvailable: { type: Number, default: 0 }, // bought - (used + wasted) + purchaseRecord: [{ + _id: false, // do not add _id field to subdocument + date: { type: Date, default: Date.now() }, + requestedBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, + quantity: { type: Number, required: true }, + priority: { type: String, enum: ['Low', 'Medium', 'High'], required: true }, + brand: String, + status: { type: String, default: 'Pending', enum: ['Approved', 'Pending', 'Rejected'] }, + }], updateRecord: [{ _id: false, date: { type: Date, required: true }, createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfile' }, quantityUsed: { type: Number, required: true }, quantityWasted: { type: Number, required: true }, - test: { type: String, default: 'testing this field' }, }], -})); - -module.exports = buildingMaterial; +}); +module.exports = mongoose.model('buildingMaterial', buildingMaterial, 'buildingMaterials'); diff --git a/src/startup/routes.js b/src/startup/routes.js index 37832c199..ff5d01b2b 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -23,7 +23,7 @@ const inventoryItemMaterial = require('../models/inventoryItemMaterial'); const mapLocations = require('../models/mapLocation'); const buildingProject = require('../models/bmdashboard/buildingProject'); const buildingInventoryType = require('../models/bmdashboard/buildingInventoryType'); -const { buildingMaterial } = require('../models/bmdashboard/buildingInventoryItem'); +const buildingMaterial = require('../models/bmdashboard/buildingMaterial'); const userProfileRouter = require('../routes/userProfileRouter')(userProfile); const badgeRouter = require('../routes/badgeRouter')(badge); From 18da208bce004ec9c8eb85052d65d899c91e3aef Mon Sep 17 00:00:00 2001 From: Olga Yudkin Date: Wed, 13 Dec 2023 14:55:32 -0500 Subject: [PATCH 206/272] updated toolcontroller query --- .../bmdashboard/bmToolController.js | 45 ++++++++++++++----- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/src/controllers/bmdashboard/bmToolController.js b/src/controllers/bmdashboard/bmToolController.js index 2b29101f3..0feec256c 100644 --- a/src/controllers/bmdashboard/bmToolController.js +++ b/src/controllers/bmdashboard/bmToolController.js @@ -4,16 +4,41 @@ const bmToolController = (BuildingTool) => { try { BuildingTool .findById(toolId) - // .populate([ - // { - // path: 'itemType', - // select: '_id name description unit imageURL', - // }, - // { - // path: 'userResponsible', - // select: '_id firstName lastName', - // }, - // ]) + .populate([ + { + path: 'itemType', + select: '_id name description unit imageUrl category', + }, + { + path: 'userResponsible', + select: '_id firstName lastName', + }, + { + path: 'purchaseRecord', + populate: { + path: 'requestedBy', + select: '_id firstName lastName', + }, + }, + { + path: 'updateRecord', + populate: { + path: 'createdBy', + select: '_id firstName lastName', + }, + }, + { + path: 'logRecord', + populate: [{ + path: 'createdBy', + select: '_id firstName lastName', + }, + { + path: 'responsibleUser', + select: '_id firstName lastName', + }], + }, + ]) .exec() .then(tool => res.status(200).send(tool)) .catch(error => res.status(500).send(error)); From 230cedc459088655359f75cc7a1752be24a4ed40 Mon Sep 17 00:00:00 2001 From: Carl Bebli Date: Fri, 15 Dec 2023 15:41:22 +0000 Subject: [PATCH 207/272] added the replyTo feature --- src/controllers/timeEntryController.js | 366 +++++++++++++++---------- src/helpers/userHelper.js | 4 +- 2 files changed, 228 insertions(+), 142 deletions(-) diff --git a/src/controllers/timeEntryController.js b/src/controllers/timeEntryController.js index 962f30170..9c4d7c5e3 100644 --- a/src/controllers/timeEntryController.js +++ b/src/controllers/timeEntryController.js @@ -1,17 +1,17 @@ -const moment = require('moment-timezone'); -const mongoose = require('mongoose'); -const { getInfringementEmailBody } = require('../helpers/userHelper')(); -const userProfile = require('../models/userProfile'); -const task = require('../models/task'); -const emailSender = require('../utilities/emailSender'); -const { hasPermission } = require('../utilities/permissions'); +const moment = require("moment-timezone"); +const mongoose = require("mongoose"); +const { getInfringementEmailBody } = require("../helpers/userHelper")(); +const userProfile = require("../models/userProfile"); +const task = require("../models/task"); +const emailSender = require("../utilities/emailSender"); +const { hasPermission } = require("../utilities/permissions"); const formatSeconds = function (seconds) { const formattedseconds = parseInt(seconds, 10); const values = `${Math.floor( - moment.duration(formattedseconds, 'seconds').asHours(), - )}:${moment.duration(formattedseconds, 'seconds').minutes()}`; - return values.split(':'); + moment.duration(formattedseconds, "seconds").asHours() + )}:${moment.duration(formattedseconds, "seconds").minutes()}`; + return values.split(":"); }; /** @@ -24,9 +24,20 @@ const formatSeconds = function (seconds) { * @param {*} requestor The userProfile object of the person that modified the time entry * @returns {String} */ -const getEditedTimeEntryEmailBody = (firstName, lastName, email, originalTime, finalTime, requestor) => { - const formattedOriginal = moment.utc(originalTime * 1000).format('HH[ hours ]mm[ minutes]'); - const formattedFinal = moment.utc(finalTime * 1000).format('HH[ hours ]mm[ minutes]'); +const getEditedTimeEntryEmailBody = ( + firstName, + lastName, + email, + originalTime, + finalTime, + requestor +) => { + const formattedOriginal = moment + .utc(originalTime * 1000) + .format("HH[ hours ]mm[ minutes]"); + const formattedFinal = moment + .utc(finalTime * 1000) + .format("HH[ hours ]mm[ minutes]"); return ` A time entry belonging to ${firstName} ${lastName} (${email}) was modified by ${requestor.firstName} ${requestor.lastName} (${requestor.email}). The entry's duration was changed from [${formattedOriginal}] to [${formattedFinal}] @@ -45,18 +56,39 @@ const notifyEditByEmail = async (personId, original, finalTime, final) => { try { const originalTime = original.totalSeconds; const record = await userProfile.findById(personId); - const requestor = (personId !== final.requestor.requestorId) ? await userProfile.findById(final.requestor.requestorId) : record; - const emailBody = getEditedTimeEntryEmailBody(record.firstName, record.lastName, record.email, originalTime, finalTime, requestor); - emailSender('onecommunityglobal@gmail.com', `A Time Entry was Edited for ${record.firstName} ${record.lastName}`, emailBody); + const requestor = + personId !== final.requestor.requestorId + ? await userProfile.findById(final.requestor.requestorId) + : record; + const emailBody = getEditedTimeEntryEmailBody( + record.firstName, + record.lastName, + record.email, + originalTime, + finalTime, + requestor + ); + emailSender( + "onecommunityglobal@gmail.com", + `A Time Entry was Edited for ${record.firstName} ${record.lastName}`, + emailBody + ); } catch (error) { - throw new Error(`Failed to send email notification about the modification of time entry belonging to user with id ${personId}`); + throw new Error( + `Failed to send email notification about the modification of time entry belonging to user with id ${personId}` + ); } }; -const notifyTaskOvertimeEmailBody = async (personId, taskName, estimatedHours, hoursLogged) => { +const notifyTaskOvertimeEmailBody = async ( + personId, + taskName, + estimatedHours, + hoursLogged +) => { try { - const record = await userProfile.findById(personId); - const text = `Dear ${record.firstName}${record.lastName}, + const record = await userProfile.findById(personId); + const text = `Dear ${record.firstName}${record.lastName},

Oops, it looks like you have logged more hours than estimated for a task

Task Name : ${taskName}

Time Estimated : ${estimatedHours}

@@ -64,24 +96,37 @@ const notifyTaskOvertimeEmailBody = async (personId, taskName, estimatedHours, h

Please connect with your manager to explain what happened and submit a new hours estimation for completion.

Thank you,

One Community

`; - emailSender( - record.email, - 'Logged more hours than estimated for a task', - text, - 'onecommunityglobal@gmail.com', - null, + emailSender( + record.email, + "Logged more hours than estimated for a task", + text, + "onecommunityglobal@gmail.com", + null, + record.email, + null ); } catch (error) { - console.log(`Failed to send email notification about the overtime for a task belonging to user with id ${personId}`); + console.log( + `Failed to send email notification about the overtime for a task belonging to user with id ${personId}` + ); } }; const checkTaskOvertime = async (timeentry, record, currentTask) => { try { // send email notification if logged in hours exceeds estiamted hours for a task - if (currentTask.hoursLogged > currentTask.estimatedHours) { notifyTaskOvertimeEmailBody(timeentry.personId.toString(), currentTask.taskName, currentTask.estimatedHours, currentTask.hoursLogged); } + if (currentTask.hoursLogged > currentTask.estimatedHours) { + notifyTaskOvertimeEmailBody( + timeentry.personId.toString(), + currentTask.taskName, + currentTask.estimatedHours, + currentTask.hoursLogged + ); + } } catch (error) { - console.log(`Failed to find task whose logged-in hours are more than estimated hours ${record.email}`); + console.log( + `Failed to find task whose logged-in hours are more than estimated hours ${record.email}` + ); } }; @@ -92,31 +137,58 @@ const timeEntrycontroller = function (TimeEntry) { try { if (!req.params.timeEntryId) { - return res.status(400).send({ error: 'ObjectId in request param is not in correct format' }); + return res + .status(400) + .send({ + error: "ObjectId in request param is not in correct format", + }); } - if (!mongoose.Types.ObjectId.isValid(req.params.timeEntryId) || !mongoose.Types.ObjectId.isValid(req.body.projectId)) { - return res.status(400).send({ error: 'ObjectIds are not correctly formed' }); + if ( + !mongoose.Types.ObjectId.isValid(req.params.timeEntryId) || + !mongoose.Types.ObjectId.isValid(req.body.projectId) + ) { + return res + .status(400) + .send({ error: "ObjectIds are not correctly formed" }); } // Get initial timeEntry by timeEntryId const timeEntry = await TimeEntry.findById(req.params.timeEntryId); if (!timeEntry) { - return res.status(400).send({ error: `No valid records found for ${req.params.timeEntryId}` }); + return res + .status(400) + .send({ + error: `No valid records found for ${req.params.timeEntryId}`, + }); } - if (!(await hasPermission(req.body.requestor, 'editTimeEntry') || timeEntry.personId.toString() === req.body.requestor.requestorId.toString())) { - return res.status(403).send({ error: 'Unauthorized request' }); + if ( + !( + (await hasPermission(req.body.requestor, "editTimeEntry")) || + timeEntry.personId.toString() === + req.body.requestor.requestorId.toString() + ) + ) { + return res.status(403).send({ error: "Unauthorized request" }); } - const hours = req.body.hours ? req.body.hours : '00'; - const minutes = req.body.minutes ? req.body.minutes : '00'; + const hours = req.body.hours ? req.body.hours : "00"; + const minutes = req.body.minutes ? req.body.minutes : "00"; const totalSeconds = moment.duration(`${hours}:${minutes}`).asSeconds(); - if (timeEntry.isTangible === true && totalSeconds !== timeEntry.totalSeconds) { - notifyEditByEmail(timeEntry.personId.toString(), timeEntry, totalSeconds, req.body); + if ( + timeEntry.isTangible === true && + totalSeconds !== timeEntry.totalSeconds + ) { + notifyEditByEmail( + timeEntry.personId.toString(), + timeEntry, + totalSeconds, + req.body + ); } const initialSeconds = timeEntry.totalSeconds; @@ -130,7 +202,7 @@ const timeEntrycontroller = function (TimeEntry) { timeEntry.isTangible = req.body.isTangible; timeEntry.lastModifiedDateTime = moment().utc().toISOString(); timeEntry.projectId = mongoose.Types.ObjectId(req.body.projectId); - timeEntry.dateOfWork = moment(req.body.dateOfWork).format('YYYY-MM-DD'); + timeEntry.dateOfWork = moment(req.body.dateOfWork).format("YYYY-MM-DD"); // Update the hoursLogged field of related tasks based on before and after timeEntries // initialIsTangible is a bealoon value, req.body.isTangible is a string @@ -138,11 +210,11 @@ const timeEntrycontroller = function (TimeEntry) { try { if (findTask) { if (initialIsTangible === true) { - findTask.hoursLogged -= (initialSeconds / 3600); + findTask.hoursLogged -= initialSeconds / 3600; } if (req.body.isTangible === true) { - findTask.hoursLogged += (totalSeconds / 3600); + findTask.hoursLogged += totalSeconds / 3600; } await findTask.save(); @@ -152,14 +224,17 @@ const timeEntrycontroller = function (TimeEntry) { } // Update edit history - if (initialSeconds !== totalSeconds - && timeEntry.isTangible - && req.body.requestor.requestorId === timeEntry.personId.toString() - && !await hasPermission(req.body.requestor, 'editTimeEntry') - ) { - const requestor = await userProfile.findById(req.body.requestor.requestorId); + if ( + initialSeconds !== totalSeconds && + timeEntry.isTangible && + req.body.requestor.requestorId === timeEntry.personId.toString() && + !(await hasPermission(req.body.requestor, "editTimeEntry")) + ) { + const requestor = await userProfile.findById( + req.body.requestor.requestorId + ); requestor.timeEntryEditHistory.push({ - date: moment().tz('America/Los_Angeles').toDate(), + date: moment().tz("America/Los_Angeles").toDate(), initialSeconds, newSeconds: totalSeconds, }); @@ -168,18 +243,23 @@ const timeEntrycontroller = function (TimeEntry) { let totalRecentEdits = 0; requestor.timeEntryEditHistory.forEach((edit) => { - if (moment().tz('America/Los_Angeles').diff(edit.date, 'days') <= 365) { + if ( + moment().tz("America/Los_Angeles").diff(edit.date, "days") <= 365 + ) { totalRecentEdits += 1; } }); if (totalRecentEdits >= 5) { requestor.infringements.push({ - date: moment().tz('America/Los_Angeles'), + date: moment().tz("America/Los_Angeles"), description: `${totalRecentEdits} time entry edits in the last calendar year`, }); - emailSender('onecommunityglobal@gmail.com', `${requestor.firstName} ${requestor.lastName} was issued a blue square for for editing a time entry ${totalRecentEdits} times`, ` + emailSender( + "onecommunityglobal@gmail.com", + `${requestor.firstName} ${requestor.lastName} was issued a blue square for for editing a time entry ${totalRecentEdits} times`, + `

${requestor.firstName} ${requestor.lastName} (${requestor.email}) was issued a blue square for editing their time entries ${totalRecentEdits} times within the last calendar year. @@ -187,28 +267,39 @@ const timeEntrycontroller = function (TimeEntry) {

This is the ${totalRecentEdits}th edit within the past 365 days.

- `); + ` + ); const emailInfringement = { - date: moment().tz('America/Los_Angeles').format('MMMM-DD-YY'), + date: moment().tz("America/Los_Angeles").format("MMMM-DD-YY"), description: `You edited your time entries ${totalRecentEdits} times within the last 365 days, exceeding the limit of 4 times per year you can edit them without penalty.`, }; - emailSender(requestor.email, 'You\'ve been issued a blue square for editing your time entry', getInfringementEmailBody(requestor.firstName, requestor.lastName, emailInfringement, requestor.infringements.length)); + emailSender( + requestor.email, + "You've been issued a blue square for editing your time entry", + getInfringementEmailBody( + requestor.firstName, + requestor.lastName, + emailInfringement, + requestor.infringements.length + ) + ); } await requestor.save(); } - await timeEntry.save(); - res.status(200).send({ message: 'Successfully updated time entry' }); + res.status(200).send({ message: "Successfully updated time entry" }); // If the time entry isn't related to a task (i.e. it's a project), then don't check for overtime (Most likely pr team) if (findTask) { // checking if logged in hours exceed estimated time after timeentry edit for a task - const record = await userProfile.findById(timeEntry.personId.toString()); + const record = await userProfile.findById( + timeEntry.personId.toString() + ); const currentTask = await task.findById(req.body.projectId); checkTaskOvertime(timeEntry, record, currentTask); } @@ -233,9 +324,9 @@ const timeEntrycontroller = function (TimeEntry) { timeentry.personId = element.personId; timeentry.projectId = element.projectId; timeentry.dateOfWork = element.dateOfWork; - timeentry.timeSpent = moment('1900-01-01 00:00:00') - .add(element.totalSeconds, 'seconds') - .format('HH:mm:ss'); + timeentry.timeSpent = moment("1900-01-01 00:00:00") + .add(element.totalSeconds, "seconds") + .format("HH:mm:ss"); timeentry.notes = element.notes; timeentry.isTangible = element.isTangible; items.push(timeentry); @@ -246,21 +337,21 @@ const timeEntrycontroller = function (TimeEntry) { const postTimeEntry = async function (req, res) { if ( - !mongoose.Types.ObjectId.isValid(req.body.personId) - || !mongoose.Types.ObjectId.isValid(req.body.projectId) - || !req.body.dateOfWork - || !moment(req.body.dateOfWork).isValid() - || !req.body.timeSpent - || !req.body.isTangible + !mongoose.Types.ObjectId.isValid(req.body.personId) || + !mongoose.Types.ObjectId.isValid(req.body.projectId) || + !req.body.dateOfWork || + !moment(req.body.dateOfWork).isValid() || + !req.body.timeSpent || + !req.body.isTangible ) { - res.status(400).send({ error: 'Bad request' }); + res.status(400).send({ error: "Bad request" }); return; } const timeentry = new TimeEntry(); const { dateOfWork, timeSpent } = req.body; timeentry.personId = req.body.personId; timeentry.projectId = req.body.projectId; - timeentry.dateOfWork = moment(dateOfWork).format('YYYY-MM-DD'); + timeentry.dateOfWork = moment(dateOfWork).format("YYYY-MM-DD"); timeentry.totalSeconds = moment.duration(timeSpent).asSeconds(); timeentry.notes = req.body.notes; timeentry.isTangible = req.body.isTangible; @@ -274,12 +365,14 @@ const timeEntrycontroller = function (TimeEntry) { .status(200) .send({ message: `Time Entry saved with id as ${results._id}` }); }) - .catch(error => res.status(400).send(error)); + .catch((error) => res.status(400).send(error)); - // Get the task related to this time entry, if not found, then it's a project sets to null - const currentTask = await task.findById(req.body.projectId).catch(() => null); + // Get the task related to this time entry, if not found, then it's a project sets to null + const currentTask = await task + .findById(req.body.projectId) + .catch(() => null); - // Add this tangbile time entry to related task's hoursLogged and checks if timeEntry is related to a task + // Add this tangbile time entry to related task's hoursLogged and checks if timeEntry is related to a task if (timeentry.isTangible === true && currentTask) { try { currentTask.hoursLogged += timeentry.totalSeconds / 3600; @@ -292,7 +385,9 @@ const timeEntrycontroller = function (TimeEntry) { // checking if logged in hours exceed estimated time after timeentry for a task, only if the time entry is related to a task (It might not be, if it's a project) if (currentTask) { try { - const record = await userProfile.findById(timeentry.personId.toString()); + const record = await userProfile.findById( + timeentry.personId.toString() + ); checkTaskOvertime(timeentry, record, currentTask); } catch (error) { throw new Error(error); @@ -302,19 +397,23 @@ const timeEntrycontroller = function (TimeEntry) { const getTimeEntriesForSpecifiedPeriod = function (req, res) { if ( - !req.params - || !req.params.fromdate - || !req.params.todate - || !req.params.userId - || !moment(req.params.fromdate).isValid() - || !moment(req.params.toDate).isValid() + !req.params || + !req.params.fromdate || + !req.params.todate || + !req.params.userId || + !moment(req.params.fromdate).isValid() || + !moment(req.params.toDate).isValid() ) { - res.status(400).send({ error: 'Invalid request' }); + res.status(400).send({ error: "Invalid request" }); return; } - const fromdate = moment(req.params.fromdate).tz('America/Los_Angeles').format('YYYY-MM-DD'); - const todate = moment(req.params.todate).tz('America/Los_Angeles').format('YYYY-MM-DD'); + const fromdate = moment(req.params.fromdate) + .tz("America/Los_Angeles") + .format("YYYY-MM-DD"); + const todate = moment(req.params.todate) + .tz("America/Los_Angeles") + .format("YYYY-MM-DD"); const { userId } = req.params; TimeEntry.aggregate([ @@ -326,18 +425,18 @@ const timeEntrycontroller = function (TimeEntry) { }, { $lookup: { - from: 'projects', - localField: 'projectId', - foreignField: '_id', - as: 'project', + from: "projects", + localField: "projectId", + foreignField: "_id", + as: "project", }, }, { $lookup: { - from: 'tasks', - localField: 'projectId', - foreignField: '_id', - as: 'task', + from: "tasks", + localField: "projectId", + foreignField: "_id", + as: "task", }, }, { @@ -349,41 +448,26 @@ const timeEntrycontroller = function (TimeEntry) { projectId: 1, lastModifiedDateTime: 1, projectName: { - $arrayElemAt: [ - '$project.projectName', - 0, - ], + $arrayElemAt: ["$project.projectName", 0], }, taskName: { - $arrayElemAt: [ - '$task.taskName', - 0, - ], + $arrayElemAt: ["$task.taskName", 0], }, category: { - $arrayElemAt: [ - '$project.category', - 0, - ], + $arrayElemAt: ["$project.category", 0], }, classification: { - $arrayElemAt: [ - '$task.classification', - 0, - ], + $arrayElemAt: ["$task.classification", 0], }, dateOfWork: 1, hours: { $floor: { - $divide: ['$totalSeconds', 3600], + $divide: ["$totalSeconds", 3600], }, }, minutes: { $floor: { - $divide: [ - { $mod: ['$totalSeconds', 3600] }, - 60, - ], + $divide: [{ $mod: ["$totalSeconds", 3600] }, 60], }, }, }, @@ -393,9 +477,11 @@ const timeEntrycontroller = function (TimeEntry) { lastModifiedDateTime: -1, }, }, - ]).then((results) => { - res.status(200).send(results); - }).catch(error => res.status(400).send(error)); + ]) + .then((results) => { + res.status(200).send(results); + }) + .catch((error) => res.status(400).send(error)); }; const getTimeEntriesForUsersList = function (req, res) { @@ -406,9 +492,9 @@ const timeEntrycontroller = function (TimeEntry) { personId: { $in: users }, dateOfWork: { $gte: fromDate, $lte: toDate }, }, - ' -createdDateTime', + " -createdDateTime" ) - .populate('projectId') + .populate("projectId") .sort({ lastModifiedDateTime: -1 }) .then((results) => { const data = []; @@ -419,72 +505,73 @@ const timeEntrycontroller = function (TimeEntry) { record.notes = element.notes; record.isTangible = element.isTangible; record.personId = element.personId; - record.projectId = element.projectId ? element.projectId._id : ''; + record.projectId = element.projectId ? element.projectId._id : ""; record.projectName = element.projectId ? element.projectId.projectName - : ''; + : ""; record.dateOfWork = element.dateOfWork; [record.hours, record.minutes] = formatSeconds(element.totalSeconds); data.push(record); }); res.status(200).send(data); }) - .catch(error => res.status(400).send(error)); + .catch((error) => res.status(400).send(error)); }; const getTimeEntriesForSpecifiedProject = function (req, res) { if ( - !req.params - || !req.params.fromDate - || !req.params.toDate - || !req.params.projectId + !req.params || + !req.params.fromDate || + !req.params.toDate || + !req.params.projectId ) { - res.status(400).send({ error: 'Invalid request' }); + res.status(400).send({ error: "Invalid request" }); return; } - const todate = moment(req.params.toDate).format('YYYY-MM-DD'); - const fromDate = moment(req.params.fromDate).format('YYYY-MM-DD'); + const todate = moment(req.params.toDate).format("YYYY-MM-DD"); + const fromDate = moment(req.params.fromDate).format("YYYY-MM-DD"); const { projectId } = req.params; TimeEntry.find( { projectId, dateOfWork: { $gte: fromDate, $lte: todate }, }, - '-createdDateTime -lastModifiedDateTime', + "-createdDateTime -lastModifiedDateTime" ) - .populate('userId') + .populate("userId") .sort({ dateOfWork: -1 }) .then((results) => { res.status(200).send(results); }) - .catch(error => res.status(400).send(error)); + .catch((error) => res.status(400).send(error)); }; const deleteTimeEntry = async function (req, res) { if (!req.params.timeEntryId) { - res.status(400).send({ error: 'Bad request' }); + res.status(400).send({ error: "Bad request" }); return; } TimeEntry.findById(req.params.timeEntryId) .then(async (record) => { if (!record) { - res.status(400).send({ message: 'No valid record found' }); + res.status(400).send({ message: "No valid record found" }); return; } if ( - record.personId.toString() - === req.body.requestor.requestorId.toString() - || await hasPermission(req.body.requestor, 'deleteTimeEntry') + record.personId.toString() === + req.body.requestor.requestorId.toString() || + (await hasPermission(req.body.requestor, "deleteTimeEntry")) ) { // Revert this tangible timeEntry of related task's hoursLogged if (record.isTangible === true) { - task.findById(record.projectId) + task + .findById(record.projectId) .then((currentTask) => { // If the time entry isn't related to a task (i.e. it's a project), then don't revert hours (Most likely pr team) if (currentTask) { - currentTask.hoursLogged -= (record.totalSeconds / 3600); + currentTask.hoursLogged -= record.totalSeconds / 3600; currentTask.save(); } }) @@ -496,13 +583,13 @@ const timeEntrycontroller = function (TimeEntry) { record .remove() .then(() => { - res.status(200).send({ message: 'Successfully deleted' }); + res.status(200).send({ message: "Successfully deleted" }); }) .catch((error) => { res.status(500).send(error); }); } else { - res.status(403).send({ error: 'Unauthorized request' }); + res.status(403).send({ error: "Unauthorized request" }); } }) .catch((error) => { @@ -510,7 +597,6 @@ const timeEntrycontroller = function (TimeEntry) { }); }; - return { getAllTimeEnteries, postTimeEntry, diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index 8bf04eb5f..42422a02d 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -492,8 +492,8 @@ const userHelper = function () { emailBody, null, "onecommunityglobal@gmail.com", - null, - status.email + status.email, + null ); const categories = await dashboardHelper.laborThisWeekByCategory( From 2df386581e81c2227d51c0d99a49770c43d34a30 Mon Sep 17 00:00:00 2001 From: Shiwani Rajagopalan Date: Sat, 16 Dec 2023 19:25:31 -0500 Subject: [PATCH 208/272] added TimeOffFrom and TimeOffTill to dashboardhelper leaderboard pipeline --- src/helpers/dashboardhelper.js | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index 64c867f71..1eaf9b723 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -259,6 +259,12 @@ const dashboardhelper = function () { }, ], }, + timeOffFrom: { + $ifNull: ["$persondata.timeOffFrom", null], + }, + timeOffTill: { + $ifNull: ["$persondata.timeOffTill", null], + }, }, }, { @@ -277,6 +283,8 @@ const dashboardhelper = function () { isVisible: 1, hasSummary: 1, weeklycommittedHours: 1, + timeOffFrom: 1, + timeOffTill: 1, timeEntryData: { $filter: { input: "$timeEntryData", @@ -309,6 +317,8 @@ const dashboardhelper = function () { isVisible: 1, hasSummary: 1, weeklycommittedHours: 1, + timeOffFrom: 1, + timeOffTill: 1, totalSeconds: { $cond: [ { @@ -356,6 +366,8 @@ const dashboardhelper = function () { _id: { personId: "$personId", weeklycommittedHours: "$weeklycommittedHours", + timeOffFrom: "$timeOffFrom", + timeOffTill: "$timeOffTill", name: "$name", role: "$role", isVisible: "$isVisible", @@ -406,12 +418,8 @@ const dashboardhelper = function () { }, ], }, - timeOffFrom: { - $ifNull: ["$persondata.timeOffFrom", null], - }, - timeOffTill: { - $ifNull: ["$persondata.timeOffTill", null], - }, + timeOffFrom: "$_id.timeOffFrom", + timeOffTill: "$_id.timeOffTill", currentDate: { $toDate: new Date() }, }, }, From 2ecf74d07810c42d71038fd1656ba632984b7dda Mon Sep 17 00:00:00 2001 From: Shiwani Rajagopalan Date: Sat, 16 Dec 2023 23:16:19 -0500 Subject: [PATCH 209/272] added pst time instead of est for current date --- src/helpers/dashboardhelper.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index 1eaf9b723..0e3c71e9b 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -420,7 +420,9 @@ const dashboardhelper = function () { }, timeOffFrom: "$_id.timeOffFrom", timeOffTill: "$_id.timeOffTill", - currentDate: { $toDate: new Date() }, + currentDate: { + $toDate: moment.tz("America/Los_Angeles").startOf("day"), + }, }, }, { From 511062fd75c0cb619eea39b06d9def6e6a7bc6d7 Mon Sep 17 00:00:00 2001 From: Shiwani Rajagopalan Date: Sun, 17 Dec 2023 11:55:54 -0500 Subject: [PATCH 210/272] removed current date from leaderboard aggregation pipeline --- src/helpers/dashboardhelper.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index 0e3c71e9b..5efeae4f7 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -420,9 +420,6 @@ const dashboardhelper = function () { }, timeOffFrom: "$_id.timeOffFrom", timeOffTill: "$_id.timeOffTill", - currentDate: { - $toDate: moment.tz("America/Los_Angeles").startOf("day"), - }, }, }, { From ecc27d33cc008ba26d694d6613ff33a5fac09f48 Mon Sep 17 00:00:00 2001 From: Shiwani Rajagopalan Date: Sun, 17 Dec 2023 14:16:00 -0500 Subject: [PATCH 211/272] added timeOffFrom and timeOffTill to taskHelper --- src/helpers/taskHelper.js | 316 ++++++++++++++++++++------------------ 1 file changed, 166 insertions(+), 150 deletions(-) diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index a94aaee94..937702e05 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -1,17 +1,17 @@ -const moment = require('moment-timezone'); -const userProfile = require('../models/userProfile'); -const myteam = require('../helpers/helperModels/myTeam'); +const moment = require("moment-timezone"); +const userProfile = require("../models/userProfile"); +const myteam = require("../helpers/helperModels/myTeam"); const taskHelper = function () { const getTasksForTeams = function (userId) { const pdtstart = moment() - .tz('America/Los_Angeles') - .startOf('week') - .format('YYYY-MM-DD'); + .tz("America/Los_Angeles") + .startOf("week") + .format("YYYY-MM-DD"); const pdtend = moment() - .tz('America/Los_Angeles') - .endOf('week') - .format('YYYY-MM-DD'); + .tz("America/Los_Angeles") + .endOf("week") + .format("YYYY-MM-DD"); return myteam.aggregate([ { $match: { @@ -19,23 +19,23 @@ const taskHelper = function () { }, }, { - $unwind: '$myteam', + $unwind: "$myteam", }, { $project: { _id: 0, - personId: '$myteam._id', - name: '$myteam.fullName', + personId: "$myteam._id", + name: "$myteam.fullName", role: 1, }, }, // have personId, name, role { $lookup: { - from: 'userProfiles', - localField: 'personId', - foreignField: '_id', - as: 'persondata', + from: "userProfiles", + localField: "personId", + foreignField: "_id", + as: "persondata", }, }, { @@ -43,31 +43,37 @@ const taskHelper = function () { // dashboard tasks user roles hierarchy $or: [ { - role: { $in: ['Owner', 'Core Team'] }, + role: { $in: ["Owner", "Core Team"] }, }, { $and: [ { - role: 'Administrator', + role: "Administrator", }, - { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, - ] + { "persondata.0.role": { $nin: ["Owner", "Administrator"] } }, + ], }, { $and: [ { - role: { $in: ['Manager', 'Mentor'] }, + role: { $in: ["Manager", "Mentor"] }, }, { - 'persondata.0.role': { - $nin: ['Manager', 'Mentor', 'Core Team', 'Administrator', 'Owner'], + "persondata.0.role": { + $nin: [ + "Manager", + "Mentor", + "Core Team", + "Administrator", + "Owner", + ], }, }, ], }, - { 'persondata.0._id': userId }, - { 'persondata.0.role': 'Volunteer' }, - { 'persondata.0.isVisible': true }, + { "persondata.0._id": userId }, + { "persondata.0.role": "Volunteer" }, + { "persondata.0.isVisible": true }, ], }, }, @@ -78,22 +84,28 @@ const taskHelper = function () { weeklycommittedHours: { $sum: [ { - $arrayElemAt: ['$persondata.weeklycommittedHours', 0], + $arrayElemAt: ["$persondata.weeklycommittedHours", 0], }, { - $ifNull: [{ $arrayElemAt: ['$persondata.missedHours', 0] }, 0], + $ifNull: [{ $arrayElemAt: ["$persondata.missedHours", 0] }, 0], }, ], }, + timeOffFrom: { + $ifNull: ["$persondata.timeOffFrom", null], + }, + timeOffTill: { + $ifNull: ["$persondata.timeOffTill", null], + }, role: 1, }, }, { $lookup: { - from: 'timeEntries', - localField: 'personId', - foreignField: 'personId', - as: 'timeEntryData', + from: "timeEntries", + localField: "personId", + foreignField: "personId", + as: "timeEntryData", }, }, { @@ -101,17 +113,19 @@ const taskHelper = function () { personId: 1, name: 1, weeklycommittedHours: 1, + timeOffFrom: 1, + timeOffTill: 1, timeEntryData: { $filter: { - input: '$timeEntryData', - as: 'timeentry', + input: "$timeEntryData", + as: "timeentry", cond: { $and: [ { - $gte: ['$$timeentry.dateOfWork', pdtstart], + $gte: ["$$timeentry.dateOfWork", pdtstart], }, { - $lte: ['$$timeentry.dateOfWork', pdtend], + $lte: ["$$timeentry.dateOfWork", pdtend], }, ], }, @@ -122,7 +136,7 @@ const taskHelper = function () { }, { $unwind: { - path: '$timeEntryData', + path: "$timeEntryData", preserveNullAndEmptyArrays: true, }, }, @@ -131,21 +145,23 @@ const taskHelper = function () { personId: 1, name: 1, weeklycommittedHours: 1, + timeOffFrom: 1, + timeOffTill: 1, totalSeconds: { $cond: [ { - $gte: ['$timeEntryData.totalSeconds', 0], + $gte: ["$timeEntryData.totalSeconds", 0], }, - '$timeEntryData.totalSeconds', + "$timeEntryData.totalSeconds", 0, ], }, isTangible: { $cond: [ { - $gte: ['$timeEntryData.totalSeconds', 0], + $gte: ["$timeEntryData.totalSeconds", 0], }, - '$timeEntryData.isTangible', + "$timeEntryData.isTangible", false, ], }, @@ -157,9 +173,9 @@ const taskHelper = function () { tangibletime: { $cond: [ { - $eq: ['$isTangible', true], + $eq: ["$isTangible", true], }, - '$totalSeconds', + "$totalSeconds", 0, ], }, @@ -168,40 +184,44 @@ const taskHelper = function () { { $group: { _id: { - personId: '$personId', - weeklycommittedHours: '$weeklycommittedHours', - name: '$name', - role: '$role', + personId: "$personId", + weeklycommittedHours: "$weeklycommittedHours", + timeOffFrom: "$timeOffFrom", + timeOffTill: "$timeOffTill", + name: "$name", + role: "$role", }, totalSeconds: { - $sum: '$totalSeconds', + $sum: "$totalSeconds", }, tangibletime: { - $sum: '$tangibletime', + $sum: "$tangibletime", }, }, }, { $project: { _id: 0, - personId: '$_id.personId', - name: '$_id.name', - weeklycommittedHours: '$_id.weeklycommittedHours', + personId: "$_id.personId", + name: "$_id.name", + weeklycommittedHours: "$_id.weeklycommittedHours", + timeOffFrom: "$_id.timeOffFrom", + timeOffTill: "$_id.timeOffTill", totaltime_hrs: { - $divide: ['$totalSeconds', 3600], + $divide: ["$totalSeconds", 3600], }, totaltangibletime_hrs: { - $divide: ['$tangibletime', 3600], + $divide: ["$tangibletime", 3600], }, - role: '$_id.role', + role: "$_id.role", }, }, { $lookup: { - from: 'tasks', - localField: 'personId', - foreignField: 'resources.userID', - as: 'tasks', + from: "tasks", + localField: "personId", + foreignField: "resources.userID", + as: "tasks", }, }, { @@ -215,25 +235,25 @@ const taskHelper = function () { }, { $unwind: { - path: '$tasks', + path: "$tasks", preserveNullAndEmptyArrays: true, }, }, { $lookup: { - from: 'wbs', - localField: 'tasks.wbsId', - foreignField: '_id', - as: 'projectId', + from: "wbs", + localField: "tasks.wbsId", + foreignField: "_id", + as: "projectId", }, }, { $addFields: { - 'tasks.projectId': { + "tasks.projectId": { $cond: [ - { $ne: ['$projectId', []] }, - { $arrayElemAt: ['$projectId', 0] }, - '$tasks.projectId', + { $ne: ["$projectId", []] }, + { $arrayElemAt: ["$projectId", 0] }, + "$tasks.projectId", ], }, }, @@ -255,55 +275,55 @@ const taskHelper = function () { }, { $addFields: { - 'tasks.projectId': '$tasks.projectId.projectId', + "tasks.projectId": "$tasks.projectId.projectId", }, }, { $lookup: { - from: 'taskNotifications', - localField: 'tasks._id', - foreignField: 'taskId', - as: 'tasks.taskNotifications', + from: "taskNotifications", + localField: "tasks._id", + foreignField: "taskId", + as: "tasks.taskNotifications", }, }, { $group: { - _id: '$personId', + _id: "$personId", tasks: { - $push: '$tasks', + $push: "$tasks", }, data: { - $first: '$$ROOT', + $first: "$$ROOT", }, }, }, { $addFields: { - 'data.tasks': { + "data.tasks": { $filter: { - input: '$tasks', - as: 'task', - cond: { $ne: ['$$task', {}] }, + input: "$tasks", + as: "task", + cond: { $ne: ["$$task", {}] }, }, }, }, }, { $replaceRoot: { - newRoot: '$data', + newRoot: "$data", }, }, ]); }; const getTasksForSingleUser = function (userId) { const pdtstart = moment() - .tz('America/Los_Angeles') - .startOf('week') - .format('YYYY-MM-DD'); + .tz("America/Los_Angeles") + .startOf("week") + .format("YYYY-MM-DD"); const pdtend = moment() - .tz('America/Los_Angeles') - .endOf('week') - .format('YYYY-MM-DD'); + .tz("America/Los_Angeles") + .endOf("week") + .format("YYYY-MM-DD"); return userProfile.aggregate([ { $match: { @@ -312,20 +332,16 @@ const taskHelper = function () { }, { $project: { - personId: '$_id', - role: '$role', + personId: "$_id", + role: "$role", name: { - $concat: [ - '$firstName', - ' ', - '$lastName', - ], + $concat: ["$firstName", " ", "$lastName"], }, weeklycommittedHours: { $sum: [ - '$weeklycommittedHours', + "$weeklycommittedHours", { - $ifNull: ['$missedHours', 0], + $ifNull: ["$missedHours", 0], }, ], }, @@ -333,10 +349,10 @@ const taskHelper = function () { }, { $lookup: { - from: 'timeEntries', - localField: 'personId', - foreignField: 'personId', - as: 'timeEntryData', + from: "timeEntries", + localField: "personId", + foreignField: "personId", + as: "timeEntryData", }, }, { @@ -347,15 +363,15 @@ const taskHelper = function () { role: 1, timeEntryData: { $filter: { - input: '$timeEntryData', - as: 'timeentry', + input: "$timeEntryData", + as: "timeentry", cond: { $and: [ { - $gte: ['$$timeentry.dateOfWork', pdtstart], + $gte: ["$$timeentry.dateOfWork", pdtstart], }, { - $lte: ['$$timeentry.dateOfWork', pdtend], + $lte: ["$$timeentry.dateOfWork", pdtend], }, ], }, @@ -365,7 +381,7 @@ const taskHelper = function () { }, { $unwind: { - path: '$timeEntryData', + path: "$timeEntryData", preserveNullAndEmptyArrays: true, }, }, @@ -378,18 +394,18 @@ const taskHelper = function () { totalSeconds: { $cond: [ { - $gte: ['$timeEntryData.totalSeconds', 0], + $gte: ["$timeEntryData.totalSeconds", 0], }, - '$timeEntryData.totalSeconds', + "$timeEntryData.totalSeconds", 0, ], }, isTangible: { $cond: [ { - $gte: ['$timeEntryData.totalSeconds', 0], + $gte: ["$timeEntryData.totalSeconds", 0], }, - '$timeEntryData.isTangible', + "$timeEntryData.isTangible", false, ], }, @@ -400,9 +416,9 @@ const taskHelper = function () { tangibletime: { $cond: [ { - $eq: ['$isTangible', true], + $eq: ["$isTangible", true], }, - '$totalSeconds', + "$totalSeconds", 0, ], }, @@ -411,40 +427,40 @@ const taskHelper = function () { { $group: { _id: { - personId: '$personId', - weeklycommittedHours: '$weeklycommittedHours', - name: '$name', - role: '$role', + personId: "$personId", + weeklycommittedHours: "$weeklycommittedHours", + name: "$name", + role: "$role", }, totalSeconds: { - $sum: '$totalSeconds', + $sum: "$totalSeconds", }, tangibletime: { - $sum: '$tangibletime', + $sum: "$tangibletime", }, }, }, { $project: { _id: 0, - personId: '$_id.personId', - name: '$_id.name', - weeklycommittedHours: '$_id.weeklycommittedHours', - role: '$_id.role', + personId: "$_id.personId", + name: "$_id.name", + weeklycommittedHours: "$_id.weeklycommittedHours", + role: "$_id.role", totaltime_hrs: { - $divide: ['$totalSeconds', 3600], + $divide: ["$totalSeconds", 3600], }, totaltangibletime_hrs: { - $divide: ['$tangibletime', 3600], + $divide: ["$tangibletime", 3600], }, }, }, { $lookup: { - from: 'tasks', - localField: 'personId', - foreignField: 'resources.userID', - as: 'tasks', + from: "tasks", + localField: "personId", + foreignField: "resources.userID", + as: "tasks", }, }, { @@ -458,25 +474,25 @@ const taskHelper = function () { }, { $unwind: { - path: '$tasks', + path: "$tasks", preserveNullAndEmptyArrays: true, }, }, { $lookup: { - from: 'wbs', - localField: 'tasks.wbsId', - foreignField: '_id', - as: 'projectId', + from: "wbs", + localField: "tasks.wbsId", + foreignField: "_id", + as: "projectId", }, }, { $addFields: { - 'tasks.projectId': { + "tasks.projectId": { $cond: [ - { $ne: ['$projectId', []] }, - { $arrayElemAt: ['$projectId', 0] }, - '$tasks.projectId', + { $ne: ["$projectId", []] }, + { $arrayElemAt: ["$projectId", 0] }, + "$tasks.projectId", ], }, }, @@ -498,40 +514,40 @@ const taskHelper = function () { }, { $addFields: { - 'tasks.projectId': '$tasks.projectId.projectId', + "tasks.projectId": "$tasks.projectId.projectId", }, }, { $lookup: { - from: 'taskNotifications', - localField: 'tasks._id', - foreignField: 'taskId', - as: 'tasks.taskNotifications', + from: "taskNotifications", + localField: "tasks._id", + foreignField: "taskId", + as: "tasks.taskNotifications", }, }, { $group: { - _id: '$personId', - tasks: { $push: '$tasks' }, + _id: "$personId", + tasks: { $push: "$tasks" }, data: { - $first: '$$ROOT', + $first: "$$ROOT", }, }, }, { $addFields: { - 'data.tasks': { + "data.tasks": { $filter: { - input: '$tasks', - as: 'task', - cond: { $ne: ['$$task', {}] }, + input: "$tasks", + as: "task", + cond: { $ne: ["$$task", {}] }, }, }, }, }, { $replaceRoot: { - newRoot: '$data', + newRoot: "$data", }, }, ]); @@ -539,7 +555,7 @@ const taskHelper = function () { const getUserProfileFirstAndLastName = function (userId) { return userProfile.findById(userId).then((results) => { if (!results) { - return ' '; + return " "; } return `${results.firstName} ${results.lastName}`; }); From 7de89472272d1c058c4c6f4f730cbe35697be5f4 Mon Sep 17 00:00:00 2001 From: Shiwani Rajagopalan Date: Sun, 17 Dec 2023 14:55:58 -0500 Subject: [PATCH 212/272] added timeOffFrom and timeOffTill to reportHelper --- src/helpers/reporthelper.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/helpers/reporthelper.js b/src/helpers/reporthelper.js index 0c2a8104d..2614a37f6 100644 --- a/src/helpers/reporthelper.js +++ b/src/helpers/reporthelper.js @@ -121,7 +121,13 @@ const reporthelper = function () { }, }, teamCode: { - $ifNull: ['$teamCode', ''], + $ifNull: ["$teamCode", ""], + }, + timeOffFrom: { + $ifNull: ["$timeOffFrom", null], + }, + timeOffTill: { + $ifNull: ["$timeOffTill", null], }, role: 1, weeklySummaries: { From 33a0546451f5f90acf74fc91fe3e49b28cb41e57 Mon Sep 17 00:00:00 2001 From: Shiwani Rajagopalan Date: Mon, 18 Dec 2023 14:32:17 -0500 Subject: [PATCH 213/272] updated dashboardhelper and taskHelper to add timeOffFrom anf timeOffTill for individual task and leaderboard data --- src/helpers/dashboardhelper.js | 2 ++ src/helpers/taskHelper.js | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index 5efeae4f7..b8c0f8293 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -485,6 +485,8 @@ const dashboardhelper = function () { totalintangibletime_hrs: intangibleSeconds / 3600, percentagespentintangible: (intangibleSeconds / tangibleSeconds) * 100, + timeOffFrom: user.timeOffFrom, + timeOffTill: user.timeOffTill, }, ]; } catch (err) { diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index 937702e05..f9353f89b 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -345,6 +345,12 @@ const taskHelper = function () { }, ], }, + timeOffFrom: { + $ifNull: ["$timeOffFrom", null], + }, + timeOffTill: { + $ifNull: ["$timeOffTill", null], + }, }, }, { @@ -360,6 +366,8 @@ const taskHelper = function () { personId: 1, name: 1, weeklycommittedHours: 1, + timeOffFrom: 1, + timeOffTill: 1, role: 1, timeEntryData: { $filter: { @@ -390,6 +398,8 @@ const taskHelper = function () { personId: 1, name: 1, weeklycommittedHours: 1, + timeOffFrom: 1, + timeOffTill: 1, role: 1, totalSeconds: { $cond: [ @@ -429,6 +439,8 @@ const taskHelper = function () { _id: { personId: "$personId", weeklycommittedHours: "$weeklycommittedHours", + timeOffFrom: "$timeOffFrom", + timeOffTill: "$timeOffTill", name: "$name", role: "$role", }, @@ -446,6 +458,8 @@ const taskHelper = function () { personId: "$_id.personId", name: "$_id.name", weeklycommittedHours: "$_id.weeklycommittedHours", + timeOffFrom: "$_id.timeOffFrom", + timeOffTill: "$_id.timeOffTill", role: "$_id.role", totaltime_hrs: { $divide: ["$totalSeconds", 3600], From 367abce5a2300d6ef666c92d6d43ef0028f4c8c9 Mon Sep 17 00:00:00 2001 From: Shiwani Rajagopalan Date: Mon, 18 Dec 2023 17:50:04 -0500 Subject: [PATCH 214/272] modified the array representation for timeOffFrom and TimeOffTill to a value instead of array --- src/helpers/dashboardhelper.js | 4 ++-- src/helpers/taskHelper.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index b8c0f8293..48f9047da 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -260,10 +260,10 @@ const dashboardhelper = function () { ], }, timeOffFrom: { - $ifNull: ["$persondata.timeOffFrom", null], + $ifNull: [{ $arrayElemAt: ["$persondata.timeOffFrom", 0] }, null], }, timeOffTill: { - $ifNull: ["$persondata.timeOffTill", null], + $ifNull: [{ $arrayElemAt: ["$persondata.timeOffTill", 0] }, null], }, }, }, diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index f9353f89b..b5268734e 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -92,10 +92,10 @@ const taskHelper = function () { ], }, timeOffFrom: { - $ifNull: ["$persondata.timeOffFrom", null], + $ifNull: [{ $arrayElemAt: ["$persondata.timeOffFrom", 0] }, null], }, timeOffTill: { - $ifNull: ["$persondata.timeOffTill", null], + $ifNull: [{ $arrayElemAt: ["$persondata.timeOffTill", 0] }, null], }, role: 1, }, From 676ab6dd93e725a65995edd07be28b2ee8a18d54 Mon Sep 17 00:00:00 2001 From: Shiwani99 <78906820+Shiwani99@users.noreply.github.com> Date: Mon, 18 Dec 2023 18:53:26 -0500 Subject: [PATCH 215/272] Added comments to reasonSchedulingController.js --- src/controllers/reasonSchedulingController.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/controllers/reasonSchedulingController.js b/src/controllers/reasonSchedulingController.js index 89b312bc2..3c6334051 100644 --- a/src/controllers/reasonSchedulingController.js +++ b/src/controllers/reasonSchedulingController.js @@ -55,12 +55,13 @@ const postReason = async (req, res) => { }); } - // new changes + // conditions added to check if timeOffFrom and timeOffTill fields existed if ( foundUser.hasOwnProperty("timeOffFrom") && foundUser.hasOwnProperty("timeOffTill") ) { + // if currentDate is greater than or equal to the last timeOffTill date then both the fields will be updated if (currentDate >= foundUser.timeOffTill) { await UserModel.findOneAndUpdate( { @@ -74,6 +75,7 @@ const postReason = async (req, res) => { } ); } else { + // else only timeOffTill will be updated await UserModel.findOneAndUpdate( { _id: userId, @@ -86,6 +88,7 @@ const postReason = async (req, res) => { ); } } else { + // if both the fields are not present then these fields will be added to mongoDB for that user await UserModel.findOneAndUpdate( { _id: userId, From 775265b4716a32e39624a1cd5516a57675bbfe40 Mon Sep 17 00:00:00 2001 From: Ruike Qiu <114443664+StrawberryCalpico@users.noreply.github.com> Date: Tue, 19 Dec 2023 20:55:06 -0800 Subject: [PATCH 216/272] added sanitizer --- package-lock.json | 127 +++++++++++++++++--------------- package.json | 1 + src/routes/userProfileRouter.js | 71 +++++++++++++----- 3 files changed, 121 insertions(+), 78 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0c8f3ee0b..ff66994e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1568,7 +1568,7 @@ "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, "@types/mime": { @@ -1729,7 +1729,7 @@ "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, "array-includes": { "version": "3.1.6", @@ -2768,7 +2768,7 @@ "bcryptjs": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", - "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" + "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" }, "bignumber.js": { "version": "9.0.2", @@ -2863,7 +2863,7 @@ "buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" }, "buffer-from": { "version": "1.1.2", @@ -2995,7 +2995,7 @@ "clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==" + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" }, "clone-deep": { "version": "4.0.1", @@ -3039,12 +3039,12 @@ "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concat-stream": { "version": "1.6.2", @@ -3100,7 +3100,7 @@ "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, "core-js": { "version": "3.21.1", @@ -3253,7 +3253,7 @@ "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "electron-to-chromium": { "version": "1.4.81", @@ -3269,7 +3269,7 @@ "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, "es-abstract": { "version": "1.19.1", @@ -3350,7 +3350,7 @@ "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, "escape-string-regexp": { "version": "1.0.5", @@ -4264,7 +4264,7 @@ "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, "event-target-shim": { "version": "5.0.1", @@ -4409,6 +4409,22 @@ } } }, + "express-validator": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-7.0.1.tgz", + "integrity": "sha512-oB+z9QOzQIE8FnlINqyIFA8eIckahC6qc8KtqLdLJcU3/phVyuhXH3bA4qzcrhme+1RYaCSwrq+TlZ/kAKIARA==", + "requires": { + "lodash": "^4.17.21", + "validator": "^13.9.0" + }, + "dependencies": { + "validator": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", + "integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==" + } + } + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -4429,7 +4445,7 @@ "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, "fast-text-encoding": { @@ -4559,7 +4575,7 @@ "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, "fs-readdir-recursive": { "version": "1.1.0", @@ -4569,7 +4585,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { "version": "2.3.2", @@ -4952,7 +4968,7 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, "indent-string": { @@ -4964,7 +4980,7 @@ "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "requires": { "once": "^1.3.0", "wrappy": "1" @@ -5069,7 +5085,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, "is-glob": { "version": "4.0.3", @@ -5171,13 +5187,13 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, "js-tokens": { "version": "4.0.0", @@ -5215,7 +5231,7 @@ "json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, "json5": { @@ -5536,7 +5552,7 @@ "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, "lodash.merge": { "version": "4.6.2", @@ -5713,7 +5729,7 @@ "lru_map": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", - "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==" + "integrity": "sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0=" }, "make-dir": { "version": "2.1.0", @@ -5727,7 +5743,7 @@ "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, "memory-pager": { "version": "1.5.0", @@ -5738,7 +5754,7 @@ "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, "merge-stream": { "version": "2.0.0", @@ -5749,7 +5765,7 @@ "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, "micromatch": { "version": "4.0.5", @@ -5806,11 +5822,6 @@ "moment": ">= 2.9.0" } }, - "mongo-round": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mongo-round/-/mongo-round-1.0.0.tgz", - "integrity": "sha512-lwvLJv827Uks+3HnTOt1I/Qr78Avke3du1oMaFqFpTwtRKtOposNOKkfpGXQN4ZGpRN3XAS8fEppIJ4TUj0xQw==" - }, "mongodb": { "version": "3.7.3", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz", @@ -5934,7 +5945,7 @@ "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, "negotiator": { @@ -6074,7 +6085,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-inspect": { "version": "1.12.0", @@ -6793,7 +6804,7 @@ "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { "wrappy": "1" } @@ -6823,7 +6834,7 @@ "os-shim": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz", - "integrity": "sha512-jd0cvB8qQ5uVt0lvCIexBaROw1KyKm5sbulg2fWOHjETisuCzWyt+eTZKEMs8v6HwzoGs8xik26jg7eCM6pS+A==", + "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=", "dev": true }, "p-limit": { @@ -6868,7 +6879,7 @@ "parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==" + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" }, "parseurl": { "version": "1.3.3", @@ -6883,7 +6894,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-key": { "version": "3.1.1", @@ -6899,7 +6910,7 @@ "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, "picocolors": { "version": "1.0.0", @@ -6946,7 +6957,7 @@ "pre-commit": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/pre-commit/-/pre-commit-1.2.2.tgz", - "integrity": "sha512-qokTiqxD6GjODy5ETAIgzsRgnBWWQHQH2ghy86PU7mIn/wuWeTwF3otyNQZxWBwVn8XNr8Tdzj/QfUXpH+gRZA==", + "integrity": "sha1-287g7p3nI15X95xW186UZBpp7sY=", "dev": true, "requires": { "cross-spawn": "^5.0.1", @@ -6957,7 +6968,7 @@ "cross-spawn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { "lru-cache": "^4.0.1", @@ -6968,7 +6979,7 @@ "which": { "version": "1.2.14", "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", - "integrity": "sha512-16uPglFkRPzgiUXYMi1Jf8Z5EzN1iB4V0ZtMXcHZnwsBtQhhHeCqoWw7tsUY42hJGNDWtUsVLTjakIa5BgAxCw==", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", "dev": true, "requires": { "isexe": "^2.0.0" @@ -7010,7 +7021,7 @@ "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, "pstree.remy": { @@ -7488,7 +7499,7 @@ "sparse-bitfield": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", "optional": true, "requires": { "memory-pager": "^1.0.2" @@ -7497,7 +7508,7 @@ "spawn-sync": { "version": "1.0.15", "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", - "integrity": "sha512-9DWBgrgYZzNghseho0JOuh+5fg9u6QWhAWa51QC7+U5rCheZ/j1DrEZnyE0RBBRqZ9uEXGPgSSM0nky6burpVw==", + "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=", "dev": true, "requires": { "concat-stream": "^1.4.7", @@ -7892,7 +7903,7 @@ "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, "strip-final-newline": { @@ -7923,19 +7934,19 @@ "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" }, "to-regex-range": { "version": "5.0.1", @@ -7962,7 +7973,7 @@ "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" }, "tsconfig-paths": { "version": "3.14.2", @@ -8080,7 +8091,7 @@ "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, "unbox-primitive": { @@ -8127,7 +8138,7 @@ "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, "uri-js": { "version": "4.4.1", @@ -8141,17 +8152,17 @@ "url-template": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", - "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==" + "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { "version": "3.4.0", @@ -8174,17 +8185,17 @@ "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" }, "whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -8302,7 +8313,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "ws": { "version": "8.8.1", diff --git a/package.json b/package.json index 1c6b8a5d4..e7fbd6307 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "cron": "^1.8.2", "dotenv": "^5.0.1", "express": "^4.17.1", + "express-validator": "^7.0.1", "googleapis": "^100.0.0", "jsonwebtoken": "^9.0.0", "lodash": "^4.17.21", diff --git a/src/routes/userProfileRouter.js b/src/routes/userProfileRouter.js index 9032359a8..8d7807514 100644 --- a/src/routes/userProfileRouter.js +++ b/src/routes/userProfileRouter.js @@ -1,53 +1,84 @@ -const express = require('express'); - +const express = require("express"); +import { body } from "express-validator"; const routes = function (userProfile) { - const controller = require('../controllers/userProfileController')(userProfile); + const controller = require("../controllers/userProfileController")( + userProfile + ); const userProfileRouter = express.Router(); - userProfileRouter.route('/userProfile') + userProfileRouter + .route("/userProfile") .get(controller.getUserProfiles) - .post(controller.postUserProfile); - - userProfileRouter.route('/userProfile/:userId') + .post( + body("firstName").customSanitizer((value) => value.trim()), + body("lastName").customSanitizer((value) => value.trim()), + controller.postUserProfile + ); + + userProfileRouter + .route("/userProfile/:userId") .get(controller.getUserById) - .put(controller.putUserProfile) + .put( + body("firstName").customSanitizer((value) => value.trim()), + body("lastName").customSanitizer((value) => value.trim()), + body("personalLinks").customSanitizer((value) => + value.map((link) => { + if (link.Name.replace(/\s/g, "") || link.Link.replace(/\s/g, "")) { + return { + ...link, + Name: link.Name.trim(), + Link: link.Link.replace(/\s/g, ""), + }; + } + throw new Error("Url not valid"); + }) + ), + controller.putUserProfile + ) .delete(controller.deleteUserProfile) .patch(controller.changeUserStatus); - userProfileRouter.route('/userProfile/name/:name') + userProfileRouter + .route("/userProfile/name/:name") .get(controller.getUserByName); - userProfileRouter.route('/refreshToken/:userId') - .get(controller.refreshToken); + userProfileRouter.route("/refreshToken/:userId").get(controller.refreshToken); - userProfileRouter.route('/userProfile/reportees/:userId') + userProfileRouter + .route("/userProfile/reportees/:userId") .get(controller.getreportees); - userProfileRouter.route('/userProfile/teammembers/:userId') + userProfileRouter + .route("/userProfile/teammembers/:userId") .get(controller.getTeamMembersofUser); - userProfileRouter.route('/userProfile/:userId/property') + userProfileRouter + .route("/userProfile/:userId/property") .patch(controller.updateOneProperty); - userProfileRouter.route('/userProfile/:userId/updatePassword') + userProfileRouter + .route("/userProfile/:userId/updatePassword") .patch(controller.updatepassword); - userProfileRouter.route('/userProfile/:userId/resetPassword') + userProfileRouter + .route("/userProfile/:userId/resetPassword") .patch(controller.resetPassword); - userProfileRouter.route('/userProfile/name/:userId') + userProfileRouter + .route("/userProfile/name/:userId") .get(controller.getUserName); - userProfileRouter.route('/userProfile/project/:projectId') + userProfileRouter + .route("/userProfile/project/:projectId") .get(controller.getProjectMembers); - userProfileRouter.route('/userProfile/socials/facebook') + userProfileRouter + .route("/userProfile/socials/facebook") .get(controller.getAllUsersWithFacebookLink); return userProfileRouter; }; - module.exports = routes; From 5c7cc8cdc7c5fcf7563008e31af9e08443b723c3 Mon Sep 17 00:00:00 2001 From: wang9hu Date: Wed, 20 Dec 2023 12:35:10 -0800 Subject: [PATCH 217/272] Refactor of timeentry controller, wbs controller, task controller and their router --- src/controllers/taskController.js | 58 ++- src/controllers/timeEntryController.js | 472 +++++++++++------------ src/controllers/wbsController.js | 23 ++ src/helpers/helperModels/userProjects.js | 1 + src/models/timeentry.js | 6 + src/routes/taskRouter.js | 4 +- src/routes/timeentryRouter.js | 4 +- src/routes/wbsRouter.js | 3 + 8 files changed, 284 insertions(+), 287 deletions(-) diff --git a/src/controllers/taskController.js b/src/controllers/taskController.js index 9bcf071de..5b087db4d 100644 --- a/src/controllers/taskController.js +++ b/src/controllers/taskController.js @@ -1,10 +1,10 @@ const mongoose = require('mongoose'); -const wbs = require('../models/wbs'); +const WBS = require('../models/wbs'); +const UserProfile = require('../models/userProfile'); const timeEntryHelper = require('../helpers/timeEntryHelper')(); const taskHelper = require('../helpers/taskHelper')(); const { hasPermission } = require('../utilities/permissions'); const emailSender = require('../utilities/emailSender'); -const userProfile = require('../models/userProfile'); const taskController = function (Task) { const getTasks = (req, res) => { @@ -33,7 +33,7 @@ const taskController = function (Task) { const getWBSId = (req, res) => { const { wbsId } = req.params; - wbs.findById(wbsId) + WBS.findById(wbsId) .then(results => res.status(200).send(results)) .catch(error => res.status(404).send(error)); }; @@ -446,7 +446,7 @@ const taskController = function (Task) { }); const saveTask = _task.save(); - const saveWbs = wbs.findById(wbsId).then((currentwbs) => { + const saveWbs = WBS.findById(wbsId).then((currentwbs) => { currentwbs.modifiedDatetime = Date.now(); return currentwbs.save(); }); @@ -803,31 +803,28 @@ const taskController = function (Task) { res.status(200).send('done'); }; - const getTasksByUserList = async (req, res) => { - const { members } = req.query; - const membersArr = members.split(','); + const getTasksByUserId = async (req, res) => { + const { userId } = req.params; try { - Task.find( - { 'resources.userID': { $in: membersArr } }, - '-resources.profilePic', - ).then((results) => { - wbs - .find({ - _id: { $in: results.map(item => item.wbsId) }, - }) - .then((projectIds) => { - const resultsWithProjectsIds = results.map((item) => { - item.set( - 'projectId', - projectIds?.find( - projectId => projectId._id.toString() === item.wbsId.toString(), - )?.projectId, - { strict: false }, - ); - return item; - }); - res.status(200).send(resultsWithProjectsIds); + Task.find({ + 'resources.userID': mongoose.Types.ObjectId(userId), + }, '-resources.profilePic') + .then((results) => { + WBS.find({ + _id: { $in: results.map(item => item.wbsId) }, + }).then((WBSs) => { + const resultsWithProjectsIds = results.map((item) => { + item.set( + 'projectId', + WBSs?.find( + wbs => wbs._id.toString() === item.wbsId.toString(), + )?.projectId, + { strict: false }, + ); + return item; }); + res.status(200).send(resultsWithProjectsIds); + }); }); } catch (error) { res.status(400).send(error); @@ -845,6 +842,7 @@ const taskController = function (Task) { res.status(200).send(singleUserData); } } catch (error) { + console.log(error); res.status(400).send(error); } }; @@ -872,8 +870,8 @@ const taskController = function (Task) { const getRecipients = async function (myUserId) { const recipients = []; - const user = await userProfile.findById(myUserId); - const membership = await userProfile.find({ role: { $in: ['Administrator', 'Manager', 'Mentor'] } }); + const user = await UserProfile.findById(myUserId); + const membership = await UserProfile.find({ role: { $in: ['Administrator', 'Manager', 'Mentor'] } }); membership.forEach((member) => { if (member.teams.some(team => user.teams.includes(team))) { recipients.push(member.email); @@ -917,7 +915,7 @@ const taskController = function (Task) { updateAllParents, deleteTaskByWBS, moveTask, - getTasksByUserList, + getTasksByUserId, getTasksForTeamsByUser, updateTaskStatus, sendReviewReq, diff --git a/src/controllers/timeEntryController.js b/src/controllers/timeEntryController.js index 9c4d7c5e3..5edd3a095 100644 --- a/src/controllers/timeEntryController.js +++ b/src/controllers/timeEntryController.js @@ -1,17 +1,18 @@ -const moment = require("moment-timezone"); -const mongoose = require("mongoose"); -const { getInfringementEmailBody } = require("../helpers/userHelper")(); -const userProfile = require("../models/userProfile"); -const task = require("../models/task"); -const emailSender = require("../utilities/emailSender"); -const { hasPermission } = require("../utilities/permissions"); +const moment = require('moment-timezone'); +const mongoose = require('mongoose'); +const { getInfringementEmailBody } = require('../helpers/userHelper')(); +const UserProfile = require('../models/userProfile'); +const Task = require('../models/task'); +const WBS = require('../models/wbs'); +const emailSender = require('../utilities/emailSender'); +const { hasPermission } = require('../utilities/permissions'); const formatSeconds = function (seconds) { const formattedseconds = parseInt(seconds, 10); const values = `${Math.floor( - moment.duration(formattedseconds, "seconds").asHours() - )}:${moment.duration(formattedseconds, "seconds").minutes()}`; - return values.split(":"); + moment.duration(formattedseconds, 'seconds').asHours(), + )}:${moment.duration(formattedseconds, 'seconds').minutes()}`; + return values.split(':'); }; /** @@ -30,14 +31,14 @@ const getEditedTimeEntryEmailBody = ( email, originalTime, finalTime, - requestor + requestor, ) => { const formattedOriginal = moment .utc(originalTime * 1000) - .format("HH[ hours ]mm[ minutes]"); + .format('HH[ hours ]mm[ minutes]'); const formattedFinal = moment .utc(finalTime * 1000) - .format("HH[ hours ]mm[ minutes]"); + .format('HH[ hours ]mm[ minutes]'); return ` A time entry belonging to ${firstName} ${lastName} (${email}) was modified by ${requestor.firstName} ${requestor.lastName} (${requestor.email}). The entry's duration was changed from [${formattedOriginal}] to [${formattedFinal}] @@ -55,10 +56,9 @@ const getEditedTimeEntryEmailBody = ( const notifyEditByEmail = async (personId, original, finalTime, final) => { try { const originalTime = original.totalSeconds; - const record = await userProfile.findById(personId); - const requestor = - personId !== final.requestor.requestorId - ? await userProfile.findById(final.requestor.requestorId) + const record = await UserProfile.findById(personId); + const requestor = personId !== final.requestor.requestorId + ? await UserProfile.findById(final.requestor.requestorId) : record; const emailBody = getEditedTimeEntryEmailBody( record.firstName, @@ -66,16 +66,16 @@ const notifyEditByEmail = async (personId, original, finalTime, final) => { record.email, originalTime, finalTime, - requestor + requestor, ); emailSender( - "onecommunityglobal@gmail.com", + 'onecommunityglobal@gmail.com', `A Time Entry was Edited for ${record.firstName} ${record.lastName}`, - emailBody + emailBody, ); } catch (error) { throw new Error( - `Failed to send email notification about the modification of time entry belonging to user with id ${personId}` + `Failed to send email notification about the modification of time entry belonging to user with id ${personId}`, ); } }; @@ -84,10 +84,10 @@ const notifyTaskOvertimeEmailBody = async ( personId, taskName, estimatedHours, - hoursLogged + hoursLogged, ) => { try { - const record = await userProfile.findById(personId); + const record = await UserProfile.findById(personId); const text = `Dear ${record.firstName}${record.lastName},

Oops, it looks like you have logged more hours than estimated for a task

Task Name : ${taskName}

@@ -98,16 +98,16 @@ const notifyTaskOvertimeEmailBody = async (

One Community

`; emailSender( record.email, - "Logged more hours than estimated for a task", + 'Logged more hours than estimated for a task', text, - "onecommunityglobal@gmail.com", + 'onecommunityglobal@gmail.com', null, record.email, - null + null, ); } catch (error) { console.log( - `Failed to send email notification about the overtime for a task belonging to user with id ${personId}` + `Failed to send email notification about the overtime for a task belonging to user with id ${personId}`, ); } }; @@ -120,122 +120,132 @@ const checkTaskOvertime = async (timeentry, record, currentTask) => { timeentry.personId.toString(), currentTask.taskName, currentTask.estimatedHours, - currentTask.hoursLogged + currentTask.hoursLogged, ); } } catch (error) { console.log( - `Failed to find task whose logged-in hours are more than estimated hours ${record.email}` + `Failed to find task whose logged-in hours are more than estimated hours ${record.email}`, ); } }; +// update timeentry with wbsId and taskId if projectId in the old timeentry is actually a taskId +const updateTaskIdInTimeEntry = async (id, timeEntry) => { + // if id is a taskId, then timeentry should have the parent wbsId and projectId for that task; + // if id is not a taskId, then it is a projectId, timeentry should have both wbsId and taskId to be null; + let taskId = null; + let wbsId = null; + let projectId = id; + const task = await Task.findById(id); + if (task) { + taskId = id; + ({ wbsId } = task); + const wbs = await WBS.findById(wbsId); + ({ projectId } = wbs); + } + Object.assign(timeEntry, { taskId, wbsId, projectId }); +}; + const timeEntrycontroller = function (TimeEntry) { const editTimeEntry = async (req, res) => { + const { timeEntryId } = req.params; + + if (!timeEntryId) { + const error = 'ObjectId in request param is not in correct format'; + return res.status(400).send({ error }); + } + + if (!mongoose.Types.ObjectId.isValid(timeEntryId)) { + const error = 'ObjectIds are not correctly formed'; + return res.status(400).send({ error }); + } + + const { + personId, + hours = '00', + minutes = '00', + notes, + isTangible, + projectId, + wbsId, + taskId, + dateOfWork, + } = req.body; + + const isForAuthUser = personId === req.body.requestor.requestorId; + const isSameDayTimeEntry = moment().tz('America/Los_Angeles').format('YYYY-MM-DD') === dateOfWork; + const canEdit = (await hasPermission(req.body.requestor, 'editTimeEntry')) || (isForAuthUser && isSameDayTimeEntry); + + if (!canEdit) { + const error = 'Unauthorized request'; + return res.status(403).send({ error }); + } + const session = await mongoose.startSession(); session.startTransaction(); try { - if (!req.params.timeEntryId) { - return res - .status(400) - .send({ - error: "ObjectId in request param is not in correct format", - }); - } - - if ( - !mongoose.Types.ObjectId.isValid(req.params.timeEntryId) || - !mongoose.Types.ObjectId.isValid(req.body.projectId) - ) { - return res - .status(400) - .send({ error: "ObjectIds are not correctly formed" }); - } - // Get initial timeEntry by timeEntryId - const timeEntry = await TimeEntry.findById(req.params.timeEntryId); - + const timeEntry = await TimeEntry.findById(timeEntryId); if (!timeEntry) { - return res - .status(400) - .send({ - error: `No valid records found for ${req.params.timeEntryId}`, - }); + const error = `No valid records found for ${timeEntryId}`; + return res.status(400).send({ error }); } - if ( - !( - (await hasPermission(req.body.requestor, "editTimeEntry")) || - timeEntry.personId.toString() === - req.body.requestor.requestorId.toString() - ) - ) { - return res.status(403).send({ error: "Unauthorized request" }); - } - - const hours = req.body.hours ? req.body.hours : "00"; - const minutes = req.body.minutes ? req.body.minutes : "00"; + const totalSeconds = moment.duration({ hours, minutes }).asSeconds(); + const { + totalSeconds: initialTotalSeconds, + projectId: initialProjectId, + wbsId: initialWBSId, + taskId: initialTaskId, + isTangible: initialIsTangible, + } = timeEntry; - const totalSeconds = moment.duration(`${hours}:${minutes}`).asSeconds(); - - if ( - timeEntry.isTangible === true && - totalSeconds !== timeEntry.totalSeconds - ) { + if (initialIsTangible && totalSeconds !== initialTotalSeconds) { notifyEditByEmail( timeEntry.personId.toString(), timeEntry, totalSeconds, - req.body + req.body, ); } - const initialSeconds = timeEntry.totalSeconds; - const initialProjectId = timeEntry.projectId; - const initialIsTangible = timeEntry.isTangible; - // Get the task related to this time entry, if not found, then it's a project and will be null - const findTask = await task.findById(initialProjectId); - - timeEntry.notes = req.body.notes; - timeEntry.totalSeconds = totalSeconds; - timeEntry.isTangible = req.body.isTangible; - timeEntry.lastModifiedDateTime = moment().utc().toISOString(); - timeEntry.projectId = mongoose.Types.ObjectId(req.body.projectId); - timeEntry.dateOfWork = moment(req.body.dateOfWork).format("YYYY-MM-DD"); - - // Update the hoursLogged field of related tasks based on before and after timeEntries - // initialIsTangible is a bealoon value, req.body.isTangible is a string - // initialProjectId may be a task id or project id, so do not throw error. - try { - if (findTask) { - if (initialIsTangible === true) { - findTask.hoursLogged -= initialSeconds / 3600; - } - - if (req.body.isTangible === true) { - findTask.hoursLogged += totalSeconds / 3600; - } + updateTaskIdInTimeEntry(projectId, timeEntry); - await findTask.save(); + if (timeEntry.taskId) { + const findTask = await Task.findById(initialProjectId); + if (initialIsTangible) { + findTask.hoursLogged -= initialTotalSeconds / 3600; } - } catch (error) { - throw new Error(error); + if (req.body.isTangible === true) { + findTask.hoursLogged += totalSeconds / 3600; + } + await findTask.save(); } + timeEntry.notes = notes; + timeEntry.totalSeconds = totalSeconds; + timeEntry.isTangible = isTangible; + timeEntry.lastModifiedDateTime = moment().utc().toISOString(); + timeEntry.projectId = mongoose.Types.ObjectId(projectId); + timeEntry.wbsId = wbsId ? mongoose.Types.ObjectId(wbsId) : null; + timeEntry.taskId = taskId ? mongoose.Types.ObjectId(taskId) : null; + timeEntry.dateOfWork = moment(dateOfWork).format('YYYY-MM-DD'); + // Update edit history if ( - initialSeconds !== totalSeconds && - timeEntry.isTangible && - req.body.requestor.requestorId === timeEntry.personId.toString() && - !(await hasPermission(req.body.requestor, "editTimeEntry")) + initialTotalSeconds !== totalSeconds + && timeEntry.isTangible + && req.body.requestor.requestorId === timeEntry.personId.toString() + && !(await hasPermission(req.body.requestor, 'editTimeEntry')) ) { - const requestor = await userProfile.findById( - req.body.requestor.requestorId + const requestor = await UserProfile.findById( + req.body.requestor.requestorId, ); requestor.timeEntryEditHistory.push({ - date: moment().tz("America/Los_Angeles").toDate(), - initialSeconds, + date: moment().tz('America/Los_Angeles').toDate(), + initialSeconds: initialTotalSeconds, newSeconds: totalSeconds, }); @@ -244,7 +254,7 @@ const timeEntrycontroller = function (TimeEntry) { requestor.timeEntryEditHistory.forEach((edit) => { if ( - moment().tz("America/Los_Angeles").diff(edit.date, "days") <= 365 + moment().tz('America/Los_Angeles').diff(edit.date, 'days') <= 365 ) { totalRecentEdits += 1; } @@ -252,12 +262,12 @@ const timeEntrycontroller = function (TimeEntry) { if (totalRecentEdits >= 5) { requestor.infringements.push({ - date: moment().tz("America/Los_Angeles"), + date: moment().tz('America/Los_Angeles'), description: `${totalRecentEdits} time entry edits in the last calendar year`, }); emailSender( - "onecommunityglobal@gmail.com", + 'onecommunityglobal@gmail.com', `${requestor.firstName} ${requestor.lastName} was issued a blue square for for editing a time entry ${totalRecentEdits} times`, `

@@ -267,11 +277,11 @@ const timeEntrycontroller = function (TimeEntry) {

This is the ${totalRecentEdits}th edit within the past 365 days.

- ` + `, ); const emailInfringement = { - date: moment().tz("America/Los_Angeles").format("MMMM-DD-YY"), + date: moment().tz('America/Los_Angeles').format('MMMM-DD-YY'), description: `You edited your time entries ${totalRecentEdits} times within the last 365 days, exceeding the limit of 4 times per year you can edit them without penalty.`, }; @@ -282,8 +292,8 @@ const timeEntrycontroller = function (TimeEntry) { requestor.firstName, requestor.lastName, emailInfringement, - requestor.infringements.length - ) + requestor.infringements.length, + ), ); } @@ -292,15 +302,15 @@ const timeEntrycontroller = function (TimeEntry) { await timeEntry.save(); - res.status(200).send({ message: "Successfully updated time entry" }); + res.status(200).send({ message: 'Successfully updated time entry' }); // If the time entry isn't related to a task (i.e. it's a project), then don't check for overtime (Most likely pr team) if (findTask) { // checking if logged in hours exceed estimated time after timeentry edit for a task - const record = await userProfile.findById( - timeEntry.personId.toString() + const record = await UserProfile.findById( + timeEntry.personId.toString(), ); - const currentTask = await task.findById(req.body.projectId); + const currentTask = await Task.findById(req.body.projectId); checkTaskOvertime(timeEntry, record, currentTask); } } catch (err) { @@ -324,9 +334,9 @@ const timeEntrycontroller = function (TimeEntry) { timeentry.personId = element.personId; timeentry.projectId = element.projectId; timeentry.dateOfWork = element.dateOfWork; - timeentry.timeSpent = moment("1900-01-01 00:00:00") - .add(element.totalSeconds, "seconds") - .format("HH:mm:ss"); + timeentry.timeSpent = moment('1900-01-01 00:00:00') + .add(element.totalSeconds, 'seconds') + .format('HH:mm:ss'); timeentry.notes = element.notes; timeentry.isTangible = element.isTangible; items.push(timeentry); @@ -337,21 +347,23 @@ const timeEntrycontroller = function (TimeEntry) { const postTimeEntry = async function (req, res) { if ( - !mongoose.Types.ObjectId.isValid(req.body.personId) || - !mongoose.Types.ObjectId.isValid(req.body.projectId) || - !req.body.dateOfWork || - !moment(req.body.dateOfWork).isValid() || - !req.body.timeSpent || - !req.body.isTangible + !mongoose.Types.ObjectId.isValid(req.body.personId) + || !mongoose.Types.ObjectId.isValid(req.body.projectId) + || !req.body.dateOfWork + || !moment(req.body.dateOfWork).isValid() + || !req.body.timeSpent + || !req.body.isTangible ) { - res.status(400).send({ error: "Bad request" }); + res.status(400).send({ error: 'Bad request' }); return; } const timeentry = new TimeEntry(); const { dateOfWork, timeSpent } = req.body; timeentry.personId = req.body.personId; timeentry.projectId = req.body.projectId; - timeentry.dateOfWork = moment(dateOfWork).format("YYYY-MM-DD"); + timeentry.wbsId = req.body.wbsId; + timeentry.taskId = req.body.taskId; + timeentry.dateOfWork = moment(dateOfWork).format('YYYY-MM-DD'); timeentry.totalSeconds = moment.duration(timeSpent).asSeconds(); timeentry.notes = req.body.notes; timeentry.isTangible = req.body.isTangible; @@ -365,10 +377,10 @@ const timeEntrycontroller = function (TimeEntry) { .status(200) .send({ message: `Time Entry saved with id as ${results._id}` }); }) - .catch((error) => res.status(400).send(error)); + .catch(error => res.status(400).send(error)); // Get the task related to this time entry, if not found, then it's a project sets to null - const currentTask = await task + const currentTask = await Task .findById(req.body.projectId) .catch(() => null); @@ -385,8 +397,8 @@ const timeEntrycontroller = function (TimeEntry) { // checking if logged in hours exceed estimated time after timeentry for a task, only if the time entry is related to a task (It might not be, if it's a project) if (currentTask) { try { - const record = await userProfile.findById( - timeentry.personId.toString() + const record = await UserProfile.findById( + timeentry.personId.toString(), ); checkTaskOvertime(timeentry, record, currentTask); } catch (error) { @@ -395,93 +407,47 @@ const timeEntrycontroller = function (TimeEntry) { } }; - const getTimeEntriesForSpecifiedPeriod = function (req, res) { + const getTimeEntriesForSpecifiedPeriod = async function (req, res) { if ( - !req.params || - !req.params.fromdate || - !req.params.todate || - !req.params.userId || - !moment(req.params.fromdate).isValid() || - !moment(req.params.toDate).isValid() + !req.params + || !req.params.fromdate + || !req.params.todate + || !req.params.userId + || !moment(req.params.fromdate).isValid() + || !moment(req.params.toDate).isValid() ) { - res.status(400).send({ error: "Invalid request" }); + res.status(400).send({ error: 'Invalid request' }); return; } const fromdate = moment(req.params.fromdate) - .tz("America/Los_Angeles") - .format("YYYY-MM-DD"); + .tz('America/Los_Angeles') + .format('YYYY-MM-DD'); const todate = moment(req.params.todate) - .tz("America/Los_Angeles") - .format("YYYY-MM-DD"); + .tz('America/Los_Angeles') + .format('YYYY-MM-DD'); const { userId } = req.params; - TimeEntry.aggregate([ - { - $match: { - personId: mongoose.Types.ObjectId(userId), - dateOfWork: { $gte: fromdate, $lte: todate }, - }, - }, - { - $lookup: { - from: "projects", - localField: "projectId", - foreignField: "_id", - as: "project", - }, - }, - { - $lookup: { - from: "tasks", - localField: "projectId", - foreignField: "_id", - as: "task", - }, - }, - { - $project: { - _id: 1, - notes: 1, - isTangible: 1, - personId: 1, - projectId: 1, - lastModifiedDateTime: 1, - projectName: { - $arrayElemAt: ["$project.projectName", 0], - }, - taskName: { - $arrayElemAt: ["$task.taskName", 0], - }, - category: { - $arrayElemAt: ["$project.category", 0], - }, - classification: { - $arrayElemAt: ["$task.classification", 0], - }, - dateOfWork: 1, - hours: { - $floor: { - $divide: ["$totalSeconds", 3600], - }, - }, - minutes: { - $floor: { - $divide: [{ $mod: ["$totalSeconds", 3600] }, 60], - }, - }, - }, - }, - { - $sort: { - lastModifiedDateTime: -1, - }, - }, - ]) - .then((results) => { - res.status(200).send(results); - }) - .catch((error) => res.status(400).send(error)); + try { + const timeEntries = await TimeEntry.find({ + personId: userId, + dateOfWork: { $gte: fromdate, $lte: todate }, + }).sort('-lastModifiedDateTime'); + + const results = await Promise.all(timeEntries.map(async (timeEntry) => { + timeEntry = { ...timeEntry.toObject() }; + const { projectId } = timeEntry; + await updateTaskIdInTimeEntry(projectId, timeEntry); + const hours = Math.floor(timeEntry.totalSeconds / 3600); + const minutes = Math.floor((timeEntry.totalSeconds % 3600) / 60); + Object.assign(timeEntry, { hours, minutes, totalSeconds: undefined }); + return timeEntry; + })); + + res.status(200).send(results); + } catch (err) { + res.status(400).send({ error: err }); + } }; const getTimeEntriesForUsersList = function (req, res) { @@ -492,9 +458,9 @@ const timeEntrycontroller = function (TimeEntry) { personId: { $in: users }, dateOfWork: { $gte: fromDate, $lte: toDate }, }, - " -createdDateTime" + ' -createdDateTime', ) - .populate("projectId") + .populate('projectId') .sort({ lastModifiedDateTime: -1 }) .then((results) => { const data = []; @@ -505,68 +471,68 @@ const timeEntrycontroller = function (TimeEntry) { record.notes = element.notes; record.isTangible = element.isTangible; record.personId = element.personId; - record.projectId = element.projectId ? element.projectId._id : ""; + record.projectId = element.projectId ? element.projectId._id : ''; record.projectName = element.projectId ? element.projectId.projectName - : ""; + : ''; record.dateOfWork = element.dateOfWork; [record.hours, record.minutes] = formatSeconds(element.totalSeconds); data.push(record); }); res.status(200).send(data); }) - .catch((error) => res.status(400).send(error)); + .catch(error => res.status(400).send(error)); }; - const getTimeEntriesForSpecifiedProject = function (req, res) { - if ( - !req.params || - !req.params.fromDate || - !req.params.toDate || - !req.params.projectId - ) { - res.status(400).send({ error: "Invalid request" }); - return; - } - const todate = moment(req.params.toDate).format("YYYY-MM-DD"); - const fromDate = moment(req.params.fromDate).format("YYYY-MM-DD"); - const { projectId } = req.params; - TimeEntry.find( - { - projectId, - dateOfWork: { $gte: fromDate, $lte: todate }, - }, - "-createdDateTime -lastModifiedDateTime" - ) - .populate("userId") - .sort({ dateOfWork: -1 }) - .then((results) => { - res.status(200).send(results); - }) - .catch((error) => res.status(400).send(error)); - }; + // const getTimeEntriesForSpecifiedProject = function (req, res) { + // if ( + // !req.params + // || !req.params.fromDate + // || !req.params.toDate + // || !req.params.projectId + // ) { + // res.status(400).send({ error: 'Invalid request' }); + // return; + // } + // const todate = moment(req.params.toDate).format('YYYY-MM-DD'); + // const fromDate = moment(req.params.fromDate).format('YYYY-MM-DD'); + // const { projectId } = req.params; + // TimeEntry.find( + // { + // projectId, + // dateOfWork: { $gte: fromDate, $lte: todate }, + // }, + // '-createdDateTime -lastModifiedDateTime', + // ) + // .populate('userId') + // .sort({ dateOfWork: -1 }) + // .then((results) => { + // res.status(200).send(results); + // }) + // .catch(error => res.status(400).send(error)); + // }; const deleteTimeEntry = async function (req, res) { if (!req.params.timeEntryId) { - res.status(400).send({ error: "Bad request" }); + res.status(400).send({ error: 'Bad request' }); return; } TimeEntry.findById(req.params.timeEntryId) .then(async (record) => { if (!record) { - res.status(400).send({ message: "No valid record found" }); + res.status(400).send({ message: 'No valid record found' }); return; } if ( - record.personId.toString() === - req.body.requestor.requestorId.toString() || - (await hasPermission(req.body.requestor, "deleteTimeEntry")) + record.personId.toString() + === req.body.requestor.requestorId.toString() + || (await hasPermission(req.body.requestor, 'deleteTimeEntry')) ) { // Revert this tangible timeEntry of related task's hoursLogged if (record.isTangible === true) { - task + Task .findById(record.projectId) .then((currentTask) => { // If the time entry isn't related to a task (i.e. it's a project), then don't revert hours (Most likely pr team) @@ -583,13 +549,13 @@ const timeEntrycontroller = function (TimeEntry) { record .remove() .then(() => { - res.status(200).send({ message: "Successfully deleted" }); + res.status(200).send({ message: 'Successfully deleted' }); }) .catch((error) => { res.status(500).send(error); }); } else { - res.status(403).send({ error: "Unauthorized request" }); + res.status(403).send({ error: 'Unauthorized request' }); } }) .catch((error) => { @@ -604,7 +570,7 @@ const timeEntrycontroller = function (TimeEntry) { getTimeEntriesForUsersList, editTimeEntry, deleteTimeEntry, - getTimeEntriesForSpecifiedProject, + // getTimeEntriesForSpecifiedProject, checkTaskOvertime, }; }; diff --git a/src/controllers/wbsController.js b/src/controllers/wbsController.js index fa7f4427f..04070eaf9 100644 --- a/src/controllers/wbsController.js +++ b/src/controllers/wbsController.js @@ -1,4 +1,7 @@ +const mongoose = require('mongoose'); const { hasPermission } = require('../utilities/permissions'); +const Project = require('../models/project'); +const Task = require('../models/task'); const wbsController = function (WBS) { const getAllWBS = function (req, res) { @@ -68,12 +71,32 @@ const wbsController = function (WBS) { .catch(error => res.status(404).send(error)); }; + const getWBSByUserId = async function (req, res) { + const { userId } = req.params; + try { + const result = await Task.aggregate() + .match({ 'resources.userID': mongoose.Types.ObjectId(userId) }) + .project('wbsId -_id') + .group({ _id: '$wbsId' }) + .lookup({ + from: 'wbs', localField: '_id', foreignField: '_id', as: 'wbs', + }) + .unwind('wbs') + .replaceRoot('wbs'); + + res.status(200).send(result); + } catch (error) { + res.status(404).send(error); + } + }; + return { postWBS, deleteWBS, getAllWBS, getWBS, getWBSById, + getWBSByUserId, }; }; diff --git a/src/helpers/helperModels/userProjects.js b/src/helpers/helperModels/userProjects.js index 108ec345b..e325a0e39 100644 --- a/src/helpers/helperModels/userProjects.js +++ b/src/helpers/helperModels/userProjects.js @@ -5,6 +5,7 @@ const { Schema } = mongoose; const ProjectSchema = new Schema({ projectId: { type: mongoose.SchemaTypes.ObjectId, ref: 'projects' }, projectName: { type: String }, + category: { type: String }, }); diff --git a/src/models/timeentry.js b/src/models/timeentry.js index aeef5fdc7..3876cfcc7 100644 --- a/src/models/timeentry.js +++ b/src/models/timeentry.js @@ -6,6 +6,12 @@ const { Schema } = mongoose; const TimeEntry = new Schema({ personId: { type: Schema.Types.ObjectId, required: [true, 'Resource is a required field'], ref: 'userProfile' }, projectId: { type: Schema.Types.ObjectId, required: [true, 'Project is a required field'], ref: 'project' }, + wbsId: { + type: Schema.Types.ObjectId, required: false, default: null, ref: 'wbs', + }, + taskId: { + type: Schema.Types.ObjectId, required: false, default: null, ref: 'task', + }, dateOfWork: { type: String, required: true }, totalSeconds: { type: Number }, notes: { type: String }, diff --git a/src/routes/taskRouter.js b/src/routes/taskRouter.js index 46e467c9d..e04b499eb 100644 --- a/src/routes/taskRouter.js +++ b/src/routes/taskRouter.js @@ -43,8 +43,8 @@ const routes = function (task, userProfile) { wbsRouter.route('/tasks/moveTasks/:wbsId') .put(controller.moveTask); - wbsRouter.route('/tasks/userProfile') - .get(controller.getTasksByUserList); + wbsRouter.route('/tasks/user/:userId') + .get(controller.getTasksByUserId); wbsRouter.route('/user/:userId/teams/tasks') .get(controller.getTasksForTeamsByUser); diff --git a/src/routes/timeentryRouter.js b/src/routes/timeentryRouter.js index b319aa595..f5a89e351 100644 --- a/src/routes/timeentryRouter.js +++ b/src/routes/timeentryRouter.js @@ -19,8 +19,8 @@ const routes = function (TimeEntry) { TimeEntryRouter.route('/TimeEntry/users') .post(controller.getTimeEntriesForUsersList); - TimeEntryRouter.route('/TimeEntry/projects/:projectId/:fromDate/:toDate') - .get(controller.getTimeEntriesForSpecifiedProject); + // TimeEntryRouter.route('/TimeEntry/projects/:projectId/:fromDate/:toDate') + // .get(controller.getTimeEntriesForSpecifiedProject); return TimeEntryRouter; }; diff --git a/src/routes/wbsRouter.js b/src/routes/wbsRouter.js index b78ada5b9..08bfdc7b5 100644 --- a/src/routes/wbsRouter.js +++ b/src/routes/wbsRouter.js @@ -14,6 +14,9 @@ const routes = function (wbs) { wbsRouter.route('/wbsId/:id') .get(controller.getWBSById); + wbsRouter.route('/wbs/user/:userId') + .get(controller.getWBSByUserId); + wbsRouter.route('/wbs').get(controller.getWBS); return wbsRouter; From 1f2d4bec21da660d2f943f14adb098d5c9aa71c5 Mon Sep 17 00:00:00 2001 From: Ruike Qiu <114443664+StrawberryCalpico@users.noreply.github.com> Date: Wed, 20 Dec 2023 17:16:31 -0800 Subject: [PATCH 218/272] Update for adminLinks --- src/routes/userProfileRouter.js | 78 +++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/src/routes/userProfileRouter.js b/src/routes/userProfileRouter.js index 8d7807514..ac567ebe8 100644 --- a/src/routes/userProfileRouter.js +++ b/src/routes/userProfileRouter.js @@ -1,81 +1,91 @@ -const express = require("express"); -import { body } from "express-validator"; +import { body } from 'express-validator'; + +const express = require('express'); + const routes = function (userProfile) { - const controller = require("../controllers/userProfileController")( - userProfile + const controller = require('../controllers/userProfileController')( + userProfile, ); const userProfileRouter = express.Router(); userProfileRouter - .route("/userProfile") + .route('/userProfile') .get(controller.getUserProfiles) .post( - body("firstName").customSanitizer((value) => value.trim()), - body("lastName").customSanitizer((value) => value.trim()), - controller.postUserProfile + body('firstName').customSanitizer(value => value.trim()), + body('lastName').customSanitizer(value => value.trim()), + controller.postUserProfile, ); userProfileRouter - .route("/userProfile/:userId") + .route('/userProfile/:userId') .get(controller.getUserById) .put( - body("firstName").customSanitizer((value) => value.trim()), - body("lastName").customSanitizer((value) => value.trim()), - body("personalLinks").customSanitizer((value) => - value.map((link) => { - if (link.Name.replace(/\s/g, "") || link.Link.replace(/\s/g, "")) { - return { - ...link, - Name: link.Name.trim(), - Link: link.Link.replace(/\s/g, ""), - }; - } - throw new Error("Url not valid"); - }) - ), - controller.putUserProfile + body('firstName').customSanitizer(value => value.trim()), + body('lastName').customSanitizer(value => value.trim()), + body('personalLinks').customSanitizer(value => value.map((link) => { + if (link.Name.replace(/\s/g, '') || link.Link.replace(/\s/g, '')) { + return { + ...link, + Name: link.Name.trim(), + Link: link.Link.replace(/\s/g, ''), + }; + } + throw new Error('Url not valid'); + })), + body('adminLinks').customSanitizer(value => value.map((link) => { + if (link.Name.replace(/\s/g, '') || link.Link.replace(/\s/g, '')) { + return { + ...link, + Name: link.Name.trim(), + Link: link.Link.replace(/\s/g, ''), + }; + } + throw new Error('Url not valid'); + })), + controller.putUserProfile, ) .delete(controller.deleteUserProfile) .patch(controller.changeUserStatus); userProfileRouter - .route("/userProfile/name/:name") + .route('/userProfile/name/:name') .get(controller.getUserByName); - userProfileRouter.route("/refreshToken/:userId").get(controller.refreshToken); + userProfileRouter.route('/refreshToken/:userId').get(controller.refreshToken); userProfileRouter - .route("/userProfile/reportees/:userId") + .route('/userProfile/reportees/:userId') .get(controller.getreportees); userProfileRouter - .route("/userProfile/teammembers/:userId") + .route('/userProfile/teammembers/:userId') .get(controller.getTeamMembersofUser); userProfileRouter - .route("/userProfile/:userId/property") + .route('/userProfile/:userId/property') .patch(controller.updateOneProperty); userProfileRouter - .route("/userProfile/:userId/updatePassword") + .route('/userProfile/:userId/updatePassword') .patch(controller.updatepassword); userProfileRouter - .route("/userProfile/:userId/resetPassword") + .route('/userProfile/:userId/resetPassword') .patch(controller.resetPassword); userProfileRouter - .route("/userProfile/name/:userId") + .route('/userProfile/name/:userId') .get(controller.getUserName); userProfileRouter - .route("/userProfile/project/:projectId") + .route('/userProfile/project/:projectId') .get(controller.getProjectMembers); userProfileRouter - .route("/userProfile/socials/facebook") + .route('/userProfile/socials/facebook') .get(controller.getAllUsersWithFacebookLink); return userProfileRouter; From 01e386b2030049c95e73e961aa6af661dba5b2eb Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Wed, 20 Dec 2023 20:59:34 -0800 Subject: [PATCH 219/272] fix issue that logged time reset on leaderboard --- src/controllers/timeEntryController.js | 29 +++++++++++++++++--------- src/helpers/dashboardhelper.js | 29 ++++++++++++++++++++------ 2 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/controllers/timeEntryController.js b/src/controllers/timeEntryController.js index 3516517cc..effe61a3b 100644 --- a/src/controllers/timeEntryController.js +++ b/src/controllers/timeEntryController.js @@ -14,6 +14,13 @@ const formatSeconds = function (seconds) { return values.split(':'); }; +const isGeneralTimeEntry = function (type) { + if (type === undefined || type === 'default') { + return true; + } + return false; +}; + /** * * @param {*} firstName First name of the owner of the time entry that was modified @@ -135,6 +142,7 @@ const timeEntrycontroller = function (TimeEntry) { session.startTransaction(); const type = req.body.entryType; + const isGeneralEntry = isGeneralTimeEntry(type); try { if (!req.params.timeEntryId) { @@ -147,7 +155,7 @@ const timeEntrycontroller = function (TimeEntry) { if ( !mongoose.Types.ObjectId.isValid(req.params.timeEntryId) - || ((type === 'default' || type === 'project') + || ((isGeneralEntry || type === 'project') && !mongoose.Types.ObjectId.isValid(req.body.projectId) )) { return res @@ -169,7 +177,7 @@ const timeEntrycontroller = function (TimeEntry) { if ( !( (await hasPermission(req.body.requestor, 'editTimeEntry')) - || (type === 'default' + || (isGeneralEntry && timeEntry.personId.toString() === req.body.requestor.requestorId.toString() ) @@ -183,7 +191,7 @@ const timeEntrycontroller = function (TimeEntry) { const totalSeconds = moment.duration(`${hours}:${minutes}`).asSeconds(); if ( - type === 'default' + isGeneralEntry && timeEntry.isTangible === true && totalSeconds !== timeEntry.totalSeconds ) { @@ -207,13 +215,13 @@ const timeEntrycontroller = function (TimeEntry) { timeEntry.lastModifiedDateTime = moment().utc().toISOString(); timeEntry.projectId = mongoose.Types.ObjectId(req.body.projectId); timeEntry.dateOfWork = moment(req.body.dateOfWork).format('YYYY-MM-DD'); - timeEntry.entryType = req.body.entryType; + timeEntry.entryType = req.body.entryType === undefined ? 'default' : req.body.entryType; // Update the hoursLogged field of related tasks based on before and after timeEntries // initialIsTangible is a bealoon value, req.body.isTangible is a string // initialProjectId may be a task id or project id, so do not throw error. try { - if (type === 'default' && findTask) { + if (isGeneralEntry && findTask) { if (initialIsTangible === true) { findTask.hoursLogged -= initialSeconds / 3600; } @@ -230,7 +238,7 @@ const timeEntrycontroller = function (TimeEntry) { // Update edit history if ( - (type === 'default' || type === 'person') + (isGeneralEntry || type === 'person') && initialSeconds !== totalSeconds && timeEntry.isTangible && req.body.requestor.requestorId === timeEntry.personId.toString() @@ -245,7 +253,7 @@ const timeEntrycontroller = function (TimeEntry) { newSeconds: totalSeconds, }); - if (type === 'default') { + if (isGeneralEntry) { // Issue infraction if edit history contains more than 5 edits in the last year let totalRecentEdits = 0; @@ -303,7 +311,7 @@ const timeEntrycontroller = function (TimeEntry) { res.status(200).send({ message: 'Successfully updated time entry' }); // If the time entry isn't related to a task (i.e. it's a project), then don't check for overtime (Most likely pr team) - if (type === 'default' && findTask) { + if (isGeneralEntry && findTask) { // checking if logged in hours exceed estimated time after timeentry edit for a task const record = await userProfile.findById( timeEntry.personId.toString(), @@ -328,7 +336,8 @@ const timeEntrycontroller = function (TimeEntry) { } const items = []; records.forEach((element) => { - if (element.entryType === 'default' || element.entryType === undefined) { + const isGeneralEntry = isGeneralTimeEntry(element.entryType); + if (isGeneralEntry) { const timeentry = new TimeEntry(); timeentry.personId = element.personId; timeentry.projectId = element.projectId; @@ -400,7 +409,7 @@ const timeEntrycontroller = function (TimeEntry) { timeentry.isTangible = req.body.isTangible; timeentry.createdDateTime = moment().utc().toISOString(); timeentry.lastModifiedDateTime = moment().utc().toISOString(); - timeentry.entryType = req.body.entryType; + timeentry.entryType = req.body.entryType === undefined ? 'default' : req.body.entryType; timeentry .save() diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index bc56fc5c6..b7ca2f131 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -70,7 +70,11 @@ const dashboardhelper = function () { $lte: ['$$timeentry.dateOfWork', pdtend], }, { - $in: ['$$timeentry.entryType', ['default', null]], + $not: [ + { + $in: ['$$timeentry.entryType', ['person', 'team', 'project']], + }, + ], }, ], }, @@ -155,7 +159,7 @@ const dashboardhelper = function () { return output; }; - const getLeaderboard = function (userId) { + const getLeaderboard = async function (userId) { const userid = mongoose.Types.ObjectId(userId); const pdtstart = moment() .tz('America/Los_Angeles') @@ -165,7 +169,7 @@ const dashboardhelper = function () { .tz('America/Los_Angeles') .endOf('week') .format('YYYY-MM-DD'); - return myTeam.aggregate([ + const output = await myTeam.aggregate([ { $match: { _id: userid, @@ -287,7 +291,11 @@ const dashboardhelper = function () { $lte: ['$$timeentry.dateOfWork', pdtend], }, { - $in: ['$$timeentry.entryType', ['default', null]], + $not: [ + { + $in: ['$$timeentry.entryType', ['person', 'team', 'project']], + }, + ], }, ], }, @@ -416,6 +424,7 @@ const dashboardhelper = function () { }, }, ]); + return output; }; /** @@ -583,7 +592,11 @@ const dashboardhelper = function () { $lte: ['$$timeentry.dateOfWork', todate], }, { - $in: ['$$timeentry.entryType', ['default', null]], + $not: [ + { + $in: ['$$timeentry.entryType', ['person', 'team', 'project']], + }, + ], }, ], }, @@ -663,7 +676,11 @@ const dashboardhelper = function () { $lte: ['$$timeentry.dateOfWork', todate], }, { - $in: ['$$timeentry.entryType', ['default', null]], + $not: [ + { + $in: ['$$timeentry.entryType', ['person', 'team', 'project']], + }, + ], }, ], }, From 62b4ff352f874123aef9726cd044f3c942f90a52 Mon Sep 17 00:00:00 2001 From: abdelmounaim lallouache Date: Thu, 21 Dec 2023 02:58:10 -0600 Subject: [PATCH 220/272] fixed error --- .../profileInitialSetupController.js | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/controllers/profileInitialSetupController.js b/src/controllers/profileInitialSetupController.js index df1f5adfb..12776442e 100644 --- a/src/controllers/profileInitialSetupController.js +++ b/src/controllers/profileInitialSetupController.js @@ -101,6 +101,18 @@ const profileInitialSetupController = function ( ) { const { JWT_SECRET } = config; + const setMapLocation = async (locationData) => { + + const location = new MapLocation(locationData); + + try { + const response = await location.save() + return response + } catch (err) { + return {type: "Error", message: err.message || 'An error occurred while saving the location'} + } + } + /* Function to handle token generation and email process: - Generates a new token and saves it to the database. @@ -319,17 +331,7 @@ const profileInitialSetupController = function ( } }; - const setMapLocation = async (locationData) => { - const location = new MapLocation(locationData); - - try { - const response = await location.save() - return response - } catch (err) { - return {type: "Error", message: err.message || 'An error occurred while saving the location'} - } - } return { getSetupToken, From 5b8c91b7120baaca0c4b4ef15e1702749271256f Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Thu, 21 Dec 2023 13:52:14 -0800 Subject: [PATCH 221/272] add equip controller, add equip func, update package-lock --- package-lock.json | 109 +++++++++--------- .../bmdashboard/bmEquipmentController.js | 17 +++ 2 files changed, 69 insertions(+), 57 deletions(-) create mode 100644 src/controllers/bmdashboard/bmEquipmentController.js diff --git a/package-lock.json b/package-lock.json index 0c8f3ee0b..97de1f352 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1568,7 +1568,7 @@ "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, "@types/mime": { @@ -1729,7 +1729,7 @@ "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, "array-includes": { "version": "3.1.6", @@ -2768,7 +2768,7 @@ "bcryptjs": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", - "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" + "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" }, "bignumber.js": { "version": "9.0.2", @@ -2863,7 +2863,7 @@ "buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" }, "buffer-from": { "version": "1.1.2", @@ -2995,7 +2995,7 @@ "clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==" + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" }, "clone-deep": { "version": "4.0.1", @@ -3039,12 +3039,12 @@ "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concat-stream": { "version": "1.6.2", @@ -3100,7 +3100,7 @@ "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, "core-js": { "version": "3.21.1", @@ -3253,7 +3253,7 @@ "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "electron-to-chromium": { "version": "1.4.81", @@ -3269,7 +3269,7 @@ "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, "es-abstract": { "version": "1.19.1", @@ -3350,7 +3350,7 @@ "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, "escape-string-regexp": { "version": "1.0.5", @@ -4264,7 +4264,7 @@ "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, "event-target-shim": { "version": "5.0.1", @@ -4429,7 +4429,7 @@ "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, "fast-text-encoding": { @@ -4559,7 +4559,7 @@ "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, "fs-readdir-recursive": { "version": "1.1.0", @@ -4569,7 +4569,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { "version": "2.3.2", @@ -4952,7 +4952,7 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, "indent-string": { @@ -4964,7 +4964,7 @@ "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "requires": { "once": "^1.3.0", "wrappy": "1" @@ -5069,7 +5069,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, "is-glob": { "version": "4.0.3", @@ -5171,13 +5171,13 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, "js-tokens": { "version": "4.0.0", @@ -5215,7 +5215,7 @@ "json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, "json5": { @@ -5713,7 +5713,7 @@ "lru_map": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", - "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==" + "integrity": "sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0=" }, "make-dir": { "version": "2.1.0", @@ -5727,7 +5727,7 @@ "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, "memory-pager": { "version": "1.5.0", @@ -5738,7 +5738,7 @@ "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, "merge-stream": { "version": "2.0.0", @@ -5749,7 +5749,7 @@ "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, "micromatch": { "version": "4.0.5", @@ -5806,11 +5806,6 @@ "moment": ">= 2.9.0" } }, - "mongo-round": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mongo-round/-/mongo-round-1.0.0.tgz", - "integrity": "sha512-lwvLJv827Uks+3HnTOt1I/Qr78Avke3du1oMaFqFpTwtRKtOposNOKkfpGXQN4ZGpRN3XAS8fEppIJ4TUj0xQw==" - }, "mongodb": { "version": "3.7.3", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz", @@ -5934,7 +5929,7 @@ "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, "negotiator": { @@ -6074,7 +6069,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-inspect": { "version": "1.12.0", @@ -6793,7 +6788,7 @@ "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { "wrappy": "1" } @@ -6823,7 +6818,7 @@ "os-shim": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz", - "integrity": "sha512-jd0cvB8qQ5uVt0lvCIexBaROw1KyKm5sbulg2fWOHjETisuCzWyt+eTZKEMs8v6HwzoGs8xik26jg7eCM6pS+A==", + "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=", "dev": true }, "p-limit": { @@ -6868,7 +6863,7 @@ "parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==" + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" }, "parseurl": { "version": "1.3.3", @@ -6883,7 +6878,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-key": { "version": "3.1.1", @@ -6899,7 +6894,7 @@ "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, "picocolors": { "version": "1.0.0", @@ -6946,7 +6941,7 @@ "pre-commit": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/pre-commit/-/pre-commit-1.2.2.tgz", - "integrity": "sha512-qokTiqxD6GjODy5ETAIgzsRgnBWWQHQH2ghy86PU7mIn/wuWeTwF3otyNQZxWBwVn8XNr8Tdzj/QfUXpH+gRZA==", + "integrity": "sha1-287g7p3nI15X95xW186UZBpp7sY=", "dev": true, "requires": { "cross-spawn": "^5.0.1", @@ -6957,7 +6952,7 @@ "cross-spawn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { "lru-cache": "^4.0.1", @@ -6968,7 +6963,7 @@ "which": { "version": "1.2.14", "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", - "integrity": "sha512-16uPglFkRPzgiUXYMi1Jf8Z5EzN1iB4V0ZtMXcHZnwsBtQhhHeCqoWw7tsUY42hJGNDWtUsVLTjakIa5BgAxCw==", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", "dev": true, "requires": { "isexe": "^2.0.0" @@ -7010,7 +7005,7 @@ "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, "pstree.remy": { @@ -7488,7 +7483,7 @@ "sparse-bitfield": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", "optional": true, "requires": { "memory-pager": "^1.0.2" @@ -7497,7 +7492,7 @@ "spawn-sync": { "version": "1.0.15", "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", - "integrity": "sha512-9DWBgrgYZzNghseho0JOuh+5fg9u6QWhAWa51QC7+U5rCheZ/j1DrEZnyE0RBBRqZ9uEXGPgSSM0nky6burpVw==", + "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=", "dev": true, "requires": { "concat-stream": "^1.4.7", @@ -7892,7 +7887,7 @@ "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, "strip-final-newline": { @@ -7923,19 +7918,19 @@ "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" }, "to-regex-range": { "version": "5.0.1", @@ -7962,7 +7957,7 @@ "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" }, "tsconfig-paths": { "version": "3.14.2", @@ -8080,7 +8075,7 @@ "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, "unbox-primitive": { @@ -8127,7 +8122,7 @@ "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, "uri-js": { "version": "4.4.1", @@ -8141,17 +8136,17 @@ "url-template": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", - "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==" + "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { "version": "3.4.0", @@ -8174,17 +8169,17 @@ "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" }, "whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -8302,7 +8297,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "ws": { "version": "8.8.1", diff --git a/src/controllers/bmdashboard/bmEquipmentController.js b/src/controllers/bmdashboard/bmEquipmentController.js new file mode 100644 index 000000000..57d73359d --- /dev/null +++ b/src/controllers/bmdashboard/bmEquipmentController.js @@ -0,0 +1,17 @@ +// const mongoose = require('mongoose'); + +function bmEquipmentController() { + async function addEquipmentType(req, res) { + console.log(req.body); + try { + res.status(201).send({ message: 'Hello world!' }); + } catch (error) { + res.status(500).send(error); + } + } + return { + addEquipmentType, + }; +} + +module.exports = bmEquipmentController; From b8996e949b5c6e944c189207ea2894bcb7775adc Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Thu, 21 Dec 2023 13:57:26 -0800 Subject: [PATCH 222/272] add equipment router --- src/routes/bmdashboard/bmEquipmentRouter.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/routes/bmdashboard/bmEquipmentRouter.js diff --git a/src/routes/bmdashboard/bmEquipmentRouter.js b/src/routes/bmdashboard/bmEquipmentRouter.js new file mode 100644 index 000000000..e4cc6972f --- /dev/null +++ b/src/routes/bmdashboard/bmEquipmentRouter.js @@ -0,0 +1,12 @@ +const express = require('express'); + +const routes = function () { + const equipmentRouter = express.Router(); + const controller = require('../../controllers/bmdashboard/bmEquipmentController')(); + equipmentRouter.route('/equipment/add') + .post(controller.addEquipmentType); + + return equipmentRouter; +}; + +module.exports = routes; From 08c45bb09da422533acc78fc0e84a103f2f1f55f Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Thu, 21 Dec 2023 13:59:40 -0800 Subject: [PATCH 223/272] add equipment endpoint to routes --- src/startup/routes.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/startup/routes.js b/src/startup/routes.js index ff5d01b2b..80b51fa9a 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -65,6 +65,7 @@ const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial, buildingMaterial); const bmProjectRouter = require('../routes/bmdashboard/bmProjectRouter')(buildingProject); const bmInventoryTypeRouter = require('../routes/bmdashboard/bmInventoryTypeRouter')(buildingInventoryType); +const bmEquipmentRouter = require('../routes/bmdashboard/bmEquipmentRouter')(); module.exports = function (app) { app.use('/api', forgotPwdRouter); @@ -101,4 +102,5 @@ module.exports = function (app) { app.use('/api/bm', bmMaterialsRouter); app.use('/api/bm', bmProjectRouter); app.use('/api/bm', bmInventoryTypeRouter); + app.use('/api/bm', bmEquipmentRouter); }; From d911d14b77f1d70e7f6f941517c77b005198a0fa Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Thu, 21 Dec 2023 15:47:24 -0800 Subject: [PATCH 224/272] move api to invtype. delete redundant files. --- .../bmdashboard/bmEquipmentController.js | 17 ----------------- .../bmdashboard/bmInventoryTypeController.js | 19 +++++++++++++++---- src/routes/bmdashboard/bmEquipmentRouter.js | 12 ------------ .../bmdashboard/bmInventoryTypeRouter.js | 3 +++ src/startup/routes.js | 2 -- 5 files changed, 18 insertions(+), 35 deletions(-) delete mode 100644 src/controllers/bmdashboard/bmEquipmentController.js delete mode 100644 src/routes/bmdashboard/bmEquipmentRouter.js diff --git a/src/controllers/bmdashboard/bmEquipmentController.js b/src/controllers/bmdashboard/bmEquipmentController.js deleted file mode 100644 index 57d73359d..000000000 --- a/src/controllers/bmdashboard/bmEquipmentController.js +++ /dev/null @@ -1,17 +0,0 @@ -// const mongoose = require('mongoose'); - -function bmEquipmentController() { - async function addEquipmentType(req, res) { - console.log(req.body); - try { - res.status(201).send({ message: 'Hello world!' }); - } catch (error) { - res.status(500).send(error); - } - } - return { - addEquipmentType, - }; -} - -module.exports = bmEquipmentController; diff --git a/src/controllers/bmdashboard/bmInventoryTypeController.js b/src/controllers/bmdashboard/bmInventoryTypeController.js index b9ced243e..48264d81b 100644 --- a/src/controllers/bmdashboard/bmInventoryTypeController.js +++ b/src/controllers/bmdashboard/bmInventoryTypeController.js @@ -1,5 +1,5 @@ -const bmInventoryTypeController = function (InvType) { - const fetchMaterialTypes = async (req, res) => { +function bmInventoryTypeController(InvType) { + async function fetchMaterialTypes(req, res) { try { InvType .find() @@ -9,11 +9,22 @@ const bmInventoryTypeController = function (InvType) { } catch (err) { res.json(err); } - }; + } + async function addEquipmentType(req, res) { + const { name, desc } = req.body; + console.log(name, desc); + try { + res.status(201).send({ message: 'Hello world!' }); + } catch (error) { + res.status(500).send(error); + } + } return { fetchMaterialTypes, + addEquipmentType, }; -}; +} + module.exports = bmInventoryTypeController; diff --git a/src/routes/bmdashboard/bmEquipmentRouter.js b/src/routes/bmdashboard/bmEquipmentRouter.js deleted file mode 100644 index e4cc6972f..000000000 --- a/src/routes/bmdashboard/bmEquipmentRouter.js +++ /dev/null @@ -1,12 +0,0 @@ -const express = require('express'); - -const routes = function () { - const equipmentRouter = express.Router(); - const controller = require('../../controllers/bmdashboard/bmEquipmentController')(); - equipmentRouter.route('/equipment/add') - .post(controller.addEquipmentType); - - return equipmentRouter; -}; - -module.exports = routes; diff --git a/src/routes/bmdashboard/bmInventoryTypeRouter.js b/src/routes/bmdashboard/bmInventoryTypeRouter.js index ceae439dc..5155fa52a 100644 --- a/src/routes/bmdashboard/bmInventoryTypeRouter.js +++ b/src/routes/bmdashboard/bmInventoryTypeRouter.js @@ -7,6 +7,9 @@ const routes = function (invType) { inventoryTypeRouter.route('/invtypes/materials') .get(controller.fetchMaterialTypes); + inventoryTypeRouter.route('/invtypes/equipment') + .post(controller.addEquipmentType); + return inventoryTypeRouter; }; diff --git a/src/startup/routes.js b/src/startup/routes.js index 80b51fa9a..ff5d01b2b 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -65,7 +65,6 @@ const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial, buildingMaterial); const bmProjectRouter = require('../routes/bmdashboard/bmProjectRouter')(buildingProject); const bmInventoryTypeRouter = require('../routes/bmdashboard/bmInventoryTypeRouter')(buildingInventoryType); -const bmEquipmentRouter = require('../routes/bmdashboard/bmEquipmentRouter')(); module.exports = function (app) { app.use('/api', forgotPwdRouter); @@ -102,5 +101,4 @@ module.exports = function (app) { app.use('/api/bm', bmMaterialsRouter); app.use('/api/bm', bmProjectRouter); app.use('/api/bm', bmInventoryTypeRouter); - app.use('/api/bm', bmEquipmentRouter); }; From a5039719ec206e9fa74407f0856cb5ceef8d37b3 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Thu, 21 Dec 2023 16:01:46 -0800 Subject: [PATCH 225/272] add invtype create method --- .../bmdashboard/bmInventoryTypeController.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/controllers/bmdashboard/bmInventoryTypeController.js b/src/controllers/bmdashboard/bmInventoryTypeController.js index 48264d81b..7914066dc 100644 --- a/src/controllers/bmdashboard/bmInventoryTypeController.js +++ b/src/controllers/bmdashboard/bmInventoryTypeController.js @@ -12,10 +12,19 @@ function bmInventoryTypeController(InvType) { } async function addEquipmentType(req, res) { - const { name, desc } = req.body; - console.log(name, desc); + const { name, desc: description } = req.body; + const newDoc = { + category: 'Equipment', + name, + description, + unit: 'irrelevant', + imageUrl: 'test string', + }; try { - res.status(201).send({ message: 'Hello world!' }); + InvType + .create(newDoc) + .then(() => res.status(201).send()) + .catch(error => res.status(500).send(error)); } catch (error) { res.status(500).send(error); } From 80d45f1077e553e494c63a38c16b16edc16331ed Mon Sep 17 00:00:00 2001 From: tsunami776 <43768723+tsunami776@users.noreply.github.com> Date: Thu, 21 Dec 2023 21:56:36 -0600 Subject: [PATCH 226/272] Update modifiedDatetime when team member added or removed from a team --- src/controllers/teamController.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/controllers/teamController.js b/src/controllers/teamController.js index 5c8cb5cc2..d625d6a93 100644 --- a/src/controllers/teamController.js +++ b/src/controllers/teamController.js @@ -157,11 +157,17 @@ const teamcontroller = function (Team) { .exec(); const addUserToTeam = Team.updateOne( { _id: team._id }, - { $addToSet: { members: { $each: assignlist.map(userId => ({ userId })) } } }, + { + $addToSet: { members: { $each: assignlist.map(userId => ({ userId })) } }, + $set: { modifiedDatetime: Date.now() }, + }, ).exec(); const removeUserFromTeam = Team.updateOne( { _id: team._id }, - { $pull: { members: { userId: { $in: unassignlist } } } }, + { + $pull: { members: { userId: { $in: unassignlist } } }, + $set: { modifiedDatetime: Date.now() }, + }, ).exec(); Promise.all([addTeamToUserProfile, removeTeamFromUserProfile, addUserToTeam, removeUserFromTeam]) From 4acbedb9a58e65adc36917c6ac5d2257ee18d206 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Fri, 22 Dec 2023 15:04:45 -0800 Subject: [PATCH 227/272] add discriminators to inv type model --- .../bmdashboard/buildingInventoryType.js | 76 ++++++++++++++++++- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/src/models/bmdashboard/buildingInventoryType.js b/src/models/bmdashboard/buildingInventoryType.js index 8d2364c64..562dddf91 100644 --- a/src/models/bmdashboard/buildingInventoryType.js +++ b/src/models/bmdashboard/buildingInventoryType.js @@ -2,12 +2,80 @@ const mongoose = require('mongoose'); const { Schema } = mongoose; -const buildingInventoryType = new Schema({ - category: { type: String, enum: ['Consumable', 'Material', 'Tool', 'Equipment'], required: true }, +//--------------------------- +// BASE INVENTORY TYPE SCHEMA +//--------------------------- + +// all schemas will inherit these properties +// all documents will live in buildingInventoryTypes collection + +const invTypeBaseSchema = new Schema({ name: { type: String, required: true }, description: { type: String, required: true }, - unit: { type: String, required: true }, // unit of measurement imageUrl: String, }); -module.exports = mongoose.model('buildingInventoryType', buildingInventoryType, 'buildingInventoryTypes'); +const invTypeBase = mongoose.model('invTypeBase', invTypeBaseSchema, 'buildingInventoryTypes'); + +//--------------------------- +// MATERIAL TYPE +//--------------------------- + +// ex: sand, stone, brick, lumber + +const materialType = invTypeBase.discriminator('material', new mongoose.Schema({ + category: { type: String, enum: ['Material'] }, + unit: { type: String, required: true }, // unit of measurement +})); + +//--------------------------- +// CONSUMABLE TYPE +//--------------------------- + +// ex: screws, nails, staples + +const consumableType = invTypeBase.discriminator('consumable', new mongoose.Schema({ + category: { type: String, enum: ['Consumable'] }, + size: { type: String, required: true }, +})); + +//--------------------------- +// REUSABLE TYPE +//--------------------------- + +// ex: gloves, brushes, hammers, screwdrivers + +const reusableType = invTypeBase.discriminator('reusable', new mongoose.Schema({ + category: { type: String, enum: ['Reusable'] }, +})); + +//--------------------------- +// TOOL TYPE +//--------------------------- + +// ex: shovels, wheelbarrows, power drills, jackhammers + +const toolType = invTypeBase.discriminator('tool', new mongoose.Schema({ + category: { type: String, enum: ['Tool'] }, + isPowered: { type: Boolean, required: true }, + powerSource: { type: String, required: () => this.isPowered }, // required if isPowered = true (syntax?) +})); + +//--------------------------- +// EQUIPMENT TYPE +//--------------------------- + +// ex: tractors, excavators + +const equipmentType = invTypeBase.discriminator('equipment', new mongoose.Schema({ + category: { type: String, enum: ['Equipment'] }, + fuelType: { type: String, required: true }, +})); + +module.exports = { + materialType, + consumableType, + reusableType, + toolType, + equipmentType, +}; From b4e05848163567749bc88352994f587ff87976cd Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Fri, 22 Dec 2023 16:43:28 -0800 Subject: [PATCH 228/272] add inv type models to routing. update controller func for new model. --- .../bmdashboard/bmInventoryTypeController.js | 14 ++++++++------ src/models/bmdashboard/buildingInventoryType.js | 2 +- src/routes/bmdashboard/bmInventoryTypeRouter.js | 4 ++-- src/startup/routes.js | 11 +++++++++-- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/controllers/bmdashboard/bmInventoryTypeController.js b/src/controllers/bmdashboard/bmInventoryTypeController.js index 7914066dc..d52be6d68 100644 --- a/src/controllers/bmdashboard/bmInventoryTypeController.js +++ b/src/controllers/bmdashboard/bmInventoryTypeController.js @@ -1,7 +1,7 @@ -function bmInventoryTypeController(InvType) { +function bmInventoryTypeController(MatType, ConsType, ReusType, ToolType, EquipType) { async function fetchMaterialTypes(req, res) { try { - InvType + MatType .find() .exec() .then(result => res.status(200).send(result)) @@ -11,17 +11,19 @@ function bmInventoryTypeController(InvType) { } } + // TODO: validate request body + // TODO: update model + // TODO: Mongo error handling async function addEquipmentType(req, res) { - const { name, desc: description } = req.body; + const { name, desc: description, fuel: fuelType } = req.body; const newDoc = { category: 'Equipment', name, description, - unit: 'irrelevant', - imageUrl: 'test string', + fuelType, }; try { - InvType + EquipType .create(newDoc) .then(() => res.status(201).send()) .catch(error => res.status(500).send(error)); diff --git a/src/models/bmdashboard/buildingInventoryType.js b/src/models/bmdashboard/buildingInventoryType.js index 562dddf91..2972db3ab 100644 --- a/src/models/bmdashboard/buildingInventoryType.js +++ b/src/models/bmdashboard/buildingInventoryType.js @@ -69,7 +69,7 @@ const toolType = invTypeBase.discriminator('tool', new mongoose.Schema({ const equipmentType = invTypeBase.discriminator('equipment', new mongoose.Schema({ category: { type: String, enum: ['Equipment'] }, - fuelType: { type: String, required: true }, + fuelType: { type: String, enum: ['Diesel', 'Biodiesel', 'Gasoline', 'Natural Gas', 'Ethanol'], required: true }, })); module.exports = { diff --git a/src/routes/bmdashboard/bmInventoryTypeRouter.js b/src/routes/bmdashboard/bmInventoryTypeRouter.js index 5155fa52a..13c8c5200 100644 --- a/src/routes/bmdashboard/bmInventoryTypeRouter.js +++ b/src/routes/bmdashboard/bmInventoryTypeRouter.js @@ -1,8 +1,8 @@ const express = require('express'); -const routes = function (invType) { +const routes = function (matType, consType, reusType, toolType, equipType) { const inventoryTypeRouter = express.Router(); - const controller = require('../../controllers/bmdashboard/bmInventoryTypeController')(invType); + const controller = require('../../controllers/bmdashboard/bmInventoryTypeController')(matType, consType, reusType, toolType, equipType); inventoryTypeRouter.route('/invtypes/materials') .get(controller.fetchMaterialTypes); diff --git a/src/startup/routes.js b/src/startup/routes.js index ff5d01b2b..8a44ac338 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -22,8 +22,15 @@ const mouseoverText = require('../models/mouseoverText'); const inventoryItemMaterial = require('../models/inventoryItemMaterial'); const mapLocations = require('../models/mapLocation'); const buildingProject = require('../models/bmdashboard/buildingProject'); -const buildingInventoryType = require('../models/bmdashboard/buildingInventoryType'); +// const buildingInventoryType = require('../models/bmdashboard/buildingInventoryType'); const buildingMaterial = require('../models/bmdashboard/buildingMaterial'); +const { + materialType, + consumableType, + reusableType, + toolType, + equipmentType, +} = require('../models/bmdashboard/buildingInventoryType'); const userProfileRouter = require('../routes/userProfileRouter')(userProfile); const badgeRouter = require('../routes/badgeRouter')(badge); @@ -64,7 +71,7 @@ const mapLocationRouter = require('../routes/mapLocationsRouter')(mapLocations); const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial, buildingMaterial); const bmProjectRouter = require('../routes/bmdashboard/bmProjectRouter')(buildingProject); -const bmInventoryTypeRouter = require('../routes/bmdashboard/bmInventoryTypeRouter')(buildingInventoryType); +const bmInventoryTypeRouter = require('../routes/bmdashboard/bmInventoryTypeRouter')(materialType, consumableType, reusableType, toolType, equipmentType); module.exports = function (app) { app.use('/api', forgotPwdRouter); From e812126c668115c7eb625c4ca473ed3c30920c9e Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Fri, 22 Dec 2023 17:16:42 -0800 Subject: [PATCH 229/272] add validation error handling to create op --- .../bmdashboard/bmInventoryTypeController.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/controllers/bmdashboard/bmInventoryTypeController.js b/src/controllers/bmdashboard/bmInventoryTypeController.js index d52be6d68..a2cae4d01 100644 --- a/src/controllers/bmdashboard/bmInventoryTypeController.js +++ b/src/controllers/bmdashboard/bmInventoryTypeController.js @@ -11,9 +11,6 @@ function bmInventoryTypeController(MatType, ConsType, ReusType, ToolType, EquipT } } - // TODO: validate request body - // TODO: update model - // TODO: Mongo error handling async function addEquipmentType(req, res) { const { name, desc: description, fuel: fuelType } = req.body; const newDoc = { @@ -26,7 +23,12 @@ function bmInventoryTypeController(MatType, ConsType, ReusType, ToolType, EquipT EquipType .create(newDoc) .then(() => res.status(201).send()) - .catch(error => res.status(500).send(error)); + .catch((error) => { + if (error._message.includes('validation failed')) { + res.status(400).send(error); + } + res.status(500).send(error); + }); } catch (error) { res.status(500).send(error); } From 9d3dda9b4792a9e62d6a548503217deab4194ce3 Mon Sep 17 00:00:00 2001 From: wang9hu Date: Sat, 23 Dec 2023 03:11:18 -0800 Subject: [PATCH 230/272] finish TimeEntryForm, TimeLog, TimeEntry refactor --- src/controllers/timeEntryController.js | 256 ++++++++++--------------- src/models/timeentry.js | 2 +- src/models/userProfile.js | 2 +- 3 files changed, 103 insertions(+), 157 deletions(-) diff --git a/src/controllers/timeEntryController.js b/src/controllers/timeEntryController.js index bc7763705..6c2269a1d 100644 --- a/src/controllers/timeEntryController.js +++ b/src/controllers/timeEntryController.js @@ -53,9 +53,8 @@ const getEditedTimeEntryEmailBody = ( * @param {*} final Final time entry object * @returns {Void} */ -const notifyEditByEmail = async (personId, original, finalTime, final) => { +const notifyEditByEmail = async (personId, originalTime, finalTime, final) => { try { - const originalTime = original.totalSeconds; const record = await UserProfile.findById(personId); const requestor = personId !== final.requestor.requestorId ? await UserProfile.findById(final.requestor.requestorId) @@ -112,7 +111,7 @@ const notifyTaskOvertimeEmailBody = async ( } }; -const checkTaskOvertime = async (timeentry, record, currentTask) => { +const checkTaskOvertime = async (timeentry, currentUser, currentTask) => { try { // send email notification if logged in hours exceeds estiamted hours for a task if (currentTask.hoursLogged > currentTask.estimatedHours) { @@ -125,7 +124,7 @@ const checkTaskOvertime = async (timeentry, record, currentTask) => { } } catch (error) { console.log( - `Failed to find task whose logged-in hours are more than estimated hours ${record.email}`, + `Failed to find task whose logged-in hours are more than estimated hours for ${currentUser.email}`, ); } }; @@ -163,18 +162,18 @@ const timeEntrycontroller = function (TimeEntry) { const { personId, - hours = '00', - minutes = '00', - notes, - isTangible, - projectId, - wbsId, - taskId, - dateOfWork, + hours: newHours = '00', + minutes: newMinutes = '00', + notes: newNotes, + isTangible: newIsTangible, + projectId: newProjectId, + wbsId: newWbsId, + taskId: newTaskId, + dateOfWork: newDateOfWork, } = req.body; const isForAuthUser = personId === req.body.requestor.requestorId; - const isSameDayTimeEntry = moment().tz('America/Los_Angeles').format('YYYY-MM-DD') === dateOfWork; + const isSameDayTimeEntry = moment().tz('America/Los_Angeles').format('YYYY-MM-DD') === newDateOfWork; const canEdit = (await hasPermission(req.body.requestor, 'editTimeEntry')) || (isForAuthUser && isSameDayTimeEntry); if (!canEdit) { @@ -189,130 +188,98 @@ const timeEntrycontroller = function (TimeEntry) { try { if (!req.params.timeEntryId) { - return res - .status(400) - .send({ - error: 'ObjectId in request param is not in correct format', - }); + const error = 'ObjectId in request param is not in correct format'; + return res.status(400).send({ error }); } - if ( - !mongoose.Types.ObjectId.isValid(req.params.timeEntryId) + if (!mongoose.Types.ObjectId.isValid(req.params.timeEntryId) || ((type === 'default' || type === 'project') && !mongoose.Types.ObjectId.isValid(req.body.projectId) )) { - return res - .status(400) - .send({ error: 'ObjectIds are not correctly formed' }); + const error = 'ObjectIds are not correctly formed'; + return res.status(400).send({ error }); } // Get initial timeEntry by timeEntryId const timeEntry = await TimeEntry.findById(timeEntryId); + if (!timeEntry) { const error = `No valid records found for ${timeEntryId}`; return res.status(400).send({ error }); } - const totalSeconds = moment.duration({ hours, minutes }).asSeconds(); - const { - totalSeconds: initialTotalSeconds, - projectId: initialProjectId, - wbsId: initialWBSId, - taskId: initialTaskId, - isTangible: initialIsTangible, - } = timeEntry; + const newTotalSeconds = moment.duration({ hours: newHours, minutes: newMinutes }).asSeconds(); - if (initialIsTangible && totalSeconds !== initialTotalSeconds) { + if (timeEntry.isTangible && newIsTangible && newTotalSeconds !== timeEntry.totalSeconds) { notifyEditByEmail( timeEntry.personId.toString(), - timeEntry, - totalSeconds, + timeEntry.totalSeconds, + newTotalSeconds, req.body, ); } - updateTaskIdInTimeEntry(projectId, timeEntry); - - if (timeEntry.taskId) { - const findTask = await Task.findById(initialProjectId); - if (initialIsTangible) { - findTask.hoursLogged -= initialTotalSeconds / 3600; + if (newTaskId) { + const timeEntryTask = await Task.findById(newTaskId); + const timeEntryUser = await UserProfile.findById(personId); + if (timeEntry.isTangible) { + timeEntryTask.hoursLogged -= timeEntry.totalSeconds / 3600; } - if (req.body.isTangible === true) { - findTask.hoursLogged += totalSeconds / 3600; + if (newIsTangible) { + timeEntryTask.hoursLogged += newTotalSeconds / 3600; } - await findTask.save(); + checkTaskOvertime(timeEntry, timeEntryUser, timeEntryTask); + await timeEntryTask.save(); } - timeEntry.notes = notes; - timeEntry.totalSeconds = totalSeconds; - timeEntry.isTangible = isTangible; - timeEntry.lastModifiedDateTime = moment().utc().toISOString(); - timeEntry.projectId = mongoose.Types.ObjectId(projectId); - timeEntry.wbsId = wbsId ? mongoose.Types.ObjectId(wbsId) : null; - timeEntry.taskId = taskId ? mongoose.Types.ObjectId(taskId) : null; - timeEntry.dateOfWork = moment(dateOfWork).format('YYYY-MM-DD'); - // Update edit history - if ( - (type === 'default' || type === 'person') - && initialSeconds !== totalSeconds + if ((type === 'default' || type === 'person') + && timeEntry.totalSeconds !== newTotalSeconds && timeEntry.isTangible - && req.body.requestor.requestorId === timeEntry.personId.toString() + && isForAuthUser && !(await hasPermission(req.body.requestor, 'editTimeEntry')) ) { const requestor = await UserProfile.findById( req.body.requestor.requestorId, ); + requestor.timeEntryEditHistory.push({ date: moment().tz('America/Los_Angeles').toDate(), - initialSeconds: initialTotalSeconds, - newSeconds: totalSeconds, + initialSeconds: timeEntry.totalSeconds, + newSeconds: newTotalSeconds, }); if (type === 'default') { // Issue infraction if edit history contains more than 5 edits in the last year let totalRecentEdits = 0; - requestor.timeEntryEditHistory.forEach((edit) => { - if ( - moment().tz('America/Los_Angeles').diff(edit.date, 'days') <= 365 - ) { - totalRecentEdits += 1; - } - }); requestor.timeEntryEditHistory.forEach((edit) => { if ( - moment().tz('America/Los_Angeles').diff(edit.date, 'days') <= 365 - ) { - totalRecentEdits += 1; - } + moment() + .tz('America/Los_Angeles') + .diff(edit.date, 'days') <= 365 + ) totalRecentEdits += 1; }); - if (totalRecentEdits >= 5) { - requestor.infringements.push({ - date: moment().tz('America/Los_Angeles'), - description: `${totalRecentEdits} time entry edits in the last calendar year`, - }); if (totalRecentEdits >= 5) { requestor.infringements.push({ date: moment().tz('America/Los_Angeles'), description: `${totalRecentEdits} time entry edits in the last calendar year`, }); - emailSender( - "onecommunityglobal@gmail.com", - `${requestor.firstName} ${requestor.lastName} was issued a blue square for for editing a time entry ${totalRecentEdits} times`, - ` -

- ${requestor.firstName} ${requestor.lastName} (${requestor.email}) was issued a blue square for editing their time entries ${totalRecentEdits} times - within the last calendar year. -

-

- This is the ${totalRecentEdits}th edit within the past 365 days. -

- ` - ); + emailSender( + 'onecommunityglobal@gmail.com', + `${requestor.firstName} ${requestor.lastName} was issued a blue square for for editing a time entry ${totalRecentEdits} times`, + ` +

+ ${requestor.firstName} ${requestor.lastName} (${requestor.email}) was issued a blue square for editing their time entries ${totalRecentEdits} times + within the last calendar year. +

+

+ This is the ${totalRecentEdits}th edit within the past 365 days. +

+ `, + ); const emailInfringement = { date: moment().tz('America/Los_Angeles').format('MMMM-DD-YY'), @@ -331,31 +298,26 @@ const timeEntrycontroller = function (TimeEntry) { ); } } - await requestor.save(); } + timeEntry.notes = newNotes; + timeEntry.totalSeconds = newTotalSeconds; + timeEntry.isTangible = newIsTangible; + timeEntry.lastModifiedDateTime = moment().utc().toISOString(); + timeEntry.projectId = mongoose.Types.ObjectId(newProjectId); + timeEntry.wbsId = newWbsId ? mongoose.Types.ObjectId(newWbsId) : null; + timeEntry.taskId = newTaskId ? mongoose.Types.ObjectId(newTaskId) : null; + timeEntry.dateOfWork = moment(newDateOfWork).format('YYYY-MM-DD'); await timeEntry.save(); - res.status(200).send({ message: 'Successfully updated time entry' }); - - // If the time entry isn't related to a task (i.e. it's a project), then don't check for overtime (Most likely pr team) - if (type === 'default' && findTask) { - // checking if logged in hours exceed estimated time after timeentry edit for a task - const record = await UserProfile.findById( - timeEntry.personId.toString(), - ); - const currentTask = await Task.findById(req.body.projectId); - checkTaskOvertime(timeEntry, record, currentTask); - } + return res.status(200).send({ message: 'Successfully updated time entry' }); } catch (err) { await session.abortTransaction(); return res.status(400).send({ error: err.toString() }); } finally { session.endSession(); } - - return res.status(200).send(); }; const getAllTimeEnteries = function (req, res) { @@ -369,6 +331,8 @@ const timeEntrycontroller = function (TimeEntry) { const timeentry = new TimeEntry(); timeentry.personId = element.personId; timeentry.projectId = element.projectId; + timeentry.wbsId = element.wbsId; + timeentry.taskId = element.taskId; timeentry.dateOfWork = element.dateOfWork; timeentry.timeSpent = moment('1900-01-01 00:00:00') .add(element.totalSeconds, 'seconds') @@ -386,8 +350,7 @@ const timeEntrycontroller = function (TimeEntry) { const postTimeEntry = async function (req, res) { const isInvalid = !req.body.dateOfWork || !moment(req.body.dateOfWork).isValid() - || !req.body.timeSpent - || !req.body.isTangible; + || !req.body.timeSpent; const returnErr = (result) => { result.status(400).send({ error: 'Bad request' }); @@ -426,57 +389,40 @@ const timeEntrycontroller = function (TimeEntry) { break; } - const timeentry = new TimeEntry(); + const timeEntry = new TimeEntry(); const { dateOfWork, timeSpent } = req.body; - timeentry.personId = req.body.personId; - timeentry.projectId = req.body.projectId; - timeentry.wbsId = req.body.wbsId; - timeentry.taskId = req.body.taskId; - timeentry.teamId = req.body.teamId; - timeentry.dateOfWork = moment(dateOfWork).format('YYYY-MM-DD'); - timeentry.totalSeconds = moment.duration(timeSpent).asSeconds(); - timeentry.notes = req.body.notes; - timeentry.isTangible = req.body.isTangible; - timeentry.createdDateTime = moment().utc().toISOString(); - timeentry.lastModifiedDateTime = moment().utc().toISOString(); - timeentry.entryType = req.body.entryType; - - timeentry - .save() - .then((results) => { - res - .status(200) - .send({ message: `Time Entry saved with id as ${results._id}` }); - }) - .catch((error) => { - res.status(400).send(error); - }); - - if (timeentry.entryType === 'default') { - // Get the task related to this time entry, if not found, then it's a project sets to null - const currentTask = await task - .findById(req.body.projectId) - .catch(() => null); - - // Add this tangbile time entry to related task's hoursLogged and checks if timeEntry is related to a task - if (timeentry.isTangible === true && currentTask) { - try { - currentTask.hoursLogged += timeentry.totalSeconds / 3600; - await currentTask.save(); - } catch (error) { - throw new Error(error); - } + timeEntry.personId = req.body.personId; + timeEntry.projectId = req.body.projectId; + timeEntry.wbsId = req.body.wbsId; + timeEntry.taskId = req.body.taskId; + timeEntry.teamId = req.body.teamId; + timeEntry.dateOfWork = moment(dateOfWork).format('YYYY-MM-DD'); + timeEntry.totalSeconds = moment.duration(timeSpent).asSeconds(); + timeEntry.notes = req.body.notes; + timeEntry.isTangible = req.body.isTangible; + timeEntry.createdDateTime = moment().utc().toISOString(); + timeEntry.lastModifiedDateTime = moment().utc().toISOString(); + timeEntry.entryType = req.body.entryType; + + if (timeEntry.taskId) { + const timeEntryTask = await Task.findById(timeEntry.taskId); + const timeEntryUser = await UserProfile.findById(timeEntry.personId); + if (timeEntry.isTangible) { + timeEntryTask.hoursLogged += timeEntry.totalSeconds / 3600; } + checkTaskOvertime(timeEntry, timeEntryUser, timeEntryTask); + await timeEntryTask.save(); + } - // checking if logged in hours exceed estimated time after timeentry for a task, only if the time entry is related to a task (It might not be, if it's a project) - if (currentTask) { - try { - const record = await UserProfile.findById(timeentry.personId.toString()); - checkTaskOvertime(timeentry, record, currentTask); - } catch (error) { - throw new Error(error); - } - } + try { + return timeEntry + .save() + .then(results => res.status(200).send({ + message: `Time Entry saved with id as ${results._id}`, + })) + .catch(error => res.status(400).send(error)); + } catch (error) { + return res.status(500).send(error); } }; @@ -510,8 +456,8 @@ const timeEntrycontroller = function (TimeEntry) { const results = await Promise.all(timeEntries.map(async (timeEntry) => { timeEntry = { ...timeEntry.toObject() }; - const { projectId } = timeEntry; - await updateTaskIdInTimeEntry(projectId, timeEntry); + const { projectId, taskId } = timeEntry; + if (!taskId) await updateTaskIdInTimeEntry(projectId, timeEntry); // if no taskId, then it might be old time entry data that didn't separate projectId with taskId const hours = Math.floor(timeEntry.totalSeconds / 3600); const minutes = Math.floor((timeEntry.totalSeconds % 3600) / 60); Object.assign(timeEntry, { hours, minutes, totalSeconds: undefined }); @@ -520,7 +466,7 @@ const timeEntrycontroller = function (TimeEntry) { res.status(200).send(results); } catch (error) { - res.status(400).send({ error}); + res.status(400).send({ error }); } }; @@ -773,7 +719,7 @@ const timeEntrycontroller = function (TimeEntry) { getTimeEntriesForUsersList, editTimeEntry, deleteTimeEntry, - // getTimeEntriesForSpecifiedProject, + getTimeEntriesForSpecifiedProject, checkTaskOvertime, getLostTimeEntriesForUserList, getLostTimeEntriesForProjectList, diff --git a/src/models/timeentry.js b/src/models/timeentry.js index 5343e9758..79504cc20 100644 --- a/src/models/timeentry.js +++ b/src/models/timeentry.js @@ -8,7 +8,7 @@ const TimeEntry = new Schema({ personId: { type: Schema.Types.ObjectId, ref: 'userProfile' }, projectId: { type: Schema.Types.ObjectId, ref: 'project' }, wbsId: { type: Schema.Types.ObjectId, ref: 'project' }, - taskId: { type: Schema.Types.ObjectId, ref: 'wbs' }, + taskId: { type: Schema.Types.ObjectId, default: null, ref: 'wbs' }, teamId: { type: Schema.Types.ObjectId, ref: 'task' }, dateOfWork: { type: String, required: true }, totalSeconds: { type: Number }, diff --git a/src/models/userProfile.js b/src/models/userProfile.js index e3f8d4a48..8a8de2e18 100644 --- a/src/models/userProfile.js +++ b/src/models/userProfile.js @@ -88,7 +88,7 @@ const userProfileSchema = new Schema({ lng: { type: Number, default: '' }, }, country: { type: String, default: '' }, - city: { type: String, default: '' } + city: { type: String, default: '' }, }, oldInfringements: [ From c1328bbe8fd64e668c5524aa58a8c66e77143e01 Mon Sep 17 00:00:00 2001 From: wang9hu Date: Sat, 23 Dec 2023 15:16:53 -0800 Subject: [PATCH 231/272] add task handle for project or task change when editing time entry --- src/controllers/timeEntryController.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/controllers/timeEntryController.js b/src/controllers/timeEntryController.js index 9aef95ddb..c8ef3d464 100644 --- a/src/controllers/timeEntryController.js +++ b/src/controllers/timeEntryController.js @@ -211,7 +211,6 @@ const timeEntrycontroller = function (TimeEntry) { // Get initial timeEntry by timeEntryId const timeEntry = await TimeEntry.findById(timeEntryId); - if (!timeEntry) { const error = `No valid records found for ${timeEntryId}`; return res.status(400).send({ error }); @@ -228,7 +227,8 @@ const timeEntrycontroller = function (TimeEntry) { ); } - if (newTaskId) { + // update task data if project/task is changed + if (newTaskId === timeEntry.taskId) { const timeEntryTask = await Task.findById(newTaskId); const timeEntryUser = await UserProfile.findById(personId); if (timeEntry.isTangible) { @@ -239,6 +239,19 @@ const timeEntrycontroller = function (TimeEntry) { } checkTaskOvertime(timeEntry, timeEntryUser, timeEntryTask); await timeEntryTask.save(); + } else { + const oldTimeEntryTask = await Task.findById(timeEntry.taskId); + const newTimeEntryTask = await Task.findById(newTaskId); + const timeEntryUser = await UserProfile.findById(personId); + if (timeEntry.isTangible) { + oldTimeEntryTask.hoursLogged -= timeEntry.totalSeconds / 3600; + } + if (newIsTangible) { + newTimeEntryTask.hoursLogged += newTotalSeconds / 3600; + } + checkTaskOvertime(timeEntry, timeEntryUser, newTimeEntryTask); + await oldTimeEntryTask.save(); + await newTimeEntryTask.save(); } // Update edit history From 6953ec3a2e3b1b741d9ca725f38bdf6e7a29bb81 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Fri, 29 Dec 2023 16:32:00 -0800 Subject: [PATCH 232/272] add createdBy field to base inv type model --- src/controllers/bmdashboard/bmInventoryTypeController.js | 8 +++++++- src/models/bmdashboard/buildingInventoryType.js | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/controllers/bmdashboard/bmInventoryTypeController.js b/src/controllers/bmdashboard/bmInventoryTypeController.js index a2cae4d01..ea2cba730 100644 --- a/src/controllers/bmdashboard/bmInventoryTypeController.js +++ b/src/controllers/bmdashboard/bmInventoryTypeController.js @@ -12,12 +12,18 @@ function bmInventoryTypeController(MatType, ConsType, ReusType, ToolType, EquipT } async function addEquipmentType(req, res) { - const { name, desc: description, fuel: fuelType } = req.body; + const { + name, + desc: description, + fuel: fuelType, + requestor: { requestorId }, + } = req.body; const newDoc = { category: 'Equipment', name, description, fuelType, + createdBy: requestorId, }; try { EquipType diff --git a/src/models/bmdashboard/buildingInventoryType.js b/src/models/bmdashboard/buildingInventoryType.js index 2972db3ab..b1512dca2 100644 --- a/src/models/bmdashboard/buildingInventoryType.js +++ b/src/models/bmdashboard/buildingInventoryType.js @@ -13,6 +13,7 @@ const invTypeBaseSchema = new Schema({ name: { type: String, required: true }, description: { type: String, required: true }, imageUrl: String, + createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfiles' }, }); const invTypeBase = mongoose.model('invTypeBase', invTypeBaseSchema, 'buildingInventoryTypes'); From 0888853ab93d3d122d670b72e1d59ff2ad22497f Mon Sep 17 00:00:00 2001 From: Vishala Ramasamy Date: Fri, 29 Dec 2023 17:16:45 -0800 Subject: [PATCH 233/272] Consumables first commit --- .../bmdashboard/bmConsumableController.js | 46 +++++++++++++++++++ src/routes/bmdashboard/bmConsumablesRouter.js | 13 ++++++ src/startup/routes.js | 4 ++ 3 files changed, 63 insertions(+) create mode 100644 src/controllers/bmdashboard/bmConsumableController.js create mode 100644 src/routes/bmdashboard/bmConsumablesRouter.js diff --git a/src/controllers/bmdashboard/bmConsumableController.js b/src/controllers/bmdashboard/bmConsumableController.js new file mode 100644 index 000000000..23ea6e5cd --- /dev/null +++ b/src/controllers/bmdashboard/bmConsumableController.js @@ -0,0 +1,46 @@ +const bmConsumableController = function (BuildingConsumable) { + const fetchBMConsumables = async (req, res) => { + try { + BuildingConsumable + .find() + .populate([ + { + path: 'project', + select: '_id name', + }, + { + path: 'itemType', + select: '_id name unit', + }, + { + path: 'updateRecord', + populate: { + path: 'createdBy', + select: '_id firstName lastName', + }, + }, + { + path: 'purchaseRecord', + populate: { + path: 'requestedBy', + select: '_id firstName lastName', + }, + }, + ]) + .exec() + .then(result => { + res.status(200).send(result); + }) + .catch(error => res.status(500).send(error)); + } catch (err) { + res.json(err); + } + }; + + return { + fetchBMConsumables, + }; + }; + +module.exports = bmConsumableController; + \ No newline at end of file diff --git a/src/routes/bmdashboard/bmConsumablesRouter.js b/src/routes/bmdashboard/bmConsumablesRouter.js new file mode 100644 index 000000000..51126e3a3 --- /dev/null +++ b/src/routes/bmdashboard/bmConsumablesRouter.js @@ -0,0 +1,13 @@ +const express = require('express'); + +const routes = function (BuildingConsumable) { + const BuildingConsumableController = express.Router(); + const controller = require('../../controllers/bmdashboard/bmConsumableController')(BuildingConsumable); + + BuildingConsumableController.route('/consumables') + .get(controller.fetchBMConsumables); + + return BuildingConsumableController; +}; + +module.exports = routes; diff --git a/src/startup/routes.js b/src/startup/routes.js index 620e8c9f8..963531627 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -24,6 +24,7 @@ const mapLocations = require('../models/mapLocation'); const buildingProject = require('../models/bmdashboard/buildingProject'); const buildingInventoryType = require('../models/bmdashboard/buildingInventoryType'); const buildingMaterial = require('../models/bmdashboard/buildingMaterial'); +const buildingInventoryItem = require('../models/bmdashboard/buildingInventoryItem'); const userProfileRouter = require('../routes/userProfileRouter')(userProfile); const badgeRouter = require('../routes/badgeRouter')(badge); @@ -65,6 +66,7 @@ const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial, buildingMaterial); const bmProjectRouter = require('../routes/bmdashboard/bmProjectRouter')(buildingProject); const bmInventoryTypeRouter = require('../routes/bmdashboard/bmInventoryTypeRouter')(buildingInventoryType); +const bmConsumablesRouter = require('../routes/bmdashboard/bmConsumablesRouter')(buildingInventoryItem.buildingConsumable); module.exports = function (app) { app.use('/api', forgotPwdRouter); @@ -101,4 +103,6 @@ module.exports = function (app) { app.use('/api/bm', bmMaterialsRouter); app.use('/api/bm', bmProjectRouter); app.use('/api/bm', bmInventoryTypeRouter); + app.use('/api/bm', bmConsumablesRouter); + }; From 25595a567d1f5a909b26609c18d1ddf05692f394 Mon Sep 17 00:00:00 2001 From: Shengwei Peng Date: Sat, 30 Dec 2023 10:01:56 -0500 Subject: [PATCH 234/272] Fix badge update feature - Add code to update badge earned date when badge count changes --- src/helpers/userHelper.js | 655 +++++++++++++++++++------------------- 1 file changed, 331 insertions(+), 324 deletions(-) diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index 1033bab2f..97beafc17 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -1,71 +1,68 @@ /* eslint-disable no-continue */ /* eslint-disable no-await-in-loop */ -const mongoose = require("mongoose"); -const moment = require("moment-timezone"); -const _ = require("lodash"); -const userProfile = require("../models/userProfile"); -const timeEntries = require("../models/timeentry"); -const badge = require("../models/badge"); -const myTeam = require("./helperModels/myTeam"); -const dashboardHelper = require("./dashboardhelper")(); -const reportHelper = require("./reporthelper")(); -const emailSender = require("../utilities/emailSender"); -const logger = require("../startup/logger"); -const hasPermission = require("../utilities/permissions"); -const Reason = require("../models/reason"); -const token = require("../models/profileInitialSetupToken"); +const mongoose = require('mongoose'); +const moment = require('moment-timezone'); +const _ = require('lodash'); +const userProfile = require('../models/userProfile'); +const timeEntries = require('../models/timeentry'); +const badge = require('../models/badge'); +const myTeam = require('./helperModels/myTeam'); +const dashboardHelper = require('./dashboardhelper')(); +const reportHelper = require('./reporthelper')(); +const emailSender = require('../utilities/emailSender'); +const logger = require('../startup/logger'); +const Reason = require('../models/reason'); +const token = require('../models/profileInitialSetupToken'); const userHelper = function () { + // Update format to "MMM-DD-YY" from "YYYY-MMM-DD" (Confirmed with Jae) + const earnedDateBadge = () => { + const currentDate = new Date(Date.now()); + return moment(currentDate).tz('America/Los_Angeles').format('MMM-DD-YY'); + }; + + const getTeamMembers = function (user) { const userId = mongoose.Types.ObjectId(user._id); // var teamid = userdetails.teamId; return myTeam.findById(userId).select({ - "myTeam._id": 0, - "myTeam.role": 0, - "myTeam.fullName": 0, + 'myTeam._id': 0, + 'myTeam.role': 0, + 'myTeam.fullName': 0, _id: 0, }); }; - // Updated By: Shengwei - // Updated Date: 12/08/2023 - // Update format to "MMM-DD-YY" from "YYYY-MMM-DD" (Confirmed with Jae) - const earnedDateBadge = () => { - const currentDate = new Date(Date.now()); - return moment(currentDate).tz('America/Los_Angeles').format('MMM-DD-YY'); - }; - const getUserName = async function (userId) { const userid = mongoose.Types.ObjectId(userId); - return userProfile.findById(userid, "firstName lastName"); + return userProfile.findById(userid, 'firstName lastName'); }; const validateProfilePic = function (profilePic) { - const picParts = profilePic.split("base64"); + const picParts = profilePic.split('base64'); let result = true; const errors = []; if (picParts.length < 2) { return { result: false, - errors: "Invalid image", + errors: 'Invalid image', }; } // validate size const imageSize = picParts[1].length; - const sizeInBytes = - (4 * Math.ceil(imageSize / 3) * 0.5624896334383812) / 1024; + const sizeInBytes = (4 * Math.ceil(imageSize / 3) * 0.5624896334383812) / 1024; if (sizeInBytes > 50) { - errors.push("Image size should not exceed 50KB"); + errors.push('Image size should not exceed 50KB'); result = false; } - const imageType = picParts[0].split("/")[1]; - if (imageType !== "jpeg;" && imageType !== "png;") { - errors.push("Image type shoud be either jpeg or png."); + const imageType = picParts[0].split('/')[1]; + if (imageType !== 'jpeg;' && imageType !== 'png;') { + errors.push('Image type shoud be either jpeg or png.'); result = false; } @@ -80,13 +77,12 @@ const userHelper = function () { lastName, infringement, totalInfringements, - timeRemaining + timeRemaining, ) { - let final_paragraph = ""; + let final_paragraph = ''; if (timeRemaining == undefined) { - final_paragraph = - "

Life happens and we understand that. That’s why we allow 5 of them before taking action. This action usually includes removal from our team though, so please let your direct supervisor know what happened and do your best to avoid future blue squares if you are getting close to 5 and wish to avoid termination. Each blue square drops off after a year.

"; + final_paragraph = '

Life happens and we understand that. That’s why we allow 5 of them before taking action. This action usually includes removal from our team though, so please let your direct supervisor know what happened and do your best to avoid future blue squares if you are getting close to 5 and wish to avoid termination. Each blue square drops off after a year.

'; } else { final_paragraph = `

Life happens and we understand that. Please make up the missed hours this following week though to avoid getting another blue square. So you know what’s needed, the missing/incomplete hours (${timeRemaining} hours) have been added to your current week and this new weekly total can be seen at the top of your dashboard.

Reminder also that each blue square is removed from your profile 1 year after it was issued.

`; @@ -117,10 +113,10 @@ const userHelper = function () { * @return {void} */ const emailWeeklySummariesForAllUsers = async (weekIndex = 1) => { - const currentFormattedDate = moment().tz("America/Los_Angeles").format(); + const currentFormattedDate = moment().tz('America/Los_Angeles').format(); logger.logInfo( - `Job for emailing all users' weekly summaries starting at ${currentFormattedDate}` + `Job for emailing all users' weekly summaries starting at ${currentFormattedDate}`, ); const emails = []; @@ -128,19 +124,15 @@ const userHelper = function () { try { const results = await reportHelper.weeklySummaries(weekIndex, weekIndex); - let emailBody = "

Weekly Summaries for all active users:

"; + let emailBody = '

Weekly Summaries for all active users:

'; - const weeklySummaryNotProvidedMessage = - '
Weekly Summary: Not provided!
'; + const weeklySummaryNotProvidedMessage = '
Weekly Summary: Not provided!
'; - const weeklySummaryNotRequiredMessage = - '
Weekly Summary: Not required for this user
'; + const weeklySummaryNotRequiredMessage = '
Weekly Summary: Not required for this user
'; - results.sort((a, b) => - `${a.firstName} ${a.lastName}`.localeCompare( - `${b.firstName} ${b.lastname}` - ) - ); + results.sort((a, b) => `${a.firstName} ${a.lastName}`.localeCompare( + `${b.firstName} ${b.lastname}`, + )); for (let i = 0; i < results.length; i += 1) { const result = results[i]; @@ -166,19 +158,19 @@ const userHelper = function () { const mediaUrlLink = mediaUrl ? `${mediaUrl}` - : "Not provided!"; + : 'Not provided!'; let weeklySummaryMessage = weeklySummaryNotProvidedMessage; const colorStyle = (() => { switch (weeklySummaryOption) { - case "Team": + case 'Team': return 'style="color: magenta;"'; - case "Not Required": + case 'Not Required': return 'style="color: green"'; - case "Required": - return ""; + case 'Required': + return ''; default: - return result.weeklySummaryNotReq ? 'style="color: green"' : ""; + return result.weeklySummaryNotReq ? 'style="color: green"' : ''; } })(); // weeklySummaries array should only have one item if any, hence weeklySummaries[0] needs be used to access it. @@ -189,16 +181,16 @@ const userHelper = function () {
Weekly Summary (for the week ending on ${moment(dueDate) - .tz("America/Los_Angeles") - .format("YYYY-MMM-DD")}): + .tz('America/Los_Angeles') + .format('YYYY-MMM-DD')}):
${summary}
`; } else if ( - weeklySummaryOption === "Not Required" || - (!weeklySummaryOption && result.weeklySummaryNotReq) + weeklySummaryOption === 'Not Required' + || (!weeklySummaryOption && result.weeklySummaryNotReq) ) { weeklySummaryMessage = weeklySummaryNotRequiredMessage; } @@ -219,16 +211,16 @@ const userHelper = function () { weeklySummariesCount === 8 ? `

Total Valid Weekly Summaries: ${weeklySummariesCount}

` : `

Total Valid Weekly Summaries: ${ - weeklySummariesCount || "No valid submissions yet!" + weeklySummariesCount || 'No valid submissions yet!' }

` } ${ hoursLogged >= weeklycommittedHours ? `

Hours logged: ${hoursLogged.toFixed( - 2 + 2, )} / ${weeklycommittedHours}

` : `

Hours logged: ${hoursLogged.toFixed( - 2 + 2, )} / ${weeklycommittedHours}

` } ${weeklySummaryMessage} @@ -238,10 +230,8 @@ const userHelper = function () { // Necessary because our version of node is outdated // and doesn't have String.prototype.replaceAll let emailString = [...new Set(emails)].toString(); - while (emailString.includes(",")) - emailString = emailString.replace(",", "\n"); - while (emailString.includes("\n")) - emailString = emailString.replace("\n", ", "); + while (emailString.includes(',')) { emailString = emailString.replace(',', '\n'); } + while (emailString.includes('\n')) { emailString = emailString.replace('\n', ', '); } emailBody += `\n
@@ -253,12 +243,12 @@ const userHelper = function () { `; emailSender( - "onecommunityglobal@gmail.com, sangam.pravah@gmail.com, onecommunityhospitality@gmail.com", - "Weekly Summaries for all active users...", + 'onecommunityglobal@gmail.com, sangam.pravah@gmail.com, onecommunityhospitality@gmail.com', + 'Weekly Summaries for all active users...', emailBody, null, null, - emailString + emailString, ); } catch (err) { logger.logException(err); @@ -279,8 +269,8 @@ const userHelper = function () { weeklySummaries: { $each: [ { - dueDate: moment().tz("America/Los_Angeles").endOf("week"), - summary: "", + dueDate: moment().tz('America/Los_Angeles').endOf('week'), + summary: '', }, ], $position: 0, @@ -288,7 +278,7 @@ const userHelper = function () { }, }, }) - .catch((error) => logger.logException(error)); + .catch(error => logger.logException(error)); }; /** @@ -299,34 +289,34 @@ const userHelper = function () { */ const assignBlueSquareForTimeNotMet = async () => { try { - const currentFormattedDate = moment().tz("America/Los_Angeles").format(); + const currentFormattedDate = moment().tz('America/Los_Angeles').format(); const currentUTCDate = moment - .tz("America/Los_Angeles") - .startOf("day") + .tz('America/Los_Angeles') + .startOf('day') .toISOString(); logger.logInfo( - `Job for assigning blue square for commitment not met starting at ${currentFormattedDate}` + `Job for assigning blue square for commitment not met starting at ${currentFormattedDate}`, ); const pdtStartOfLastWeek = moment() - .tz("America/Los_Angeles") - .startOf("week") - .subtract(1, "week"); + .tz('America/Los_Angeles') + .startOf('week') + .subtract(1, 'week'); const pdtEndOfLastWeek = moment() - .tz("America/Los_Angeles") - .endOf("week") - .subtract(1, "week"); + .tz('America/Los_Angeles') + .endOf('week') + .subtract(1, 'week'); const users = await userProfile.find( { isActive: true }, - "_id weeklycommittedHours weeklySummaries missedHours" + '_id weeklycommittedHours weeklySummaries missedHours', ); - //this part is supposed to be a for, so it'll be slower when sending emails, so the emails will not be - //targeted as spam - //There's no need to put Promise.all here + // this part is supposed to be a for, so it'll be slower when sending emails, so the emails will not be + // targeted as spam + // There's no need to put Promise.all here for (let i = 0; i < users.length; i += 1) { const user = users[i]; @@ -342,8 +332,8 @@ const userHelper = function () { let hasWeeklySummary = false; if ( - Array.isArray(user.weeklySummaries) && - user.weeklySummaries.length + Array.isArray(user.weeklySummaries) + && user.weeklySummaries.length ) { const { summary } = user.weeklySummaries[0]; if (summary) { @@ -357,13 +347,12 @@ const userHelper = function () { const results = await dashboardHelper.laborthisweek( personId, pdtStartOfLastWeek, - pdtEndOfLastWeek + pdtEndOfLastWeek, ); const { timeSpent_hrs: timeSpent } = results[0]; - const weeklycommittedHours = - user.weeklycommittedHours + (user.missedHours ?? 0); + const weeklycommittedHours = user.weeklycommittedHours + (user.missedHours ?? 0); const timeNotMet = timeSpent < weeklycommittedHours; let description; @@ -386,23 +375,23 @@ const userHelper = function () { lastWeekTangibleHrs: timeSpent || 0, }, }, - { new: true } + { new: true }, ); if ( - updateResult?.weeklySummaryOption === "Not Required" || - updateResult?.weeklySummaryNotReq + updateResult?.weeklySummaryOption === 'Not Required' + || updateResult?.weeklySummaryNotReq ) { hasWeeklySummary = true; } - const cutOffDate = moment().subtract(1, "year"); + const cutOffDate = moment().subtract(1, 'year'); const oldInfringements = []; for (let k = 0; k < updateResult?.infringements.length; k += 1) { if ( - updateResult?.infringements && - moment(updateResult?.infringements[k].date).diff(cutOffDate) >= 0 + updateResult?.infringements + && moment(updateResult?.infringements[k].date).diff(cutOffDate) >= 0 ) { oldInfringements.push(updateResult.infringements[k]); } else { @@ -418,35 +407,33 @@ const userHelper = function () { oldInfringements: { $each: oldInfringements, $slice: -10 }, }, }, - { new: true } + { new: true }, ); } if (timeNotMet || !hasWeeklySummary) { if (foundReason) { description = foundReason.reason; - } else { - if (timeNotMet && !hasWeeklySummary) { + } else if (timeNotMet && !hasWeeklySummary) { description = `System auto-assigned infringement for two reasons: not meeting weekly volunteer time commitment as well as not submitting a weekly summary. For the hours portion, you logged ${timeSpent.toFixed( - 2 + 2, )} hours against committed effort of ${weeklycommittedHours} hours in the week starting ${pdtStartOfLastWeek.format( - "dddd YYYY-MM-DD" - )} and ending ${pdtEndOfLastWeek.format("dddd YYYY-MM-DD")}.`; + 'dddd YYYY-MM-DD', + )} and ending ${pdtEndOfLastWeek.format('dddd YYYY-MM-DD')}.`; } else if (timeNotMet) { description = `System auto-assigned infringement for not meeting weekly volunteer time commitment. You logged ${timeSpent.toFixed( - 2 + 2, )} hours against committed effort of ${weeklycommittedHours} hours in the week starting ${pdtStartOfLastWeek.format( - "dddd YYYY-MM-DD" - )} and ending ${pdtEndOfLastWeek.format("dddd YYYY-MM-DD")}.`; + 'dddd YYYY-MM-DD', + )} and ending ${pdtEndOfLastWeek.format('dddd YYYY-MM-DD')}.`; } else { description = `System auto-assigned infringement for not submitting a weekly summary for the week starting ${pdtStartOfLastWeek.format( - "dddd YYYY-MM-DD" - )} and ending ${pdtEndOfLastWeek.format("dddd YYYY-MM-DD")}.`; + 'dddd YYYY-MM-DD', + )} and ending ${pdtEndOfLastWeek.format('dddd YYYY-MM-DD')}.`; } - } const infringement = { - date: moment().utc().format("YYYY-MM-DD"), + date: moment().utc().format('YYYY-MM-DD'), description, }; @@ -457,47 +444,47 @@ const userHelper = function () { infringements: infringement, }, }, - { new: true } + { new: true }, ); - let emailBody = ""; - if (person.role == "Core Team" && timeRemaining > 0) { + let emailBody = ''; + if (person.role === 'Core Team' && timeRemaining > 0) { emailBody = getInfringementEmailBody( status.firstName, status.lastName, infringement, status.infringements.length, - timeRemaining + timeRemaining, ); } else { emailBody = getInfringementEmailBody( status.firstName, status.lastName, infringement, - status.infringements.length + status.infringements.length, ); } emailSender( status.email, - "New Infringement Assigned", + 'New Infringement Assigned', emailBody, null, - "onecommunityglobal@gmail.com", + 'onecommunityglobal@gmail.com', status.email, - null + null, ); const categories = await dashboardHelper.laborThisWeekByCategory( personId, pdtStartOfLastWeek, - pdtEndOfLastWeek + pdtEndOfLastWeek, ); if (Array.isArray(categories) && categories.length > 0) { await userProfile.findOneAndUpdate( { _id: personId, categoryTangibleHrs: { $exists: false } }, - { $set: { categoryTangibleHrs: [] } } + { $set: { categoryTangibleHrs: [] } }, ); } else { continue; @@ -507,20 +494,20 @@ const userHelper = function () { const elem = categories[j]; if (elem._id == null) { - elem._id = "Other"; + elem._id = 'Other'; } const updateResult2 = await userProfile.findOneAndUpdate( - { _id: personId, "categoryTangibleHrs.category": elem._id }, - { $inc: { "categoryTangibleHrs.$.hrs": elem.timeSpent_hrs } }, - { new: true } + { _id: personId, 'categoryTangibleHrs.category': elem._id }, + { $inc: { 'categoryTangibleHrs.$.hrs': elem.timeSpent_hrs } }, + { new: true }, ); if (!updateResult2) { await userProfile.findOneAndUpdate( { _id: personId, - "categoryTangibleHrs.category": { $ne: elem._id }, + 'categoryTangibleHrs.category': { $ne: elem._id }, }, { $addToSet: { @@ -529,7 +516,7 @@ const userHelper = function () { hrs: elem.timeSpent_hrs, }, }, - } + }, ); } } @@ -541,13 +528,13 @@ const userHelper = function () { // processWeeklySummaries for nonActive users try { - const inactiveUsers = await userProfile.find({ isActive: false }, "_id"); + const inactiveUsers = await userProfile.find({ isActive: false }, '_id'); for (let i = 0; i < inactiveUsers.length; i += 1) { const user = inactiveUsers[i]; await processWeeklySummariesByUserId( mongoose.Types.ObjectId(user._id), - false + false, ); } } catch (err) { @@ -557,28 +544,28 @@ const userHelper = function () { const applyMissedHourForCoreTeam = async () => { try { - const currentDate = moment().tz("America/Los_Angeles").format(); + const currentDate = moment().tz('America/Los_Angeles').format(); logger.logInfo( - `Job for applying missed hours for Core Team members starting at ${currentDate}` + `Job for applying missed hours for Core Team members starting at ${currentDate}`, ); const startOfLastWeek = moment() - .tz("America/Los_Angeles") - .startOf("week") - .subtract(1, "week") - .format("YYYY-MM-DD"); + .tz('America/Los_Angeles') + .startOf('week') + .subtract(1, 'week') + .format('YYYY-MM-DD'); const endOfLastWeek = moment() - .tz("America/Los_Angeles") - .endOf("week") - .subtract(1, "week") - .format("YYYY-MM-DD"); + .tz('America/Los_Angeles') + .endOf('week') + .subtract(1, 'week') + .format('YYYY-MM-DD'); const missedHours = await userProfile.aggregate([ { $match: { - role: "Core Team", + role: 'Core Team', isActive: true, }, }, @@ -592,16 +579,15 @@ const userHelper = function () { $match: { $expr: { $and: [ - { $eq: ["$isTangible", true] }, - { $gte: ["$dateOfWork", startOfLastWeek] }, - { $lte: ["$dateOfWork", endOfLastWeek] }, - { $in: ["$entryType", 'default', null] }, + { $eq: ['$isTangible', true] }, + { $gte: ['$dateOfWork', startOfLastWeek] }, + { $lte: ['$dateOfWork', endOfLastWeek] }, ], }, }, }, ], - as: "timeEntries", + as: 'timeEntries', }, }, { @@ -613,8 +599,8 @@ const userHelper = function () { $subtract: [ { $sum: [ - { $ifNull: ["$missedHours", 0] }, - "$weeklycommittedHours", + { $ifNull: ['$missedHours', 0] }, + '$weeklycommittedHours', ], }, { @@ -622,8 +608,8 @@ const userHelper = function () { { $sum: { $map: { - input: "$timeEntries", - in: "$$this.totalSeconds", + input: '$timeEntries', + in: '$$this.totalSeconds', }, }, }, @@ -657,13 +643,13 @@ const userHelper = function () { }; const deleteBlueSquareAfterYear = async () => { - const currentFormattedDate = moment().tz("America/Los_Angeles").format(); + const currentFormattedDate = moment().tz('America/Los_Angeles').format(); logger.logInfo( - `Job for deleting blue squares older than 1 year starting at ${currentFormattedDate}` + `Job for deleting blue squares older than 1 year starting at ${currentFormattedDate}`, ); - const cutOffDate = moment().subtract(1, "year").format("YYYY-MM-DD"); + const cutOffDate = moment().subtract(1, 'year').format('YYYY-MM-DD'); try { const results = await userProfile.updateMany( @@ -676,7 +662,7 @@ const userHelper = function () { }, }, }, - } + }, ); logger.logInfo(results); @@ -686,16 +672,16 @@ const userHelper = function () { }; const reActivateUser = async () => { - const currentFormattedDate = moment().tz("America/Los_Angeles").format(); + const currentFormattedDate = moment().tz('America/Los_Angeles').format(); logger.logInfo( - `Job for activating users based on scheduled re-activation date starting at ${currentFormattedDate}` + `Job for activating users based on scheduled re-activation date starting at ${currentFormattedDate}`, ); try { const users = await userProfile.find( { isActive: false, reactivationDate: { $exists: true } }, - "_id isActive reactivationDate" + '_id isActive reactivationDate', ); for (let i = 0; i < users.length; i += 1) { const user = users[i]; @@ -710,21 +696,21 @@ const userHelper = function () { endDate: user.endDate, }, }, - { new: true } + { new: true }, ); logger.logInfo( `User with id: ${user._id} was re-acticated at ${moment() - .tz("America/Los_Angeles") - .format()}.` + .tz('America/Los_Angeles') + .format()}.`, ); const id = user._id; const person = await userProfile.findById(id); - const endDate = moment(person.endDate).format("YYYY-MM-DD"); + const endDate = moment(person.endDate).format('YYYY-MM-DD'); logger.logInfo( `User with id: ${ user._id - } was re-acticated at ${moment().format()}.` + } was re-acticated at ${moment().format()}.`, ); const subject = `IMPORTANT:${person.firstName} ${person.lastName} has been RE-activated in the Highest Good Network`; @@ -740,12 +726,12 @@ const userHelper = function () {

The HGN A.I. (and One Community)

`; emailSender( - "onecommunityglobal@gmail.com", + 'onecommunityglobal@gmail.com', subject, emailBody, null, null, - person.email + person.email, ); } } @@ -759,7 +745,7 @@ const userHelper = function () { current, firstName, lastName, - emailAddress + emailAddress, ) { if (!current) return; const newOriginal = original.toObject(); @@ -770,58 +756,58 @@ const userHelper = function () { newInfringements = _.differenceWith( newCurrent, newOriginal, - (arrVal, othVal) => arrVal._id.equals(othVal._id) + (arrVal, othVal) => arrVal._id.equals(othVal._id), ); newInfringements.forEach((element) => { emailSender( emailAddress, - "New Infringement Assigned", + 'New Infringement Assigned', getInfringementEmailBody( firstName, lastName, element, - totalInfringements + totalInfringements, ), null, - "onecommunityglobal@gmail.com", - emailAddress + 'onecommunityglobal@gmail.com', + emailAddress, ); }); }; const replaceBadge = async function (personId, oldBadgeId, newBadgeId) { userProfile.updateOne( - { _id: personId, "badgeCollection.badge": oldBadgeId }, + { _id: personId, 'badgeCollection.badge': oldBadgeId }, { $set: { - "badgeCollection.$.badge": newBadgeId, - "badgeCollection.$.lastModified": Date.now().toString(), - "badgeCollection.$.count": 1, + 'badgeCollection.$.badge': newBadgeId, + 'badgeCollection.$.lastModified': Date.now().toString(), + 'badgeCollection.$.count': 1, + 'badgeCollection.$.earnedDate': [earnedDateBadge()], }, }, (err) => { if (err) { throw new Error(err); } - } + }, ); }; const increaseBadgeCount = async function (personId, badgeId) { - console.log("Increase Badge Count", personId, badgeId); userProfile.updateOne( - { _id: personId, "badgeCollection.badge": badgeId }, + { _id: personId, 'badgeCollection.badge': badgeId }, { - $inc: { "badgeCollection.$.count": 1 }, - $set: { "badgeCollection.$.lastModified": Date.now().toString() }, - $push: { "badgeCollection.$.earnedDate": earnedDateBadge() }, + $inc: { 'badgeCollection.$.count': 1 }, + $set: { 'badgeCollection.$.lastModified': Date.now().toString() }, + $push: { 'badgeCollection.$.earnedDate': earnedDateBadge() }, }, (err) => { if (err) { console.log(err); } - } + }, ); }; @@ -829,9 +815,8 @@ const userHelper = function () { personId, badgeId, count = 1, - featured = false + featured = false, ) { - console.log("Adding Badge"); userProfile.findByIdAndUpdate( personId, { @@ -849,7 +834,7 @@ const userHelper = function () { if (err) { throw new Error(err); } - } + }, ); }; @@ -865,27 +850,49 @@ const userHelper = function () { if (err) { throw new Error(err); } - } + }, ); }; - const changeBadgeCount = async function (personId, badgeId, count) { +const changeBadgeCount = async function (personId, badgeId, count) { if (count === 0) { removeDupBadge(personId, badgeId); } else if (count) { + // Process exisiting earned date to match the new count + const userInfo = await userProfile.findById(personId); + let newEarnedDate = []; + const recordToUpdate = userInfo.badgeCollection.find(item => item.badge._id.toString() === badgeId.toString()); + if (!recordToUpdate) { + throw new Error('Badge not found'); + } + const copyOfEarnedDate = recordToUpdate.earnedDate; + if (copyOfEarnedDate.length < count) { + // if the EarnedDate count is less than the new count, add a earned date to the end of the collection + while (copyOfEarnedDate.length < count) { + copyOfEarnedDate.push(earnedDateBadge()); + } + } else { + // if the EarnedDate count is greater than the new count, remove the oldest earned date of the collection until it matches the new count - 1 + while (copyOfEarnedDate.length >= count) { + copyOfEarnedDate.shift(); + } + copyOfEarnedDate.push(earnedDateBadge()); + } + newEarnedDate = [...copyOfEarnedDate]; userProfile.updateOne( - { _id: personId, "badgeCollection.badge": badgeId }, + { _id: personId, 'badgeCollection.badge': badgeId }, { $set: { - "badgeCollection.$.count": count, - "badgeCollection.$.lastModified": Date.now().toString(), + 'badgeCollection.$.count': count, + 'badgeCollection.$.lastModified': Date.now().toString(), + 'badgeCollection.$.earnedDate': newEarnedDate, }, }, (err) => { if (err) { throw new Error(err); } - } + }, ); } }; @@ -897,7 +904,7 @@ const userHelper = function () { user, badgeCollection, hrs, - weeks + weeks, ) { // Check each Streak Greater than One to check if it works if (weeks < 3) { @@ -908,7 +915,7 @@ const userHelper = function () { .aggregate([ { $match: { - type: "X Hours for X Week Streak", + type: 'X Hours for X Week Streak', weeks: { $gt: 1, $lt: weeks }, totalHrs: hrs, }, @@ -916,9 +923,9 @@ const userHelper = function () { { $sort: { weeks: -1, totalHrs: -1 } }, { $group: { - _id: "$weeks", + _id: '$weeks', badges: { - $push: { _id: "$_id", hrs: "$totalHrs", weeks: "$weeks" }, + $push: { _id: '$_id', hrs: '$totalHrs', weeks: '$weeks' }, }, }, }, @@ -928,16 +935,16 @@ const userHelper = function () { streak.badges.every((bdge) => { for (let i = 0; i < badgeCollection.length; i += 1) { if ( - badgeCollection[i].badge?.type === - "X Hours for X Week Streak" && - badgeCollection[i].badge?.weeks === bdge.weeks && - bdge.hrs === hrs && - !removed + badgeCollection[i].badge?.type + === 'X Hours for X Week Streak' + && badgeCollection[i].badge?.weeks === bdge.weeks + && bdge.hrs === hrs + && !removed ) { changeBadgeCount( personId, badgeCollection[i].badge._id, - badgeCollection[i].badge.count - 1 + badgeCollection[i].badge.count - 1, ); removed = true; return false; @@ -950,24 +957,23 @@ const userHelper = function () { }; // 'No Infringement Streak', - const checkNoInfringementStreak = async function ( personId, user, - badgeCollection + badgeCollection, ) { let badgeOfType; for (let i = 0; i < badgeCollection.length; i += 1) { - if (badgeCollection[i].badge?.type === "No Infringement Streak") { + if (badgeCollection[i].badge?.type === 'No Infringement Streak') { if ( - badgeOfType && - badgeOfType.months <= badgeCollection[i].badge.months + badgeOfType + && badgeOfType.months <= badgeCollection[i].badge.months ) { removeDupBadge(personId, badgeOfType._id); badgeOfType = badgeCollection[i].badge; } else if ( - badgeOfType && - badgeOfType.months > badgeCollection[i].badge.months + badgeOfType + && badgeOfType.months > badgeCollection[i].badge.months ) { removeDupBadge(personId, badgeCollection[i].badge._id); } else if (!badgeOfType) { @@ -976,7 +982,7 @@ const userHelper = function () { } } await badge - .find({ type: "No Infringement Streak" }) + .find({ type: 'No Infringement Streak' }) .sort({ months: -1 }) .then((results) => { if (!Array.isArray(results) || !results.length) { @@ -988,19 +994,19 @@ const userHelper = function () { if (elem.months <= 12) { if ( - moment().diff(moment(user.createdDate), "months", true) >= - elem.months + moment().diff(moment(user.createdDate), 'months', true) + >= elem.months ) { if ( - user.infringements.length === 0 || - Math.abs( + user.infringements.length === 0 + || Math.abs( moment().diff( moment( - user.infringements[user.infringements?.length - 1].date + user.infringements[user.infringements?.length - 1].date, ), - "months", - true - ) + 'months', + true, + ), ) >= elem.months ) { if (badgeOfType) { @@ -1008,7 +1014,7 @@ const userHelper = function () { replaceBadge( personId, mongoose.Types.ObjectId(badgeOfType._id), - mongoose.Types.ObjectId(elem._id) + mongoose.Types.ObjectId(elem._id), ); } return false; @@ -1019,29 +1025,29 @@ const userHelper = function () { } } else if (user?.infringements?.length === 0) { if ( - moment().diff(moment(user.createdDate), "months", true) >= - elem.months + moment().diff(moment(user.createdDate), 'months', true) + >= elem.months ) { if ( - user.oldInfringements.length === 0 || - Math.abs( + user.oldInfringements.length === 0 + || Math.abs( moment().diff( moment( user.oldInfringements[user.oldInfringements?.length - 1] - .date + .date, ), - "months", - true - ) - ) >= - elem.months - 12 + 'months', + true, + ), + ) + >= elem.months - 12 ) { if (badgeOfType) { if (badgeOfType._id.toString() !== elem._id.toString()) { replaceBadge( personId, mongoose.Types.ObjectId(badgeOfType._id), - mongoose.Types.ObjectId(elem._id) + mongoose.Types.ObjectId(elem._id), ); } return false; @@ -1060,13 +1066,13 @@ const userHelper = function () { const checkMinHoursMultiple = async function ( personId, user, - badgeCollection + badgeCollection, ) { const badgesOfType = badgeCollection - .map((obj) => obj.badge) - .filter((badge) => badge.type === "Minimum Hours Multiple"); + .map(obj => obj.badge) + .filter(badgeItem => badgeItem.type === 'Minimum Hours Multiple'); await badge - .find({ type: "Minimum Hours Multiple" }) + .find({ type: 'Minimum Hours Multiple' }) .sort({ multiple: -1 }) .then((results) => { if (!Array.isArray(results) || !results.length) { @@ -1077,16 +1083,16 @@ const userHelper = function () { const elem = results[i]; // making variable elem accessible for below code if ( - user.lastWeekTangibleHrs / user.weeklycommittedHours >= - elem.multiple + user.lastWeekTangibleHrs / user.weeklycommittedHours + >= elem.multiple ) { const theBadge = badgesOfType.find( - (badge) => badge._id.toString() === elem._id.toString() + badgeItem => badgeItem._id.toString() === elem._id.toString(), ); return theBadge ? increaseBadgeCount( personId, - mongoose.Types.ObjectId(theBadge._id) + mongoose.Types.ObjectId(theBadge._id), ) : addBadge(personId, mongoose.Types.ObjectId(elem._id)); } @@ -1098,29 +1104,29 @@ const userHelper = function () { const checkPersonalMax = async function (personId, user, badgeCollection) { let badgeOfType; for (let i = 0; i < badgeCollection.length; i += 1) { - if (badgeCollection[i].badge?.type === "Personal Max") { + if (badgeCollection[i].badge?.type === 'Personal Max') { if (badgeOfType) { removeDupBadge(personId, badgeOfType._id); } } } - await badge.findOne({ type: "Personal Max" }).then((results) => { + await badge.findOne({ type: 'Personal Max' }).then((results) => { if ( - user.lastWeekTangibleHrs && - user.lastWeekTangibleHrs >= 1 && - user.lastWeekTangibleHrs === user.personalBestMaxHrs + user.lastWeekTangibleHrs + && user.lastWeekTangibleHrs >= 1 + && user.lastWeekTangibleHrs === user.personalBestMaxHrs ) { if (badgeOfType) { changeBadgeCount( personId, mongoose.Types.ObjectId(badgeOfType._id), - user.personalBestMaxHrs + user.personalBestMaxHrs, ); } else { addBadge( personId, mongoose.Types.ObjectId(results._id), - user.personalBestMaxHrs + user.personalBestMaxHrs, ); } } @@ -1131,17 +1137,17 @@ const userHelper = function () { const checkMostHrsWeek = async function (personId, user, badgeCollection) { if ( - user.weeklycommittedHours > 0 && - user.lastWeekTangibleHrs > user.weeklycommittedHours + user.weeklycommittedHours > 0 + && user.lastWeekTangibleHrs > user.weeklycommittedHours ) { const badgeOfType = badgeCollection - .filter((object) => object.badge.type === "Most Hrs in Week") - .map((object) => object.badge); - await badge.findOne({ type: "Most Hrs in Week" }).then((results) => { + .filter(object => object.badge.type === 'Most Hrs in Week') + .map(object => object.badge); + await badge.findOne({ type: 'Most Hrs in Week' }).then((results) => { userProfile .aggregate([ { $match: { isActive: true } }, - { $group: { _id: 1, maxHours: { $max: "$lastWeekTangibleHrs" } } }, + { $group: { _id: 1, maxHours: { $max: '$lastWeekTangibleHrs' } } }, ]) .then((userResults) => { if (badgeOfType.length > 1) { @@ -1149,13 +1155,13 @@ const userHelper = function () { } if ( - user.lastWeekTangibleHrs && - user.lastWeekTangibleHrs >= userResults[0].maxHours + user.lastWeekTangibleHrs + && user.lastWeekTangibleHrs >= userResults[0].maxHours ) { if (badgeOfType.length) { increaseBadgeCount( personId, - mongoose.Types.ObjectId(badgeOfType[0]._id) + mongoose.Types.ObjectId(badgeOfType[0]._id), ); } else { addBadge(personId, mongoose.Types.ObjectId(results._id)); @@ -1171,12 +1177,12 @@ const userHelper = function () { // Handle Increasing the 1 week streak badges const badgesOfType = []; for (let i = 0; i < badgeCollection.length; i += 1) { - if (badgeCollection[i].badge?.type === "X Hours for X Week Streak") { + if (badgeCollection[i].badge?.type === 'X Hours for X Week Streak') { badgesOfType.push(badgeCollection[i].badge); } } await badge - .find({ type: "X Hours for X Week Streak", weeks: 1 }) + .find({ type: 'X Hours for X Week Streak', weeks: 1 }) .sort({ totalHrs: -1 }) .then((results) => { results.every((elem) => { @@ -1201,13 +1207,13 @@ const userHelper = function () { // Check each Streak Greater than One to check if it works await badge .aggregate([ - { $match: { type: "X Hours for X Week Streak", weeks: { $gt: 1 } } }, + { $match: { type: 'X Hours for X Week Streak', weeks: { $gt: 1 } } }, { $sort: { weeks: -1, totalHrs: -1 } }, { $group: { - _id: "$weeks", + _id: '$weeks', badges: { - $push: { _id: "$_id", hrs: "$totalHrs", weeks: "$weeks" }, + $push: { _id: '$_id', hrs: '$totalHrs', weeks: '$weeks' }, }, }, }, @@ -1219,19 +1225,19 @@ const userHelper = function () { let badgeOfType; for (let i = 0; i < badgeCollection.length; i += 1) { if ( - badgeCollection[i].badge?.type === - "X Hours for X Week Streak" && - badgeCollection[i].badge?.weeks === bdge.weeks + badgeCollection[i].badge?.type + === 'X Hours for X Week Streak' + && badgeCollection[i].badge?.weeks === bdge.weeks ) { if ( - badgeOfType && - badgeOfType.totalHrs <= badgeCollection[i].badge.totalHrs + badgeOfType + && badgeOfType.totalHrs <= badgeCollection[i].badge.totalHrs ) { removeDupBadge(personId, badgeOfType._id); badgeOfType = badgeCollection[i].badge; } else if ( - badgeOfType && - badgeOfType.totalHrs > badgeCollection[i].badge.totalHrs + badgeOfType + && badgeOfType.totalHrs > badgeCollection[i].badge.totalHrs ) { removeDupBadge(personId, badgeCollection[i].badge._id); } else if (!badgeOfType) { @@ -1256,7 +1262,7 @@ const userHelper = function () { replaceBadge( personId, mongoose.Types.ObjectId(badgeOfType._id), - mongoose.Types.ObjectId(bdge._id) + mongoose.Types.ObjectId(bdge._id), ); removePrevHrBadge( @@ -1264,7 +1270,7 @@ const userHelper = function () { user, badgeCollection, bdge.hrs, - bdge.weeks + bdge.weeks, ); } else if (!badgeOfType) { addBadge(personId, mongoose.Types.ObjectId(bdge._id)); @@ -1273,19 +1279,19 @@ const userHelper = function () { user, badgeCollection, bdge.hrs, - bdge.weeks + bdge.weeks, ); } else if (badgeOfType && badgeOfType.totalHrs === bdge.hrs) { increaseBadgeCount( personId, - mongoose.Types.ObjectId(badgeOfType._id) + mongoose.Types.ObjectId(badgeOfType._id), ); removePrevHrBadge( personId, user, badgeCollection, bdge.hrs, - bdge.weeks + bdge.weeks, ); } return false; @@ -1302,16 +1308,16 @@ const userHelper = function () { const checkLeadTeamOfXplus = async function ( personId, user, - badgeCollection + badgeCollection, ) { const leaderRoles = [ - "Mentor", - "Manager", - "Administrator", - "Owner", - "Core Team", + 'Mentor', + 'Manager', + 'Administrator', + 'Owner', + 'Core Team', ]; - const approvedRoles = ["Mentor", "Manager"]; + const approvedRoles = ['Mentor', 'Manager']; if (!approvedRoles.includes(user.role)) return; let teamMembers; @@ -1336,16 +1342,16 @@ const userHelper = function () { }); let badgeOfType; for (let i = 0; i < badgeCollection.length; i += 1) { - if (badgeCollection[i].badge?.type === "Lead a team of X+") { + if (badgeCollection[i].badge?.type === 'Lead a team of X+') { if ( - badgeOfType && - badgeOfType.people <= badgeCollection[i].badge.people + badgeOfType + && badgeOfType.people <= badgeCollection[i].badge.people ) { removeDupBadge(personId, badgeOfType._id); badgeOfType = badgeCollection[i].badge; } else if ( - badgeOfType && - badgeOfType.people > badgeCollection[i].badge.people + badgeOfType + && badgeOfType.people > badgeCollection[i].badge.people ) { removeDupBadge(personId, badgeCollection[i].badge._id); } else if (!badgeOfType) { @@ -1354,7 +1360,7 @@ const userHelper = function () { } } await badge - .find({ type: "Lead a team of X+" }) + .find({ type: 'Lead a team of X+' }) .sort({ people: -1 }) .then((results) => { if (!Array.isArray(results) || !results.length) { @@ -1364,14 +1370,14 @@ const userHelper = function () { if (teamMembers && teamMembers.length >= badge.people) { if (badgeOfType) { if ( - badgeOfType._id.toString() !== badge._id.toString() && - badgeOfType.people < badge.people + badgeOfType._id.toString() !== badge._id.toString() + && badgeOfType.people < badge.people ) { replaceBadge( personId, mongoose.Types.ObjectId(badgeOfType._id), - mongoose.Types.ObjectId(badge._id) + mongoose.Types.ObjectId(badge._id), ); } return false; @@ -1388,39 +1394,39 @@ const userHelper = function () { const checkTotalHrsInCat = async function (personId, user, badgeCollection) { const hoursByCategory = user.hoursByCategory || {}; const categories = [ - "food", - "energy", - "housing", - "education", - "society", - "economics", - "stewardship", + 'food', + 'energy', + 'housing', + 'education', + 'society', + 'economics', + 'stewardship', ]; const badgesOfType = badgeCollection - .filter((object) => object.badge.type === "Total Hrs in Category") - .map((object) => object.badge); + .filter(object => object.badge.type === 'Total Hrs in Category') + .map(object => object.badge); categories.forEach(async (category) => { const categoryHrs = Object.keys(hoursByCategory).find( - (elem) => elem === category + elem => elem === category, ); let badgeOfType; for (let i = 0; i < badgeCollection.length; i += 1) { if ( - badgeCollection[i].badge?.type === "Total Hrs in Category" && - badgeCollection[i].badge?.category === category + badgeCollection[i].badge?.type === 'Total Hrs in Category' + && badgeCollection[i].badge?.category === category ) { if ( - badgeOfType && - badgeOfType.totalHrs <= badgeCollection[i].badge.totalHrs + badgeOfType + && badgeOfType.totalHrs <= badgeCollection[i].badge.totalHrs ) { removeDupBadge(personId, badgeOfType._id); badgeOfType = badgeCollection[i].badge; } else if ( - badgeOfType && - badgeOfType.totalHrs > badgeCollection[i].badge.totalHrs + badgeOfType + && badgeOfType.totalHrs > badgeCollection[i].badge.totalHrs ) { removeDupBadge(personId, badgeCollection[i].badge._id); } else if (!badgeOfType) { @@ -1432,7 +1438,7 @@ const userHelper = function () { const newCatg = category.charAt(0).toUpperCase() + category.slice(1); await badge - .find({ type: "Total Hrs in Category", category: newCatg }) + .find({ type: 'Total Hrs in Category', category: newCatg }) .sort({ totalHrs: -1 }) .then((results) => { @@ -1442,8 +1448,8 @@ const userHelper = function () { results.every((elem) => { if ( - hoursByCategory[categoryHrs] >= 100 && - hoursByCategory[categoryHrs] >= elem.totalHrs + hoursByCategory[categoryHrs] >= 100 + && hoursByCategory[categoryHrs] >= elem.totalHrs ) { let theBadge; for (let i = 0; i < badgesOfType.length; i += 1) { @@ -1458,13 +1464,13 @@ const userHelper = function () { } if (badgeOfType) { if ( - badgeOfType._id.toString() !== elem._id.toString() && - badgeOfType.totalHrs < elem.totalHrs + badgeOfType._id.toString() !== elem._id.toString() + && badgeOfType.totalHrs < elem.totalHrs ) { replaceBadge( personId, mongoose.Types.ObjectId(badgeOfType._id), - mongoose.Types.ObjectId(elem._id) + mongoose.Types.ObjectId(elem._id), ); } return false; @@ -1479,11 +1485,11 @@ const userHelper = function () { }; const awardNewBadges = async () => { - console.log("Awarding"); + console.log('Awarding'); try { const users = await userProfile .find({ isActive: true }) - .populate("badgeCollection.badge"); + .populate('badgeCollection.badge'); for (let i = 0; i < users.length; i += 1) { const user = users[i]; @@ -1506,13 +1512,13 @@ const userHelper = function () { const userId = mongoose.Types.ObjectId(personId); const pdtstart = moment() - .tz("America/Los_Angeles") - .startOf("week") - .format("YYYY-MM-DD"); + .tz('America/Los_Angeles') + .startOf('week') + .format('YYYY-MM-DD'); const pdtend = moment() - .tz("America/Los_Angeles") - .endOf("week") - .format("YYYY-MM-DD"); + .tz('America/Los_Angeles') + .endOf('week') + .format('YYYY-MM-DD'); return timeEntries .find( @@ -1521,12 +1527,12 @@ const userHelper = function () { dateOfWork: { $gte: pdtstart, $lte: pdtend }, isTangible: true, }, - "totalSeconds" + 'totalSeconds', ) .then((results) => { const totalTangibleWeeklySeconds = results.reduce( (acc, { totalSeconds }) => acc + totalSeconds, - 0 + 0, ); return (totalTangibleWeeklySeconds / 3600).toFixed(2); }); @@ -1536,28 +1542,28 @@ const userHelper = function () { try { const users = await userProfile.find( { isActive: true, endDate: { $exists: true } }, - "_id isActive endDate" + '_id isActive endDate', ); for (let i = 0; i < users.length; i += 1) { const user = users[i]; const { endDate } = user; endDate.setHours(endDate.getHours() + 7); - if (moment().isAfter(moment(endDate).add(1, "days"))) { + if (moment().isAfter(moment(endDate).add(1, 'days'))) { await userProfile.findByIdAndUpdate( user._id, user.set({ isActive: false, }), - { new: true } + { new: true }, ); const id = user._id; const person = await userProfile.findById(id); - const lastDay = moment(person.endDate).format("YYYY-MM-DD"); + const lastDay = moment(person.endDate).format('YYYY-MM-DD'); logger.logInfo( `User with id: ${ user._id - } was de-acticated at ${moment().format()}.` + } was de-acticated at ${moment().format()}.`, ); const subject = `IMPORTANT:${person.firstName} ${person.lastName} has been deactivated in the Highest Good Network`; @@ -1573,12 +1579,12 @@ const userHelper = function () {

The HGN A.I. (and One Community)

`; emailSender( - "onecommunityglobal@gmail.com", + 'onecommunityglobal@gmail.com', subject, emailBody, null, null, - person.email + person.email, ); } } @@ -1598,6 +1604,7 @@ const userHelper = function () { }; return { + changeBadgeCount, getUserName, getTeamMembers, validateProfilePic, @@ -1615,4 +1622,4 @@ const userHelper = function () { }; }; -module.exports = userHelper; \ No newline at end of file +module.exports = userHelper; From a538fd14b032d998f0f33c1d0f5aaf116ddb38fe Mon Sep 17 00:00:00 2001 From: Shengwei Peng Date: Sat, 30 Dec 2023 12:41:56 -0500 Subject: [PATCH 235/272] fix bug in changeBadgeCount --- src/helpers/userHelper.js | 78 +++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 32 deletions(-) diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index 97beafc17..4026b1462 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -859,41 +859,45 @@ const changeBadgeCount = async function (personId, badgeId, count) { removeDupBadge(personId, badgeId); } else if (count) { // Process exisiting earned date to match the new count - const userInfo = await userProfile.findById(personId); - let newEarnedDate = []; - const recordToUpdate = userInfo.badgeCollection.find(item => item.badge._id.toString() === badgeId.toString()); - if (!recordToUpdate) { - throw new Error('Badge not found'); - } - const copyOfEarnedDate = recordToUpdate.earnedDate; - if (copyOfEarnedDate.length < count) { - // if the EarnedDate count is less than the new count, add a earned date to the end of the collection - while (copyOfEarnedDate.length < count) { - copyOfEarnedDate.push(earnedDateBadge()); + try { + const userInfo = await userProfile.findById(personId); + let newEarnedDate = []; + const recordToUpdate = userInfo.badgeCollection.find(item => item.badge._id.toString() === badgeId.toString()); + if (!recordToUpdate) { + throw new Error('Badge not found'); } - } else { - // if the EarnedDate count is greater than the new count, remove the oldest earned date of the collection until it matches the new count - 1 - while (copyOfEarnedDate.length >= count) { - copyOfEarnedDate.shift(); + const copyOfEarnedDate = recordToUpdate.earnedDate; + if (copyOfEarnedDate.length < count) { + // if the EarnedDate count is less than the new count, add a earned date to the end of the collection + while (copyOfEarnedDate.length < count) { + copyOfEarnedDate.push(earnedDateBadge()); + } + } else { + // if the EarnedDate count is greater than the new count, remove the oldest earned date of the collection until it matches the new count - 1 + while (copyOfEarnedDate.length >= count) { + copyOfEarnedDate.shift(); + } + copyOfEarnedDate.push(earnedDateBadge()); } - copyOfEarnedDate.push(earnedDateBadge()); - } - newEarnedDate = [...copyOfEarnedDate]; - userProfile.updateOne( - { _id: personId, 'badgeCollection.badge': badgeId }, - { - $set: { - 'badgeCollection.$.count': count, - 'badgeCollection.$.lastModified': Date.now().toString(), - 'badgeCollection.$.earnedDate': newEarnedDate, + newEarnedDate = [...copyOfEarnedDate]; + userProfile.updateOne( + { _id: personId, 'badgeCollection.badge': badgeId }, + { + $set: { + 'badgeCollection.$.count': count, + 'badgeCollection.$.lastModified': Date.now().toString(), + 'badgeCollection.$.earnedDate': newEarnedDate, + }, }, - }, - (err) => { - if (err) { - throw new Error(err); - } - }, - ); + (err) => { + if (err) { + throw new Error(err); + } + }, + ); + } catch (err) { + logger.logException(err); + } } }; @@ -1487,6 +1491,7 @@ const changeBadgeCount = async function (personId, badgeId, count) { const awardNewBadges = async () => { console.log('Awarding'); try { + // This will be used in production to run task on all users const users = await userProfile .find({ isActive: true }) .populate('badgeCollection.badge'); @@ -1503,6 +1508,15 @@ const changeBadgeCount = async function (personId, badgeId, count) { await checkXHrsForXWeeks(personId, user, badgeCollection); await checkNoInfringementStreak(personId, user, badgeCollection); } + + // Testing purpose only + // You can lookup your user id in view profile and get the id from the url + // const user = await userProfile + // .findOne({ _id: '65500b658e0b2922b80d5f9f' }) + // .populate('badgeCollection.badge'); + // for (let badgeItem of user.badgeCollection){ + // await changeBadgeCount('65500b658e0b2922b80d5f9f', badgeItem.badge._id, badgeItem.count + 1); + // } } catch (err) { logger.logException(err); } From af91cadfe4f95f412980e5a6d8302440cc727956 Mon Sep 17 00:00:00 2001 From: Shengwei Peng Date: Sat, 30 Dec 2023 12:42:58 -0500 Subject: [PATCH 236/272] Remove testing code --- src/helpers/userHelper.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index 4026b1462..dba1369f3 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -1508,15 +1508,6 @@ const changeBadgeCount = async function (personId, badgeId, count) { await checkXHrsForXWeeks(personId, user, badgeCollection); await checkNoInfringementStreak(personId, user, badgeCollection); } - - // Testing purpose only - // You can lookup your user id in view profile and get the id from the url - // const user = await userProfile - // .findOne({ _id: '65500b658e0b2922b80d5f9f' }) - // .populate('badgeCollection.badge'); - // for (let badgeItem of user.badgeCollection){ - // await changeBadgeCount('65500b658e0b2922b80d5f9f', badgeItem.badge._id, badgeItem.count + 1); - // } } catch (err) { logger.logException(err); } From 04cbd643091cae073f58477efde6a9a6d218e206 Mon Sep 17 00:00:00 2001 From: wang9hu Date: Sat, 30 Dec 2023 21:24:15 -0800 Subject: [PATCH 237/272] fix editTimeEntry --- src/controllers/timeEntryController.js | 43 ++++++++++++++------------ 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/controllers/timeEntryController.js b/src/controllers/timeEntryController.js index c8ef3d464..1cbab61c4 100644 --- a/src/controllers/timeEntryController.js +++ b/src/controllers/timeEntryController.js @@ -195,15 +195,15 @@ const timeEntrycontroller = function (TimeEntry) { const isGeneralEntry = isGeneralTimeEntry(type); try { - if (!req.params.timeEntryId) { + if (!timeEntryId) { const error = 'ObjectId in request param is not in correct format'; return res.status(400).send({ error }); } if ( - !mongoose.Types.ObjectId.isValid(req.params.timeEntryId) + !mongoose.Types.ObjectId.isValid(timeEntryId) || ((isGeneralEntry || type === 'project') - && !mongoose.Types.ObjectId.isValid(req.body.projectId) + && !mongoose.Types.ObjectId.isValid(newProjectId) )) { const error = 'ObjectIds are not correctly formed'; return res.status(400).send({ error }); @@ -228,30 +228,35 @@ const timeEntrycontroller = function (TimeEntry) { } // update task data if project/task is changed - if (newTaskId === timeEntry.taskId) { + if (newTaskId === timeEntry.taskId && newProjectId === timeEntry.projectId) { + // when project/task is the same const timeEntryTask = await Task.findById(newTaskId); - const timeEntryUser = await UserProfile.findById(personId); - if (timeEntry.isTangible) { - timeEntryTask.hoursLogged -= timeEntry.totalSeconds / 3600; - } - if (newIsTangible) { - timeEntryTask.hoursLogged += newTotalSeconds / 3600; + if (timeEntryTask) { + const timeEntryUser = await UserProfile.findById(personId); + if (timeEntry.isTangible) { + timeEntryTask.hoursLogged -= timeEntry.totalSeconds / 3600; + } + if (newIsTangible) { + timeEntryTask.hoursLogged += newTotalSeconds / 3600; + } + checkTaskOvertime(timeEntry, timeEntryUser, timeEntryTask); + await timeEntryTask.save(); } - checkTaskOvertime(timeEntry, timeEntryUser, timeEntryTask); - await timeEntryTask.save(); } else { + // update oldtTimeEntryTask const oldTimeEntryTask = await Task.findById(timeEntry.taskId); - const newTimeEntryTask = await Task.findById(newTaskId); - const timeEntryUser = await UserProfile.findById(personId); - if (timeEntry.isTangible) { + if (oldTimeEntryTask && timeEntry.isTangible) { oldTimeEntryTask.hoursLogged -= timeEntry.totalSeconds / 3600; + oldTimeEntryTask.save(); } - if (newIsTangible) { + // update newtTimeEntryTask + const newTimeEntryTask = await Task.findById(newTaskId); + if (newTimeEntryTask && newIsTangible) { + const timeEntryUser = await UserProfile.findById(personId); newTimeEntryTask.hoursLogged += newTotalSeconds / 3600; + checkTaskOvertime(timeEntry, timeEntryUser, newTimeEntryTask); + await newTimeEntryTask.save(); } - checkTaskOvertime(timeEntry, timeEntryUser, newTimeEntryTask); - await oldTimeEntryTask.save(); - await newTimeEntryTask.save(); } // Update edit history From 57c0267b2d1a04da276a20d57f3806d70f56336e Mon Sep 17 00:00:00 2001 From: Shengwei Peng Date: Tue, 2 Jan 2024 15:42:54 -0500 Subject: [PATCH 238/272] Update the scheduler to run every Sunday at midnight --- src/cronjobs/userProfileJobs.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cronjobs/userProfileJobs.js b/src/cronjobs/userProfileJobs.js index f3903c057..8ca6ff95c 100644 --- a/src/cronjobs/userProfileJobs.js +++ b/src/cronjobs/userProfileJobs.js @@ -5,7 +5,8 @@ const userhelper = require('../helpers/userHelper')(); const userProfileJobs = () => { const allUserProfileJobs = new CronJob( - '1 0 * * *', // Every day, 1 minute past midnight (PST). + // '* * * * *', // Comment out for testing. Run Every minute. + '0 0 * * 0', // Every Sunday, at midnight. async () => { const SUNDAY = 0; if (moment().tz('America/Los_Angeles').day() === SUNDAY) { From 0d805bc24041186ac9bb95d5b5e22ddd10ba7e9a Mon Sep 17 00:00:00 2001 From: Shengwei Peng Date: Tue, 2 Jan 2024 15:52:18 -0500 Subject: [PATCH 239/272] Update cron config to run at 1 minute past midnight every Sunday in PST --- src/cronjobs/userProfileJobs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cronjobs/userProfileJobs.js b/src/cronjobs/userProfileJobs.js index 8ca6ff95c..8bc94c0f1 100644 --- a/src/cronjobs/userProfileJobs.js +++ b/src/cronjobs/userProfileJobs.js @@ -6,7 +6,7 @@ const userhelper = require('../helpers/userHelper')(); const userProfileJobs = () => { const allUserProfileJobs = new CronJob( // '* * * * *', // Comment out for testing. Run Every minute. - '0 0 * * 0', // Every Sunday, at midnight. + '1 0 * * 0', // Every Sunday, 1 minute past midnight. async () => { const SUNDAY = 0; if (moment().tz('America/Los_Angeles').day() === SUNDAY) { From e587b6a4ad2083f18abc5b047cf4d609ca1c7a70 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Tue, 2 Jan 2024 15:44:40 -0800 Subject: [PATCH 240/272] add char limit to desc --- src/models/bmdashboard/buildingInventoryType.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/bmdashboard/buildingInventoryType.js b/src/models/bmdashboard/buildingInventoryType.js index b1512dca2..b130c6ae9 100644 --- a/src/models/bmdashboard/buildingInventoryType.js +++ b/src/models/bmdashboard/buildingInventoryType.js @@ -11,7 +11,7 @@ const { Schema } = mongoose; const invTypeBaseSchema = new Schema({ name: { type: String, required: true }, - description: { type: String, required: true }, + description: { type: String, required: true, maxLength: 150 }, imageUrl: String, createdBy: { type: mongoose.SchemaTypes.ObjectId, ref: 'userProfiles' }, }); From bda1712e367d2b7d1b5e64846a4ed13bac3c6682 Mon Sep 17 00:00:00 2001 From: wang9hu Date: Tue, 2 Jan 2024 16:59:35 -0800 Subject: [PATCH 241/272] change request body format for adding and deleting team member, refactor request handler --- src/controllers/teamController.js | 82 +++++++++++-------------------- 1 file changed, 28 insertions(+), 54 deletions(-) diff --git a/src/controllers/teamController.js b/src/controllers/teamController.js index 5c8cb5cc2..0570afc00 100644 --- a/src/controllers/teamController.js +++ b/src/controllers/teamController.js @@ -115,66 +115,40 @@ const teamcontroller = function (Team) { return; } - if ( - !req.params.teamId - || !mongoose.Types.ObjectId.isValid(req.params.teamId) - || !req.body.users - || req.body.users.length === 0 - ) { - res.status(400).send({ error: 'Invalid request' }); + const { teamId } = req.params; + + if (!teamId || !mongoose.Types.ObjectId.isValid(teamId)) { + res.status(400).send({ error: 'Invalid teamId' }); return; } // verify team exists + const targetTeam = await Team.findById(teamId); - Team.findById(req.params.teamId) - .then((team) => { - if (!team || team.length === 0) { - res.status(400).send({ error: 'Invalid team' }); - return; - } - const { users } = req.body; - const assignlist = []; - const unassignlist = []; - - users.forEach((element) => { - const { userId, operation } = element; - // if user's profile is stored in cache, clear it so when you visit their profile page it will be up to date - if (cache.hasCache(`user-${userId}`)) cache.removeCache(`user-${userId}`); - - if (operation === 'Assign') { - assignlist.push(userId); - } else { - unassignlist.push(userId); - } - }); + if (!targetTeam || targetTeam.length === 0) { + res.status(400).send({ error: 'Invalid team' }); + return; + } - const addTeamToUserProfile = userProfile - .updateMany({ _id: { $in: assignlist } }, { $addToSet: { teams: team._id } }) - .exec(); - const removeTeamFromUserProfile = userProfile - .updateMany({ _id: { $in: unassignlist } }, { $pull: { teams: team._id } }) - .exec(); - const addUserToTeam = Team.updateOne( - { _id: team._id }, - { $addToSet: { members: { $each: assignlist.map(userId => ({ userId })) } } }, - ).exec(); - const removeUserFromTeam = Team.updateOne( - { _id: team._id }, - { $pull: { members: { userId: { $in: unassignlist } } } }, - ).exec(); - - Promise.all([addTeamToUserProfile, removeTeamFromUserProfile, addUserToTeam, removeUserFromTeam]) - .then(() => { - res.status(200).send({ result: 'Done' }); - }) - .catch((error) => { - res.status(500).send({ error }); - }); - }) - .catch((error) => { - res.status(500).send({ error }); - }); + try { + const { userId, operation } = req.body; + + // if user's profile is stored in cache, clear it so when you visit their profile page it will be up to date + if (cache.hasCache(`user-${userId}`)) cache.removeCache(`user-${userId}`); + + + if (operation === 'Assign') { + await Team.findOneAndUpdate({ _id: teamId }, { $addToSet: { members: { userId } } }, { new: true }); + const newMember = await userProfile.findOneAndUpdate({ _id: userId }, { $addToSet: { teams: teamId } }, { new: true }); + res.status(200).send({ newMember }); + } else { + await Team.findOneAndUpdate({ _id: teamId }, { $pull: { members: { userId } } }); + await userProfile.findOneAndUpdate({ _id: userId }, { $pull: { teams: teamId } }, { new: true }); + res.status(200).send({ result: 'Delete Success' }); + } + } catch (error) { + res.status(500).send({ error }); + } }; const getTeamMembership = function (req, res) { From b83b1b54b94df722b249dde96aff9eeb48153249 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Tue, 2 Jan 2024 17:33:50 -0800 Subject: [PATCH 242/272] add duplicate name check --- .../bmdashboard/bmInventoryTypeController.js | 43 +++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/controllers/bmdashboard/bmInventoryTypeController.js b/src/controllers/bmdashboard/bmInventoryTypeController.js index ea2cba730..bab55c386 100644 --- a/src/controllers/bmdashboard/bmInventoryTypeController.js +++ b/src/controllers/bmdashboard/bmInventoryTypeController.js @@ -18,32 +18,41 @@ function bmInventoryTypeController(MatType, ConsType, ReusType, ToolType, EquipT fuel: fuelType, requestor: { requestorId }, } = req.body; - const newDoc = { - category: 'Equipment', - name, - description, - fuelType, - createdBy: requestorId, - }; try { EquipType - .create(newDoc) - .then(() => res.status(201).send()) - .catch((error) => { - if (error._message.includes('validation failed')) { - res.status(400).send(error); + .find({ name }) + .then((result) => { + if (result.length) { + res.status(409).send(); + } else { + const newDoc = { + category: 'Equipment', + name, + description, + fuelType, + createdBy: requestorId, + }; + EquipType + .create(newDoc) + .then(() => res.status(201).send()) + .catch((error) => { + if (error._message.includes('validation failed')) { + res.status(400).send(error); + } else { + res.status(500).send(error); + } + }); } - res.status(500).send(error); - }); - } catch (error) { + }) + .catch(error => res.status(500).send(error)); + } catch (error) { res.status(500).send(error); + } } - } return { fetchMaterialTypes, addEquipmentType, }; } - module.exports = bmInventoryTypeController; From 3dd167170b4d5945821ed64fb9e1e256cca27628 Mon Sep 17 00:00:00 2001 From: Shengwei Peng Date: Wed, 3 Jan 2024 12:41:46 -0500 Subject: [PATCH 243/272] Update cache removal after badge awarding --- src/helpers/userHelper.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index dba1369f3..5e6b0870b 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -13,7 +13,7 @@ const emailSender = require('../utilities/emailSender'); const logger = require('../startup/logger'); const Reason = require('../models/reason'); const token = require('../models/profileInitialSetupToken'); - +const cache = require('../utilities/nodeCache')(); const userHelper = function () { // Update format to "MMM-DD-YY" from "YYYY-MMM-DD" (Confirmed with Jae) @@ -860,6 +860,7 @@ const changeBadgeCount = async function (personId, badgeId, count) { } else if (count) { // Process exisiting earned date to match the new count try { + console.log('changeBadgeCount'); const userInfo = await userProfile.findById(personId); let newEarnedDate = []; const recordToUpdate = userInfo.badgeCollection.find(item => item.badge._id.toString() === badgeId.toString()); @@ -1507,6 +1508,10 @@ const changeBadgeCount = async function (personId, badgeId, count) { await checkLeadTeamOfXplus(personId, user, badgeCollection); await checkXHrsForXWeeks(personId, user, badgeCollection); await checkNoInfringementStreak(personId, user, badgeCollection); + // remove cache after badge asssignment. + if (cache.hasCache(`user-${_id}`)) { + cache.removeCache(`user-${_id}`); + } } } catch (err) { logger.logException(err); From fdbbd1d76c981b6c8c04f6c32d81134b47bcfd9a Mon Sep 17 00:00:00 2001 From: Shengwei Peng Date: Wed, 3 Jan 2024 15:38:48 -0500 Subject: [PATCH 244/272] Remove log statement from changeBadgeCount --- src/helpers/userHelper.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index 5e6b0870b..b4b2acb46 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -860,7 +860,6 @@ const changeBadgeCount = async function (personId, badgeId, count) { } else if (count) { // Process exisiting earned date to match the new count try { - console.log('changeBadgeCount'); const userInfo = await userProfile.findById(personId); let newEarnedDate = []; const recordToUpdate = userInfo.badgeCollection.find(item => item.badge._id.toString() === badgeId.toString()); From 8c077b0f71365cab26348f075578d021dfda9d3a Mon Sep 17 00:00:00 2001 From: Vishala Ramasamy Date: Wed, 3 Jan 2024 14:10:42 -0800 Subject: [PATCH 245/272] Leaderboard api and task api fix --- src/controllers/taskController.js | 2 +- src/helpers/dashboardhelper.js | 11 +- src/helpers/taskHelper.js | 705 ++++++++++++++++++------------ 3 files changed, 430 insertions(+), 288 deletions(-) diff --git a/src/controllers/taskController.js b/src/controllers/taskController.js index 9bcf071de..8d1559ebc 100644 --- a/src/controllers/taskController.js +++ b/src/controllers/taskController.js @@ -837,7 +837,7 @@ const taskController = function (Task) { const getTasksForTeamsByUser = async (req, res) => { try { const userId = mongoose.Types.ObjectId(req.params.userId); - const teamsData = await taskHelper.getTasksForTeams(userId).exec(); + const teamsData = await taskHelper.getTasksForTeams(userId); if (teamsData.length > 0) { res.status(200).send(teamsData); } else { diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index 59b1d7f51..76c0e8554 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -171,19 +171,20 @@ const dashboardhelper = function () { let teamMemberIds = [userid] let teamMembers = []; + if(userRole!='Administrator' && userRole!='Owner' && userRole!='Core Team') //Manager , Mentor , Volunteer ... , Show only team members { const teamsResult = await team.find( { "members.userId": { $in: [userid] } }, {members:1} ) .then((res)=>{ return res; }).catch((e)=>{}) - + teamsResult.map((_myTeam)=>{ _myTeam.members.map((teamMember)=> { if(!teamMember.userId.equals(userid)) teamMemberIds.push( teamMember.userId ); } ) }) - + teamMembers = await userProfile.find({ _id: { $in: teamMemberIds } , isActive:true }, {role:1,firstName:1,lastName:1,isVisible:1,weeklycommittedHours:1,weeklySummaries:1}) .then((res)=>{ return res; }).catch((e)=>{}) @@ -202,9 +203,9 @@ const dashboardhelper = function () { .then((res)=>{ return res; }).catch((e)=>{}) } - + } - + teamMemberIds = teamMembers.map(member => member._id); const timeEntries = await timeentry.find({ @@ -231,6 +232,7 @@ const dashboardhelper = function () { timeEntryByPerson[personIdStr].totalSeconds += timeEntry.totalSeconds; }) + let leaderBoardData = []; teamMembers.map((teamMember)=>{ @@ -267,6 +269,7 @@ const dashboardhelper = function () { // Finally, sort by role in ascending order return a.role.localeCompare(b.role); }); + return sortedLBData; // return myTeam.aggregate([ diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index f59dedcbc..2a49439f8 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -1,9 +1,23 @@ const moment = require('moment-timezone'); const userProfile = require('../models/userProfile'); -const myteam = require('../helpers/helperModels/myTeam'); +const timeentry = require('../models/timeentry'); +const myTeam = require('../helpers/helperModels/myTeam'); +const team = require('../models/team'); +const Task = require('../models/task'); +const TaskNotification = require('../models/taskNotification'); +const Wbs = require('../models/wbs'); +const mongoose = require('mongoose'); const taskHelper = function () { - const getTasksForTeams = function (userId) { + const getTasksForTeams = async function (userId) { + + const userid = mongoose.Types.ObjectId(userId); + const userById = await userProfile.findOne({ _id: userid , isActive:true}, {role:1,firstName:1, lastName:1, role:1, isVisible:1, weeklycommittedHours:1, weeklySummaries:1}) + .then((res)=>{ return res; }).catch((e)=>{}); + + if(userById==null) return null; + const userRole = userById.role; + const pdtstart = moment() .tz('America/Los_Angeles') .startOf('week') @@ -12,288 +26,413 @@ const taskHelper = function () { .tz('America/Los_Angeles') .endOf('week') .format('YYYY-MM-DD'); - return myteam.aggregate([ - { - $match: { - _id: userId, - }, - }, - { - $unwind: '$myteam', - }, - { - $project: { - _id: 0, - personId: '$myteam._id', - name: '$myteam.fullName', - role: 1, - }, - }, - // have personId, name, role - { - $lookup: { - from: 'userProfiles', - localField: 'personId', - foreignField: '_id', - as: 'persondata', - }, - }, - { - $match: { - // dashboard tasks user roles hierarchy - $or: [ - { - role: { $in: ['Owner', 'Core Team'] }, - }, - { - $and: [ - { - role: 'Administrator', - }, - { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, - ], - }, - { - $and: [ - { - role: { $in: ['Manager', 'Mentor'] }, - }, - { - 'persondata.0.role': { - $nin: ['Manager', 'Mentor', 'Core Team', 'Administrator', 'Owner'], - }, - }, - ], - }, - { 'persondata.0._id': userId }, - { 'persondata.0.role': 'Volunteer' }, - { 'persondata.0.isVisible': true }, - ], - }, - }, - { - $project: { - personId: 1, - name: 1, - weeklycommittedHours: { - $sum: [ - { - $arrayElemAt: ['$persondata.weeklycommittedHours', 0], - }, - { - $ifNull: [{ $arrayElemAt: ['$persondata.missedHours', 0] }, 0], - }, - ], - }, - role: 1, - }, - }, - { - $lookup: { - from: 'timeEntries', - localField: 'personId', - foreignField: 'personId', - as: 'timeEntryData', - }, - }, - { - $project: { - personId: 1, - name: 1, - weeklycommittedHours: 1, - timeEntryData: { - $filter: { - input: '$timeEntryData', - as: 'timeentry', - cond: { - $and: [ - { - $gte: ['$$timeentry.dateOfWork', pdtstart], - }, - { - $lte: ['$$timeentry.dateOfWork', pdtend], - }, - ], - }, - }, - }, - role: 1, - }, - }, - { - $unwind: { - path: '$timeEntryData', - preserveNullAndEmptyArrays: true, - }, - }, - { - $project: { - personId: 1, - name: 1, - weeklycommittedHours: 1, - totalSeconds: { - $cond: [ - { - $gte: ['$timeEntryData.totalSeconds', 0], - }, - '$timeEntryData.totalSeconds', - 0, - ], - }, - isTangible: { - $cond: [ - { - $gte: ['$timeEntryData.totalSeconds', 0], - }, - '$timeEntryData.isTangible', - false, - ], - }, - role: 1, - }, - }, - { - $addFields: { - tangibletime: { - $cond: [ - { - $eq: ['$isTangible', true], - }, - '$totalSeconds', - 0, - ], - }, - }, - }, - { - $group: { - _id: { - personId: '$personId', - weeklycommittedHours: '$weeklycommittedHours', - name: '$name', - role: '$role', - }, - totalSeconds: { - $sum: '$totalSeconds', - }, - tangibletime: { - $sum: '$tangibletime', - }, - }, - }, - { - $project: { - _id: 0, - personId: '$_id.personId', - name: '$_id.name', - weeklycommittedHours: '$_id.weeklycommittedHours', - totaltime_hrs: { - $divide: ['$totalSeconds', 3600], - }, - totaltangibletime_hrs: { - $divide: ['$tangibletime', 3600], - }, - role: '$_id.role', - }, - }, - { - $lookup: { - from: 'tasks', - localField: 'personId', - foreignField: 'resources.userID', - as: 'tasks', - }, - }, - { - $project: { - tasks: { - resources: { - profilePic: 0, - }, - }, - }, - }, - { - $unwind: { - path: '$tasks', - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: 'wbs', - localField: 'tasks.wbsId', - foreignField: '_id', - as: 'projectId', - }, - }, - { - $addFields: { - 'tasks.projectId': { - $cond: [ - { $ne: ['$projectId', []] }, - { $arrayElemAt: ['$projectId', 0] }, - '$tasks.projectId', - ], - }, - }, - }, - { - $project: { - projectId: 0, - tasks: { - projectId: { - _id: 0, - isActive: 0, - modifiedDatetime: 0, - wbsName: 0, - createdDatetime: 0, - __v: 0, - }, - }, - }, - }, - { - $addFields: { - 'tasks.projectId': '$tasks.projectId.projectId', - }, - }, - { - $lookup: { - from: 'taskNotifications', - localField: 'tasks._id', - foreignField: 'taskId', - as: 'tasks.taskNotifications', - }, - }, - { - $group: { - _id: '$personId', - tasks: { - $push: '$tasks', - }, - data: { - $first: '$$ROOT', - }, - }, - }, - { - $addFields: { - 'data.tasks': { - $filter: { - input: '$tasks', - as: 'task', - cond: { $ne: ['$$task', {}] }, - }, - }, - }, - }, + + let teamMemberIds = [userid] + let teamMembers = []; + + if(userRole!='Administrator' && userRole!='Owner' && userRole!='Core Team') //Manager , Mentor , Volunteer ... , Show only team members { - $replaceRoot: { - newRoot: '$data', - }, - }, - ]); + + const teamsResult = await team.find( { "members.userId": { $in: [userid] } }, {members:1} ) + .then((res)=>{ return res; }).catch((e)=>{}) + + teamsResult.map((_myTeam)=>{ + _myTeam.members.map((teamMember)=> { + if(!teamMember.userId.equals(userid)) + teamMemberIds.push( teamMember.userId ); + } ) + }) + + teamMembers = await userProfile.find({ _id: { $in: teamMemberIds } , isActive:true }, + {role:1,firstName:1,lastName:1,weeklycommittedHours:1}) + .then((res)=>{ return res; }).catch((e)=>{}) + } + else { + if(userRole == 'Administrator'){ //All users except Owner and Core Team + const excludedRoles = ['Core Team', 'Owner']; + teamMembers = await userProfile.find({ isActive:true , role: { $nin: excludedRoles } }, + {role:1,firstName:1,lastName:1,weeklycommittedHours:1}) + .then((res)=>{ return res; }).catch((e)=>{}) + } + else{ //'Core Team', 'Owner' //All users + teamMembers = await userProfile.find({ isActive:true}, + {role:1,firstName:1,lastName:1,weeklycommittedHours:1}) + .then((res)=>{ return res; }).catch((e)=>{}) + } + } + + teamMemberIds = teamMembers.map(member => member._id); + + const timeEntries = await timeentry.find({ + dateOfWork: { + $gte: pdtstart, + $lte: pdtend, + }, + personId: { $in: teamMemberIds } + }); + + let timeEntryByPerson = {} + timeEntries.map((timeEntry)=>{ + + let personIdStr = timeEntry.personId.toString(); + + if(timeEntryByPerson[personIdStr]==null) + timeEntryByPerson[personIdStr] = {tangibleSeconds:0,intangibleSeconds:0,totalSeconds:0}; + + if (timeEntry.isTangible === true) { + timeEntryByPerson[personIdStr].tangibleSeconds += timeEntry.totalSeconds; + } + timeEntryByPerson[personIdStr].totalSeconds += timeEntry.totalSeconds; + }) + + const teamMemberTasks = await Task.find({"resources.userID" : {$in : teamMemberIds }}, { 'resources.profilePic': 0 }) + .populate( { + path: 'wbsId', + select: 'projectId', + }) + const teamMemberTaskIds = teamMemberTasks.map(task => task._id); + const teamMemberTaskNotifications = await TaskNotification.find({"taskId" : {$in : teamMemberTaskIds }}) + + const taskNotificationByTaskNdUser = [] + teamMemberTaskNotifications.map(teamMemberTaskNotification => { + + let taskIdStr = teamMemberTaskNotification.taskId.toString(); + let userIdStr = teamMemberTaskNotification.userId.toString(); + let taskNdUserID = taskIdStr+","+userIdStr; + + if(taskNotificationByTaskNdUser[taskNdUserID]) { + taskNotificationByTaskNdUser[taskNdUserID].push(teamMemberTaskNotification) + } + else{ + taskNotificationByTaskNdUser[taskNdUserID] = [teamMemberTaskNotification] + } + + }) + + const taskByPerson = [] + + teamMemberTasks.map(teamMemberTask => { + + let projId = teamMemberTask.wbsId?.projectId; + let _teamMemberTask = {...teamMemberTask._doc} + _teamMemberTask.projectId = projId; + let taskIdStr = _teamMemberTask._id.toString(); + + teamMemberTask.resources.map(resource => { + + let resourceIdStr = resource.userID.toString(); + let taskNdUserID = taskIdStr+","+resourceIdStr; + _teamMemberTask.taskNotifications = taskNotificationByTaskNdUser[taskNdUserID] || [] + if(taskByPerson[resourceIdStr]) { + taskByPerson[resourceIdStr].push(_teamMemberTask) + } + else{ + taskByPerson[resourceIdStr] = [_teamMemberTask] + } + }) + }) + + + let teamMemberTasksData = []; + teamMembers.map((teamMember)=>{ + let obj = { + personId : teamMember._id, + role : teamMember.role, + name : teamMember.firstName + ' ' + teamMember.lastName, + weeklycommittedHours : teamMember.weeklycommittedHours, + totaltangibletime_hrs : ((timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / 3600) || 0), + totaltime_hrs : ((timeEntryByPerson[teamMember._id.toString()]?.totalSeconds / 3600) || 0), + tasks : taskByPerson[teamMember._id.toString()] || [] + } + teamMemberTasksData.push(obj); + }) + + + return teamMemberTasksData; + + + // return myteam.aggregate([ + // { + // $match: { + // _id: userId, + // }, + // }, + // { + // $unwind: '$myteam', + // }, + // { + // $project: { + // _id: 0, + // personId: '$myteam._id', + // name: '$myteam.fullName', + // role: 1, + // }, + // }, + // // have personId, name, role + // { + // $lookup: { + // from: 'userProfiles', + // localField: 'personId', + // foreignField: '_id', + // as: 'persondata', + // }, + // }, + // { + // $match: { + // // dashboard tasks user roles hierarchy + // $or: [ + // { + // role: { $in: ['Owner', 'Core Team'] }, + // }, + // { + // $and: [ + // { + // role: 'Administrator', + // }, + // { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, + // ], + // }, + // { + // $and: [ + // { + // role: { $in: ['Manager', 'Mentor'] }, + // }, + // { + // 'persondata.0.role': { + // $nin: ['Manager', 'Mentor', 'Core Team', 'Administrator', 'Owner'], + // }, + // }, + // ], + // }, + // { 'persondata.0._id': userId }, + // { 'persondata.0.role': 'Volunteer' }, + // { 'persondata.0.isVisible': true }, + // ], + // }, + // }, + // { + // $project: { + // personId: 1, + // name: 1, + // weeklycommittedHours: { + // $sum: [ + // { + // $arrayElemAt: ['$persondata.weeklycommittedHours', 0], + // }, + // { + // $ifNull: [{ $arrayElemAt: ['$persondata.missedHours', 0] }, 0], + // }, + // ], + // }, + // role: 1, + // }, + // }, + // { + // $lookup: { + // from: 'timeEntries', + // localField: 'personId', + // foreignField: 'personId', + // as: 'timeEntryData', + // }, + // }, + // { + // $project: { + // personId: 1, + // name: 1, + // weeklycommittedHours: 1, + // timeEntryData: { + // $filter: { + // input: '$timeEntryData', + // as: 'timeentry', + // cond: { + // $and: [ + // { + // $gte: ['$$timeentry.dateOfWork', pdtstart], + // }, + // { + // $lte: ['$$timeentry.dateOfWork', pdtend], + // }, + // ], + // }, + // }, + // }, + // role: 1, + // }, + // }, + // { + // $unwind: { + // path: '$timeEntryData', + // preserveNullAndEmptyArrays: true, + // }, + // }, + // { + // $project: { + // personId: 1, + // name: 1, + // weeklycommittedHours: 1, + // totalSeconds: { + // $cond: [ + // { + // $gte: ['$timeEntryData.totalSeconds', 0], + // }, + // '$timeEntryData.totalSeconds', + // 0, + // ], + // }, + // isTangible: { + // $cond: [ + // { + // $gte: ['$timeEntryData.totalSeconds', 0], + // }, + // '$timeEntryData.isTangible', + // false, + // ], + // }, + // role: 1, + // }, + // }, + // { + // $addFields: { + // tangibletime: { + // $cond: [ + // { + // $eq: ['$isTangible', true], + // }, + // '$totalSeconds', + // 0, + // ], + // }, + // }, + // }, + // { + // $group: { + // _id: { + // personId: '$personId', + // weeklycommittedHours: '$weeklycommittedHours', + // name: '$name', + // role: '$role', + // }, + // totalSeconds: { + // $sum: '$totalSeconds', + // }, + // tangibletime: { + // $sum: '$tangibletime', + // }, + // }, + // }, + // { + // $project: { + // _id: 0, + // personId: '$_id.personId', + // name: '$_id.name', + // weeklycommittedHours: '$_id.weeklycommittedHours', + // totaltime_hrs: { + // $divide: ['$totalSeconds', 3600], + // }, + // totaltangibletime_hrs: { + // $divide: ['$tangibletime', 3600], + // }, + // role: '$_id.role', + // }, + // }, + // { + // $lookup: { + // from: 'tasks', + // localField: 'personId', + // foreignField: 'resources.userID', + // as: 'tasks', + // }, + // }, + // { + // $project: { + // tasks: { + // resources: { + // profilePic: 0, + // }, + // }, + // }, + // }, + // { + // $unwind: { + // path: '$tasks', + // preserveNullAndEmptyArrays: true, + // }, + // }, + // { + // $lookup: { + // from: 'wbs', + // localField: 'tasks.wbsId', + // foreignField: '_id', + // as: 'projectId', + // }, + // }, + // { + // $addFields: { + // 'tasks.projectId': { + // $cond: [ + // { $ne: ['$projectId', []] }, + // { $arrayElemAt: ['$projectId', 0] }, + // '$tasks.projectId', + // ], + // }, + // }, + // }, + // { + // $project: { + // projectId: 0, + // tasks: { + // projectId: { + // _id: 0, + // isActive: 0, + // modifiedDatetime: 0, + // wbsName: 0, + // createdDatetime: 0, + // __v: 0, + // }, + // }, + // }, + // }, + // { + // $addFields: { + // 'tasks.projectId': '$tasks.projectId.projectId', + // }, + // }, + // { + // $lookup: { + // from: 'taskNotifications', + // localField: 'tasks._id', + // foreignField: 'taskId', + // as: 'tasks.taskNotifications', + // }, + // }, + // { + // $group: { + // _id: '$personId', + // tasks: { + // $push: '$tasks', + // }, + // data: { + // $first: '$$ROOT', + // }, + // }, + // }, + // { + // $addFields: { + // 'data.tasks': { + // $filter: { + // input: '$tasks', + // as: 'task', + // cond: { $ne: ['$$task', {}] }, + // }, + // }, + // }, + // }, + // { + // $replaceRoot: { + // newRoot: '$data', + // }, + // }, + // ]); }; const getTasksForSingleUser = function (userId) { const pdtstart = moment() From 9e6589608a82300e4d9d4f024df09198b9f3957d Mon Sep 17 00:00:00 2001 From: Vishala Ramasamy Date: Wed, 3 Jan 2024 16:10:55 -0800 Subject: [PATCH 246/272] merged with dev bracnh --- src/helpers/taskHelper.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index 19551b0ed..e1e2acb13 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -15,6 +15,7 @@ const taskHelper = function () { const userById = await userProfile.findOne({ _id: userid , isActive:true}, {role:1,firstName:1, lastName:1, role:1, isVisible:1, weeklycommittedHours:1, weeklySummaries:1}) .then((res)=>{ return res; }).catch((e)=>{}); + if(userById==null) return null; const userRole = userById.role; From d3c2daebe1a1fa8eaafd0556a2bf0b21754fee27 Mon Sep 17 00:00:00 2001 From: Vishala Ramasamy Date: Wed, 3 Jan 2024 16:21:53 -0800 Subject: [PATCH 247/272] api fix --- src/helpers/dashboardhelper.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index 0b85cb004..ca534b894 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -176,7 +176,6 @@ const dashboardhelper = function () { .endOf('week') .format('YYYY-MM-DD'); - let teamMemberIds = [userid] let teamMembers = []; @@ -211,7 +210,6 @@ const dashboardhelper = function () { .then((res)=>{ return res; }).catch((e)=>{}) } - } teamMemberIds = teamMembers.map(member => member._id); From 1e8f5e46f27d7e9418b0a0a5445599cf186850a8 Mon Sep 17 00:00:00 2001 From: Vishala09 <65274029+Vishala09@users.noreply.github.com> Date: Wed, 3 Jan 2024 16:49:49 -0800 Subject: [PATCH 248/272] Revert "Vishala LB and Task api fix" --- src/helpers/dashboardhelper.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index ca534b894..0b85cb004 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -176,6 +176,7 @@ const dashboardhelper = function () { .endOf('week') .format('YYYY-MM-DD'); + let teamMemberIds = [userid] let teamMembers = []; @@ -210,6 +211,7 @@ const dashboardhelper = function () { .then((res)=>{ return res; }).catch((e)=>{}) } + } teamMemberIds = teamMembers.map(member => member._id); From 9c913c709d714af5f3901262112245f051770916 Mon Sep 17 00:00:00 2001 From: Vishala09 <65274029+Vishala09@users.noreply.github.com> Date: Wed, 3 Jan 2024 16:53:22 -0800 Subject: [PATCH 249/272] Revert "Vishala Leaderboard and Team Member Tasks Api Fix" --- src/controllers/taskController.js | 2 +- src/helpers/dashboardhelper.js | 614 +++++++++++--------------- src/helpers/taskHelper.js | 708 ++++++++++++------------------ 3 files changed, 542 insertions(+), 782 deletions(-) diff --git a/src/controllers/taskController.js b/src/controllers/taskController.js index 753dbba11..5b087db4d 100644 --- a/src/controllers/taskController.js +++ b/src/controllers/taskController.js @@ -834,7 +834,7 @@ const taskController = function (Task) { const getTasksForTeamsByUser = async (req, res) => { try { const userId = mongoose.Types.ObjectId(req.params.userId); - const teamsData = await taskHelper.getTasksForTeams(userId); + const teamsData = await taskHelper.getTasksForTeams(userId).exec(); if (teamsData.length > 0) { res.status(200).send(teamsData); } else { diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index 0b85cb004..b7ca2f131 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -3,7 +3,6 @@ const mongoose = require('mongoose'); const userProfile = require('../models/userProfile'); const timeentry = require('../models/timeentry'); const myTeam = require('../helpers/helperModels/myTeam'); -const team = require('../models/team'); const dashboardhelper = function () { const personaldetails = function (userId) { @@ -162,11 +161,6 @@ const dashboardhelper = function () { const getLeaderboard = async function (userId) { const userid = mongoose.Types.ObjectId(userId); - const userById = await userProfile.findOne({ _id: userid , isActive:true}, {role:1}) - .then((res)=>{ return res; }).catch((e)=>{}); - - if(userById==null) return null; - const userRole = userById.role; const pdtstart = moment() .tz('America/Los_Angeles') .startOf('week') @@ -175,360 +169,262 @@ const dashboardhelper = function () { .tz('America/Los_Angeles') .endOf('week') .format('YYYY-MM-DD'); - - - let teamMemberIds = [userid] - let teamMembers = []; - - if(userRole!='Administrator' && userRole!='Owner' && userRole!='Core Team') //Manager , Mentor , Volunteer ... , Show only team members - { - - const teamsResult = await team.find( { "members.userId": { $in: [userid] } }, {members:1} ) - .then((res)=>{ return res; }).catch((e)=>{}) - - teamsResult.map((_myTeam)=>{ - _myTeam.members.map((teamMember)=> { - if(!teamMember.userId.equals(userid)) - teamMemberIds.push( teamMember.userId ); - } ) - }) - - teamMembers = await userProfile.find({ _id: { $in: teamMemberIds } , isActive:true }, - {role:1,firstName:1,lastName:1,isVisible:1,weeklycommittedHours:1,weeklySummaries:1}) - .then((res)=>{ return res; }).catch((e)=>{}) - - } - else { - if(userRole == 'Administrator'){ //All users except Owner and Core Team - const excludedRoles = ['Core Team', 'Owner']; - teamMembers = await userProfile.find({ isActive:true , role: { $nin: excludedRoles } }, - {role:1,firstName:1,lastName:1,isVisible:1,weeklycommittedHours:1,weeklySummaries:1}) - .then((res)=>{ return res; }).catch((e)=>{}) - } - else{ //'Core Team', 'Owner' //All users - teamMembers = await userProfile.find({ isActive:true}, - {role:1,firstName:1,lastName:1,isVisible:1,weeklycommittedHours:1,weeklySummaries:1}) - .then((res)=>{ return res; }).catch((e)=>{}) - } - - - } - - teamMemberIds = teamMembers.map(member => member._id); - - const timeEntries = await timeentry.find({ - dateOfWork: { - $gte: pdtstart, - $lte: pdtend, + const output = await myTeam.aggregate([ + { + $match: { + _id: userid, + }, }, - personId: { $in: teamMemberIds } - }); - - let timeEntryByPerson = {} - timeEntries.map((timeEntry)=>{ - - let personIdStr = timeEntry.personId.toString(); - - if(timeEntryByPerson[personIdStr]==null) - timeEntryByPerson[personIdStr] = {tangibleSeconds:0,intangibleSeconds:0,totalSeconds:0}; - - if (timeEntry.isTangible === true) { - timeEntryByPerson[personIdStr].tangibleSeconds += timeEntry.totalSeconds; - } else { - timeEntryByPerson[personIdStr].intangibleSeconds += timeEntry.totalSeconds; - } - - timeEntryByPerson[personIdStr].totalSeconds += timeEntry.totalSeconds; - }) - - - let leaderBoardData = []; - teamMembers.map((teamMember)=>{ - let obj = { - personId : teamMember._id, - role : teamMember.role, - name : teamMember.firstName + ' ' + teamMember.lastName, - isVisible : teamMember.isVisible, - hasSummary : teamMember.weeklySummaries?.length > 0 ? teamMember.weeklySummaries[0].summary!='' : false, - weeklycommittedHours : teamMember.weeklycommittedHours, - totaltangibletime_hrs : ((timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / 3600) || 0), - totalintangibletime_hrs : ((timeEntryByPerson[teamMember._id.toString()]?.intangibleSeconds / 3600) || 0), - totaltime_hrs : ((timeEntryByPerson[teamMember._id.toString()]?.totalSeconds / 3600) || 0), - percentagespentintangible : - (timeEntryByPerson[teamMember._id.toString()] && timeEntryByPerson[teamMember._id.toString()]?.totalSeconds !=0 && timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds !=0) ? - (timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / timeEntryByPerson[teamMember._id.toString()]?.totalSeconds) * 100 - : - 0 - } - leaderBoardData.push(obj); - }) - - let sortedLBData = leaderBoardData.sort((a, b) => { - // Sort by totaltangibletime_hrs in descending order - if (b.totaltangibletime_hrs !== a.totaltangibletime_hrs) { - return b.totaltangibletime_hrs - a.totaltangibletime_hrs; - } - - // Then sort by name in ascending order - if (a.name !== b.name) { - return a.name.localeCompare(b.name); - } - - // Finally, sort by role in ascending order - return a.role.localeCompare(b.role); - }); - - return sortedLBData; - - // return myTeam.aggregate([ - // { - // $match: { - // _id: userid, - // }, - // }, - // { - // $unwind: '$myteam', - // }, - // { - // $project: { - // _id: 0, - // role: 1, - // personId: '$myteam._id', - // name: '$myteam.fullName', - // }, - // }, - // { - // $lookup: { - // from: 'userProfiles', - // localField: 'personId', - // foreignField: '_id', - // as: 'persondata', - // }, - // }, - // { - // $match: { - // // leaderboard user roles hierarchy - // $or: [ - // { - // role: { $in: ['Owner', 'Core Team'] }, - // }, - // { - // $and: [ - // { - // role: 'Administrator', - // }, - // { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, - // ], - // }, - // { - // $and: [ - // { - // role: { $in: ['Manager', 'Mentor'] }, - // }, - // { - // 'persondata.0.role': { - // $nin: ['Manager', 'Mentor', 'Core Team', 'Administrator', 'Owner'], - // }, - // }, - // ], - // }, - // { 'persondata.0._id': userId }, - // { 'persondata.0.role': 'Volunteer' }, - // { 'persondata.0.isVisible': true }, - // ], - // }, - // }, - // { - // $project: { - // personId: 1, - // name: 1, - // role: { - // $arrayElemAt: ['$persondata.role', 0], - // }, - // isVisible: { - // $arrayElemAt: ['$persondata.isVisible', 0], - // }, - // hasSummary: { - // $ne: [ - // { - // $arrayElemAt: [ - // { - // $arrayElemAt: ['$persondata.weeklySummaries.summary', 0], - // }, - // 0, - // ], - // }, - // '', - // ], - // }, - // weeklycommittedHours: { - // $sum: [ - // { - // $arrayElemAt: ['$persondata.weeklycommittedHours', 0], - // }, - // { - // $ifNull: [{ $arrayElemAt: ['$persondata.missedHours', 0] }, 0], - // }, - // ], - // }, - // }, - // }, - // { - // $lookup: { - // from: 'timeEntries', - // localField: 'personId', - // foreignField: 'personId', - // as: 'timeEntryData', - // }, - // }, - // { - // $project: { - // personId: 1, - // name: 1, - // role: 1, - // isVisible: 1, - // hasSummary: 1, - // weeklycommittedHours: 1, - // timeEntryData: { - // $filter: { - // input: '$timeEntryData', - // as: 'timeentry', - // cond: { - // $and: [ - // { - // $gte: ['$$timeentry.dateOfWork', pdtstart], - // }, - // { - // $lte: ['$$timeentry.dateOfWork', pdtend], - // }, - // ], - // }, - // }, - // }, - // }, - // }, - // { - // $unwind: { - // path: '$timeEntryData', - // preserveNullAndEmptyArrays: true, - // }, - // }, - // { - // $project: { - // personId: 1, - // name: 1, - // role: 1, - // isVisible: 1, - // hasSummary: 1, - // weeklycommittedHours: 1, - // totalSeconds: { - // $cond: [ - // { - // $gte: ['$timeEntryData.totalSeconds', 0], - // }, - // '$timeEntryData.totalSeconds', - // 0, - // ], - // }, - // isTangible: { - // $cond: [ - // { - // $gte: ['$timeEntryData.totalSeconds', 0], - // }, - // '$timeEntryData.isTangible', - // false, - // ], - // }, - // }, - // }, - // { - // $addFields: { - // tangibletime: { - // $cond: [ - // { - // $eq: ['$isTangible', true], - // }, - // '$totalSeconds', - // 0, - // ], - // }, - // intangibletime: { - // $cond: [ - // { - // $eq: ['$isTangible', false], - // }, - // '$totalSeconds', - // 0, - // ], - // }, - // }, - // }, - // { - // $group: { - // _id: { - // personId: '$personId', - // weeklycommittedHours: '$weeklycommittedHours', - // name: '$name', - // role: '$role', - // isVisible: '$isVisible', - // hasSummary: '$hasSummary', - // }, - // totalSeconds: { - // $sum: '$totalSeconds', - // }, - // tangibletime: { - // $sum: '$tangibletime', - // }, - // intangibletime: { - // $sum: '$intangibletime', - // }, - // }, - // }, - // { - // $project: { - // _id: 0, - // personId: '$_id.personId', - // name: '$_id.name', - // role: '$_id.role', - // isVisible: '$_id.isVisible', - // hasSummary: '$_id.hasSummary', - // weeklycommittedHours: '$_id.weeklycommittedHours', - // totaltime_hrs: { - // $divide: ['$totalSeconds', 3600], - // }, - // totaltangibletime_hrs: { - // $divide: ['$tangibletime', 3600], - // }, - // totalintangibletime_hrs: { - // $divide: ['$intangibletime', 3600], - // }, - // percentagespentintangible: { - // $cond: [ - // { - // $eq: ['$totalSeconds', 0], - // }, - // 0, - // { - // $multiply: [ - // { - // $divide: ['$tangibletime', '$totalSeconds'], - // }, - // 100, - // ], - // }, - // ], - // }, - // }, - // }, - // { - // $sort: { - // totaltangibletime_hrs: -1, - // name: 1, - // role: 1, - // }, - // }, - // ]); - + { + $unwind: '$myteam', + }, + { + $project: { + _id: 0, + role: 1, + personId: '$myteam._id', + name: '$myteam.fullName', + }, + }, + { + $lookup: { + from: 'userProfiles', + localField: 'personId', + foreignField: '_id', + as: 'persondata', + }, + }, + { + $match: { + // leaderboard user roles hierarchy + $or: [ + { + role: { $in: ['Owner', 'Core Team'] }, + }, + { + $and: [ + { + role: 'Administrator', + }, + { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, + ], + }, + { + $and: [ + { + role: { $in: ['Manager', 'Mentor'] }, + }, + { + 'persondata.0.role': { + $nin: ['Manager', 'Mentor', 'Core Team', 'Administrator', 'Owner'], + }, + }, + ], + }, + { 'persondata.0._id': userId }, + { 'persondata.0.role': 'Volunteer' }, + { 'persondata.0.isVisible': true }, + ], + }, + }, + { + $project: { + personId: 1, + name: 1, + role: { + $arrayElemAt: ['$persondata.role', 0], + }, + isVisible: { + $arrayElemAt: ['$persondata.isVisible', 0], + }, + hasSummary: { + $ne: [ + { + $arrayElemAt: [ + { + $arrayElemAt: ['$persondata.weeklySummaries.summary', 0], + }, + 0, + ], + }, + '', + ], + }, + weeklycommittedHours: { + $sum: [ + { + $arrayElemAt: ['$persondata.weeklycommittedHours', 0], + }, + { + $ifNull: [{ $arrayElemAt: ['$persondata.missedHours', 0] }, 0], + }, + ], + }, + }, + }, + { + $lookup: { + from: 'timeEntries', + localField: 'personId', + foreignField: 'personId', + as: 'timeEntryData', + }, + }, + { + $project: { + personId: 1, + name: 1, + role: 1, + isVisible: 1, + hasSummary: 1, + weeklycommittedHours: 1, + timeEntryData: { + $filter: { + input: '$timeEntryData', + as: 'timeentry', + cond: { + $and: [ + { + $gte: ['$$timeentry.dateOfWork', pdtstart], + }, + { + $lte: ['$$timeentry.dateOfWork', pdtend], + }, + { + $not: [ + { + $in: ['$$timeentry.entryType', ['person', 'team', 'project']], + }, + ], + }, + ], + }, + }, + }, + }, + }, + { + $unwind: { + path: '$timeEntryData', + preserveNullAndEmptyArrays: true, + }, + }, + { + $project: { + personId: 1, + name: 1, + role: 1, + isVisible: 1, + hasSummary: 1, + weeklycommittedHours: 1, + totalSeconds: { + $cond: [ + { + $gte: ['$timeEntryData.totalSeconds', 0], + }, + '$timeEntryData.totalSeconds', + 0, + ], + }, + isTangible: { + $cond: [ + { + $gte: ['$timeEntryData.totalSeconds', 0], + }, + '$timeEntryData.isTangible', + false, + ], + }, + }, + }, + { + $addFields: { + tangibletime: { + $cond: [ + { + $eq: ['$isTangible', true], + }, + '$totalSeconds', + 0, + ], + }, + intangibletime: { + $cond: [ + { + $eq: ['$isTangible', false], + }, + '$totalSeconds', + 0, + ], + }, + }, + }, + { + $group: { + _id: { + personId: '$personId', + weeklycommittedHours: '$weeklycommittedHours', + name: '$name', + role: '$role', + isVisible: '$isVisible', + hasSummary: '$hasSummary', + }, + totalSeconds: { + $sum: '$totalSeconds', + }, + tangibletime: { + $sum: '$tangibletime', + }, + intangibletime: { + $sum: '$intangibletime', + }, + }, + }, + { + $project: { + _id: 0, + personId: '$_id.personId', + name: '$_id.name', + role: '$_id.role', + isVisible: '$_id.isVisible', + hasSummary: '$_id.hasSummary', + weeklycommittedHours: '$_id.weeklycommittedHours', + totaltime_hrs: { + $divide: ['$totalSeconds', 3600], + }, + totaltangibletime_hrs: { + $divide: ['$tangibletime', 3600], + }, + totalintangibletime_hrs: { + $divide: ['$intangibletime', 3600], + }, + percentagespentintangible: { + $cond: [ + { + $eq: ['$totalSeconds', 0], + }, + 0, + { + $multiply: [ + { + $divide: ['$tangibletime', '$totalSeconds'], + }, + 100, + ], + }, + ], + }, + }, + }, + { + $sort: { + totaltangibletime_hrs: -1, + name: 1, + role: 1, + }, + }, + ]); + return output; }; /** diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index 19551b0ed..cfb1235fd 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -1,23 +1,9 @@ const moment = require('moment-timezone'); const userProfile = require('../models/userProfile'); -const timeentry = require('../models/timeentry'); -const myTeam = require('../helpers/helperModels/myTeam'); -const team = require('../models/team'); -const Task = require('../models/task'); -const TaskNotification = require('../models/taskNotification'); -const Wbs = require('../models/wbs'); -const mongoose = require('mongoose'); +const myteam = require('../helpers/helperModels/myTeam'); const taskHelper = function () { - const getTasksForTeams = async function (userId) { - - const userid = mongoose.Types.ObjectId(userId); - const userById = await userProfile.findOne({ _id: userid , isActive:true}, {role:1,firstName:1, lastName:1, role:1, isVisible:1, weeklycommittedHours:1, weeklySummaries:1}) - .then((res)=>{ return res; }).catch((e)=>{}); - - if(userById==null) return null; - const userRole = userById.role; - + const getTasksForTeams = function (userId) { const pdtstart = moment() .tz('America/Los_Angeles') .startOf('week') @@ -26,413 +12,291 @@ const taskHelper = function () { .tz('America/Los_Angeles') .endOf('week') .format('YYYY-MM-DD'); - - let teamMemberIds = [userid] - let teamMembers = []; - - if(userRole!='Administrator' && userRole!='Owner' && userRole!='Core Team') //Manager , Mentor , Volunteer ... , Show only team members + return myteam.aggregate([ { - - const teamsResult = await team.find( { "members.userId": { $in: [userid] } }, {members:1} ) - .then((res)=>{ return res; }).catch((e)=>{}) - - teamsResult.map((_myTeam)=>{ - _myTeam.members.map((teamMember)=> { - if(!teamMember.userId.equals(userid)) - teamMemberIds.push( teamMember.userId ); - } ) - }) - - teamMembers = await userProfile.find({ _id: { $in: teamMemberIds } , isActive:true }, - {role:1,firstName:1,lastName:1,weeklycommittedHours:1}) - .then((res)=>{ return res; }).catch((e)=>{}) - } - else { - if(userRole == 'Administrator'){ //All users except Owner and Core Team - const excludedRoles = ['Core Team', 'Owner']; - teamMembers = await userProfile.find({ isActive:true , role: { $nin: excludedRoles } }, - {role:1,firstName:1,lastName:1,weeklycommittedHours:1}) - .then((res)=>{ return res; }).catch((e)=>{}) - } - else{ //'Core Team', 'Owner' //All users - teamMembers = await userProfile.find({ isActive:true}, - {role:1,firstName:1,lastName:1,weeklycommittedHours:1}) - .then((res)=>{ return res; }).catch((e)=>{}) - } - } - - teamMemberIds = teamMembers.map(member => member._id); - - const timeEntries = await timeentry.find({ - dateOfWork: { - $gte: pdtstart, - $lte: pdtend, - }, - personId: { $in: teamMemberIds } - }); - - let timeEntryByPerson = {} - timeEntries.map((timeEntry)=>{ - - let personIdStr = timeEntry.personId.toString(); - - if(timeEntryByPerson[personIdStr]==null) - timeEntryByPerson[personIdStr] = {tangibleSeconds:0,intangibleSeconds:0,totalSeconds:0}; - - if (timeEntry.isTangible === true) { - timeEntryByPerson[personIdStr].tangibleSeconds += timeEntry.totalSeconds; - } - timeEntryByPerson[personIdStr].totalSeconds += timeEntry.totalSeconds; - }) - - const teamMemberTasks = await Task.find({"resources.userID" : {$in : teamMemberIds }}, { 'resources.profilePic': 0 }) - .populate( { - path: 'wbsId', - select: 'projectId', - }) - const teamMemberTaskIds = teamMemberTasks.map(task => task._id); - const teamMemberTaskNotifications = await TaskNotification.find({"taskId" : {$in : teamMemberTaskIds }}) - - const taskNotificationByTaskNdUser = [] - teamMemberTaskNotifications.map(teamMemberTaskNotification => { - - let taskIdStr = teamMemberTaskNotification.taskId.toString(); - let userIdStr = teamMemberTaskNotification.userId.toString(); - let taskNdUserID = taskIdStr+","+userIdStr; - - if(taskNotificationByTaskNdUser[taskNdUserID]) { - taskNotificationByTaskNdUser[taskNdUserID].push(teamMemberTaskNotification) - } - else{ - taskNotificationByTaskNdUser[taskNdUserID] = [teamMemberTaskNotification] - } - - }) - - const taskByPerson = [] - - teamMemberTasks.map(teamMemberTask => { - - let projId = teamMemberTask.wbsId?.projectId; - let _teamMemberTask = {...teamMemberTask._doc} - _teamMemberTask.projectId = projId; - let taskIdStr = _teamMemberTask._id.toString(); - - teamMemberTask.resources.map(resource => { - - let resourceIdStr = resource.userID.toString(); - let taskNdUserID = taskIdStr+","+resourceIdStr; - _teamMemberTask.taskNotifications = taskNotificationByTaskNdUser[taskNdUserID] || [] - if(taskByPerson[resourceIdStr]) { - taskByPerson[resourceIdStr].push(_teamMemberTask) - } - else{ - taskByPerson[resourceIdStr] = [_teamMemberTask] - } - }) - }) - - - let teamMemberTasksData = []; - teamMembers.map((teamMember)=>{ - let obj = { - personId : teamMember._id, - role : teamMember.role, - name : teamMember.firstName + ' ' + teamMember.lastName, - weeklycommittedHours : teamMember.weeklycommittedHours, - totaltangibletime_hrs : ((timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / 3600) || 0), - totaltime_hrs : ((timeEntryByPerson[teamMember._id.toString()]?.totalSeconds / 3600) || 0), - tasks : taskByPerson[teamMember._id.toString()] || [] - } - teamMemberTasksData.push(obj); - }) - - - return teamMemberTasksData; - - - // return myteam.aggregate([ - // { - // $match: { - // _id: userId, - // }, - // }, - // { - // $unwind: '$myteam', - // }, - // { - // $project: { - // _id: 0, - // personId: '$myteam._id', - // name: '$myteam.fullName', - // role: 1, - // }, - // }, - // // have personId, name, role - // { - // $lookup: { - // from: 'userProfiles', - // localField: 'personId', - // foreignField: '_id', - // as: 'persondata', - // }, - // }, - // { - // $match: { - // // dashboard tasks user roles hierarchy - // $or: [ - // { - // role: { $in: ['Owner', 'Core Team'] }, - // }, - // { - // $and: [ - // { - // role: 'Administrator', - // }, - // { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, - // ], - // }, - // { - // $and: [ - // { - // role: { $in: ['Manager', 'Mentor'] }, - // }, - // { - // 'persondata.0.role': { - // $nin: ['Manager', 'Mentor', 'Core Team', 'Administrator', 'Owner'], - // }, - // }, - // ], - // }, - // { 'persondata.0._id': userId }, - // { 'persondata.0.role': 'Volunteer' }, - // { 'persondata.0.isVisible': true }, - // ], - // }, - // }, - // { - // $project: { - // personId: 1, - // name: 1, - // weeklycommittedHours: { - // $sum: [ - // { - // $arrayElemAt: ['$persondata.weeklycommittedHours', 0], - // }, - // { - // $ifNull: [{ $arrayElemAt: ['$persondata.missedHours', 0] }, 0], - // }, - // ], - // }, - // role: 1, - // }, - // }, - // { - // $lookup: { - // from: 'timeEntries', - // localField: 'personId', - // foreignField: 'personId', - // as: 'timeEntryData', - // }, - // }, - // { - // $project: { - // personId: 1, - // name: 1, - // weeklycommittedHours: 1, - // timeEntryData: { - // $filter: { - // input: '$timeEntryData', - // as: 'timeentry', - // cond: { - // $and: [ - // { - // $gte: ['$$timeentry.dateOfWork', pdtstart], - // }, - // { - // $lte: ['$$timeentry.dateOfWork', pdtend], - // }, - // ], - // }, - // }, - // }, - // role: 1, - // }, - // }, - // { - // $unwind: { - // path: '$timeEntryData', - // preserveNullAndEmptyArrays: true, - // }, - // }, - // { - // $project: { - // personId: 1, - // name: 1, - // weeklycommittedHours: 1, - // totalSeconds: { - // $cond: [ - // { - // $gte: ['$timeEntryData.totalSeconds', 0], - // }, - // '$timeEntryData.totalSeconds', - // 0, - // ], - // }, - // isTangible: { - // $cond: [ - // { - // $gte: ['$timeEntryData.totalSeconds', 0], - // }, - // '$timeEntryData.isTangible', - // false, - // ], - // }, - // role: 1, - // }, - // }, - // { - // $addFields: { - // tangibletime: { - // $cond: [ - // { - // $eq: ['$isTangible', true], - // }, - // '$totalSeconds', - // 0, - // ], - // }, - // }, - // }, - // { - // $group: { - // _id: { - // personId: '$personId', - // weeklycommittedHours: '$weeklycommittedHours', - // name: '$name', - // role: '$role', - // }, - // totalSeconds: { - // $sum: '$totalSeconds', - // }, - // tangibletime: { - // $sum: '$tangibletime', - // }, - // }, - // }, - // { - // $project: { - // _id: 0, - // personId: '$_id.personId', - // name: '$_id.name', - // weeklycommittedHours: '$_id.weeklycommittedHours', - // totaltime_hrs: { - // $divide: ['$totalSeconds', 3600], - // }, - // totaltangibletime_hrs: { - // $divide: ['$tangibletime', 3600], - // }, - // role: '$_id.role', - // }, - // }, - // { - // $lookup: { - // from: 'tasks', - // localField: 'personId', - // foreignField: 'resources.userID', - // as: 'tasks', - // }, - // }, - // { - // $project: { - // tasks: { - // resources: { - // profilePic: 0, - // }, - // }, - // }, - // }, - // { - // $unwind: { - // path: '$tasks', - // preserveNullAndEmptyArrays: true, - // }, - // }, - // { - // $lookup: { - // from: 'wbs', - // localField: 'tasks.wbsId', - // foreignField: '_id', - // as: 'projectId', - // }, - // }, - // { - // $addFields: { - // 'tasks.projectId': { - // $cond: [ - // { $ne: ['$projectId', []] }, - // { $arrayElemAt: ['$projectId', 0] }, - // '$tasks.projectId', - // ], - // }, - // }, - // }, - // { - // $project: { - // projectId: 0, - // tasks: { - // projectId: { - // _id: 0, - // isActive: 0, - // modifiedDatetime: 0, - // wbsName: 0, - // createdDatetime: 0, - // __v: 0, - // }, - // }, - // }, - // }, - // { - // $addFields: { - // 'tasks.projectId': '$tasks.projectId.projectId', - // }, - // }, - // { - // $lookup: { - // from: 'taskNotifications', - // localField: 'tasks._id', - // foreignField: 'taskId', - // as: 'tasks.taskNotifications', - // }, - // }, - // { - // $group: { - // _id: '$personId', - // tasks: { - // $push: '$tasks', - // }, - // data: { - // $first: '$$ROOT', - // }, - // }, - // }, - // { - // $addFields: { - // 'data.tasks': { - // $filter: { - // input: '$tasks', - // as: 'task', - // cond: { $ne: ['$$task', {}] }, - // }, - // }, - // }, - // }, - // { - // $replaceRoot: { - // newRoot: '$data', - // }, - // }, - // ]); + $match: { + _id: userId, + }, + }, + { + $unwind: '$myteam', + }, + { + $project: { + _id: 0, + personId: '$myteam._id', + name: '$myteam.fullName', + role: 1, + }, + }, + // have personId, name, role + { + $lookup: { + from: 'userProfiles', + localField: 'personId', + foreignField: '_id', + as: 'persondata', + }, + }, + { + $match: { + // dashboard tasks user roles hierarchy + $or: [ + { + role: { $in: ['Owner', 'Core Team'] }, + }, + { + $and: [ + { + role: 'Administrator', + }, + { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, + ], + }, + { + $and: [ + { + role: { $in: ['Manager', 'Mentor'] }, + }, + { + 'persondata.0.role': { + $nin: ['Manager', 'Mentor', 'Core Team', 'Administrator', 'Owner'], + }, + }, + ], + }, + { 'persondata.0._id': userId }, + { 'persondata.0.role': 'Volunteer' }, + { 'persondata.0.isVisible': true }, + ], + }, + }, + { + $project: { + personId: 1, + name: 1, + weeklycommittedHours: { + $sum: [ + { + $arrayElemAt: ['$persondata.weeklycommittedHours', 0], + }, + { + $ifNull: [{ $arrayElemAt: ['$persondata.missedHours', 0] }, 0], + }, + ], + }, + role: 1, + }, + }, + { + $lookup: { + from: 'timeEntries', + localField: 'personId', + foreignField: 'personId', + as: 'timeEntryData', + }, + }, + { + $project: { + personId: 1, + name: 1, + weeklycommittedHours: 1, + timeEntryData: { + $filter: { + input: '$timeEntryData', + as: 'timeentry', + cond: { + $and: [ + { + $gte: ['$$timeentry.dateOfWork', pdtstart], + }, + { + $lte: ['$$timeentry.dateOfWork', pdtend], + }, + { + $in: ['$$timeentry.entryType', ['default', null]], + }, + ], + }, + }, + }, + role: 1, + }, + }, + { + $unwind: { + path: '$timeEntryData', + preserveNullAndEmptyArrays: true, + }, + }, + { + $project: { + personId: 1, + name: 1, + weeklycommittedHours: 1, + totalSeconds: { + $cond: [ + { + $gte: ['$timeEntryData.totalSeconds', 0], + }, + '$timeEntryData.totalSeconds', + 0, + ], + }, + isTangible: { + $cond: [ + { + $gte: ['$timeEntryData.totalSeconds', 0], + }, + '$timeEntryData.isTangible', + false, + ], + }, + role: 1, + }, + }, + { + $addFields: { + tangibletime: { + $cond: [ + { + $eq: ['$isTangible', true], + }, + '$totalSeconds', + 0, + ], + }, + }, + }, + { + $group: { + _id: { + personId: '$personId', + weeklycommittedHours: '$weeklycommittedHours', + name: '$name', + role: '$role', + }, + totalSeconds: { + $sum: '$totalSeconds', + }, + tangibletime: { + $sum: '$tangibletime', + }, + }, + }, + { + $project: { + _id: 0, + personId: '$_id.personId', + name: '$_id.name', + weeklycommittedHours: '$_id.weeklycommittedHours', + totaltime_hrs: { + $divide: ['$totalSeconds', 3600], + }, + totaltangibletime_hrs: { + $divide: ['$tangibletime', 3600], + }, + role: '$_id.role', + }, + }, + { + $lookup: { + from: 'tasks', + localField: 'personId', + foreignField: 'resources.userID', + as: 'tasks', + }, + }, + { + $project: { + tasks: { + resources: { + profilePic: 0, + }, + }, + }, + }, + { + $unwind: { + path: '$tasks', + preserveNullAndEmptyArrays: true, + }, + }, + { + $lookup: { + from: 'wbs', + localField: 'tasks.wbsId', + foreignField: '_id', + as: 'projectId', + }, + }, + { + $addFields: { + 'tasks.projectId': { + $cond: [ + { $ne: ['$projectId', []] }, + { $arrayElemAt: ['$projectId', 0] }, + '$tasks.projectId', + ], + }, + }, + }, + { + $project: { + projectId: 0, + tasks: { + projectId: { + _id: 0, + isActive: 0, + modifiedDatetime: 0, + wbsName: 0, + createdDatetime: 0, + __v: 0, + }, + }, + }, + }, + { + $addFields: { + 'tasks.projectId': '$tasks.projectId.projectId', + }, + }, + { + $lookup: { + from: 'taskNotifications', + localField: 'tasks._id', + foreignField: 'taskId', + as: 'tasks.taskNotifications', + }, + }, + { + $group: { + _id: '$personId', + tasks: { + $push: '$tasks', + }, + data: { + $first: '$$ROOT', + }, + }, + }, + { + $addFields: { + 'data.tasks': { + $filter: { + input: '$tasks', + as: 'task', + cond: { $ne: ['$$task', {}] }, + }, + }, + }, + }, + { + $replaceRoot: { + newRoot: '$data', + }, + }, + ]); }; const getTasksForSingleUser = function (userId) { const pdtstart = moment() From e214e9cc7e1c9df313b42c5258c93720f7e07504 Mon Sep 17 00:00:00 2001 From: Vishala Ramasamy Date: Wed, 3 Jan 2024 17:13:02 -0800 Subject: [PATCH 250/272] task api --- src/helpers/taskHelper.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index e1e2acb13..5a17f8b20 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -1,12 +1,6 @@ const moment = require('moment-timezone'); const userProfile = require('../models/userProfile'); -const timeentry = require('../models/timeentry'); -const myTeam = require('../helpers/helperModels/myTeam'); -const team = require('../models/team'); -const Task = require('../models/task'); -const TaskNotification = require('../models/taskNotification'); -const Wbs = require('../models/wbs'); -const mongoose = require('mongoose'); +const myteam = require('../helpers/helperModels/myTeam'); const taskHelper = function () { const getTasksForTeams = async function (userId) { @@ -15,7 +9,6 @@ const taskHelper = function () { const userById = await userProfile.findOne({ _id: userid , isActive:true}, {role:1,firstName:1, lastName:1, role:1, isVisible:1, weeklycommittedHours:1, weeklySummaries:1}) .then((res)=>{ return res; }).catch((e)=>{}); - if(userById==null) return null; const userRole = userById.role; From 38ffc5f0e3b49f88e8a14046440bc07935c8ce81 Mon Sep 17 00:00:00 2001 From: Vishala Ramasamy Date: Wed, 3 Jan 2024 17:29:41 -0800 Subject: [PATCH 251/272] leaderboard ,task api fix --- src/controllers/taskController.js | 2 +- src/helpers/dashboardhelper.js | 611 +++++++++++++++----------- src/helpers/taskHelper.js | 699 ++++++++++++++++++------------ 3 files changed, 771 insertions(+), 541 deletions(-) diff --git a/src/controllers/taskController.js b/src/controllers/taskController.js index 5b087db4d..753dbba11 100644 --- a/src/controllers/taskController.js +++ b/src/controllers/taskController.js @@ -834,7 +834,7 @@ const taskController = function (Task) { const getTasksForTeamsByUser = async (req, res) => { try { const userId = mongoose.Types.ObjectId(req.params.userId); - const teamsData = await taskHelper.getTasksForTeams(userId).exec(); + const teamsData = await taskHelper.getTasksForTeams(userId); if (teamsData.length > 0) { res.status(200).send(teamsData); } else { diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index b7ca2f131..dea392e4f 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -161,6 +161,11 @@ const dashboardhelper = function () { const getLeaderboard = async function (userId) { const userid = mongoose.Types.ObjectId(userId); + const userById = await userProfile.findOne({ _id: userid , isActive:true}, {role:1}) + .then((res)=>{ return res; }).catch((e)=>{}); + + if(userById==null) return null; + const userRole = userById.role; const pdtstart = moment() .tz('America/Los_Angeles') .startOf('week') @@ -169,262 +174,358 @@ const dashboardhelper = function () { .tz('America/Los_Angeles') .endOf('week') .format('YYYY-MM-DD'); - const output = await myTeam.aggregate([ - { - $match: { - _id: userid, - }, - }, - { - $unwind: '$myteam', - }, - { - $project: { - _id: 0, - role: 1, - personId: '$myteam._id', - name: '$myteam.fullName', - }, - }, - { - $lookup: { - from: 'userProfiles', - localField: 'personId', - foreignField: '_id', - as: 'persondata', - }, - }, - { - $match: { - // leaderboard user roles hierarchy - $or: [ - { - role: { $in: ['Owner', 'Core Team'] }, - }, - { - $and: [ - { - role: 'Administrator', - }, - { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, - ], - }, - { - $and: [ - { - role: { $in: ['Manager', 'Mentor'] }, - }, - { - 'persondata.0.role': { - $nin: ['Manager', 'Mentor', 'Core Team', 'Administrator', 'Owner'], - }, - }, - ], - }, - { 'persondata.0._id': userId }, - { 'persondata.0.role': 'Volunteer' }, - { 'persondata.0.isVisible': true }, - ], - }, - }, - { - $project: { - personId: 1, - name: 1, - role: { - $arrayElemAt: ['$persondata.role', 0], - }, - isVisible: { - $arrayElemAt: ['$persondata.isVisible', 0], - }, - hasSummary: { - $ne: [ - { - $arrayElemAt: [ - { - $arrayElemAt: ['$persondata.weeklySummaries.summary', 0], - }, - 0, - ], - }, - '', - ], - }, - weeklycommittedHours: { - $sum: [ - { - $arrayElemAt: ['$persondata.weeklycommittedHours', 0], - }, - { - $ifNull: [{ $arrayElemAt: ['$persondata.missedHours', 0] }, 0], - }, - ], - }, - }, - }, - { - $lookup: { - from: 'timeEntries', - localField: 'personId', - foreignField: 'personId', - as: 'timeEntryData', - }, - }, - { - $project: { - personId: 1, - name: 1, - role: 1, - isVisible: 1, - hasSummary: 1, - weeklycommittedHours: 1, - timeEntryData: { - $filter: { - input: '$timeEntryData', - as: 'timeentry', - cond: { - $and: [ - { - $gte: ['$$timeentry.dateOfWork', pdtstart], - }, - { - $lte: ['$$timeentry.dateOfWork', pdtend], - }, - { - $not: [ - { - $in: ['$$timeentry.entryType', ['person', 'team', 'project']], - }, - ], - }, - ], - }, - }, - }, - }, - }, - { - $unwind: { - path: '$timeEntryData', - preserveNullAndEmptyArrays: true, - }, - }, - { - $project: { - personId: 1, - name: 1, - role: 1, - isVisible: 1, - hasSummary: 1, - weeklycommittedHours: 1, - totalSeconds: { - $cond: [ - { - $gte: ['$timeEntryData.totalSeconds', 0], - }, - '$timeEntryData.totalSeconds', - 0, - ], - }, - isTangible: { - $cond: [ - { - $gte: ['$timeEntryData.totalSeconds', 0], - }, - '$timeEntryData.isTangible', - false, - ], - }, - }, - }, - { - $addFields: { - tangibletime: { - $cond: [ - { - $eq: ['$isTangible', true], - }, - '$totalSeconds', - 0, - ], - }, - intangibletime: { - $cond: [ - { - $eq: ['$isTangible', false], - }, - '$totalSeconds', - 0, - ], - }, - }, - }, - { - $group: { - _id: { - personId: '$personId', - weeklycommittedHours: '$weeklycommittedHours', - name: '$name', - role: '$role', - isVisible: '$isVisible', - hasSummary: '$hasSummary', - }, - totalSeconds: { - $sum: '$totalSeconds', - }, - tangibletime: { - $sum: '$tangibletime', - }, - intangibletime: { - $sum: '$intangibletime', - }, - }, - }, - { - $project: { - _id: 0, - personId: '$_id.personId', - name: '$_id.name', - role: '$_id.role', - isVisible: '$_id.isVisible', - hasSummary: '$_id.hasSummary', - weeklycommittedHours: '$_id.weeklycommittedHours', - totaltime_hrs: { - $divide: ['$totalSeconds', 3600], - }, - totaltangibletime_hrs: { - $divide: ['$tangibletime', 3600], - }, - totalintangibletime_hrs: { - $divide: ['$intangibletime', 3600], - }, - percentagespentintangible: { - $cond: [ - { - $eq: ['$totalSeconds', 0], - }, - 0, - { - $multiply: [ - { - $divide: ['$tangibletime', '$totalSeconds'], - }, - 100, - ], - }, - ], - }, - }, - }, - { - $sort: { - totaltangibletime_hrs: -1, - name: 1, - role: 1, - }, + + let teamMemberIds = [userid] + let teamMembers = []; + + if(userRole!='Administrator' && userRole!='Owner' && userRole!='Core Team') //Manager , Mentor , Volunteer ... , Show only team members + { + + const teamsResult = await team.find( { "members.userId": { $in: [userid] } }, {members:1} ) + .then((res)=>{ return res; }).catch((e)=>{}) + + teamsResult.map((_myTeam)=>{ + _myTeam.members.map((teamMember)=> { + if(!teamMember.userId.equals(userid)) + teamMemberIds.push( teamMember.userId ); + } ) + }) + + teamMembers = await userProfile.find({ _id: { $in: teamMemberIds } , isActive:true }, + {role:1,firstName:1,lastName:1,isVisible:1,weeklycommittedHours:1,weeklySummaries:1}) + .then((res)=>{ return res; }).catch((e)=>{}) + + } + else { + if(userRole == 'Administrator'){ //All users except Owner and Core Team + const excludedRoles = ['Core Team', 'Owner']; + teamMembers = await userProfile.find({ isActive:true , role: { $nin: excludedRoles } }, + {role:1,firstName:1,lastName:1,isVisible:1,weeklycommittedHours:1,weeklySummaries:1}) + .then((res)=>{ return res; }).catch((e)=>{}) + } + else{ //'Core Team', 'Owner' //All users + teamMembers = await userProfile.find({ isActive:true}, + {role:1,firstName:1,lastName:1,isVisible:1,weeklycommittedHours:1,weeklySummaries:1}) + .then((res)=>{ return res; }).catch((e)=>{}) + } + + + } + + teamMemberIds = teamMembers.map(member => member._id); + + const timeEntries = await timeentry.find({ + dateOfWork: { + $gte: pdtstart, + $lte: pdtend, }, - ]); - return output; + personId: { $in: teamMemberIds } + }); + + let timeEntryByPerson = {} + timeEntries.map((timeEntry)=>{ + + let personIdStr = timeEntry.personId.toString(); + + if(timeEntryByPerson[personIdStr]==null) + timeEntryByPerson[personIdStr] = {tangibleSeconds:0,intangibleSeconds:0,totalSeconds:0}; + + if (timeEntry.isTangible === true) { + timeEntryByPerson[personIdStr].tangibleSeconds += timeEntry.totalSeconds; + } else { + timeEntryByPerson[personIdStr].intangibleSeconds += timeEntry.totalSeconds; + } + + timeEntryByPerson[personIdStr].totalSeconds += timeEntry.totalSeconds; + }) + + + let leaderBoardData = []; + teamMembers.map((teamMember)=>{ + let obj = { + personId : teamMember._id, + role : teamMember.role, + name : teamMember.firstName + ' ' + teamMember.lastName, + isVisible : teamMember.isVisible, + hasSummary : teamMember.weeklySummaries?.length > 0 ? teamMember.weeklySummaries[0].summary!='' : false, + weeklycommittedHours : teamMember.weeklycommittedHours, + totaltangibletime_hrs : ((timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / 3600) || 0), + totalintangibletime_hrs : ((timeEntryByPerson[teamMember._id.toString()]?.intangibleSeconds / 3600) || 0), + totaltime_hrs : ((timeEntryByPerson[teamMember._id.toString()]?.totalSeconds / 3600) || 0), + percentagespentintangible : + (timeEntryByPerson[teamMember._id.toString()] && timeEntryByPerson[teamMember._id.toString()]?.totalSeconds !=0 && timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds !=0) ? + (timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / timeEntryByPerson[teamMember._id.toString()]?.totalSeconds) * 100 + : + 0 + } + leaderBoardData.push(obj); + }) + + let sortedLBData = leaderBoardData.sort((a, b) => { + // Sort by totaltangibletime_hrs in descending order + if (b.totaltangibletime_hrs !== a.totaltangibletime_hrs) { + return b.totaltangibletime_hrs - a.totaltangibletime_hrs; + } + + // Then sort by name in ascending order + if (a.name !== b.name) { + return a.name.localeCompare(b.name); + } + + // Finally, sort by role in ascending order + return a.role.localeCompare(b.role); + }); + + return sortedLBData; + + // return myTeam.aggregate([ + // { + // $match: { + // _id: userid, + // }, + // }, + // { + // $unwind: '$myteam', + // }, + // { + // $project: { + // _id: 0, + // role: 1, + // personId: '$myteam._id', + // name: '$myteam.fullName', + // }, + // }, + // { + // $lookup: { + // from: 'userProfiles', + // localField: 'personId', + // foreignField: '_id', + // as: 'persondata', + // }, + // }, + // { + // $match: { + // // leaderboard user roles hierarchy + // $or: [ + // { + // role: { $in: ['Owner', 'Core Team'] }, + // }, + // { + // $and: [ + // { + // role: 'Administrator', + // }, + // { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, + // ], + // }, + // { + // $and: [ + // { + // role: { $in: ['Manager', 'Mentor'] }, + // }, + // { + // 'persondata.0.role': { + // $nin: ['Manager', 'Mentor', 'Core Team', 'Administrator', 'Owner'], + // }, + // }, + // ], + // }, + // { 'persondata.0._id': userId }, + // { 'persondata.0.role': 'Volunteer' }, + // { 'persondata.0.isVisible': true }, + // ], + // }, + // }, + // { + // $project: { + // personId: 1, + // name: 1, + // role: { + // $arrayElemAt: ['$persondata.role', 0], + // }, + // isVisible: { + // $arrayElemAt: ['$persondata.isVisible', 0], + // }, + // hasSummary: { + // $ne: [ + // { + // $arrayElemAt: [ + // { + // $arrayElemAt: ['$persondata.weeklySummaries.summary', 0], + // }, + // 0, + // ], + // }, + // '', + // ], + // }, + // weeklycommittedHours: { + // $sum: [ + // { + // $arrayElemAt: ['$persondata.weeklycommittedHours', 0], + // }, + // { + // $ifNull: [{ $arrayElemAt: ['$persondata.missedHours', 0] }, 0], + // }, + // ], + // }, + // }, + // }, + // { + // $lookup: { + // from: 'timeEntries', + // localField: 'personId', + // foreignField: 'personId', + // as: 'timeEntryData', + // }, + // }, + // { + // $project: { + // personId: 1, + // name: 1, + // role: 1, + // isVisible: 1, + // hasSummary: 1, + // weeklycommittedHours: 1, + // timeEntryData: { + // $filter: { + // input: '$timeEntryData', + // as: 'timeentry', + // cond: { + // $and: [ + // { + // $gte: ['$$timeentry.dateOfWork', pdtstart], + // }, + // { + // $lte: ['$$timeentry.dateOfWork', pdtend], + // }, + // ], + // }, + // }, + // }, + // }, + // }, + // { + // $unwind: { + // path: '$timeEntryData', + // preserveNullAndEmptyArrays: true, + // }, + // }, + // { + // $project: { + // personId: 1, + // name: 1, + // role: 1, + // isVisible: 1, + // hasSummary: 1, + // weeklycommittedHours: 1, + // totalSeconds: { + // $cond: [ + // { + // $gte: ['$timeEntryData.totalSeconds', 0], + // }, + // '$timeEntryData.totalSeconds', + // 0, + // ], + // }, + // isTangible: { + // $cond: [ + // { + // $gte: ['$timeEntryData.totalSeconds', 0], + // }, + // '$timeEntryData.isTangible', + // false, + // ], + // }, + // }, + // }, + // { + // $addFields: { + // tangibletime: { + // $cond: [ + // { + // $eq: ['$isTangible', true], + // }, + // '$totalSeconds', + // 0, + // ], + // }, + // intangibletime: { + // $cond: [ + // { + // $eq: ['$isTangible', false], + // }, + // '$totalSeconds', + // 0, + // ], + // }, + // }, + // }, + // { + // $group: { + // _id: { + // personId: '$personId', + // weeklycommittedHours: '$weeklycommittedHours', + // name: '$name', + // role: '$role', + // isVisible: '$isVisible', + // hasSummary: '$hasSummary', + // }, + // totalSeconds: { + // $sum: '$totalSeconds', + // }, + // tangibletime: { + // $sum: '$tangibletime', + // }, + // intangibletime: { + // $sum: '$intangibletime', + // }, + // }, + // }, + // { + // $project: { + // _id: 0, + // personId: '$_id.personId', + // name: '$_id.name', + // role: '$_id.role', + // isVisible: '$_id.isVisible', + // hasSummary: '$_id.hasSummary', + // weeklycommittedHours: '$_id.weeklycommittedHours', + // totaltime_hrs: { + // $divide: ['$totalSeconds', 3600], + // }, + // totaltangibletime_hrs: { + // $divide: ['$tangibletime', 3600], + // }, + // totalintangibletime_hrs: { + // $divide: ['$intangibletime', 3600], + // }, + // percentagespentintangible: { + // $cond: [ + // { + // $eq: ['$totalSeconds', 0], + // }, + // 0, + // { + // $multiply: [ + // { + // $divide: ['$tangibletime', '$totalSeconds'], + // }, + // 100, + // ], + // }, + // ], + // }, + // }, + // }, + // { + // $sort: { + // totaltangibletime_hrs: -1, + // name: 1, + // role: 1, + // }, + // }, + // ]); }; /** diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index cfb1235fd..9135f7573 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -3,7 +3,14 @@ const userProfile = require('../models/userProfile'); const myteam = require('../helpers/helperModels/myTeam'); const taskHelper = function () { - const getTasksForTeams = function (userId) { + const getTasksForTeams = async function (userId) { + const userid = mongoose.Types.ObjectId(userId); + const userById = await userProfile.findOne({ _id: userid , isActive:true}, {role:1,firstName:1, lastName:1, role:1, isVisible:1, weeklycommittedHours:1, weeklySummaries:1}) + .then((res)=>{ return res; }).catch((e)=>{}); + + if(userById==null) return null; + const userRole = userById.role; + const pdtstart = moment() .tz('America/Los_Angeles') .startOf('week') @@ -12,291 +19,413 @@ const taskHelper = function () { .tz('America/Los_Angeles') .endOf('week') .format('YYYY-MM-DD'); - return myteam.aggregate([ - { - $match: { - _id: userId, - }, - }, - { - $unwind: '$myteam', - }, - { - $project: { - _id: 0, - personId: '$myteam._id', - name: '$myteam.fullName', - role: 1, - }, - }, - // have personId, name, role - { - $lookup: { - from: 'userProfiles', - localField: 'personId', - foreignField: '_id', - as: 'persondata', - }, - }, - { - $match: { - // dashboard tasks user roles hierarchy - $or: [ - { - role: { $in: ['Owner', 'Core Team'] }, - }, - { - $and: [ - { - role: 'Administrator', - }, - { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, - ], - }, - { - $and: [ - { - role: { $in: ['Manager', 'Mentor'] }, - }, - { - 'persondata.0.role': { - $nin: ['Manager', 'Mentor', 'Core Team', 'Administrator', 'Owner'], - }, - }, - ], - }, - { 'persondata.0._id': userId }, - { 'persondata.0.role': 'Volunteer' }, - { 'persondata.0.isVisible': true }, - ], - }, - }, - { - $project: { - personId: 1, - name: 1, - weeklycommittedHours: { - $sum: [ - { - $arrayElemAt: ['$persondata.weeklycommittedHours', 0], - }, - { - $ifNull: [{ $arrayElemAt: ['$persondata.missedHours', 0] }, 0], - }, - ], - }, - role: 1, - }, - }, - { - $lookup: { - from: 'timeEntries', - localField: 'personId', - foreignField: 'personId', - as: 'timeEntryData', - }, - }, - { - $project: { - personId: 1, - name: 1, - weeklycommittedHours: 1, - timeEntryData: { - $filter: { - input: '$timeEntryData', - as: 'timeentry', - cond: { - $and: [ - { - $gte: ['$$timeentry.dateOfWork', pdtstart], - }, - { - $lte: ['$$timeentry.dateOfWork', pdtend], - }, - { - $in: ['$$timeentry.entryType', ['default', null]], - }, - ], - }, - }, - }, - role: 1, - }, - }, - { - $unwind: { - path: '$timeEntryData', - preserveNullAndEmptyArrays: true, - }, - }, - { - $project: { - personId: 1, - name: 1, - weeklycommittedHours: 1, - totalSeconds: { - $cond: [ - { - $gte: ['$timeEntryData.totalSeconds', 0], - }, - '$timeEntryData.totalSeconds', - 0, - ], - }, - isTangible: { - $cond: [ - { - $gte: ['$timeEntryData.totalSeconds', 0], - }, - '$timeEntryData.isTangible', - false, - ], - }, - role: 1, - }, - }, - { - $addFields: { - tangibletime: { - $cond: [ - { - $eq: ['$isTangible', true], - }, - '$totalSeconds', - 0, - ], - }, - }, - }, - { - $group: { - _id: { - personId: '$personId', - weeklycommittedHours: '$weeklycommittedHours', - name: '$name', - role: '$role', - }, - totalSeconds: { - $sum: '$totalSeconds', - }, - tangibletime: { - $sum: '$tangibletime', - }, - }, - }, - { - $project: { - _id: 0, - personId: '$_id.personId', - name: '$_id.name', - weeklycommittedHours: '$_id.weeklycommittedHours', - totaltime_hrs: { - $divide: ['$totalSeconds', 3600], - }, - totaltangibletime_hrs: { - $divide: ['$tangibletime', 3600], - }, - role: '$_id.role', - }, - }, - { - $lookup: { - from: 'tasks', - localField: 'personId', - foreignField: 'resources.userID', - as: 'tasks', - }, - }, - { - $project: { - tasks: { - resources: { - profilePic: 0, - }, - }, - }, - }, - { - $unwind: { - path: '$tasks', - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: 'wbs', - localField: 'tasks.wbsId', - foreignField: '_id', - as: 'projectId', - }, - }, - { - $addFields: { - 'tasks.projectId': { - $cond: [ - { $ne: ['$projectId', []] }, - { $arrayElemAt: ['$projectId', 0] }, - '$tasks.projectId', - ], - }, - }, - }, - { - $project: { - projectId: 0, - tasks: { - projectId: { - _id: 0, - isActive: 0, - modifiedDatetime: 0, - wbsName: 0, - createdDatetime: 0, - __v: 0, - }, - }, - }, - }, - { - $addFields: { - 'tasks.projectId': '$tasks.projectId.projectId', - }, - }, - { - $lookup: { - from: 'taskNotifications', - localField: 'tasks._id', - foreignField: 'taskId', - as: 'tasks.taskNotifications', - }, - }, - { - $group: { - _id: '$personId', - tasks: { - $push: '$tasks', - }, - data: { - $first: '$$ROOT', - }, - }, - }, - { - $addFields: { - 'data.tasks': { - $filter: { - input: '$tasks', - as: 'task', - cond: { $ne: ['$$task', {}] }, - }, - }, - }, - }, + + let teamMemberIds = [userid] + let teamMembers = []; + + if(userRole!='Administrator' && userRole!='Owner' && userRole!='Core Team') //Manager , Mentor , Volunteer ... , Show only team members { - $replaceRoot: { - newRoot: '$data', - }, - }, - ]); + + const teamsResult = await team.find( { "members.userId": { $in: [userid] } }, {members:1} ) + .then((res)=>{ return res; }).catch((e)=>{}) + + teamsResult.map((_myTeam)=>{ + _myTeam.members.map((teamMember)=> { + if(!teamMember.userId.equals(userid)) + teamMemberIds.push( teamMember.userId ); + } ) + }) + + teamMembers = await userProfile.find({ _id: { $in: teamMemberIds } , isActive:true }, + {role:1,firstName:1,lastName:1,weeklycommittedHours:1}) + .then((res)=>{ return res; }).catch((e)=>{}) + } + else { + if(userRole == 'Administrator'){ //All users except Owner and Core Team + const excludedRoles = ['Core Team', 'Owner']; + teamMembers = await userProfile.find({ isActive:true , role: { $nin: excludedRoles } }, + {role:1,firstName:1,lastName:1,weeklycommittedHours:1}) + .then((res)=>{ return res; }).catch((e)=>{}) + } + else{ //'Core Team', 'Owner' //All users + teamMembers = await userProfile.find({ isActive:true}, + {role:1,firstName:1,lastName:1,weeklycommittedHours:1}) + .then((res)=>{ return res; }).catch((e)=>{}) + } + } + + teamMemberIds = teamMembers.map(member => member._id); + + const timeEntries = await timeentry.find({ + dateOfWork: { + $gte: pdtstart, + $lte: pdtend, + }, + personId: { $in: teamMemberIds } + }); + + let timeEntryByPerson = {} + timeEntries.map((timeEntry)=>{ + + let personIdStr = timeEntry.personId.toString(); + + if(timeEntryByPerson[personIdStr]==null) + timeEntryByPerson[personIdStr] = {tangibleSeconds:0,intangibleSeconds:0,totalSeconds:0}; + + if (timeEntry.isTangible === true) { + timeEntryByPerson[personIdStr].tangibleSeconds += timeEntry.totalSeconds; + } + timeEntryByPerson[personIdStr].totalSeconds += timeEntry.totalSeconds; + }) + + const teamMemberTasks = await Task.find({"resources.userID" : {$in : teamMemberIds }}, { 'resources.profilePic': 0 }) + .populate( { + path: 'wbsId', + select: 'projectId', + }) + const teamMemberTaskIds = teamMemberTasks.map(task => task._id); + const teamMemberTaskNotifications = await TaskNotification.find({"taskId" : {$in : teamMemberTaskIds }}) + + const taskNotificationByTaskNdUser = [] + teamMemberTaskNotifications.map(teamMemberTaskNotification => { + + let taskIdStr = teamMemberTaskNotification.taskId.toString(); + let userIdStr = teamMemberTaskNotification.userId.toString(); + let taskNdUserID = taskIdStr+","+userIdStr; + + if(taskNotificationByTaskNdUser[taskNdUserID]) { + taskNotificationByTaskNdUser[taskNdUserID].push(teamMemberTaskNotification) + } + else{ + taskNotificationByTaskNdUser[taskNdUserID] = [teamMemberTaskNotification] + } + + }) + + const taskByPerson = [] + + teamMemberTasks.map(teamMemberTask => { + + let projId = teamMemberTask.wbsId?.projectId; + let _teamMemberTask = {...teamMemberTask._doc} + _teamMemberTask.projectId = projId; + let taskIdStr = _teamMemberTask._id.toString(); + + teamMemberTask.resources.map(resource => { + + let resourceIdStr = resource.userID.toString(); + let taskNdUserID = taskIdStr+","+resourceIdStr; + _teamMemberTask.taskNotifications = taskNotificationByTaskNdUser[taskNdUserID] || [] + if(taskByPerson[resourceIdStr]) { + taskByPerson[resourceIdStr].push(_teamMemberTask) + } + else{ + taskByPerson[resourceIdStr] = [_teamMemberTask] + } + }) + }) + + + let teamMemberTasksData = []; + teamMembers.map((teamMember)=>{ + let obj = { + personId : teamMember._id, + role : teamMember.role, + name : teamMember.firstName + ' ' + teamMember.lastName, + weeklycommittedHours : teamMember.weeklycommittedHours, + totaltangibletime_hrs : ((timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / 3600) || 0), + totaltime_hrs : ((timeEntryByPerson[teamMember._id.toString()]?.totalSeconds / 3600) || 0), + tasks : taskByPerson[teamMember._id.toString()] || [] + } + teamMemberTasksData.push(obj); + }) + + + return teamMemberTasksData; + + + // return myteam.aggregate([ + // { + // $match: { + // _id: userId, + // }, + // }, + // { + // $unwind: '$myteam', + // }, + // { + // $project: { + // _id: 0, + // personId: '$myteam._id', + // name: '$myteam.fullName', + // role: 1, + // }, + // }, + // // have personId, name, role + // { + // $lookup: { + // from: 'userProfiles', + // localField: 'personId', + // foreignField: '_id', + // as: 'persondata', + // }, + // }, + // { + // $match: { + // // dashboard tasks user roles hierarchy + // $or: [ + // { + // role: { $in: ['Owner', 'Core Team'] }, + // }, + // { + // $and: [ + // { + // role: 'Administrator', + // }, + // { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, + // ], + // }, + // { + // $and: [ + // { + // role: { $in: ['Manager', 'Mentor'] }, + // }, + // { + // 'persondata.0.role': { + // $nin: ['Manager', 'Mentor', 'Core Team', 'Administrator', 'Owner'], + // }, + // }, + // ], + // }, + // { 'persondata.0._id': userId }, + // { 'persondata.0.role': 'Volunteer' }, + // { 'persondata.0.isVisible': true }, + // ], + // }, + // }, + // { + // $project: { + // personId: 1, + // name: 1, + // weeklycommittedHours: { + // $sum: [ + // { + // $arrayElemAt: ['$persondata.weeklycommittedHours', 0], + // }, + // { + // $ifNull: [{ $arrayElemAt: ['$persondata.missedHours', 0] }, 0], + // }, + // ], + // }, + // role: 1, + // }, + // }, + // { + // $lookup: { + // from: 'timeEntries', + // localField: 'personId', + // foreignField: 'personId', + // as: 'timeEntryData', + // }, + // }, + // { + // $project: { + // personId: 1, + // name: 1, + // weeklycommittedHours: 1, + // timeEntryData: { + // $filter: { + // input: '$timeEntryData', + // as: 'timeentry', + // cond: { + // $and: [ + // { + // $gte: ['$$timeentry.dateOfWork', pdtstart], + // }, + // { + // $lte: ['$$timeentry.dateOfWork', pdtend], + // }, + // ], + // }, + // }, + // }, + // role: 1, + // }, + // }, + // { + // $unwind: { + // path: '$timeEntryData', + // preserveNullAndEmptyArrays: true, + // }, + // }, + // { + // $project: { + // personId: 1, + // name: 1, + // weeklycommittedHours: 1, + // totalSeconds: { + // $cond: [ + // { + // $gte: ['$timeEntryData.totalSeconds', 0], + // }, + // '$timeEntryData.totalSeconds', + // 0, + // ], + // }, + // isTangible: { + // $cond: [ + // { + // $gte: ['$timeEntryData.totalSeconds', 0], + // }, + // '$timeEntryData.isTangible', + // false, + // ], + // }, + // role: 1, + // }, + // }, + // { + // $addFields: { + // tangibletime: { + // $cond: [ + // { + // $eq: ['$isTangible', true], + // }, + // '$totalSeconds', + // 0, + // ], + // }, + // }, + // }, + // { + // $group: { + // _id: { + // personId: '$personId', + // weeklycommittedHours: '$weeklycommittedHours', + // name: '$name', + // role: '$role', + // }, + // totalSeconds: { + // $sum: '$totalSeconds', + // }, + // tangibletime: { + // $sum: '$tangibletime', + // }, + // }, + // }, + // { + // $project: { + // _id: 0, + // personId: '$_id.personId', + // name: '$_id.name', + // weeklycommittedHours: '$_id.weeklycommittedHours', + // totaltime_hrs: { + // $divide: ['$totalSeconds', 3600], + // }, + // totaltangibletime_hrs: { + // $divide: ['$tangibletime', 3600], + // }, + // role: '$_id.role', + // }, + // }, + // { + // $lookup: { + // from: 'tasks', + // localField: 'personId', + // foreignField: 'resources.userID', + // as: 'tasks', + // }, + // }, + // { + // $project: { + // tasks: { + // resources: { + // profilePic: 0, + // }, + // }, + // }, + // }, + // { + // $unwind: { + // path: '$tasks', + // preserveNullAndEmptyArrays: true, + // }, + // }, + // { + // $lookup: { + // from: 'wbs', + // localField: 'tasks.wbsId', + // foreignField: '_id', + // as: 'projectId', + // }, + // }, + // { + // $addFields: { + // 'tasks.projectId': { + // $cond: [ + // { $ne: ['$projectId', []] }, + // { $arrayElemAt: ['$projectId', 0] }, + // '$tasks.projectId', + // ], + // }, + // }, + // }, + // { + // $project: { + // projectId: 0, + // tasks: { + // projectId: { + // _id: 0, + // isActive: 0, + // modifiedDatetime: 0, + // wbsName: 0, + // createdDatetime: 0, + // __v: 0, + // }, + // }, + // }, + // }, + // { + // $addFields: { + // 'tasks.projectId': '$tasks.projectId.projectId', + // }, + // }, + // { + // $lookup: { + // from: 'taskNotifications', + // localField: 'tasks._id', + // foreignField: 'taskId', + // as: 'tasks.taskNotifications', + // }, + // }, + // { + // $group: { + // _id: '$personId', + // tasks: { + // $push: '$tasks', + // }, + // data: { + // $first: '$$ROOT', + // }, + // }, + // }, + // { + // $addFields: { + // 'data.tasks': { + // $filter: { + // input: '$tasks', + // as: 'task', + // cond: { $ne: ['$$task', {}] }, + // }, + // }, + // }, + // }, + // { + // $replaceRoot: { + // newRoot: '$data', + // }, + // }, + // ]); }; const getTasksForSingleUser = function (userId) { const pdtstart = moment() From 3784309815e64465d8210ec6e08ec5b6ef1d4256 Mon Sep 17 00:00:00 2001 From: Vishala Ramasamy Date: Wed, 3 Jan 2024 17:37:23 -0800 Subject: [PATCH 252/272] fix imports --- src/helpers/dashboardhelper.js | 2 ++ src/helpers/taskHelper.js | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index dea392e4f..929b5781b 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -3,6 +3,8 @@ const mongoose = require('mongoose'); const userProfile = require('../models/userProfile'); const timeentry = require('../models/timeentry'); const myTeam = require('../helpers/helperModels/myTeam'); +const team = require('../models/team'); + const dashboardhelper = function () { const personaldetails = function (userId) { diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index 9135f7573..8c45df737 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -1,6 +1,12 @@ const moment = require('moment-timezone'); const userProfile = require('../models/userProfile'); -const myteam = require('../helpers/helperModels/myTeam'); +const timeentry = require('../models/timeentry'); +const myTeam = require('../helpers/helperModels/myTeam'); +const team = require('../models/team'); +const Task = require('../models/task'); +const TaskNotification = require('../models/taskNotification'); +const Wbs = require('../models/wbs'); +const mongoose = require('mongoose'); const taskHelper = function () { const getTasksForTeams = async function (userId) { From 037cc6f1b28407af489643e7a65bd6449001473c Mon Sep 17 00:00:00 2001 From: Carl Bebli Date: Thu, 4 Jan 2024 13:11:23 +0000 Subject: [PATCH 253/272] took out the cc for review requests --- src/controllers/taskController.js | 460 +++++++++++++++++------------- 1 file changed, 263 insertions(+), 197 deletions(-) diff --git a/src/controllers/taskController.js b/src/controllers/taskController.js index 753dbba11..126d17914 100644 --- a/src/controllers/taskController.js +++ b/src/controllers/taskController.js @@ -1,10 +1,10 @@ -const mongoose = require('mongoose'); -const WBS = require('../models/wbs'); -const UserProfile = require('../models/userProfile'); -const timeEntryHelper = require('../helpers/timeEntryHelper')(); -const taskHelper = require('../helpers/taskHelper')(); -const { hasPermission } = require('../utilities/permissions'); -const emailSender = require('../utilities/emailSender'); +const mongoose = require("mongoose"); +const WBS = require("../models/wbs"); +const UserProfile = require("../models/userProfile"); +const timeEntryHelper = require("../helpers/timeEntryHelper")(); +const taskHelper = require("../helpers/taskHelper")(); +const { hasPermission } = require("../utilities/permissions"); +const emailSender = require("../utilities/emailSender"); const taskController = function (Task) { const getTasks = (req, res) => { @@ -17,7 +17,7 @@ const taskController = function (Task) { const { mother } = req.params; - if (mother !== '0') { + if (mother !== "0") { query = { wbsId: { $in: [req.params.wbsId] }, level: { $in: [level] }, @@ -26,16 +26,16 @@ const taskController = function (Task) { } Task.find(query) - .then(results => res.status(200).send(results)) - .catch(error => res.status(404).send(error)); + .then((results) => res.status(200).send(results)) + .catch((error) => res.status(404).send(error)); }; const getWBSId = (req, res) => { const { wbsId } = req.params; WBS.findById(wbsId) - .then(results => res.status(200).send(results)) - .catch(error => res.status(404).send(error)); + .then((results) => res.status(200).send(results)) + .catch((error) => res.status(404).send(error)); }; const updateSumUp = ( @@ -45,7 +45,7 @@ const taskController = function (Task) { hoursMost, hoursLogged, estimatedHours, - resources, + resources ) => { Task.findById(taskId, (error, task) => { task.hoursBest = hoursBest; @@ -81,10 +81,10 @@ const taskController = function (Task) { }; const calculateSubTasks = (level, tasks) => { - const parentTasks = tasks.filter(task => task.level === level); + const parentTasks = tasks.filter((task) => task.level === level); parentTasks.forEach((task) => { const childTasks = tasks.filter( - taskChild => taskChild.level === level + 1, + (taskChild) => taskChild.level === level + 1 ); let sumHoursBest = 0; let sumHoursWorst = 0; @@ -96,14 +96,19 @@ const taskController = function (Task) { childTasks.forEach((childTask) => { if (childTask.mother.equals(task.taskId)) { hasChild = true; - sumHoursBest = parseFloat(childTask.hoursBest, 10) + parseFloat(sumHoursBest, 10); - sumHoursWorst = parseFloat(childTask.hoursWorst, 10) - + parseFloat(sumHoursWorst, 10); - sumHoursMost = parseFloat(childTask.hoursMost, 10) + parseFloat(sumHoursMost, 10); - sumHoursLogged = parseFloat(childTask.hoursLogged, 10) - + parseFloat(sumHoursLogged, 10); - sumEstimatedHours = parseFloat(childTask.estimatedHours, 10) - + parseFloat(sumEstimatedHours, 10); + sumHoursBest = + parseFloat(childTask.hoursBest, 10) + parseFloat(sumHoursBest, 10); + sumHoursWorst = + parseFloat(childTask.hoursWorst, 10) + + parseFloat(sumHoursWorst, 10); + sumHoursMost = + parseFloat(childTask.hoursMost, 10) + parseFloat(sumHoursMost, 10); + sumHoursLogged = + parseFloat(childTask.hoursLogged, 10) + + parseFloat(sumHoursLogged, 10); + sumEstimatedHours = + parseFloat(childTask.estimatedHours, 10) + + parseFloat(sumEstimatedHours, 10); childTask.resources.forEach((member) => { let isInResource = false; resources.forEach((mem) => { @@ -136,7 +141,7 @@ const taskController = function (Task) { sumHoursMost, sumHoursLogged, sumEstimatedHours, - resources, + resources ); } }); @@ -144,10 +149,10 @@ const taskController = function (Task) { }; const setDatesSubTasks = (level, tasks) => { - const parentTasks = tasks.filter(task => task.level === level); + const parentTasks = tasks.filter((task) => task.level === level); parentTasks.forEach((task) => { const childTasks = tasks.filter( - taskChild => taskChild.level === level + 1, + (taskChild) => taskChild.level === level + 1 ); let minStartedDate = task.startedDatetime; let maxDueDatetime = task.dueDatetime; @@ -178,10 +183,10 @@ const taskController = function (Task) { }; const calculatePriority = (level, tasks) => { - const parentTasks = tasks.filter(task => task.level === level); + const parentTasks = tasks.filter((task) => task.level === level); parentTasks.forEach((task) => { const childTasks = tasks.filter( - taskChild => taskChild.level === level + 1, + (taskChild) => taskChild.level === level + 1 ); let totalNumberPriority = 0; let totalChild = 0; @@ -190,11 +195,11 @@ const taskController = function (Task) { if (childTask.mother.equals(task.taskId)) { hasChild = true; totalChild += 1; - if (childTask.priority === 'Primary') { + if (childTask.priority === "Primary") { totalNumberPriority += 3; - } else if (childTask.priority === 'Secondary') { + } else if (childTask.priority === "Secondary") { totalNumberPriority += 2; - } else if (childTask.priority === 'Tertiary') { + } else if (childTask.priority === "Tertiary") { totalNumberPriority += 1; } } @@ -207,11 +212,11 @@ const taskController = function (Task) { if (mainTask._id.equals(task._id)) { const avg = totalNumberPriority / totalChild; if (avg <= 1.6) { - priority = 'Tertiary'; + priority = "Tertiary"; } else if (avg > 1.6 && avg < 2.5) { - priority = 'Secondary'; + priority = "Secondary"; } else { - priority = 'Primary'; + priority = "Primary"; } } }); @@ -222,10 +227,10 @@ const taskController = function (Task) { }; const setAssigned = (level, tasks) => { - const parentTasks = tasks.filter(task => task.level === level); + const parentTasks = tasks.filter((task) => task.level === level); parentTasks.forEach((task) => { const childTasks = tasks.filter( - taskChild => taskChild.level === level + 1, + (taskChild) => taskChild.level === level + 1 ); let isAssigned = false; let hasChild = false; @@ -259,7 +264,7 @@ const taskController = function (Task) { { wbsId: { $in: [wbsId] } }, ], }).then((tasks) => { - tasks = [...new Set(tasks.map(item => item))]; + tasks = [...new Set(tasks.map((item) => item))]; for (let lv = 3; lv > 0; lv -= 1) { calculateSubTasks(lv, tasks); setDatesSubTasks(lv, tasks); @@ -285,18 +290,20 @@ const taskController = function (Task) { const tasksWithId = tasks.map((task) => { const _id = new mongoose.Types.ObjectId(); const resources = task.resources.map((resource) => { - const [name, userID, profilePic] = resource.split('|'); + const [name, userID, profilePic] = resource.split("|"); return { name, userID, profilePic }; }); return { - ...task, _id, resources, + ...task, + _id, + resources, }; }); // update tasks makes sure its parentIds and mother props are correct assigned, tasksWithId.forEach((task) => { - const taskNumArr = task.num.split('.'); + const taskNumArr = task.num.split("."); switch (task.level) { case 1: // task.num is x, no parentId1 or mother task.parentId1 = null; // no parent so its value is null @@ -305,21 +312,34 @@ const taskController = function (Task) { task.mother = null; break; case 2: // task.num is x.x, only has one level of parent (x) - task.parentId1 = tasksWithId.find(pTask => pTask.num === taskNumArr[0])._id; // task of parentId1 has num prop of x + task.parentId1 = tasksWithId.find( + (pTask) => pTask.num === taskNumArr[0] + )._id; // task of parentId1 has num prop of x task.parentId2 = null; task.parentId3 = null; task.mother = task.parentId1; // parent task num prop is x break; case 3: // task.num is x.x.x, has two levels of parent (parent: x.x and grandparent: x) - task.parentId1 = tasksWithId.find(pTask => pTask.num === taskNumArr[0])._id; // task of parentId1 has num prop of x - task.parentId2 = tasksWithId.find(pTask => pTask.num === `${taskNumArr[0]}.${taskNumArr[1]}`)._id; // task of parentId2 has num prop of x.x + task.parentId1 = tasksWithId.find( + (pTask) => pTask.num === taskNumArr[0] + )._id; // task of parentId1 has num prop of x + task.parentId2 = tasksWithId.find( + (pTask) => pTask.num === `${taskNumArr[0]}.${taskNumArr[1]}` + )._id; // task of parentId2 has num prop of x.x task.parentId3 = null; task.mother = task.parentId2; // parent task num prop is x.x break; case 4: // task.num is x.x.x.x, has three levels of parent (x.x.x, x.x and x) - task.parentId1 = tasksWithId.find(pTask => pTask.num === taskNumArr[0])._id; // x - task.parentId2 = tasksWithId.find(pTask => pTask.num === `${taskNumArr[0]}.${taskNumArr[1]}`)._id; // x.x - task.parentId3 = tasksWithId.find(pTask => pTask.num === `${taskNumArr[0]}.${taskNumArr[1]}.${taskNumArr[2]}`)._id; // x.x.x + task.parentId1 = tasksWithId.find( + (pTask) => pTask.num === taskNumArr[0] + )._id; // x + task.parentId2 = tasksWithId.find( + (pTask) => pTask.num === `${taskNumArr[0]}.${taskNumArr[1]}` + )._id; // x.x + task.parentId3 = tasksWithId.find( + (pTask) => + pTask.num === `${taskNumArr[0]}.${taskNumArr[1]}.${taskNumArr[2]}` + )._id; // x.x.x task.mother = task.parentId3; // parent task num prop is x.x.x break; default: @@ -327,7 +347,9 @@ const taskController = function (Task) { }); // create an array of four empty arrays - const tasksFromSameLevelArr = Array(4).fill(null).map(() => []); + const tasksFromSameLevelArr = Array(4) + .fill(null) + .map(() => []); // sort them out into an array of four arrays based on their levels tasksWithId.forEach((task) => { @@ -358,18 +380,32 @@ const taskController = function (Task) { task.hoursMost += childTask.hoursMost; task.hoursLogged += childTask.hoursLogged; task.estimatedHours += childTask.estimatedHours; - task.startedDatetime = Math.min(task.startedDatetime, childTask.startedDatetime); - task.dueDatetime = Math.max(task.dueDatetime, childTask.dueDatetime); + task.startedDatetime = Math.min( + task.startedDatetime, + childTask.startedDatetime + ); + task.dueDatetime = Math.max( + task.dueDatetime, + childTask.dueDatetime + ); task.childrenQty = (task.childrenQty || 0) + 1; task.isAssigned = task.isAssigned || childTask.isAssigned; - task.resources = childTask.resources.reduce((resources, childTaskMember) => { - if (task.resources.every(member => member.name !== childTaskMember.name)) return [...resources, childTaskMember]; - return resources; - }, [...task.resources]); + task.resources = childTask.resources.reduce( + (resources, childTaskMember) => { + if ( + task.resources.every( + (member) => member.name !== childTaskMember.name + ) + ) + return [...resources, childTaskMember]; + return resources; + }, + [...task.resources] + ); // add priority pts for task.priority - if (childTask.priority === 'Primary') { + if (childTask.priority === "Primary") { priorityPts += 3; - } else if (childTask.priority === 'Secondary') { + } else if (childTask.priority === "Secondary") { priorityPts += 2; } else { priorityPts += 1; @@ -379,11 +415,11 @@ const taskController = function (Task) { }); const averagePts = priorityPts / task.childrenQty; if (averagePts >= 2.5) { - task.priority = 'Primary'; + task.priority = "Primary"; } else if (averagePts >= 1.6) { - task.priority = 'Secondary'; + task.priority = "Secondary"; } else { - task.priority = 'Tertiary'; + task.priority = "Tertiary"; } }); } @@ -392,10 +428,10 @@ const taskController = function (Task) { }; const importTask = async (req, res) => { - if (!await hasPermission(req.body.requestor, 'importTask')) { + if (!(await hasPermission(req.body.requestor, "importTask"))) { res .status(403) - .send({ error: 'You are not authorized to create new Task.' }); + .send({ error: "You are not authorized to create new Task." }); return; } @@ -407,7 +443,10 @@ const taskController = function (Task) { const createdDatetime = Date.now(); const modifiedDatetime = Date.now(); const _task = new Task({ - ...task, wbsId, createdDatetime, modifiedDatetime, + ...task, + wbsId, + createdDatetime, + modifiedDatetime, }); _task @@ -418,20 +457,20 @@ const taskController = function (Task) { }); }); - res.status(201).send('done'); + res.status(201).send("done"); }; const postTask = async (req, res) => { - if (!await hasPermission(req.body.requestor, 'postTask')) { + if (!(await hasPermission(req.body.requestor, "postTask"))) { res .status(403) - .send({ error: 'You are not authorized to create new Task.' }); + .send({ error: "You are not authorized to create new Task." }); return; } if (!req.body.taskName || !req.body.isActive) { res.status(400).send({ - error: 'Task Name, Active status, Task Number are mandatory fields', + error: "Task Name, Active status, Task Number are mandatory fields", }); return; } @@ -442,7 +481,10 @@ const taskController = function (Task) { const modifiedDatetime = Date.now(); const _task = new Task({ - ...task, wbsId, createdDatetime, modifiedDatetime, + ...task, + wbsId, + createdDatetime, + modifiedDatetime, }); const saveTask = _task.save(); @@ -451,22 +493,23 @@ const taskController = function (Task) { return currentwbs.save(); }); - Promise.all([saveTask, saveWbs]).then(results => res.status(201).send(results[0])) + Promise.all([saveTask, saveWbs]) + .then((results) => res.status(201).send(results[0])) .catch((errors) => { res.status(400).send(errors); }); }; const updateNum = async (req, res) => { - if (!await hasPermission(req.body.requestor, 'updateNum')) { + if (!(await hasPermission(req.body.requestor, "updateNum"))) { res .status(403) - .send({ error: 'You are not authorized to create new projects.' }); + .send({ error: "You are not authorized to create new projects." }); return; } if (!req.body.nums) { - res.status(400).send({ error: 'Num is a mandatory fields' }); + res.status(400).send({ error: "Num is a mandatory fields" }); return; } @@ -477,7 +520,7 @@ const taskController = function (Task) { task .save() .then() - .catch(errors => res.status(400).send(errors)); + .catch((errors) => res.status(400).send(errors)); }); // level 2 @@ -487,13 +530,13 @@ const taskController = function (Task) { childTasks1.forEach((childTask1) => { childTask1.num = childTask1.num.replace( childTask1.num.substring(0, elm.num.length), - elm.num, + elm.num ); childTask1 .save() .then(true) - .catch(errors => res.status(400).send(errors)); + .catch((errors) => res.status(400).send(errors)); // level 3 Task.find({ parentId: { $in: [childTask1._id] } }) @@ -502,13 +545,13 @@ const taskController = function (Task) { childTasks2.forEach((childTask2) => { childTask2.num = childTask2.num.replace( childTask2.num.substring(0, childTask1.num.length), - childTask1.num, + childTask1.num ); childTask2 .save() .then(true) - .catch(errors => res.status(400).send(errors)); + .catch((errors) => res.status(400).send(errors)); // level 4 Task.find({ parentId: { $in: [childTask2._id] } }) @@ -518,27 +561,29 @@ const taskController = function (Task) { childTask3.num = childTask3.num.replace( childTask3.num.substring( 0, - childTask2.num.length, + childTask2.num.length ), - childTask2.num, + childTask2.num ); childTask3 .save() .then(true) - .catch(errors => res.status(400).send(errors)); + .catch((errors) => + res.status(400).send(errors) + ); }); } }) - .catch(error => res.status(404).send(error)); + .catch((error) => res.status(404).send(error)); }); } }) - .catch(error => res.status(404).send(error)); + .catch((error) => res.status(404).send(error)); }); } }) - .catch(error => res.status(404).send(error)); + .catch((error) => res.status(404).send(error)); }); res.status(200).send(true); @@ -548,106 +593,113 @@ const taskController = function (Task) { if (!req.body.fromNum || !req.body.toNum) { res .status(400) - .send({ error: 'wbsId, fromNum, toNum are mandatory fields' }); + .send({ error: "wbsId, fromNum, toNum are mandatory fields" }); return; } Task.find({ wbsId: { $in: req.params.wbsId } }).then((tasks) => { - const fromNumArr = req.body.fromNum.replace(/\.0/g, '').split('.'); - const toNumArr = req.body.toNum.replace(/\.0/g, '').split('.'); + const fromNumArr = req.body.fromNum.replace(/\.0/g, "").split("."); + const toNumArr = req.body.toNum.replace(/\.0/g, "").split("."); const changedLvl = fromNumArr.length; const fromLastLvl = parseInt(fromNumArr.pop(), 10); const toLastLvl = parseInt(toNumArr.pop(), 10); - const leadingLvls = fromNumArr.length ? fromNumArr.join('.').concat('.') : ''; // in a format of x, x.x, or x.x.x, also could be '' if move level one tasks + const leadingLvls = fromNumArr.length + ? fromNumArr.join(".").concat(".") + : ""; // in a format of x, x.x, or x.x.x, also could be '' if move level one tasks const changingNums = []; - for (let i = Math.min(fromLastLvl, toLastLvl); i <= Math.max(fromLastLvl, toLastLvl); i += 1) { + for ( + let i = Math.min(fromLastLvl, toLastLvl); + i <= Math.max(fromLastLvl, toLastLvl); + i += 1 + ) { changingNums.push(leadingLvls.concat(`${i}`)); } const changingNumTasks = tasks.filter((task) => { - const taskLeadingNum = task.num.split('.').slice(0, changedLvl).join('.'); + const taskLeadingNum = task.num + .split(".") + .slice(0, changedLvl) + .join("."); return changingNums.includes(taskLeadingNum); }); const queries = []; changingNumTasks.forEach((task) => { - const taskNumArr = task.num.split('.'); + const taskNumArr = task.num.split("."); const taskChanedLvlNum = parseInt(taskNumArr[changedLvl - 1], 10); let newTaskLastLvl; if (fromLastLvl > toLastLvl) { - newTaskLastLvl = taskChanedLvlNum === fromLastLvl ? toLastLvl : taskChanedLvlNum + 1; + newTaskLastLvl = + taskChanedLvlNum === fromLastLvl ? toLastLvl : taskChanedLvlNum + 1; } else { - newTaskLastLvl = taskChanedLvlNum === fromLastLvl ? toLastLvl : taskChanedLvlNum - 1; + newTaskLastLvl = + taskChanedLvlNum === fromLastLvl ? toLastLvl : taskChanedLvlNum - 1; } taskNumArr[changedLvl - 1] = String(newTaskLastLvl); - task.num = taskNumArr.join('.'); + task.num = taskNumArr.join("."); queries.push(task.save()); }); Promise.all(queries) - .then(() => res.status(200).send('Success!')) - .catch(err => res.status(400).send(err)); + .then(() => res.status(200).send("Success!")) + .catch((err) => res.status(400).send(err)); }); }; const deleteTask = async (req, res) => { - if (!await hasPermission(req.body.requestor, 'deleteTask')) { - res - .status(403) - .send({ error: 'You are not authorized to deleteTasks.' }); + if (!(await hasPermission(req.body.requestor, "deleteTask"))) { + res.status(403).send({ error: "You are not authorized to deleteTasks." }); return; } const { taskId } = req.params; const { mother } = req.params; - const removeChildTasks = Task.find( - { - $or: [ - { _id: taskId }, - { parentId1: taskId }, - { parentId2: taskId }, - { parentId3: taskId }, - ], - }, - ) - .then((record) => { - if (!record || record === null || record.length === 0) return res.status(400).send({ error: 'No valid records found' }); - const removeTasks = record.map(rec => rec.remove()); - return removeTasks; + const removeChildTasks = Task.find({ + $or: [ + { _id: taskId }, + { parentId1: taskId }, + { parentId2: taskId }, + { parentId3: taskId }, + ], + }).then((record) => { + if (!record || record === null || record.length === 0) + return res.status(400).send({ error: "No valid records found" }); + const removeTasks = record.map((rec) => rec.remove()); + return removeTasks; }); - const updateMotherChildrenQty = mother !== 'null' - ? Task.findById(mother).then((task) => { - let newQty = 0; - let child = true; - if (task.childrenQty > 0) { - newQty = task.childrenQty - 1; - if (newQty === 0) { - child = false; + const updateMotherChildrenQty = + mother !== "null" + ? Task.findById(mother).then((task) => { + let newQty = 0; + let child = true; + if (task.childrenQty > 0) { + newQty = task.childrenQty - 1; + if (newQty === 0) { + child = false; + } } - } - task.hasChild = child; - task.childrenQty = newQty; - return task.save(); - }) - : Promise.resolve(1); - - Promise - .all([removeChildTasks, updateMotherChildrenQty]) - .then(() => res.status(200).send({ message: 'Task successfully deleted' })) // no need to resetNum(taskId, mother); - .catch(errors => res.status(400).send(errors)); + task.hasChild = child; + task.childrenQty = newQty; + return task.save(); + }) + : Promise.resolve(1); + + Promise.all([removeChildTasks, updateMotherChildrenQty]) + .then(() => + res.status(200).send({ message: "Task successfully deleted" }) + ) // no need to resetNum(taskId, mother); + .catch((errors) => res.status(400).send(errors)); }; const deleteTaskByWBS = async (req, res) => { - if (!await hasPermission(req.body.requestor, 'deleteTask')) { - res - .status(403) - .send({ error: 'You are not authorized to deleteTasks.' }); + if (!(await hasPermission(req.body.requestor, "deleteTask"))) { + res.status(403).send({ error: "You are not authorized to deleteTasks." }); return; } @@ -655,7 +707,7 @@ const taskController = function (Task) { Task.find({ wbsId: { $in: [wbsId] } }, (error, record) => { if (error || !record || record === null || record.length === 0) { - res.status(400).send({ error: 'No valid records found' }); + res.status(400).send({ error: "No valid records found" }); return; } @@ -665,7 +717,9 @@ const taskController = function (Task) { }); Promise.all([...removeTasks]) - .then(() => res.status(200).send({ message: ' Tasks were successfully deleted' })) + .then(() => + res.status(200).send({ message: " Tasks were successfully deleted" }) + ) .catch((errors) => { res.status(400).send(errors); }); @@ -675,8 +729,8 @@ const taskController = function (Task) { }; const updateTask = async (req, res) => { - if (!await hasPermission(req.body.requestor, 'updateTask')) { - res.status(403).send({ error: 'You are not authorized to update Task.' }); + if (!(await hasPermission(req.body.requestor, "updateTask"))) { + res.status(403).send({ error: "You are not authorized to update Task." }); return; } @@ -684,46 +738,46 @@ const taskController = function (Task) { Task.findOneAndUpdate( { _id: mongoose.Types.ObjectId(taskId) }, - { ...req.body, modifiedDatetime: Date.now() }, + { ...req.body, modifiedDatetime: Date.now() } ) .then(() => res.status(201).send()) - .catch(error => res.status(404).send(error)); + .catch((error) => res.status(404).send(error)); }; const swap = async function (req, res) { - if (!await hasPermission(req.body.requestor, 'swapTask')) { + if (!(await hasPermission(req.body.requestor, "swapTask"))) { res .status(403) - .send({ error: 'You are not authorized to create new projects.' }); + .send({ error: "You are not authorized to create new projects." }); return; } if (!req.body.taskId1 || !req.body.taskId2) { res .status(400) - .send({ error: 'taskId1 and taskId2 are mandatory fields' }); + .send({ error: "taskId1 and taskId2 are mandatory fields" }); return; } Task.findById(req.body.taskId1, (error1, task1) => { if (error1 || task1 === null) { - res.status(400).send('No valid records found'); + res.status(400).send("No valid records found"); return; } Task.findById(req.body.taskId2, (error2, task2) => { if (error2 || task2 === null) { - res.status(400).send('No valid records found'); + res.status(400).send("No valid records found"); return; } if (task1.parentId.toString() === task2.parentId.toString()) { - let tmpNum = ''; + let tmpNum = ""; tmpNum = task1.num; task1.num = task2.num; task2.num = tmpNum; } else { - let tmpName = ''; + let tmpName = ""; tmpName = task1.taskName; task1.taskName = task2.taskName; task2.taskName = tmpName; @@ -732,53 +786,62 @@ const taskController = function (Task) { task1 .save() .then() - .catch(errors => res.status(400).send(errors)); + .catch((errors) => res.status(400).send(errors)); task2 .save() .then() - .catch(errors => res.status(400).send(errors)); + .catch((errors) => res.status(400).send(errors)); Task.find({ wbsId: { $in: [task1.wbsId] }, }) - .then(results => res.status(200).send(results)) - .catch(error => res.status(404).send(error)); + .then((results) => res.status(200).send(results)) + .catch((error) => res.status(404).send(error)); }); }); }; const getTaskById = async (req, res) => { try { - const taskId = req.params.id; + const taskId = req.params.id; - // Ensure the task ID is provided - if (!taskId || taskId === 'undefined') { - return res.status(400).send({ error: 'Task ID is missing' }); - } + // Ensure the task ID is provided + if (!taskId || taskId === "undefined") { + return res.status(400).send({ error: "Task ID is missing" }); + } - const task = await Task.findById(taskId, '-__v -createdDatetime -modifiedDatetime'); + const task = await Task.findById( + taskId, + "-__v -createdDatetime -modifiedDatetime" + ); - if (!task) { - return res.status(400).send({ error: 'This is not a valid task' }); - } + if (!task) { + return res.status(400).send({ error: "This is not a valid task" }); + } - const hoursLogged = await timeEntryHelper.getAllHoursLoggedForSpecifiedProject(taskId); - task.set('hoursLogged', hoursLogged, { strict: false }); + const hoursLogged = + await timeEntryHelper.getAllHoursLoggedForSpecifiedProject(taskId); + task.set("hoursLogged", hoursLogged, { strict: false }); - // Fetch the resource names for all resources - const resourceNamesPromises = task.resources.map(resource => taskHelper.getUserProfileFirstAndLastName(resource.userID)); - const resourceNames = await Promise.all(resourceNamesPromises); + // Fetch the resource names for all resources + const resourceNamesPromises = task.resources.map((resource) => + taskHelper.getUserProfileFirstAndLastName(resource.userID) + ); + const resourceNames = await Promise.all(resourceNamesPromises); - // Update the task's resources with the fetched names - task.resources.forEach((resource, index) => { - resource.name = resourceNames[index] !== ' ' ? resourceNames[index] : resource.name; - }); + // Update the task's resources with the fetched names + task.resources.forEach((resource, index) => { + resource.name = + resourceNames[index] !== " " ? resourceNames[index] : resource.name; + }); - res.status(200).send(task); + res.status(200).send(task); } catch (error) { - // Generic error message, you can adjust as needed - res.status(500).send({ error: 'Internal Server Error', details: error.message }); + // Generic error message, you can adjust as needed + res + .status(500) + .send({ error: "Internal Server Error", details: error.message }); } }; @@ -787,39 +850,40 @@ const taskController = function (Task) { try { Task.find({ wbsId: { $in: [wbsId] } }).then((tasks) => { - tasks = tasks.filter(task => task.level === 1); + tasks = tasks.filter((task) => task.level === 1); tasks.forEach((task) => { updateParents(task.wbsId, task.taskId.toString()); }); - res.status(200).send('done'); + res.status(200).send("done"); }); - res.status(200).send('done'); + res.status(200).send("done"); } catch (error) { res.status(400).send(error); } }; const fixTasks = function (req, res) { - res.status(200).send('done'); + res.status(200).send("done"); }; const getTasksByUserId = async (req, res) => { const { userId } = req.params; try { - Task.find({ - 'resources.userID': mongoose.Types.ObjectId(userId), - }, '-resources.profilePic') - .then((results) => { + Task.find( + { + "resources.userID": mongoose.Types.ObjectId(userId), + }, + "-resources.profilePic" + ).then((results) => { WBS.find({ - _id: { $in: results.map(item => item.wbsId) }, + _id: { $in: results.map((item) => item.wbsId) }, }).then((WBSs) => { const resultsWithProjectsIds = results.map((item) => { item.set( - 'projectId', - WBSs?.find( - wbs => wbs._id.toString() === item.wbsId.toString(), - )?.projectId, - { strict: false }, + "projectId", + WBSs?.find((wbs) => wbs._id.toString() === item.wbsId.toString()) + ?.projectId, + { strict: false } ); return item; }); @@ -838,7 +902,9 @@ const taskController = function (Task) { if (teamsData.length > 0) { res.status(200).send(teamsData); } else { - const singleUserData = await taskHelper.getTasksForSingleUser(userId).exec(); + const singleUserData = await taskHelper + .getTasksForSingleUser(userId) + .exec(); res.status(200).send(singleUserData); } } catch (error) { @@ -852,10 +918,10 @@ const taskController = function (Task) { Task.findOneAndUpdate( { _id: mongoose.Types.ObjectId(taskId) }, - { ...req.body, modifiedDatetime: Date.now() }, + { ...req.body, modifiedDatetime: Date.now() } ) .then(() => res.status(201).send()) - .catch(error => res.status(404).send(error)); + .catch((error) => res.status(404).send(error)); }; const getReviewReqEmailBody = function (name, taskName) { @@ -871,9 +937,11 @@ const taskController = function (Task) { const getRecipients = async function (myUserId) { const recipients = []; const user = await UserProfile.findById(myUserId); - const membership = await UserProfile.find({ role: { $in: ['Administrator', 'Manager', 'Mentor'] } }); + const membership = await UserProfile.find({ + role: { $in: ["Administrator", "Manager", "Mentor"] }, + }); membership.forEach((member) => { - if (member.teams.some(team => user.teams.includes(team))) { + if (member.teams.some((team) => user.teams.includes(team))) { recipients.push(member.email); } }); @@ -881,9 +949,7 @@ const taskController = function (Task) { }; const sendReviewReq = async function (req, res) { - const { - myUserId, name, taskName, - } = req.body; + const { myUserId, name, taskName } = req.body; const emailBody = getReviewReqEmailBody(name, taskName); const recipients = await getRecipients(myUserId); @@ -892,12 +958,12 @@ const taskController = function (Task) { recipients, `Review Request from ${name}`, emailBody, - 'highestgoodnetwork@gmail.com', null, + null ); - res.status(200).send('Success'); + res.status(200).send("Success"); } catch (err) { - res.status(500).send('Failed'); + res.status(500).send("Failed"); } }; From ae8bb2bb6119d644aa683ee62eb67881b2b6dcd3 Mon Sep 17 00:00:00 2001 From: tsunami776 <43768723+tsunami776@users.noreply.github.com> Date: Fri, 5 Jan 2024 22:07:22 -0600 Subject: [PATCH 254/272] revert lint --- .../bmdashboard/bmMaterialsController.js | 90 +++--- src/controllers/dashBoardController.js | 2 +- src/controllers/mapLocationsController.js | 45 +-- .../profileInitialSetupController.js | 42 +-- src/controllers/reasonSchedulingController.js | 45 +-- src/controllers/taskController.js | 303 ++++++++++-------- src/controllers/teamController.js | 4 +- src/helpers/dashboardhelper.js | 126 ++++---- src/helpers/taskHelper.js | 176 +++++----- src/models/mapLocation.js | 4 +- src/routes/bmdashboard/bmMaterialsRouter.js | 6 +- src/routes/mapLocationsRouter.js | 2 +- src/routes/profileInitialSetupRouter.js | 4 +- src/startup/routes.js | 2 +- src/utilities/emailSender.js | 12 +- 15 files changed, 461 insertions(+), 402 deletions(-) diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index da45aad1d..911ca0b55 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -1,6 +1,6 @@ const mongoose = require('mongoose'); -const bmMaterialsController = function (ItemMaterial, BuildingMaterial) { +const bmMaterialsController = function (ItemMaterial,BuildingMaterial) { const bmMaterialsList = async function _matsList(req, res) { try { BuildingMaterial.find() @@ -91,20 +91,25 @@ const bmMaterialsController = function (ItemMaterial, BuildingMaterial) { }; const bmPostMaterialUpdateRecord = function (req, res) { - const payload = req.body; + let payload = req.body; let quantityUsed = +req.body.quantityUsed; let quantityWasted = +req.body.quantityWasted; - const { material } = req.body; - if (payload.QtyUsedLogUnit == 'percent' && quantityWasted >= 0) { + let material = req.body.material; + if(payload.QtyUsedLogUnit=='percent' && quantityWasted>=0) + { quantityUsed = +((+quantityUsed / 100) * material.stockAvailable).toFixed(4); } - if (payload.QtyWastedLogUnit == 'percent' && quantityUsed >= 0) { + if(payload.QtyWastedLogUnit=='percent' && quantityUsed>=0) + { quantityWasted = +((+quantityWasted / 100) * material.stockAvailable).toFixed(4); } - if (quantityUsed > material.stockAvailable || quantityWasted > material.stockAvailable || (quantityUsed + quantityWasted) > material.stockAvailable) { - res.status(500).send('Please check the used and wasted stock values. Either individual values or their sum exceeds the total stock available.'); - } else { + if(quantityUsed>material.stockAvailable || quantityWasted>material.stockAvailable || (quantityUsed+quantityWasted)>material.stockAvailable) + { + res.status(500).send('Please check the used and wasted stock values. Either individual values or their sum exceeds the total stock available.') + } + else + { let newStockUsed = +material.stockUsed + parseFloat(quantityUsed); let newStockWasted = +material.stockWasted + parseFloat(quantityWasted); let newAvailable = +material.stockAvailable - parseFloat(quantityUsed) - parseFloat(quantityWasted); @@ -113,42 +118,45 @@ const bmMaterialsController = function (ItemMaterial, BuildingMaterial) { newAvailable = parseFloat(newAvailable.toFixed(4)); BuildingMaterial.updateOne( { _id: req.body.material._id }, - + { $set: { - stockUsed: newStockUsed, - stockWasted: newStockWasted, - stockAvailable: newAvailable, + 'stockUsed': newStockUsed, + 'stockWasted': newStockWasted, + 'stockAvailable': newAvailable }, $push: { updateRecord: { date: req.body.date, createdBy: req.body.requestor.requestorId, - quantityUsed, - quantityWasted, + quantityUsed: quantityUsed, + quantityWasted: quantityWasted }, - }, - }, - + } + } + ) - .then((results) => { res.status(200).send(results); }) - .catch(error => res.status(500).send({ message: error })); + .then(results => {res.status(200).send(results)}) + .catch(error => res.status(500).send({'message':error})); } }; const bmPostMaterialUpdateBulk = function (req, res) { - const materialUpdates = req.body.upadateMaterials; + const materialUpdates= req.body.upadateMaterials; let errorFlag = false; const updateRecordsToBeAdded = []; - for (let i = 0; i < materialUpdates.length; i++) { - const payload = materialUpdates[i]; + for(let i=0;i= 0) { + let material = payload.material; + if(payload.QtyUsedLogUnit=='percent' && quantityWasted>=0) + { quantityUsed = +((+quantityUsed / 100) * material.stockAvailable).toFixed(4); } - if (payload.QtyWastedLogUnit == 'percent' && quantityUsed >= 0) { + if(payload.QtyWastedLogUnit=='percent' && quantityUsed>=0) + { quantityWasted = +((+quantityWasted / 100) * material.stockAvailable).toFixed(4); } @@ -158,36 +166,38 @@ const bmMaterialsController = function (ItemMaterial, BuildingMaterial) { newStockUsed = parseFloat(newStockUsed.toFixed(4)); newStockWasted = parseFloat(newStockWasted.toFixed(4)); newAvailable = parseFloat(newAvailable.toFixed(4)); - if (newAvailable < 0) { + if(newAvailable<0) + { errorFlag = true; break; } - updateRecordsToBeAdded.push({ + updateRecordsToBeAdded.push ({ updateId: material._id, set: { - stockUsed: newStockUsed, - stockWasted: newStockWasted, - stockAvailable: newAvailable, + 'stockUsed': newStockUsed, + 'stockWasted': newStockWasted, + 'stockAvailable': newAvailable }, updateValue: { createdBy: req.body.requestor.requestorId, - quantityUsed, - quantityWasted, + quantityUsed: quantityUsed, + quantityWasted: quantityWasted, date: req.body.date, - }, -}); + }}); + } try { - if (errorFlag) { - res.status(500).send('Stock quantities submitted seems to be invalid'); + if(errorFlag) + { + res.status(500).send('Stock quantities submitted seems to be invalid') return; } const updatePromises = updateRecordsToBeAdded.map(updateItem => BuildingMaterial.updateOne( { _id: updateItem.updateId }, - { - $set: updateItem.set, - $push: { updateRecord: updateItem.updateValue }, + { + $set : updateItem.set, + $push: { updateRecord: updateItem.updateValue } }, ).exec()); Promise.all(updatePromises) @@ -203,7 +213,7 @@ const bmMaterialsController = function (ItemMaterial, BuildingMaterial) { bmMaterialsList, bmPostMaterialUpdateRecord, bmPostMaterialUpdateBulk, - bmPurchaseMaterials, + bmPurchaseMaterials }; }; diff --git a/src/controllers/dashBoardController.js b/src/controllers/dashBoardController.js index 1cf730a5a..3fdda9eb7 100644 --- a/src/controllers/dashBoardController.js +++ b/src/controllers/dashBoardController.js @@ -211,7 +211,7 @@ const dashboardcontroller = function () { null, null, email, - null, + null ); res.status(200).send('Success'); } catch { diff --git a/src/controllers/mapLocationsController.js b/src/controllers/mapLocationsController.js index 76fad59f9..29af9e3d6 100644 --- a/src/controllers/mapLocationsController.js +++ b/src/controllers/mapLocationsController.js @@ -4,15 +4,17 @@ const cache = require('../utilities/nodeCache')(); const mapLocationsController = function (MapLocation) { const getAllLocations = async function (req, res) { + try { const users = []; const results = await UserProfile.find({}, - '_id firstName lastName isActive location jobTitle totalTangibleHrs hoursByCategory'); + '_id firstName lastName isActive location jobTitle totalTangibleHrs hoursByCategory' + ); results.forEach((item) => { if ( - (item.location?.coords.lat && item.location?.coords.lng && item.totalTangibleHrs >= 10) - || (item.location?.coords.lat && item.location?.coords.lng && calculateTotalHours(item.hoursByCategory) >= 10) + (item.location?.coords.lat && item.location?.coords.lng && item.totalTangibleHrs >= 10) || + (item.location?.coords.lat && item.location?.coords.lng && calculateTotalHours(item.hoursByCategory) >= 10) ) { users.push(item); } @@ -23,7 +25,7 @@ const mapLocationsController = function (MapLocation) { jobTitle: item.jobTitle[0], _id: item._id, firstName: item.firstName, - lastName: item.lastName, + lastName: item.lastName })); const mUsers = await MapLocation.find({}); @@ -31,19 +33,22 @@ const mapLocationsController = function (MapLocation) { } catch (err) { res.status(404).send(err); } + }; const deleteLocation = async function (req, res) { + if (!req.body.requestor.role === 'Administrator' || !req.body.requestor.role === 'Owner') { res.status(403).send('You are not authorized to make changes in the teams.'); return; } - const { locationId } = req.params; + const locationId = req.params.locationId MapLocation.findOneAndDelete({ _id: locationId }) - .then(() => res.status(200).send({ message: 'The location was successfully removed!' })) + .then(() => res.status(200).send({ message: "The location was successfully removed!" })) .catch(error => res.status(500).send({ message: error || "Couldn't remove the location" })); }; const putUserLocation = async function (req, res) { + if (!req.body.requestor.role === 'Owner') { res.status(403).send('You are not authorized to make changes in the teams.'); return; @@ -53,17 +58,17 @@ const mapLocationsController = function (MapLocation) { lastName: req.body.lastName, jobTitle: req.body.jobTitle, location: req.body.location, - }; + } const location = new MapLocation(locationData); try { - const response = await location.save(); + const response = await location.save() if (!response) { - throw new Error('Something went wrong during saving the location...'); + throw new Error('Something went wrong during saving the location...') } res.status(200).send(response); } catch (err) { - console.log(err.message); + console.log(err.message) res.status(500).json({ message: err.message || 'Something went wrong...' }); } }; @@ -79,26 +84,26 @@ const mapLocationsController = function (MapLocation) { lastName: req.body.lastName, jobTitle: req.body.jobTitle, location: req.body.location, - }; + } if (req.body.timeZone) { - updateData.timeZone = req.body.timeZone; + updateData.timeZone = req.body.timeZone } try { let response; if (userType === 'user') { response = await UserProfile.findOneAndUpdate({ _id: userId }, { $set: { ...updateData, jobTitle: [updateData.jobTitle] } }, { new: true }); - cache.removeCache('allusers'); + cache.removeCache('allusers') cache.removeCache(`user-${userId}`); cache.setCache(`user-${userId}`, JSON.stringify(response)); } else { - response = await MapLocation.findOneAndUpdate({ _id: userId }, { $set: updateData }, { new: true }); + response = await MapLocation.findOneAndUpdate({ _id: userId }, { $set: updateData }, { new: true }) } if (!response) { - throw new Error('Something went wrong during saving the location...'); + throw new Error('Something went wrong during saving the location...') } const newData = { firstName: response.firstName, @@ -106,12 +111,12 @@ const mapLocationsController = function (MapLocation) { jobTitle: response.jobTitle, location: response.location, _id: response._id, - type: userType, - }; + type: userType + } res.status(200).send(newData); } catch (err) { - console.log(err.message); + console.log(err.message) res.status(500).json({ message: err.message || 'Something went wrong...' }); } }; @@ -123,12 +128,12 @@ const mapLocationsController = function (MapLocation) { }); return hours; } - + return { getAllLocations, deleteLocation, putUserLocation, - updateUserLocation, + updateUserLocation }; }; diff --git a/src/controllers/profileInitialSetupController.js b/src/controllers/profileInitialSetupController.js index 84f801671..12776442e 100644 --- a/src/controllers/profileInitialSetupController.js +++ b/src/controllers/profileInitialSetupController.js @@ -76,7 +76,8 @@ function informManagerMessage(user) { return message; } -const sendEmailWithAcknowledgment = (email, subject, message) => new Promise((resolve, reject) => { +const sendEmailWithAcknowledgment = (email, subject, message) => { + return new Promise((resolve, reject) => { emailSender( email, subject, @@ -84,31 +85,33 @@ const sendEmailWithAcknowledgment = (email, subject, message) => new Promise((re null, null, null, - (error, result) => { - if (result) resolve(result); - if (error) reject(result); - }, + (error,result) => { + if (result) resolve(result) + if (error) reject(result) + } ); }); +}; const profileInitialSetupController = function ( ProfileInitialSetupToken, userProfile, Project, - MapLocation, + MapLocation ) { const { JWT_SECRET } = config; const setMapLocation = async (locationData) => { + const location = new MapLocation(locationData); try { - const response = await location.save(); - return response; + const response = await location.save() + return response } catch (err) { - return { type: 'Error', message: err.message || 'An error occurred while saving the location' }; + return {type: "Error", message: err.message || 'An error occurred while saving the location'} } - }; + } /* Function to handle token generation and email process: @@ -143,10 +146,10 @@ const profileInitialSetupController = function ( const acknowledgment = await sendEmailWithAcknowledgment( email, - 'NEEDED: Complete your One Community profile setup', - sendLinkMessage(link), + "NEEDED: Complete your One Community profile setup", + sendLinkMessage(link) ); - + res.status(200).send(acknowledgment); } } catch (error) { @@ -275,15 +278,15 @@ const profileInitialSetupController = function ( lastName: req.body.lastName, jobTitle: req.body.jobTitle, location: req.body.homeCountry, - }; + } res.send({ token }).status(200); - const mapEntryResult = await setMapLocation(locationData); - if (mapEntryResult.type === 'Error') { - console.log(mapEntryResult.message); + const mapEntryResult = await setMapLocation(locationData) + if(mapEntryResult.type === "Error"){ + console.log(mapEntryResult.message) } - + const NewUserCache = { permissions: savedUser.permissions, isActive: true, @@ -324,10 +327,11 @@ const profileInitialSetupController = function ( if (foundToken) { res.status(200).send({ userAPIKey: premiumKey }); } else { - res.status(403).send('Unauthorized Request'); + res.status(403).send("Unauthorized Request"); } }; + return { getSetupToken, diff --git a/src/controllers/reasonSchedulingController.js b/src/controllers/reasonSchedulingController.js index 6f872f338..e310049c2 100644 --- a/src/controllers/reasonSchedulingController.js +++ b/src/controllers/reasonSchedulingController.js @@ -2,7 +2,7 @@ const moment = require('moment-timezone'); const UserModel = require('../models/userProfile'); const ReasonModel = require('../models/reason'); -const emailSender = require('../utilities/emailSender'); +const emailSender = require("../utilities/emailSender"); const postReason = async (req, res) => { @@ -39,7 +39,7 @@ const postReason = async (req, res) => { }); } - // Commented this condition to make reason scheduler available to all the users. + //Commented this condition to make reason scheduler available to all the users. // error case 1 // if (requestor.role !== 'Owner' && requestor.role !== 'Administrator') { // return res.status(403).json({ @@ -86,11 +86,13 @@ const postReason = async (req, res) => { userId, }); - - // await newReason.save(); + + //await newReason.save(); const savedData = await newReason.save(); - if (savedData) { - // Upon clicking the "Save" button in the Blue Square Reason Scheduler, an email will be automatically sent to the user and Jae. + if(savedData) + { + + //Upon clicking the "Save" button in the Blue Square Reason Scheduler, an email will be automatically sent to the user and Jae. const subject = `Blue Square Reason for ${foundUser.firstName} ${foundUser.lastName} has been set`; const emailBody = `

Hi !

@@ -102,18 +104,19 @@ const postReason = async (req, res) => {

Thank you,
One Community

`; - - + + // 1 hardcoded email- emailSender('@gmail.com', subject, emailBody, null, null); - // 2 user email - + // 2 user email - emailSender(`${foundUser.email}`, subject, emailBody, null, null); - // 3 - user email and hardcoded email ( After PR approval hardcode Jae's email) + //3 - user email and hardcoded email ( After PR approval hardcode Jae's email) // emailSender(`${foundUser.email},@gmail.com`, subject, emailBody, null, null); } - + return res.sendStatus(200); + } catch (error) { console.log(error); return res.status(400).json({ @@ -256,10 +259,12 @@ const patchReason = async (req, res) => { } foundReason.reason = reasonData.message; - + const savedData = await foundReason.save(); - if (savedData) { - // Upon clicking the "Save" button in the Blue Square Reason Scheduler, an email will be automatically sent to the user and Jae. + if(savedData) + { + + //Upon clicking the "Save" button in the Blue Square Reason Scheduler, an email will be automatically sent to the user and Jae. const subject = `Blue Square Reason for ${foundUser.firstName} ${foundUser.lastName} has been updated`; const emailBody = `

Hi !

@@ -271,15 +276,17 @@ const patchReason = async (req, res) => {

Thank you,
One Community

`; - - + + // 1 hardcoded email- emailSender('@gmail.com', subject, emailBody, null, null); - // 2 user email - + // 2 user email - emailSender(`${foundUser.email}`, subject, emailBody, null, null); - // 3 - user email and hardcoded email ( After PR approval hardcode Jae's email) + //3 - user email and hardcoded email ( After PR approval hardcode Jae's email) // emailSender(`${foundUser.email},@gmail.com`, subject, emailBody, null, null); + + } return res.status(200).json({ @@ -297,7 +304,7 @@ const deleteReason = async (req, res) => { const { reasonData, requestor } = req.body; const { userId } = req.params; - // error case 1 + //error case 1 if (requestor.role !== 'Owner' && requestor.role !== 'Administrator') { return res.status(403).json({ message: diff --git a/src/controllers/taskController.js b/src/controllers/taskController.js index a91a2b90d..126d17914 100644 --- a/src/controllers/taskController.js +++ b/src/controllers/taskController.js @@ -1,10 +1,10 @@ -const mongoose = require('mongoose'); -const WBS = require('../models/wbs'); -const UserProfile = require('../models/userProfile'); -const timeEntryHelper = require('../helpers/timeEntryHelper')(); -const taskHelper = require('../helpers/taskHelper')(); -const { hasPermission } = require('../utilities/permissions'); -const emailSender = require('../utilities/emailSender'); +const mongoose = require("mongoose"); +const WBS = require("../models/wbs"); +const UserProfile = require("../models/userProfile"); +const timeEntryHelper = require("../helpers/timeEntryHelper")(); +const taskHelper = require("../helpers/taskHelper")(); +const { hasPermission } = require("../utilities/permissions"); +const emailSender = require("../utilities/emailSender"); const taskController = function (Task) { const getTasks = (req, res) => { @@ -17,7 +17,7 @@ const taskController = function (Task) { const { mother } = req.params; - if (mother !== '0') { + if (mother !== "0") { query = { wbsId: { $in: [req.params.wbsId] }, level: { $in: [level] }, @@ -26,16 +26,16 @@ const taskController = function (Task) { } Task.find(query) - .then(results => res.status(200).send(results)) - .catch(error => res.status(404).send(error)); + .then((results) => res.status(200).send(results)) + .catch((error) => res.status(404).send(error)); }; const getWBSId = (req, res) => { const { wbsId } = req.params; WBS.findById(wbsId) - .then(results => res.status(200).send(results)) - .catch(error => res.status(404).send(error)); + .then((results) => res.status(200).send(results)) + .catch((error) => res.status(404).send(error)); }; const updateSumUp = ( @@ -45,7 +45,7 @@ const taskController = function (Task) { hoursMost, hoursLogged, estimatedHours, - resources, + resources ) => { Task.findById(taskId, (error, task) => { task.hoursBest = hoursBest; @@ -81,10 +81,10 @@ const taskController = function (Task) { }; const calculateSubTasks = (level, tasks) => { - const parentTasks = tasks.filter(task => task.level === level); + const parentTasks = tasks.filter((task) => task.level === level); parentTasks.forEach((task) => { const childTasks = tasks.filter( - taskChild => taskChild.level === level + 1, + (taskChild) => taskChild.level === level + 1 ); let sumHoursBest = 0; let sumHoursWorst = 0; @@ -96,14 +96,19 @@ const taskController = function (Task) { childTasks.forEach((childTask) => { if (childTask.mother.equals(task.taskId)) { hasChild = true; - sumHoursBest = parseFloat(childTask.hoursBest, 10) + parseFloat(sumHoursBest, 10); - sumHoursWorst = parseFloat(childTask.hoursWorst, 10) - + parseFloat(sumHoursWorst, 10); - sumHoursMost = parseFloat(childTask.hoursMost, 10) + parseFloat(sumHoursMost, 10); - sumHoursLogged = parseFloat(childTask.hoursLogged, 10) - + parseFloat(sumHoursLogged, 10); - sumEstimatedHours = parseFloat(childTask.estimatedHours, 10) - + parseFloat(sumEstimatedHours, 10); + sumHoursBest = + parseFloat(childTask.hoursBest, 10) + parseFloat(sumHoursBest, 10); + sumHoursWorst = + parseFloat(childTask.hoursWorst, 10) + + parseFloat(sumHoursWorst, 10); + sumHoursMost = + parseFloat(childTask.hoursMost, 10) + parseFloat(sumHoursMost, 10); + sumHoursLogged = + parseFloat(childTask.hoursLogged, 10) + + parseFloat(sumHoursLogged, 10); + sumEstimatedHours = + parseFloat(childTask.estimatedHours, 10) + + parseFloat(sumEstimatedHours, 10); childTask.resources.forEach((member) => { let isInResource = false; resources.forEach((mem) => { @@ -136,7 +141,7 @@ const taskController = function (Task) { sumHoursMost, sumHoursLogged, sumEstimatedHours, - resources, + resources ); } }); @@ -144,10 +149,10 @@ const taskController = function (Task) { }; const setDatesSubTasks = (level, tasks) => { - const parentTasks = tasks.filter(task => task.level === level); + const parentTasks = tasks.filter((task) => task.level === level); parentTasks.forEach((task) => { const childTasks = tasks.filter( - taskChild => taskChild.level === level + 1, + (taskChild) => taskChild.level === level + 1 ); let minStartedDate = task.startedDatetime; let maxDueDatetime = task.dueDatetime; @@ -178,10 +183,10 @@ const taskController = function (Task) { }; const calculatePriority = (level, tasks) => { - const parentTasks = tasks.filter(task => task.level === level); + const parentTasks = tasks.filter((task) => task.level === level); parentTasks.forEach((task) => { const childTasks = tasks.filter( - taskChild => taskChild.level === level + 1, + (taskChild) => taskChild.level === level + 1 ); let totalNumberPriority = 0; let totalChild = 0; @@ -190,11 +195,11 @@ const taskController = function (Task) { if (childTask.mother.equals(task.taskId)) { hasChild = true; totalChild += 1; - if (childTask.priority === 'Primary') { + if (childTask.priority === "Primary") { totalNumberPriority += 3; - } else if (childTask.priority === 'Secondary') { + } else if (childTask.priority === "Secondary") { totalNumberPriority += 2; - } else if (childTask.priority === 'Tertiary') { + } else if (childTask.priority === "Tertiary") { totalNumberPriority += 1; } } @@ -207,11 +212,11 @@ const taskController = function (Task) { if (mainTask._id.equals(task._id)) { const avg = totalNumberPriority / totalChild; if (avg <= 1.6) { - priority = 'Tertiary'; + priority = "Tertiary"; } else if (avg > 1.6 && avg < 2.5) { - priority = 'Secondary'; + priority = "Secondary"; } else { - priority = 'Primary'; + priority = "Primary"; } } }); @@ -222,10 +227,10 @@ const taskController = function (Task) { }; const setAssigned = (level, tasks) => { - const parentTasks = tasks.filter(task => task.level === level); + const parentTasks = tasks.filter((task) => task.level === level); parentTasks.forEach((task) => { const childTasks = tasks.filter( - taskChild => taskChild.level === level + 1, + (taskChild) => taskChild.level === level + 1 ); let isAssigned = false; let hasChild = false; @@ -259,7 +264,7 @@ const taskController = function (Task) { { wbsId: { $in: [wbsId] } }, ], }).then((tasks) => { - tasks = [...new Set(tasks.map(item => item))]; + tasks = [...new Set(tasks.map((item) => item))]; for (let lv = 3; lv > 0; lv -= 1) { calculateSubTasks(lv, tasks); setDatesSubTasks(lv, tasks); @@ -285,7 +290,7 @@ const taskController = function (Task) { const tasksWithId = tasks.map((task) => { const _id = new mongoose.Types.ObjectId(); const resources = task.resources.map((resource) => { - const [name, userID, profilePic] = resource.split('|'); + const [name, userID, profilePic] = resource.split("|"); return { name, userID, profilePic }; }); @@ -298,7 +303,7 @@ const taskController = function (Task) { // update tasks makes sure its parentIds and mother props are correct assigned, tasksWithId.forEach((task) => { - const taskNumArr = task.num.split('.'); + const taskNumArr = task.num.split("."); switch (task.level) { case 1: // task.num is x, no parentId1 or mother task.parentId1 = null; // no parent so its value is null @@ -308,7 +313,7 @@ const taskController = function (Task) { break; case 2: // task.num is x.x, only has one level of parent (x) task.parentId1 = tasksWithId.find( - pTask => pTask.num === taskNumArr[0], + (pTask) => pTask.num === taskNumArr[0] )._id; // task of parentId1 has num prop of x task.parentId2 = null; task.parentId3 = null; @@ -316,23 +321,24 @@ const taskController = function (Task) { break; case 3: // task.num is x.x.x, has two levels of parent (parent: x.x and grandparent: x) task.parentId1 = tasksWithId.find( - pTask => pTask.num === taskNumArr[0], + (pTask) => pTask.num === taskNumArr[0] )._id; // task of parentId1 has num prop of x task.parentId2 = tasksWithId.find( - pTask => pTask.num === `${taskNumArr[0]}.${taskNumArr[1]}`, + (pTask) => pTask.num === `${taskNumArr[0]}.${taskNumArr[1]}` )._id; // task of parentId2 has num prop of x.x task.parentId3 = null; task.mother = task.parentId2; // parent task num prop is x.x break; case 4: // task.num is x.x.x.x, has three levels of parent (x.x.x, x.x and x) task.parentId1 = tasksWithId.find( - pTask => pTask.num === taskNumArr[0], + (pTask) => pTask.num === taskNumArr[0] )._id; // x task.parentId2 = tasksWithId.find( - pTask => pTask.num === `${taskNumArr[0]}.${taskNumArr[1]}`, + (pTask) => pTask.num === `${taskNumArr[0]}.${taskNumArr[1]}` )._id; // x.x task.parentId3 = tasksWithId.find( - pTask => pTask.num === `${taskNumArr[0]}.${taskNumArr[1]}.${taskNumArr[2]}`, + (pTask) => + pTask.num === `${taskNumArr[0]}.${taskNumArr[1]}.${taskNumArr[2]}` )._id; // x.x.x task.mother = task.parentId3; // parent task num prop is x.x.x break; @@ -376,11 +382,11 @@ const taskController = function (Task) { task.estimatedHours += childTask.estimatedHours; task.startedDatetime = Math.min( task.startedDatetime, - childTask.startedDatetime, + childTask.startedDatetime ); task.dueDatetime = Math.max( task.dueDatetime, - childTask.dueDatetime, + childTask.dueDatetime ); task.childrenQty = (task.childrenQty || 0) + 1; task.isAssigned = task.isAssigned || childTask.isAssigned; @@ -388,17 +394,18 @@ const taskController = function (Task) { (resources, childTaskMember) => { if ( task.resources.every( - member => member.name !== childTaskMember.name, + (member) => member.name !== childTaskMember.name ) - ) return [...resources, childTaskMember]; + ) + return [...resources, childTaskMember]; return resources; }, - [...task.resources], + [...task.resources] ); // add priority pts for task.priority - if (childTask.priority === 'Primary') { + if (childTask.priority === "Primary") { priorityPts += 3; - } else if (childTask.priority === 'Secondary') { + } else if (childTask.priority === "Secondary") { priorityPts += 2; } else { priorityPts += 1; @@ -408,11 +415,11 @@ const taskController = function (Task) { }); const averagePts = priorityPts / task.childrenQty; if (averagePts >= 2.5) { - task.priority = 'Primary'; + task.priority = "Primary"; } else if (averagePts >= 1.6) { - task.priority = 'Secondary'; + task.priority = "Secondary"; } else { - task.priority = 'Tertiary'; + task.priority = "Tertiary"; } }); } @@ -421,10 +428,10 @@ const taskController = function (Task) { }; const importTask = async (req, res) => { - if (!(await hasPermission(req.body.requestor, 'importTask'))) { + if (!(await hasPermission(req.body.requestor, "importTask"))) { res .status(403) - .send({ error: 'You are not authorized to create new Task.' }); + .send({ error: "You are not authorized to create new Task." }); return; } @@ -450,20 +457,20 @@ const taskController = function (Task) { }); }); - res.status(201).send('done'); + res.status(201).send("done"); }; const postTask = async (req, res) => { - if (!(await hasPermission(req.body.requestor, 'postTask'))) { + if (!(await hasPermission(req.body.requestor, "postTask"))) { res .status(403) - .send({ error: 'You are not authorized to create new Task.' }); + .send({ error: "You are not authorized to create new Task." }); return; } if (!req.body.taskName || !req.body.isActive) { res.status(400).send({ - error: 'Task Name, Active status, Task Number are mandatory fields', + error: "Task Name, Active status, Task Number are mandatory fields", }); return; } @@ -487,22 +494,22 @@ const taskController = function (Task) { }); Promise.all([saveTask, saveWbs]) - .then(results => res.status(201).send(results[0])) + .then((results) => res.status(201).send(results[0])) .catch((errors) => { res.status(400).send(errors); }); }; const updateNum = async (req, res) => { - if (!(await hasPermission(req.body.requestor, 'updateNum'))) { + if (!(await hasPermission(req.body.requestor, "updateNum"))) { res .status(403) - .send({ error: 'You are not authorized to create new projects.' }); + .send({ error: "You are not authorized to create new projects." }); return; } if (!req.body.nums) { - res.status(400).send({ error: 'Num is a mandatory fields' }); + res.status(400).send({ error: "Num is a mandatory fields" }); return; } @@ -513,7 +520,7 @@ const taskController = function (Task) { task .save() .then() - .catch(errors => res.status(400).send(errors)); + .catch((errors) => res.status(400).send(errors)); }); // level 2 @@ -523,13 +530,13 @@ const taskController = function (Task) { childTasks1.forEach((childTask1) => { childTask1.num = childTask1.num.replace( childTask1.num.substring(0, elm.num.length), - elm.num, + elm.num ); childTask1 .save() .then(true) - .catch(errors => res.status(400).send(errors)); + .catch((errors) => res.status(400).send(errors)); // level 3 Task.find({ parentId: { $in: [childTask1._id] } }) @@ -538,13 +545,13 @@ const taskController = function (Task) { childTasks2.forEach((childTask2) => { childTask2.num = childTask2.num.replace( childTask2.num.substring(0, childTask1.num.length), - childTask1.num, + childTask1.num ); childTask2 .save() .then(true) - .catch(errors => res.status(400).send(errors)); + .catch((errors) => res.status(400).send(errors)); // level 4 Task.find({ parentId: { $in: [childTask2._id] } }) @@ -554,27 +561,29 @@ const taskController = function (Task) { childTask3.num = childTask3.num.replace( childTask3.num.substring( 0, - childTask2.num.length, + childTask2.num.length ), - childTask2.num, + childTask2.num ); childTask3 .save() .then(true) - .catch(errors => res.status(400).send(errors)); + .catch((errors) => + res.status(400).send(errors) + ); }); } }) - .catch(error => res.status(404).send(error)); + .catch((error) => res.status(404).send(error)); }); } }) - .catch(error => res.status(404).send(error)); + .catch((error) => res.status(404).send(error)); }); } }) - .catch(error => res.status(404).send(error)); + .catch((error) => res.status(404).send(error)); }); res.status(200).send(true); @@ -584,13 +593,13 @@ const taskController = function (Task) { if (!req.body.fromNum || !req.body.toNum) { res .status(400) - .send({ error: 'wbsId, fromNum, toNum are mandatory fields' }); + .send({ error: "wbsId, fromNum, toNum are mandatory fields" }); return; } Task.find({ wbsId: { $in: req.params.wbsId } }).then((tasks) => { - const fromNumArr = req.body.fromNum.replace(/\.0/g, '').split('.'); - const toNumArr = req.body.toNum.replace(/\.0/g, '').split('.'); + const fromNumArr = req.body.fromNum.replace(/\.0/g, "").split("."); + const toNumArr = req.body.toNum.replace(/\.0/g, "").split("."); const changedLvl = fromNumArr.length; @@ -598,8 +607,8 @@ const taskController = function (Task) { const toLastLvl = parseInt(toNumArr.pop(), 10); const leadingLvls = fromNumArr.length - ? fromNumArr.join('.').concat('.') - : ''; // in a format of x, x.x, or x.x.x, also could be '' if move level one tasks + ? fromNumArr.join(".").concat(".") + : ""; // in a format of x, x.x, or x.x.x, also could be '' if move level one tasks const changingNums = []; for ( @@ -611,37 +620,39 @@ const taskController = function (Task) { } const changingNumTasks = tasks.filter((task) => { const taskLeadingNum = task.num - .split('.') + .split(".") .slice(0, changedLvl) - .join('.'); + .join("."); return changingNums.includes(taskLeadingNum); }); const queries = []; changingNumTasks.forEach((task) => { - const taskNumArr = task.num.split('.'); + const taskNumArr = task.num.split("."); const taskChanedLvlNum = parseInt(taskNumArr[changedLvl - 1], 10); let newTaskLastLvl; if (fromLastLvl > toLastLvl) { - newTaskLastLvl = taskChanedLvlNum === fromLastLvl ? toLastLvl : taskChanedLvlNum + 1; + newTaskLastLvl = + taskChanedLvlNum === fromLastLvl ? toLastLvl : taskChanedLvlNum + 1; } else { - newTaskLastLvl = taskChanedLvlNum === fromLastLvl ? toLastLvl : taskChanedLvlNum - 1; + newTaskLastLvl = + taskChanedLvlNum === fromLastLvl ? toLastLvl : taskChanedLvlNum - 1; } taskNumArr[changedLvl - 1] = String(newTaskLastLvl); - task.num = taskNumArr.join('.'); + task.num = taskNumArr.join("."); queries.push(task.save()); }); Promise.all(queries) - .then(() => res.status(200).send('Success!')) - .catch(err => res.status(400).send(err)); + .then(() => res.status(200).send("Success!")) + .catch((err) => res.status(400).send(err)); }); }; const deleteTask = async (req, res) => { - if (!(await hasPermission(req.body.requestor, 'deleteTask'))) { - res.status(403).send({ error: 'You are not authorized to deleteTasks.' }); + if (!(await hasPermission(req.body.requestor, "deleteTask"))) { + res.status(403).send({ error: "You are not authorized to deleteTasks." }); return; } @@ -656,12 +667,14 @@ const taskController = function (Task) { { parentId3: taskId }, ], }).then((record) => { - if (!record || record === null || record.length === 0) return res.status(400).send({ error: 'No valid records found' }); - const removeTasks = record.map(rec => rec.remove()); + if (!record || record === null || record.length === 0) + return res.status(400).send({ error: "No valid records found" }); + const removeTasks = record.map((rec) => rec.remove()); return removeTasks; }); - const updateMotherChildrenQty = mother !== 'null' + const updateMotherChildrenQty = + mother !== "null" ? Task.findById(mother).then((task) => { let newQty = 0; let child = true; @@ -678,13 +691,15 @@ const taskController = function (Task) { : Promise.resolve(1); Promise.all([removeChildTasks, updateMotherChildrenQty]) - .then(() => res.status(200).send({ message: 'Task successfully deleted' })) // no need to resetNum(taskId, mother); - .catch(errors => res.status(400).send(errors)); + .then(() => + res.status(200).send({ message: "Task successfully deleted" }) + ) // no need to resetNum(taskId, mother); + .catch((errors) => res.status(400).send(errors)); }; const deleteTaskByWBS = async (req, res) => { - if (!(await hasPermission(req.body.requestor, 'deleteTask'))) { - res.status(403).send({ error: 'You are not authorized to deleteTasks.' }); + if (!(await hasPermission(req.body.requestor, "deleteTask"))) { + res.status(403).send({ error: "You are not authorized to deleteTasks." }); return; } @@ -692,7 +707,7 @@ const taskController = function (Task) { Task.find({ wbsId: { $in: [wbsId] } }, (error, record) => { if (error || !record || record === null || record.length === 0) { - res.status(400).send({ error: 'No valid records found' }); + res.status(400).send({ error: "No valid records found" }); return; } @@ -702,7 +717,9 @@ const taskController = function (Task) { }); Promise.all([...removeTasks]) - .then(() => res.status(200).send({ message: ' Tasks were successfully deleted' })) + .then(() => + res.status(200).send({ message: " Tasks were successfully deleted" }) + ) .catch((errors) => { res.status(400).send(errors); }); @@ -712,8 +729,8 @@ const taskController = function (Task) { }; const updateTask = async (req, res) => { - if (!(await hasPermission(req.body.requestor, 'updateTask'))) { - res.status(403).send({ error: 'You are not authorized to update Task.' }); + if (!(await hasPermission(req.body.requestor, "updateTask"))) { + res.status(403).send({ error: "You are not authorized to update Task." }); return; } @@ -721,46 +738,46 @@ const taskController = function (Task) { Task.findOneAndUpdate( { _id: mongoose.Types.ObjectId(taskId) }, - { ...req.body, modifiedDatetime: Date.now() }, + { ...req.body, modifiedDatetime: Date.now() } ) .then(() => res.status(201).send()) - .catch(error => res.status(404).send(error)); + .catch((error) => res.status(404).send(error)); }; const swap = async function (req, res) { - if (!(await hasPermission(req.body.requestor, 'swapTask'))) { + if (!(await hasPermission(req.body.requestor, "swapTask"))) { res .status(403) - .send({ error: 'You are not authorized to create new projects.' }); + .send({ error: "You are not authorized to create new projects." }); return; } if (!req.body.taskId1 || !req.body.taskId2) { res .status(400) - .send({ error: 'taskId1 and taskId2 are mandatory fields' }); + .send({ error: "taskId1 and taskId2 are mandatory fields" }); return; } Task.findById(req.body.taskId1, (error1, task1) => { if (error1 || task1 === null) { - res.status(400).send('No valid records found'); + res.status(400).send("No valid records found"); return; } Task.findById(req.body.taskId2, (error2, task2) => { if (error2 || task2 === null) { - res.status(400).send('No valid records found'); + res.status(400).send("No valid records found"); return; } if (task1.parentId.toString() === task2.parentId.toString()) { - let tmpNum = ''; + let tmpNum = ""; tmpNum = task1.num; task1.num = task2.num; task2.num = tmpNum; } else { - let tmpName = ''; + let tmpName = ""; tmpName = task1.taskName; task1.taskName = task2.taskName; task2.taskName = tmpName; @@ -769,18 +786,18 @@ const taskController = function (Task) { task1 .save() .then() - .catch(errors => res.status(400).send(errors)); + .catch((errors) => res.status(400).send(errors)); task2 .save() .then() - .catch(errors => res.status(400).send(errors)); + .catch((errors) => res.status(400).send(errors)); Task.find({ wbsId: { $in: [task1.wbsId] }, }) - .then(results => res.status(200).send(results)) - .catch(error => res.status(404).send(error)); + .then((results) => res.status(200).send(results)) + .catch((error) => res.status(404).send(error)); }); }); }; @@ -790,29 +807,33 @@ const taskController = function (Task) { const taskId = req.params.id; // Ensure the task ID is provided - if (!taskId || taskId === 'undefined') { - return res.status(400).send({ error: 'Task ID is missing' }); + if (!taskId || taskId === "undefined") { + return res.status(400).send({ error: "Task ID is missing" }); } const task = await Task.findById( taskId, - '-__v -createdDatetime -modifiedDatetime', + "-__v -createdDatetime -modifiedDatetime" ); if (!task) { - return res.status(400).send({ error: 'This is not a valid task' }); + return res.status(400).send({ error: "This is not a valid task" }); } - const hoursLogged = await timeEntryHelper.getAllHoursLoggedForSpecifiedProject(taskId); - task.set('hoursLogged', hoursLogged, { strict: false }); + const hoursLogged = + await timeEntryHelper.getAllHoursLoggedForSpecifiedProject(taskId); + task.set("hoursLogged", hoursLogged, { strict: false }); // Fetch the resource names for all resources - const resourceNamesPromises = task.resources.map(resource => taskHelper.getUserProfileFirstAndLastName(resource.userID)); + const resourceNamesPromises = task.resources.map((resource) => + taskHelper.getUserProfileFirstAndLastName(resource.userID) + ); const resourceNames = await Promise.all(resourceNamesPromises); // Update the task's resources with the fetched names task.resources.forEach((resource, index) => { - resource.name = resourceNames[index] !== ' ' ? resourceNames[index] : resource.name; + resource.name = + resourceNames[index] !== " " ? resourceNames[index] : resource.name; }); res.status(200).send(task); @@ -820,7 +841,7 @@ const taskController = function (Task) { // Generic error message, you can adjust as needed res .status(500) - .send({ error: 'Internal Server Error', details: error.message }); + .send({ error: "Internal Server Error", details: error.message }); } }; @@ -829,20 +850,20 @@ const taskController = function (Task) { try { Task.find({ wbsId: { $in: [wbsId] } }).then((tasks) => { - tasks = tasks.filter(task => task.level === 1); + tasks = tasks.filter((task) => task.level === 1); tasks.forEach((task) => { updateParents(task.wbsId, task.taskId.toString()); }); - res.status(200).send('done'); + res.status(200).send("done"); }); - res.status(200).send('done'); + res.status(200).send("done"); } catch (error) { res.status(400).send(error); } }; const fixTasks = function (req, res) { - res.status(200).send('done'); + res.status(200).send("done"); }; const getTasksByUserId = async (req, res) => { @@ -850,19 +871,19 @@ const taskController = function (Task) { try { Task.find( { - 'resources.userID': mongoose.Types.ObjectId(userId), + "resources.userID": mongoose.Types.ObjectId(userId), }, - '-resources.profilePic', + "-resources.profilePic" ).then((results) => { WBS.find({ - _id: { $in: results.map(item => item.wbsId) }, + _id: { $in: results.map((item) => item.wbsId) }, }).then((WBSs) => { const resultsWithProjectsIds = results.map((item) => { item.set( - 'projectId', - WBSs?.find(wbs => wbs._id.toString() === item.wbsId.toString()) + "projectId", + WBSs?.find((wbs) => wbs._id.toString() === item.wbsId.toString()) ?.projectId, - { strict: false }, + { strict: false } ); return item; }); @@ -897,10 +918,10 @@ const taskController = function (Task) { Task.findOneAndUpdate( { _id: mongoose.Types.ObjectId(taskId) }, - { ...req.body, modifiedDatetime: Date.now() }, + { ...req.body, modifiedDatetime: Date.now() } ) .then(() => res.status(201).send()) - .catch(error => res.status(404).send(error)); + .catch((error) => res.status(404).send(error)); }; const getReviewReqEmailBody = function (name, taskName) { @@ -917,10 +938,10 @@ const taskController = function (Task) { const recipients = []; const user = await UserProfile.findById(myUserId); const membership = await UserProfile.find({ - role: { $in: ['Administrator', 'Manager', 'Mentor'] }, + role: { $in: ["Administrator", "Manager", "Mentor"] }, }); membership.forEach((member) => { - if (member.teams.some(team => user.teams.includes(team))) { + if (member.teams.some((team) => user.teams.includes(team))) { recipients.push(member.email); } }); @@ -938,11 +959,11 @@ const taskController = function (Task) { `Review Request from ${name}`, emailBody, null, - null, + null ); - res.status(200).send('Success'); + res.status(200).send("Success"); } catch (err) { - res.status(500).send('Failed'); + res.status(500).send("Failed"); } }; diff --git a/src/controllers/teamController.js b/src/controllers/teamController.js index 9cd98036e..0570afc00 100644 --- a/src/controllers/teamController.js +++ b/src/controllers/teamController.js @@ -138,11 +138,11 @@ const teamcontroller = function (Team) { if (operation === 'Assign') { - await Team.findOneAndUpdate({ _id: teamId }, { $addToSet: { members: { userId } }, $set: { modifiedDatetime: Date.now() } }, { new: true }); + await Team.findOneAndUpdate({ _id: teamId }, { $addToSet: { members: { userId } } }, { new: true }); const newMember = await userProfile.findOneAndUpdate({ _id: userId }, { $addToSet: { teams: teamId } }, { new: true }); res.status(200).send({ newMember }); } else { - await Team.findOneAndUpdate({ _id: teamId }, { $pull: { members: { userId } }, $set: { modifiedDatetime: Date.now() } }); + await Team.findOneAndUpdate({ _id: teamId }, { $pull: { members: { userId } } }); await userProfile.findOneAndUpdate({ _id: userId }, { $pull: { teams: teamId } }, { new: true }); res.status(200).send({ result: 'Delete Success' }); } diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index 9bedb0e8f..929b5781b 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -163,10 +163,10 @@ const dashboardhelper = function () { const getLeaderboard = async function (userId) { const userid = mongoose.Types.ObjectId(userId); - const userById = await userProfile.findOne({ _id: userid, isActive: true }, { role: 1 }) - .then(res => res).catch((e) => {}); + const userById = await userProfile.findOne({ _id: userid , isActive:true}, {role:1}) + .then((res)=>{ return res; }).catch((e)=>{}); - if (userById == null) return null; + if(userById==null) return null; const userRole = userById.role; const pdtstart = moment() .tz('America/Los_Angeles') @@ -177,39 +177,42 @@ const dashboardhelper = function () { .endOf('week') .format('YYYY-MM-DD'); - let teamMemberIds = [userid]; + let teamMemberIds = [userid] let teamMembers = []; - if (userRole != 'Administrator' && userRole != 'Owner' && userRole != 'Core Team') // Manager , Mentor , Volunteer ... , Show only team members + if(userRole!='Administrator' && userRole!='Owner' && userRole!='Core Team') //Manager , Mentor , Volunteer ... , Show only team members { - const teamsResult = await team.find({ 'members.userId': { $in: [userid] } }, { members: 1 }) - .then(res => res).catch((e) => {}); - - teamsResult.map((_myTeam) => { - _myTeam.members.map((teamMember) => { - if (!teamMember.userId.equals(userid)) teamMemberIds.push(teamMember.userId); - }); - }); - - teamMembers = await userProfile.find({ _id: { $in: teamMemberIds }, isActive: true }, - { - role: 1, firstName: 1, lastName: 1, isVisible: 1, weeklycommittedHours: 1, weeklySummaries: 1, -}) - .then(res => res).catch((e) => {}); - } else if (userRole == 'Administrator') { // All users except Owner and Core Team + + const teamsResult = await team.find( { "members.userId": { $in: [userid] } }, {members:1} ) + .then((res)=>{ return res; }).catch((e)=>{}) + + teamsResult.map((_myTeam)=>{ + _myTeam.members.map((teamMember)=> { + if(!teamMember.userId.equals(userid)) + teamMemberIds.push( teamMember.userId ); + } ) + }) + + teamMembers = await userProfile.find({ _id: { $in: teamMemberIds } , isActive:true }, + {role:1,firstName:1,lastName:1,isVisible:1,weeklycommittedHours:1,weeklySummaries:1}) + .then((res)=>{ return res; }).catch((e)=>{}) + + } + else { + if(userRole == 'Administrator'){ //All users except Owner and Core Team const excludedRoles = ['Core Team', 'Owner']; - teamMembers = await userProfile.find({ isActive: true, role: { $nin: excludedRoles } }, - { - role: 1, firstName: 1, lastName: 1, isVisible: 1, weeklycommittedHours: 1, weeklySummaries: 1, -}) - .then(res => res).catch((e) => {}); - } else { // 'Core Team', 'Owner' //All users - teamMembers = await userProfile.find({ isActive: true }, - { - role: 1, firstName: 1, lastName: 1, isVisible: 1, weeklycommittedHours: 1, weeklySummaries: 1, -}) - .then(res => res).catch((e) => {}); + teamMembers = await userProfile.find({ isActive:true , role: { $nin: excludedRoles } }, + {role:1,firstName:1,lastName:1,isVisible:1,weeklycommittedHours:1,weeklySummaries:1}) + .then((res)=>{ return res; }).catch((e)=>{}) } + else{ //'Core Team', 'Owner' //All users + teamMembers = await userProfile.find({ isActive:true}, + {role:1,firstName:1,lastName:1,isVisible:1,weeklycommittedHours:1,weeklySummaries:1}) + .then((res)=>{ return res; }).catch((e)=>{}) + } + + + } teamMemberIds = teamMembers.map(member => member._id); @@ -218,14 +221,16 @@ const dashboardhelper = function () { $gte: pdtstart, $lte: pdtend, }, - personId: { $in: teamMemberIds }, + personId: { $in: teamMemberIds } }); - const timeEntryByPerson = {}; - timeEntries.map((timeEntry) => { - const personIdStr = timeEntry.personId.toString(); + let timeEntryByPerson = {} + timeEntries.map((timeEntry)=>{ + + let personIdStr = timeEntry.personId.toString(); - if (timeEntryByPerson[personIdStr] == null) { timeEntryByPerson[personIdStr] = { tangibleSeconds: 0, intangibleSeconds: 0, totalSeconds: 0 }; } + if(timeEntryByPerson[personIdStr]==null) + timeEntryByPerson[personIdStr] = {tangibleSeconds:0,intangibleSeconds:0,totalSeconds:0}; if (timeEntry.isTangible === true) { timeEntryByPerson[personIdStr].tangibleSeconds += timeEntry.totalSeconds; @@ -234,40 +239,41 @@ const dashboardhelper = function () { } timeEntryByPerson[personIdStr].totalSeconds += timeEntry.totalSeconds; - }); - - - const leaderBoardData = []; - teamMembers.map((teamMember) => { - const obj = { - personId: teamMember._id, - role: teamMember.role, - name: `${teamMember.firstName } ${ teamMember.lastName}`, - isVisible: teamMember.isVisible, - hasSummary: teamMember.weeklySummaries?.length > 0 ? teamMember.weeklySummaries[0].summary != '' : false, - weeklycommittedHours: teamMember.weeklycommittedHours, - totaltangibletime_hrs: ((timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / 3600) || 0), - totalintangibletime_hrs: ((timeEntryByPerson[teamMember._id.toString()]?.intangibleSeconds / 3600) || 0), - totaltime_hrs: ((timeEntryByPerson[teamMember._id.toString()]?.totalSeconds / 3600) || 0), - percentagespentintangible: - (timeEntryByPerson[teamMember._id.toString()] && timeEntryByPerson[teamMember._id.toString()]?.totalSeconds != 0 && timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds != 0) - ? (timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / timeEntryByPerson[teamMember._id.toString()]?.totalSeconds) * 100 - : 0, - }; + }) + + + let leaderBoardData = []; + teamMembers.map((teamMember)=>{ + let obj = { + personId : teamMember._id, + role : teamMember.role, + name : teamMember.firstName + ' ' + teamMember.lastName, + isVisible : teamMember.isVisible, + hasSummary : teamMember.weeklySummaries?.length > 0 ? teamMember.weeklySummaries[0].summary!='' : false, + weeklycommittedHours : teamMember.weeklycommittedHours, + totaltangibletime_hrs : ((timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / 3600) || 0), + totalintangibletime_hrs : ((timeEntryByPerson[teamMember._id.toString()]?.intangibleSeconds / 3600) || 0), + totaltime_hrs : ((timeEntryByPerson[teamMember._id.toString()]?.totalSeconds / 3600) || 0), + percentagespentintangible : + (timeEntryByPerson[teamMember._id.toString()] && timeEntryByPerson[teamMember._id.toString()]?.totalSeconds !=0 && timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds !=0) ? + (timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / timeEntryByPerson[teamMember._id.toString()]?.totalSeconds) * 100 + : + 0 + } leaderBoardData.push(obj); - }); + }) - const sortedLBData = leaderBoardData.sort((a, b) => { + let sortedLBData = leaderBoardData.sort((a, b) => { // Sort by totaltangibletime_hrs in descending order if (b.totaltangibletime_hrs !== a.totaltangibletime_hrs) { return b.totaltangibletime_hrs - a.totaltangibletime_hrs; } - + // Then sort by name in ascending order if (a.name !== b.name) { return a.name.localeCompare(b.name); } - + // Finally, sort by role in ascending order return a.role.localeCompare(b.role); }); diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index 800d1ee6b..8c45df737 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -1,5 +1,4 @@ const moment = require('moment-timezone'); -const mongoose = require('mongoose'); const userProfile = require('../models/userProfile'); const timeentry = require('../models/timeentry'); const myTeam = require('../helpers/helperModels/myTeam'); @@ -7,16 +6,15 @@ const team = require('../models/team'); const Task = require('../models/task'); const TaskNotification = require('../models/taskNotification'); const Wbs = require('../models/wbs'); +const mongoose = require('mongoose'); const taskHelper = function () { const getTasksForTeams = async function (userId) { const userid = mongoose.Types.ObjectId(userId); - const userById = await userProfile.findOne({ _id: userid, isActive: true }, { - role: 1, firstName: 1, lastName: 1, role: 1, isVisible: 1, weeklycommittedHours: 1, weeklySummaries: 1, -}) - .then(res => res).catch((e) => {}); + const userById = await userProfile.findOne({ _id: userid , isActive:true}, {role:1,firstName:1, lastName:1, role:1, isVisible:1, weeklycommittedHours:1, weeklySummaries:1}) + .then((res)=>{ return res; }).catch((e)=>{}); - if (userById == null) return null; + if(userById==null) return null; const userRole = userById.role; const pdtstart = moment() @@ -28,39 +26,39 @@ const taskHelper = function () { .endOf('week') .format('YYYY-MM-DD'); - let teamMemberIds = [userid]; + let teamMemberIds = [userid] let teamMembers = []; - if (userRole != 'Administrator' && userRole != 'Owner' && userRole != 'Core Team') // Manager , Mentor , Volunteer ... , Show only team members + if(userRole!='Administrator' && userRole!='Owner' && userRole!='Core Team') //Manager , Mentor , Volunteer ... , Show only team members { - const teamsResult = await team.find({ 'members.userId': { $in: [userid] } }, { members: 1 }) - .then(res => res).catch((e) => {}); + + const teamsResult = await team.find( { "members.userId": { $in: [userid] } }, {members:1} ) + .then((res)=>{ return res; }).catch((e)=>{}) - teamsResult.map((_myTeam) => { - _myTeam.members.map((teamMember) => { - if (!teamMember.userId.equals(userid)) teamMemberIds.push(teamMember.userId); - }); - }); + teamsResult.map((_myTeam)=>{ + _myTeam.members.map((teamMember)=> { + if(!teamMember.userId.equals(userid)) + teamMemberIds.push( teamMember.userId ); + } ) + }) - teamMembers = await userProfile.find({ _id: { $in: teamMemberIds }, isActive: true }, - { - role: 1, firstName: 1, lastName: 1, weeklycommittedHours: 1, -}) - .then(res => res).catch((e) => {}); - } else if (userRole == 'Administrator') { // All users except Owner and Core Team + teamMembers = await userProfile.find({ _id: { $in: teamMemberIds } , isActive:true }, + {role:1,firstName:1,lastName:1,weeklycommittedHours:1}) + .then((res)=>{ return res; }).catch((e)=>{}) + } + else { + if(userRole == 'Administrator'){ //All users except Owner and Core Team const excludedRoles = ['Core Team', 'Owner']; - teamMembers = await userProfile.find({ isActive: true, role: { $nin: excludedRoles } }, - { - role: 1, firstName: 1, lastName: 1, weeklycommittedHours: 1, -}) - .then(res => res).catch((e) => {}); - } else { // 'Core Team', 'Owner' //All users - teamMembers = await userProfile.find({ isActive: true }, - { - role: 1, firstName: 1, lastName: 1, weeklycommittedHours: 1, -}) - .then(res => res).catch((e) => {}); + teamMembers = await userProfile.find({ isActive:true , role: { $nin: excludedRoles } }, + {role:1,firstName:1,lastName:1,weeklycommittedHours:1}) + .then((res)=>{ return res; }).catch((e)=>{}) } + else{ //'Core Team', 'Owner' //All users + teamMembers = await userProfile.find({ isActive:true}, + {role:1,firstName:1,lastName:1,weeklycommittedHours:1}) + .then((res)=>{ return res; }).catch((e)=>{}) + } + } teamMemberIds = teamMembers.map(member => member._id); @@ -69,80 +67,88 @@ const taskHelper = function () { $gte: pdtstart, $lte: pdtend, }, - personId: { $in: teamMemberIds }, + personId: { $in: teamMemberIds } }); - - const timeEntryByPerson = {}; - timeEntries.map((timeEntry) => { - const personIdStr = timeEntry.personId.toString(); - - if (timeEntryByPerson[personIdStr] == null) { timeEntryByPerson[personIdStr] = { tangibleSeconds: 0, intangibleSeconds: 0, totalSeconds: 0 }; } - + + let timeEntryByPerson = {} + timeEntries.map((timeEntry)=>{ + + let personIdStr = timeEntry.personId.toString(); + + if(timeEntryByPerson[personIdStr]==null) + timeEntryByPerson[personIdStr] = {tangibleSeconds:0,intangibleSeconds:0,totalSeconds:0}; + if (timeEntry.isTangible === true) { timeEntryByPerson[personIdStr].tangibleSeconds += timeEntry.totalSeconds; - } + } timeEntryByPerson[personIdStr].totalSeconds += timeEntry.totalSeconds; - }); + }) - const teamMemberTasks = await Task.find({ 'resources.userID': { $in: teamMemberIds } }, { 'resources.profilePic': 0 }) - .populate({ + const teamMemberTasks = await Task.find({"resources.userID" : {$in : teamMemberIds }}, { 'resources.profilePic': 0 }) + .populate( { path: 'wbsId', select: 'projectId', - }); + }) const teamMemberTaskIds = teamMemberTasks.map(task => task._id); - const teamMemberTaskNotifications = await TaskNotification.find({ taskId: { $in: teamMemberTaskIds } }); + const teamMemberTaskNotifications = await TaskNotification.find({"taskId" : {$in : teamMemberTaskIds }}) + + const taskNotificationByTaskNdUser = [] + teamMemberTaskNotifications.map(teamMemberTaskNotification => { - const taskNotificationByTaskNdUser = []; - teamMemberTaskNotifications.map((teamMemberTaskNotification) => { - const taskIdStr = teamMemberTaskNotification.taskId.toString(); - const userIdStr = teamMemberTaskNotification.userId.toString(); - const taskNdUserID = `${taskIdStr},${userIdStr}`; + let taskIdStr = teamMemberTaskNotification.taskId.toString(); + let userIdStr = teamMemberTaskNotification.userId.toString(); + let taskNdUserID = taskIdStr+","+userIdStr; - if (taskNotificationByTaskNdUser[taskNdUserID]) { - taskNotificationByTaskNdUser[taskNdUserID].push(teamMemberTaskNotification); - } else { - taskNotificationByTaskNdUser[taskNdUserID] = [teamMemberTaskNotification]; + if(taskNotificationByTaskNdUser[taskNdUserID]) { + taskNotificationByTaskNdUser[taskNdUserID].push(teamMemberTaskNotification) + } + else{ + taskNotificationByTaskNdUser[taskNdUserID] = [teamMemberTaskNotification] } - }); - const taskByPerson = []; + }) + + const taskByPerson = [] + + teamMemberTasks.map(teamMemberTask => { - teamMemberTasks.map((teamMemberTask) => { - const projId = teamMemberTask.wbsId?.projectId; - const _teamMemberTask = { ...teamMemberTask._doc }; + let projId = teamMemberTask.wbsId?.projectId; + let _teamMemberTask = {...teamMemberTask._doc} _teamMemberTask.projectId = projId; - const taskIdStr = _teamMemberTask._id.toString(); + let taskIdStr = _teamMemberTask._id.toString(); - teamMemberTask.resources.map((resource) => { - const resourceIdStr = resource.userID.toString(); - const taskNdUserID = `${taskIdStr},${resourceIdStr}`; - _teamMemberTask.taskNotifications = taskNotificationByTaskNdUser[taskNdUserID] || []; - if (taskByPerson[resourceIdStr]) { - taskByPerson[resourceIdStr].push(_teamMemberTask); - } else { - taskByPerson[resourceIdStr] = [_teamMemberTask]; + teamMemberTask.resources.map(resource => { + + let resourceIdStr = resource.userID.toString(); + let taskNdUserID = taskIdStr+","+resourceIdStr; + _teamMemberTask.taskNotifications = taskNotificationByTaskNdUser[taskNdUserID] || [] + if(taskByPerson[resourceIdStr]) { + taskByPerson[resourceIdStr].push(_teamMemberTask) } - }); - }); - + else{ + taskByPerson[resourceIdStr] = [_teamMemberTask] + } + }) + }) - const teamMemberTasksData = []; - teamMembers.map((teamMember) => { - const obj = { - personId: teamMember._id, - role: teamMember.role, - name: `${teamMember.firstName } ${ teamMember.lastName}`, - weeklycommittedHours: teamMember.weeklycommittedHours, - totaltangibletime_hrs: ((timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / 3600) || 0), - totaltime_hrs: ((timeEntryByPerson[teamMember._id.toString()]?.totalSeconds / 3600) || 0), - tasks: taskByPerson[teamMember._id.toString()] || [], - }; + + let teamMemberTasksData = []; + teamMembers.map((teamMember)=>{ + let obj = { + personId : teamMember._id, + role : teamMember.role, + name : teamMember.firstName + ' ' + teamMember.lastName, + weeklycommittedHours : teamMember.weeklycommittedHours, + totaltangibletime_hrs : ((timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / 3600) || 0), + totaltime_hrs : ((timeEntryByPerson[teamMember._id.toString()]?.totalSeconds / 3600) || 0), + tasks : taskByPerson[teamMember._id.toString()] || [] + } teamMemberTasksData.push(obj); - }); + }) return teamMemberTasksData; - + // return myteam.aggregate([ // { diff --git a/src/models/mapLocation.js b/src/models/mapLocation.js index cb5644d31..851587dc3 100644 --- a/src/models/mapLocation.js +++ b/src/models/mapLocation.js @@ -5,7 +5,7 @@ const { Schema } = mongoose; const mapLocation = new Schema({ title: { type: String, - default: 'Prior to HGN Data Collection', + default: 'Prior to HGN Data Collection' }, firstName: String, lastName: String, @@ -27,7 +27,7 @@ const mapLocation = new Schema({ lng: { type: String, required: true, - }, + } }, country: { type: String, diff --git a/src/routes/bmdashboard/bmMaterialsRouter.js b/src/routes/bmdashboard/bmMaterialsRouter.js index 9a520d7d6..51c5f437f 100644 --- a/src/routes/bmdashboard/bmMaterialsRouter.js +++ b/src/routes/bmdashboard/bmMaterialsRouter.js @@ -9,11 +9,11 @@ const routes = function (itemMaterial, buildingMaterial) { materialsRouter.route('/updateMaterialRecord') .post(controller.bmPostMaterialUpdateRecord); - + materialsRouter.route('/updateMaterialRecordBulk') .post(controller.bmPostMaterialUpdateBulk); - - + + return materialsRouter; }; diff --git a/src/routes/mapLocationsRouter.js b/src/routes/mapLocationsRouter.js index 84cb85feb..db004ff18 100644 --- a/src/routes/mapLocationsRouter.js +++ b/src/routes/mapLocationsRouter.js @@ -11,7 +11,7 @@ const router = function (mapLocations) { .patch(controller.updateUserLocation); mapRouter.route('/mapLocations/:locationId') - .delete(controller.deleteLocation); + .delete(controller.deleteLocation) return mapRouter; }; diff --git a/src/routes/profileInitialSetupRouter.js b/src/routes/profileInitialSetupRouter.js index 544c5c878..12f677224 100644 --- a/src/routes/profileInitialSetupRouter.js +++ b/src/routes/profileInitialSetupRouter.js @@ -1,8 +1,8 @@ const express = require('express'); -const routes = function (ProfileInitialSetupToken, userProfile, Project, mapLocations) { +const routes = function (ProfileInitialSetupToken, userProfile, Project , mapLocations) { const ProfileInitialSetup = express.Router(); - const controller = require('../controllers/profileInitialSetupController')(ProfileInitialSetupToken, userProfile, Project, mapLocations); + const controller = require('../controllers/profileInitialSetupController')(ProfileInitialSetupToken, userProfile, Project , mapLocations); ProfileInitialSetup.route('/getInitialSetuptoken') .post(controller.getSetupToken); ProfileInitialSetup.route('/ProfileInitialSetup').post(controller.setUpNewUser); diff --git a/src/startup/routes.js b/src/startup/routes.js index 95cade0fd..da7515021 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -46,7 +46,7 @@ const popupBackupRouter = require('../routes/popupEditorBackupRouter')(popupBack const taskNotificationRouter = require('../routes/taskNotificationRouter')(taskNotification); const inventoryRouter = require('../routes/inventoryRouter')(inventoryItem, inventoryItemType); const timeZoneAPIRouter = require('../routes/timeZoneAPIRoutes')(); -const profileInitialSetupRouter = require('../routes/profileInitialSetupRouter')(profileInitialSetuptoken, userProfile, project, mapLocations); +const profileInitialSetupRouter = require('../routes/profileInitialSetupRouter')(profileInitialSetuptoken, userProfile, project , mapLocations); const isEmailExistsRouter = require('../routes/isEmailExistsRouter')(); diff --git a/src/utilities/emailSender.js b/src/utilities/emailSender.js index 7199202e9..b07f9a8c9 100644 --- a/src/utilities/emailSender.js +++ b/src/utilities/emailSender.js @@ -35,7 +35,7 @@ const closure = () => { if (!nextItem) return; const { - recipient, subject, message, cc, bcc, replyTo, acknowledgingReceipt, + recipient, subject, message, cc, bcc, replyTo, acknowledgingReceipt } = nextItem; try { @@ -60,13 +60,13 @@ const closure = () => { const result = await transporter.sendMail(mailOptions); if (typeof acknowledgingReceipt === 'function') { - acknowledgingReceipt(null, result); - } + acknowledgingReceipt(null,result); + } logger.logInfo(result); } catch (error) { if (typeof acknowledgingReceipt === 'function') { - acknowledgingReceipt(error, null); - } + acknowledgingReceipt(error,null); + } logger.logException(error); } }, process.env.MAIL_QUEUE_INTERVAL || 1000); @@ -88,7 +88,7 @@ const closure = () => { cc, bcc, replyTo, - acknowledgingReceipt, + acknowledgingReceipt }); } }; From 33f99abc2e707af336d50a25eb8ab05bdc81acce Mon Sep 17 00:00:00 2001 From: tsunami776 <43768723+tsunami776@users.noreply.github.com> Date: Fri, 5 Jan 2024 22:14:07 -0600 Subject: [PATCH 255/272] revert changes --- src/controllers/teamController.js | 4 ++-- src/routes/bmdashboard/bmMaterialsRouter.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/controllers/teamController.js b/src/controllers/teamController.js index 0570afc00..9cd98036e 100644 --- a/src/controllers/teamController.js +++ b/src/controllers/teamController.js @@ -138,11 +138,11 @@ const teamcontroller = function (Team) { if (operation === 'Assign') { - await Team.findOneAndUpdate({ _id: teamId }, { $addToSet: { members: { userId } } }, { new: true }); + await Team.findOneAndUpdate({ _id: teamId }, { $addToSet: { members: { userId } }, $set: { modifiedDatetime: Date.now() } }, { new: true }); const newMember = await userProfile.findOneAndUpdate({ _id: userId }, { $addToSet: { teams: teamId } }, { new: true }); res.status(200).send({ newMember }); } else { - await Team.findOneAndUpdate({ _id: teamId }, { $pull: { members: { userId } } }); + await Team.findOneAndUpdate({ _id: teamId }, { $pull: { members: { userId } }, $set: { modifiedDatetime: Date.now() } }); await userProfile.findOneAndUpdate({ _id: userId }, { $pull: { teams: teamId } }, { new: true }); res.status(200).send({ result: 'Delete Success' }); } diff --git a/src/routes/bmdashboard/bmMaterialsRouter.js b/src/routes/bmdashboard/bmMaterialsRouter.js index 51c5f437f..9fef2f956 100644 --- a/src/routes/bmdashboard/bmMaterialsRouter.js +++ b/src/routes/bmdashboard/bmMaterialsRouter.js @@ -17,4 +17,4 @@ const routes = function (itemMaterial, buildingMaterial) { return materialsRouter; }; -module.exports = routes; +module.exports = routes; \ No newline at end of file From f939225f6a6a7b5404c423a533392b91287cd99a Mon Sep 17 00:00:00 2001 From: tsunami776 <43768723+tsunami776@users.noreply.github.com> Date: Fri, 5 Jan 2024 22:15:57 -0600 Subject: [PATCH 256/272] revert lint --- src/controllers/dashBoardController.js | 2 +- src/routes/bmdashboard/bmMaterialsRouter.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/dashBoardController.js b/src/controllers/dashBoardController.js index 3fdda9eb7..30bddc871 100644 --- a/src/controllers/dashBoardController.js +++ b/src/controllers/dashBoardController.js @@ -274,4 +274,4 @@ const dashboardcontroller = function () { }; }; -module.exports = dashboardcontroller; +module.exports = dashboardcontroller; \ No newline at end of file diff --git a/src/routes/bmdashboard/bmMaterialsRouter.js b/src/routes/bmdashboard/bmMaterialsRouter.js index 9fef2f956..51c5f437f 100644 --- a/src/routes/bmdashboard/bmMaterialsRouter.js +++ b/src/routes/bmdashboard/bmMaterialsRouter.js @@ -17,4 +17,4 @@ const routes = function (itemMaterial, buildingMaterial) { return materialsRouter; }; -module.exports = routes; \ No newline at end of file +module.exports = routes; From f08d2d5066115bfd10ef6d3d5781d7e464438099 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Sun, 7 Jan 2024 12:18:39 -0800 Subject: [PATCH 257/272] update mats route, controller to use updated model. isolate populate method causing fetch err. --- src/controllers/bmdashboard/bmMaterialsController.js | 10 +++++----- src/routes/bmdashboard/bmMaterialsRouter.js | 4 ++-- src/startup/routes.js | 7 ++++--- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index da45aad1d..0191b56fc 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -1,6 +1,6 @@ const mongoose = require('mongoose'); -const bmMaterialsController = function (ItemMaterial, BuildingMaterial) { +const bmMaterialsController = function (BuildingMaterial) { const bmMaterialsList = async function _matsList(req, res) { try { BuildingMaterial.find() @@ -9,10 +9,10 @@ const bmMaterialsController = function (ItemMaterial, BuildingMaterial) { path: 'project', select: '_id name', }, - { - path: 'itemType', - select: '_id name unit', - }, + // { + // path: 'itemType', + // select: '_id name unit', + // }, { path: 'updateRecord', populate: { diff --git a/src/routes/bmdashboard/bmMaterialsRouter.js b/src/routes/bmdashboard/bmMaterialsRouter.js index 9a520d7d6..733148d14 100644 --- a/src/routes/bmdashboard/bmMaterialsRouter.js +++ b/src/routes/bmdashboard/bmMaterialsRouter.js @@ -1,8 +1,8 @@ const express = require('express'); -const routes = function (itemMaterial, buildingMaterial) { +const routes = function (buildingMaterial) { const materialsRouter = express.Router(); - const controller = require('../../controllers/bmdashboard/bmMaterialsController')(itemMaterial, buildingMaterial); + const controller = require('../../controllers/bmdashboard/bmMaterialsController')(buildingMaterial); materialsRouter.route('/materials') .get(controller.bmMaterialsList) .post(controller.bmPurchaseMaterials); diff --git a/src/startup/routes.js b/src/startup/routes.js index 1ac1d669b..492e455cd 100644 --- a/src/startup/routes.js +++ b/src/startup/routes.js @@ -21,10 +21,10 @@ const weeklySummaryAIPrompt = require('../models/weeklySummaryAIPrompt'); const profileInitialSetuptoken = require('../models/profileInitialSetupToken'); const reason = require('../models/reason'); const mouseoverText = require('../models/mouseoverText'); -const inventoryItemMaterial = require('../models/inventoryItemMaterial'); +// const inventoryItemMaterial = require('../models/inventoryItemMaterial'); const mapLocations = require('../models/mapLocation'); const buildingProject = require('../models/bmdashboard/buildingProject'); -const buildingMaterial = require('../models/bmdashboard/buildingMaterial'); +// const buildingMaterial = require('../models/bmdashboard/buildingMaterial'); const { invTypeBase, materialType, @@ -35,6 +35,7 @@ const { } = require('../models/bmdashboard/buildingInventoryType'); const { buildingConsumable, + buildingMaterial, } = require('../models/bmdashboard/buildingInventoryItem'); const buildingTool = require('../models/bmdashboard/buildingTool'); @@ -75,7 +76,7 @@ const mapLocationRouter = require('../routes/mapLocationsRouter')(mapLocations); // bm dashboard const bmLoginRouter = require('../routes/bmdashboard/bmLoginRouter')(); -const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(inventoryItemMaterial, buildingMaterial); +const bmMaterialsRouter = require('../routes/bmdashboard/bmMaterialsRouter')(buildingMaterial); const bmProjectRouter = require('../routes/bmdashboard/bmProjectRouter')(buildingProject); const bmConsumablesRouter = require('../routes/bmdashboard/bmConsumablesRouter')(buildingConsumable); const bmInventoryTypeRouter = require('../routes/bmdashboard/bmInventoryTypeRouter')(invTypeBase, materialType, consumableType, reusableType, toolType, equipmentType); From 273fa005f4cf6ebd3f1d60b734858cba39fa436b Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Sun, 7 Jan 2024 12:52:01 -0800 Subject: [PATCH 258/272] update populate ref string --- src/controllers/bmdashboard/bmMaterialsController.js | 8 ++++---- src/models/bmdashboard/buildingInventoryItem.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index 0191b56fc..51295d035 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -9,10 +9,10 @@ const bmMaterialsController = function (BuildingMaterial) { path: 'project', select: '_id name', }, - // { - // path: 'itemType', - // select: '_id name unit', - // }, + { + path: 'itemType', + select: '_id name unit', + }, { path: 'updateRecord', populate: { diff --git a/src/models/bmdashboard/buildingInventoryItem.js b/src/models/bmdashboard/buildingInventoryItem.js index dfaa8c73a..c44f37211 100644 --- a/src/models/bmdashboard/buildingInventoryItem.js +++ b/src/models/bmdashboard/buildingInventoryItem.js @@ -11,7 +11,7 @@ const mongoose = require('mongoose'); // documents stored in 'buildingInventoryItems' collection const smallItemBaseSchema = mongoose.Schema({ - itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, + itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'invTypeBase' }, project: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingProject' }, stockBought: { type: Number, default: 0 }, // total amount of item bought for use in the project // TODO: can stockAvailable default be a function? From 66d3814f11d40fc94c0b028556cde2d1b7e2aaf4 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Sun, 7 Jan 2024 13:27:58 -0800 Subject: [PATCH 259/272] update brand to brandPref --- .../bmdashboard/bmMaterialsController.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/controllers/bmdashboard/bmMaterialsController.js b/src/controllers/bmdashboard/bmMaterialsController.js index 51295d035..207e2428a 100644 --- a/src/controllers/bmdashboard/bmMaterialsController.js +++ b/src/controllers/bmdashboard/bmMaterialsController.js @@ -42,15 +42,9 @@ const bmMaterialsController = function (BuildingMaterial) { matTypeId, quantity, priority, - brand, + brand: brandPref, requestor: { requestorId }, } = req.body; - const newPurchaseRecord = { - quantity, - priority, - brand, - requestedBy: requestorId, - }; try { // check if requestor has permission to make purchase request //! Note: this code is disabled until permissions are added @@ -64,6 +58,12 @@ const bmMaterialsController = function (BuildingMaterial) { // check if the material is already being used in the project // if no, add a new document to the collection // if yes, update the existing document + const newPurchaseRecord = { + quantity, + priority, + brandPref, + requestedBy: requestorId, + }; const doc = await BuildingMaterial.findOne({ project: projectId, itemType: matTypeId }); if (!doc) { const newDoc = { From 7b4f5431ff0fdf48b097fb9fea7181fef8d93f2d Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Sun, 7 Jan 2024 19:55:18 -0800 Subject: [PATCH 260/272] update lookup func in BuildingProject aggregator to fetch from correct collection and limit results to materials --- src/controllers/bmdashboard/bmProjectController.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/controllers/bmdashboard/bmProjectController.js b/src/controllers/bmdashboard/bmProjectController.js index b6b3e4e18..a4f6712e0 100644 --- a/src/controllers/bmdashboard/bmProjectController.js +++ b/src/controllers/bmdashboard/bmProjectController.js @@ -31,10 +31,11 @@ const bmMProjectController = function (BuildingProject) { { $unwind: '$buildingManager' }, { $lookup: { - from: 'buildingMaterials', + from: 'buildingInventoryItems', let: { id: '$_id' }, pipeline: [ { $match: { $expr: { $eq: ['$project', '$$id'] } } }, + { $match: { __t: 'material_item' } }, { $project: { updateRecord: 0, project: 0 } }, { $lookup: { From 90692149b687e823f3de95c2ba21bf71b03ef376 Mon Sep 17 00:00:00 2001 From: Tim Kent Date: Sun, 7 Jan 2024 20:32:38 -0800 Subject: [PATCH 261/272] update itemType ref in large item schema --- src/models/bmdashboard/buildingInventoryItem.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/bmdashboard/buildingInventoryItem.js b/src/models/bmdashboard/buildingInventoryItem.js index c44f37211..fdcfde3dd 100644 --- a/src/models/bmdashboard/buildingInventoryItem.js +++ b/src/models/bmdashboard/buildingInventoryItem.js @@ -41,7 +41,7 @@ const smallItemBase = mongoose.model('smallItemBase', smallItemBaseSchema, 'buil // documents stored in 'buildingInventoryItems' collection const largeItemBaseSchema = mongoose.Schema({ - itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingInventoryType' }, + itemType: { type: mongoose.SchemaTypes.ObjectId, ref: 'invTypeBase' }, project: { type: mongoose.SchemaTypes.ObjectId, ref: 'buildingProject' }, purchaseStatus: { type: String, enum: ['Rental', 'Purchase'], required: true }, // rental fields are required if purchaseStatus = "Rental" (hopefully correct syntax) From 37ba941687f2a59a3b5741089fd5b7215288590f Mon Sep 17 00:00:00 2001 From: Shiwani Rajagopalan Date: Mon, 8 Jan 2024 03:45:22 -0500 Subject: [PATCH 262/272] added timeOffFrom and timeOffTill fields to new aggregation in taskHelper and dashboardHelper --- src/helpers/dashboardhelper.js | 719 +++++++++++++++++++----------- src/helpers/taskHelper.js | 789 ++++++++++++++++++++------------- 2 files changed, 935 insertions(+), 573 deletions(-) diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index 48f9047da..4a6605213 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -3,6 +3,7 @@ const mongoose = require("mongoose"); const userProfile = require("../models/userProfile"); const timeentry = require("../models/timeentry"); const myTeam = require("../helpers/helperModels/myTeam"); +const team = require("../models/team"); const dashboardhelper = function () { const personaldetails = function (userId) { @@ -69,6 +70,16 @@ const dashboardhelper = function () { { $lte: ["$$timeentry.dateOfWork", pdtend], }, + { + $not: [ + { + $in: [ + "$$timeentry.entryType", + ["person", "team", "project"], + ], + }, + ], + }, ], }, }, @@ -152,8 +163,15 @@ const dashboardhelper = function () { return output; }; - const getLeaderboard = function (userId) { + const getLeaderboard = async function (userId) { const userid = mongoose.Types.ObjectId(userId); + const userById = await userProfile + .findOne({ _id: userid, isActive: true }, { role: 1 }) + .then((res) => res) + .catch((e) => {}); + + if (userById == null) return null; + const userRole = userById.role; const pdtstart = moment() .tz("America/Los_Angeles") .startOf("week") @@ -162,274 +180,416 @@ const dashboardhelper = function () { .tz("America/Los_Angeles") .endOf("week") .format("YYYY-MM-DD"); - return myTeam.aggregate([ - { - $match: { - _id: userid, - }, - }, - { - $unwind: "$myteam", - }, - { - $project: { - _id: 0, - role: 1, - personId: "$myteam._id", - name: "$myteam.fullName", - }, - }, - { - $lookup: { - from: "userProfiles", - localField: "personId", - foreignField: "_id", - as: "persondata", - }, - }, - { - $match: { - // leaderboard user roles hierarchy - $or: [ - { - role: { $in: ["Owner", "Core Team"] }, - }, - { - $and: [ - { - role: "Administrator", - }, - { "persondata.0.role": { $nin: ["Owner", "Administrator"] } }, - ], - }, - { - $and: [ - { - role: { $in: ["Manager", "Mentor"] }, - }, - { - "persondata.0.role": { - $nin: [ - "Manager", - "Mentor", - "Core Team", - "Administrator", - "Owner", - ], - }, - }, - ], - }, - { "persondata.0._id": userId }, - { "persondata.0.role": "Volunteer" }, - { "persondata.0.isVisible": true }, - ], - }, - }, - { - $project: { - personId: 1, - name: 1, - role: { - $arrayElemAt: ["$persondata.role", 0], - }, - isVisible: { - $arrayElemAt: ["$persondata.isVisible", 0], - }, - hasSummary: { - $ne: [ - { - $arrayElemAt: [ - { - $arrayElemAt: ["$persondata.weeklySummaries.summary", 0], - }, - 0, - ], - }, - "", - ], - }, - weeklycommittedHours: { - $sum: [ - { - $arrayElemAt: ["$persondata.weeklycommittedHours", 0], - }, - { - $ifNull: [{ $arrayElemAt: ["$persondata.missedHours", 0] }, 0], - }, - ], - }, - timeOffFrom: { - $ifNull: [{ $arrayElemAt: ["$persondata.timeOffFrom", 0] }, null], - }, - timeOffTill: { - $ifNull: [{ $arrayElemAt: ["$persondata.timeOffTill", 0] }, null], - }, - }, - }, - { - $lookup: { - from: "timeEntries", - localField: "personId", - foreignField: "personId", - as: "timeEntryData", - }, - }, - { - $project: { - personId: 1, - name: 1, - role: 1, - isVisible: 1, - hasSummary: 1, - weeklycommittedHours: 1, - timeOffFrom: 1, - timeOffTill: 1, - timeEntryData: { - $filter: { - input: "$timeEntryData", - as: "timeentry", - cond: { - $and: [ - { - $gte: ["$$timeentry.dateOfWork", pdtstart], - }, - { - $lte: ["$$timeentry.dateOfWork", pdtend], - }, - ], - }, - }, - }, - }, - }, - { - $unwind: { - path: "$timeEntryData", - preserveNullAndEmptyArrays: true, - }, - }, - { - $project: { - personId: 1, - name: 1, - role: 1, - isVisible: 1, - hasSummary: 1, - weeklycommittedHours: 1, - timeOffFrom: 1, - timeOffTill: 1, - totalSeconds: { - $cond: [ - { - $gte: ["$timeEntryData.totalSeconds", 0], - }, - "$timeEntryData.totalSeconds", - 0, - ], - }, - isTangible: { - $cond: [ - { - $gte: ["$timeEntryData.totalSeconds", 0], - }, - "$timeEntryData.isTangible", - false, - ], - }, - }, - }, - { - $addFields: { - tangibletime: { - $cond: [ - { - $eq: ["$isTangible", true], - }, - "$totalSeconds", - 0, - ], - }, - intangibletime: { - $cond: [ - { - $eq: ["$isTangible", false], - }, - "$totalSeconds", - 0, - ], - }, - }, - }, - { - $group: { - _id: { - personId: "$personId", - weeklycommittedHours: "$weeklycommittedHours", - timeOffFrom: "$timeOffFrom", - timeOffTill: "$timeOffTill", - name: "$name", - role: "$role", - isVisible: "$isVisible", - hasSummary: "$hasSummary", - }, - totalSeconds: { - $sum: "$totalSeconds", - }, - tangibletime: { - $sum: "$tangibletime", - }, - intangibletime: { - $sum: "$intangibletime", - }, - }, - }, - { - $project: { - _id: 0, - personId: "$_id.personId", - name: "$_id.name", - role: "$_id.role", - isVisible: "$_id.isVisible", - hasSummary: "$_id.hasSummary", - weeklycommittedHours: "$_id.weeklycommittedHours", - totaltime_hrs: { - $divide: ["$totalSeconds", 3600], - }, - totaltangibletime_hrs: { - $divide: ["$tangibletime", 3600], - }, - totalintangibletime_hrs: { - $divide: ["$intangibletime", 3600], - }, - percentagespentintangible: { - $cond: [ - { - $eq: ["$totalSeconds", 0], - }, - 0, - { - $multiply: [ - { - $divide: ["$tangibletime", "$totalSeconds"], - }, - 100, - ], - }, - ], - }, - timeOffFrom: "$_id.timeOffFrom", - timeOffTill: "$_id.timeOffTill", - }, - }, - { - $sort: { - totaltangibletime_hrs: -1, - name: 1, - role: 1, - }, + + let teamMemberIds = [userid]; + let teamMembers = []; + + if ( + userRole != "Administrator" && + userRole != "Owner" && + userRole != "Core Team" + ) { + // Manager , Mentor , Volunteer ... , Show only team members + const teamsResult = await team + .find({ "members.userId": { $in: [userid] } }, { members: 1 }) + .then((res) => res) + .catch((e) => {}); + + teamsResult.map((_myTeam) => { + _myTeam.members.map((teamMember) => { + if (!teamMember.userId.equals(userid)) + teamMemberIds.push(teamMember.userId); + }); + }); + + teamMembers = await userProfile + .find( + { _id: { $in: teamMemberIds }, isActive: true }, + { + role: 1, + firstName: 1, + lastName: 1, + isVisible: 1, + weeklycommittedHours: 1, + weeklySummaries: 1, + timeOffFrom: 1, + timeOffTill: 1, + } + ) + .then((res) => res) + .catch((e) => {}); + } else if (userRole == "Administrator") { + // All users except Owner and Core Team + const excludedRoles = ["Core Team", "Owner"]; + teamMembers = await userProfile + .find( + { isActive: true, role: { $nin: excludedRoles } }, + { + role: 1, + firstName: 1, + lastName: 1, + isVisible: 1, + weeklycommittedHours: 1, + weeklySummaries: 1, + timeOffFrom: 1, + timeOffTill: 1, + } + ) + .then((res) => res) + .catch((e) => {}); + } else { + // 'Core Team', 'Owner' //All users + teamMembers = await userProfile + .find( + { isActive: true }, + { + role: 1, + firstName: 1, + lastName: 1, + isVisible: 1, + weeklycommittedHours: 1, + weeklySummaries: 1, + timeOffFrom: 1, + timeOffTill: 1, + } + ) + .then((res) => res) + .catch((e) => {}); + } + + teamMemberIds = teamMembers.map((member) => member._id); + + const timeEntries = await timeentry.find({ + dateOfWork: { + $gte: pdtstart, + $lte: pdtend, }, - ]); + personId: { $in: teamMemberIds }, + }); + + const timeEntryByPerson = {}; + timeEntries.map((timeEntry) => { + const personIdStr = timeEntry.personId.toString(); + + if (timeEntryByPerson[personIdStr] == null) { + timeEntryByPerson[personIdStr] = { + tangibleSeconds: 0, + intangibleSeconds: 0, + totalSeconds: 0, + }; + } + + if (timeEntry.isTangible === true) { + timeEntryByPerson[personIdStr].tangibleSeconds += + timeEntry.totalSeconds; + } else { + timeEntryByPerson[personIdStr].intangibleSeconds += + timeEntry.totalSeconds; + } + + timeEntryByPerson[personIdStr].totalSeconds += timeEntry.totalSeconds; + }); + + const leaderBoardData = []; + teamMembers.map((teamMember) => { + const obj = { + personId: teamMember._id, + role: teamMember.role, + name: `${teamMember.firstName} ${teamMember.lastName}`, + isVisible: teamMember.isVisible, + hasSummary: + teamMember.weeklySummaries?.length > 0 + ? teamMember.weeklySummaries[0].summary != "" + : false, + weeklycommittedHours: teamMember.weeklycommittedHours, + totaltangibletime_hrs: + timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / + 3600 || 0, + totalintangibletime_hrs: + timeEntryByPerson[teamMember._id.toString()]?.intangibleSeconds / + 3600 || 0, + totaltime_hrs: + timeEntryByPerson[teamMember._id.toString()]?.totalSeconds / 3600 || + 0, + percentagespentintangible: + timeEntryByPerson[teamMember._id.toString()] && + timeEntryByPerson[teamMember._id.toString()]?.totalSeconds != 0 && + timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds != 0 + ? (timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / + timeEntryByPerson[teamMember._id.toString()]?.totalSeconds) * + 100 + : 0, + timeOffFrom: teamMember.timeOffFrom || null, + timeOffTill: teamMember.timeOffTill || null, + }; + leaderBoardData.push(obj); + }); + + const sortedLBData = leaderBoardData.sort((a, b) => { + // Sort by totaltangibletime_hrs in descending order + if (b.totaltangibletime_hrs !== a.totaltangibletime_hrs) { + return b.totaltangibletime_hrs - a.totaltangibletime_hrs; + } + + // Then sort by name in ascending order + if (a.name !== b.name) { + return a.name.localeCompare(b.name); + } + + // Finally, sort by role in ascending order + return a.role.localeCompare(b.role); + }); + + return sortedLBData; + + // return myTeam.aggregate([ + // { + // $match: { + // _id: userid, + // }, + // }, + // { + // $unwind: '$myteam', + // }, + // { + // $project: { + // _id: 0, + // role: 1, + // personId: '$myteam._id', + // name: '$myteam.fullName', + // }, + // }, + // { + // $lookup: { + // from: 'userProfiles', + // localField: 'personId', + // foreignField: '_id', + // as: 'persondata', + // }, + // }, + // { + // $match: { + // // leaderboard user roles hierarchy + // $or: [ + // { + // role: { $in: ['Owner', 'Core Team'] }, + // }, + // { + // $and: [ + // { + // role: 'Administrator', + // }, + // { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, + // ], + // }, + // { + // $and: [ + // { + // role: { $in: ['Manager', 'Mentor'] }, + // }, + // { + // 'persondata.0.role': { + // $nin: ['Manager', 'Mentor', 'Core Team', 'Administrator', 'Owner'], + // }, + // }, + // ], + // }, + // { 'persondata.0._id': userId }, + // { 'persondata.0.role': 'Volunteer' }, + // { 'persondata.0.isVisible': true }, + // ], + // }, + // }, + // { + // $project: { + // personId: 1, + // name: 1, + // role: { + // $arrayElemAt: ['$persondata.role', 0], + // }, + // isVisible: { + // $arrayElemAt: ['$persondata.isVisible', 0], + // }, + // hasSummary: { + // $ne: [ + // { + // $arrayElemAt: [ + // { + // $arrayElemAt: ['$persondata.weeklySummaries.summary', 0], + // }, + // 0, + // ], + // }, + // '', + // ], + // }, + // weeklycommittedHours: { + // $sum: [ + // { + // $arrayElemAt: ['$persondata.weeklycommittedHours', 0], + // }, + // { + // $ifNull: [{ $arrayElemAt: ['$persondata.missedHours', 0] }, 0], + // }, + // ], + // }, + // }, + // }, + // { + // $lookup: { + // from: 'timeEntries', + // localField: 'personId', + // foreignField: 'personId', + // as: 'timeEntryData', + // }, + // }, + // { + // $project: { + // personId: 1, + // name: 1, + // role: 1, + // isVisible: 1, + // hasSummary: 1, + // weeklycommittedHours: 1, + // timeEntryData: { + // $filter: { + // input: '$timeEntryData', + // as: 'timeentry', + // cond: { + // $and: [ + // { + // $gte: ['$$timeentry.dateOfWork', pdtstart], + // }, + // { + // $lte: ['$$timeentry.dateOfWork', pdtend], + // }, + // ], + // }, + // }, + // }, + // }, + // }, + // { + // $unwind: { + // path: '$timeEntryData', + // preserveNullAndEmptyArrays: true, + // }, + // }, + // { + // $project: { + // personId: 1, + // name: 1, + // role: 1, + // isVisible: 1, + // hasSummary: 1, + // weeklycommittedHours: 1, + // totalSeconds: { + // $cond: [ + // { + // $gte: ['$timeEntryData.totalSeconds', 0], + // }, + // '$timeEntryData.totalSeconds', + // 0, + // ], + // }, + // isTangible: { + // $cond: [ + // { + // $gte: ['$timeEntryData.totalSeconds', 0], + // }, + // '$timeEntryData.isTangible', + // false, + // ], + // }, + // }, + // }, + // { + // $addFields: { + // tangibletime: { + // $cond: [ + // { + // $eq: ['$isTangible', true], + // }, + // '$totalSeconds', + // 0, + // ], + // }, + // intangibletime: { + // $cond: [ + // { + // $eq: ['$isTangible', false], + // }, + // '$totalSeconds', + // 0, + // ], + // }, + // }, + // }, + // { + // $group: { + // _id: { + // personId: '$personId', + // weeklycommittedHours: '$weeklycommittedHours', + // name: '$name', + // role: '$role', + // isVisible: '$isVisible', + // hasSummary: '$hasSummary', + // }, + // totalSeconds: { + // $sum: '$totalSeconds', + // }, + // tangibletime: { + // $sum: '$tangibletime', + // }, + // intangibletime: { + // $sum: '$intangibletime', + // }, + // }, + // }, + // { + // $project: { + // _id: 0, + // personId: '$_id.personId', + // name: '$_id.name', + // role: '$_id.role', + // isVisible: '$_id.isVisible', + // hasSummary: '$_id.hasSummary', + // weeklycommittedHours: '$_id.weeklycommittedHours', + // totaltime_hrs: { + // $divide: ['$totalSeconds', 3600], + // }, + // totaltangibletime_hrs: { + // $divide: ['$tangibletime', 3600], + // }, + // totalintangibletime_hrs: { + // $divide: ['$intangibletime', 3600], + // }, + // percentagespentintangible: { + // $cond: [ + // { + // $eq: ['$totalSeconds', 0], + // }, + // 0, + // { + // $multiply: [ + // { + // $divide: ['$tangibletime', '$totalSeconds'], + // }, + // 100, + // ], + // }, + // ], + // }, + // }, + // }, + // { + // $sort: { + // totaltangibletime_hrs: -1, + // name: 1, + // role: 1, + // }, + // }, + // ]); }; /** @@ -458,6 +618,7 @@ const dashboardhelper = function () { $gte: pdtStart, $lte: pdtEnd, }, + entryType: { $in: ["default", null] }, personId: userId, }); @@ -485,8 +646,6 @@ const dashboardhelper = function () { totalintangibletime_hrs: intangibleSeconds / 3600, percentagespentintangible: (intangibleSeconds / tangibleSeconds) * 100, - timeOffFrom: user.timeOffFrom, - timeOffTill: user.timeOffTill, }, ]; } catch (err) { @@ -597,6 +756,16 @@ const dashboardhelper = function () { { $lte: ["$$timeentry.dateOfWork", todate], }, + { + $not: [ + { + $in: [ + "$$timeentry.entryType", + ["person", "team", "project"], + ], + }, + ], + }, ], }, }, @@ -674,6 +843,16 @@ const dashboardhelper = function () { { $lte: ["$$timeentry.dateOfWork", todate], }, + { + $not: [ + { + $in: [ + "$$timeentry.entryType", + ["person", "team", "project"], + ], + }, + ], + }, ], }, }, diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index b5268734e..f96257a67 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -1,9 +1,37 @@ const moment = require("moment-timezone"); +const mongoose = require("mongoose"); const userProfile = require("../models/userProfile"); -const myteam = require("../helpers/helperModels/myTeam"); +const timeentry = require("../models/timeentry"); +const myTeam = require("../helpers/helperModels/myTeam"); +const team = require("../models/team"); +const Task = require("../models/task"); +const TaskNotification = require("../models/taskNotification"); +const Wbs = require("../models/wbs"); const taskHelper = function () { - const getTasksForTeams = function (userId) { + const getTasksForTeams = async function (userId) { + const userid = mongoose.Types.ObjectId(userId); + const userById = await userProfile + .findOne( + { _id: userid, isActive: true }, + { + role: 1, + firstName: 1, + lastName: 1, + role: 1, + isVisible: 1, + weeklycommittedHours: 1, + weeklySummaries: 1, + timeOffFrom: 1, + timeOffTill: 1, + } + ) + .then((res) => res) + .catch((e) => {}); + + if (userById == null) return null; + const userRole = userById.role; + const pdtstart = moment() .tz("America/Los_Angeles") .startOf("week") @@ -12,308 +40,460 @@ const taskHelper = function () { .tz("America/Los_Angeles") .endOf("week") .format("YYYY-MM-DD"); - return myteam.aggregate([ - { - $match: { - _id: userId, - }, - }, - { - $unwind: "$myteam", - }, - { - $project: { - _id: 0, - personId: "$myteam._id", - name: "$myteam.fullName", - role: 1, - }, - }, - // have personId, name, role - { - $lookup: { - from: "userProfiles", - localField: "personId", - foreignField: "_id", - as: "persondata", - }, - }, - { - $match: { - // dashboard tasks user roles hierarchy - $or: [ - { - role: { $in: ["Owner", "Core Team"] }, - }, - { - $and: [ - { - role: "Administrator", - }, - { "persondata.0.role": { $nin: ["Owner", "Administrator"] } }, - ], - }, - { - $and: [ - { - role: { $in: ["Manager", "Mentor"] }, - }, - { - "persondata.0.role": { - $nin: [ - "Manager", - "Mentor", - "Core Team", - "Administrator", - "Owner", - ], - }, - }, - ], - }, - { "persondata.0._id": userId }, - { "persondata.0.role": "Volunteer" }, - { "persondata.0.isVisible": true }, - ], - }, - }, - { - $project: { - personId: 1, - name: 1, - weeklycommittedHours: { - $sum: [ - { - $arrayElemAt: ["$persondata.weeklycommittedHours", 0], - }, - { - $ifNull: [{ $arrayElemAt: ["$persondata.missedHours", 0] }, 0], - }, - ], - }, - timeOffFrom: { - $ifNull: [{ $arrayElemAt: ["$persondata.timeOffFrom", 0] }, null], - }, - timeOffTill: { - $ifNull: [{ $arrayElemAt: ["$persondata.timeOffTill", 0] }, null], - }, - role: 1, - }, - }, - { - $lookup: { - from: "timeEntries", - localField: "personId", - foreignField: "personId", - as: "timeEntryData", - }, - }, - { - $project: { - personId: 1, - name: 1, - weeklycommittedHours: 1, - timeOffFrom: 1, - timeOffTill: 1, - timeEntryData: { - $filter: { - input: "$timeEntryData", - as: "timeentry", - cond: { - $and: [ - { - $gte: ["$$timeentry.dateOfWork", pdtstart], - }, - { - $lte: ["$$timeentry.dateOfWork", pdtend], - }, - ], - }, - }, - }, - role: 1, - }, - }, - { - $unwind: { - path: "$timeEntryData", - preserveNullAndEmptyArrays: true, - }, - }, - { - $project: { - personId: 1, - name: 1, - weeklycommittedHours: 1, - timeOffFrom: 1, - timeOffTill: 1, - totalSeconds: { - $cond: [ - { - $gte: ["$timeEntryData.totalSeconds", 0], - }, - "$timeEntryData.totalSeconds", - 0, - ], - }, - isTangible: { - $cond: [ - { - $gte: ["$timeEntryData.totalSeconds", 0], - }, - "$timeEntryData.isTangible", - false, - ], - }, - role: 1, - }, - }, - { - $addFields: { - tangibletime: { - $cond: [ - { - $eq: ["$isTangible", true], - }, - "$totalSeconds", - 0, - ], - }, - }, - }, - { - $group: { - _id: { - personId: "$personId", - weeklycommittedHours: "$weeklycommittedHours", - timeOffFrom: "$timeOffFrom", - timeOffTill: "$timeOffTill", - name: "$name", - role: "$role", - }, - totalSeconds: { - $sum: "$totalSeconds", - }, - tangibletime: { - $sum: "$tangibletime", - }, - }, - }, - { - $project: { - _id: 0, - personId: "$_id.personId", - name: "$_id.name", - weeklycommittedHours: "$_id.weeklycommittedHours", - timeOffFrom: "$_id.timeOffFrom", - timeOffTill: "$_id.timeOffTill", - totaltime_hrs: { - $divide: ["$totalSeconds", 3600], - }, - totaltangibletime_hrs: { - $divide: ["$tangibletime", 3600], - }, - role: "$_id.role", - }, - }, - { - $lookup: { - from: "tasks", - localField: "personId", - foreignField: "resources.userID", - as: "tasks", - }, - }, - { - $project: { - tasks: { - resources: { - profilePic: 0, - }, - }, - }, - }, - { - $unwind: { - path: "$tasks", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "wbs", - localField: "tasks.wbsId", - foreignField: "_id", - as: "projectId", - }, - }, - { - $addFields: { - "tasks.projectId": { - $cond: [ - { $ne: ["$projectId", []] }, - { $arrayElemAt: ["$projectId", 0] }, - "$tasks.projectId", - ], - }, - }, - }, - { - $project: { - projectId: 0, - tasks: { - projectId: { - _id: 0, - isActive: 0, - modifiedDatetime: 0, - wbsName: 0, - createdDatetime: 0, - __v: 0, - }, - }, - }, - }, - { - $addFields: { - "tasks.projectId": "$tasks.projectId.projectId", - }, - }, - { - $lookup: { - from: "taskNotifications", - localField: "tasks._id", - foreignField: "taskId", - as: "tasks.taskNotifications", - }, - }, - { - $group: { - _id: "$personId", - tasks: { - $push: "$tasks", - }, - data: { - $first: "$$ROOT", - }, - }, - }, - { - $addFields: { - "data.tasks": { - $filter: { - input: "$tasks", - as: "task", - cond: { $ne: ["$$task", {}] }, - }, - }, - }, - }, - { - $replaceRoot: { - newRoot: "$data", - }, + + let teamMemberIds = [userid]; + let teamMembers = []; + + if ( + userRole != "Administrator" && + userRole != "Owner" && + userRole != "Core Team" + ) { + // Manager , Mentor , Volunteer ... , Show only team members + const teamsResult = await team + .find({ "members.userId": { $in: [userid] } }, { members: 1 }) + .then((res) => res) + .catch((e) => {}); + + teamsResult.map((_myTeam) => { + _myTeam.members.map((teamMember) => { + if (!teamMember.userId.equals(userid)) + teamMemberIds.push(teamMember.userId); + }); + }); + + teamMembers = await userProfile + .find( + { _id: { $in: teamMemberIds }, isActive: true }, + { + role: 1, + firstName: 1, + lastName: 1, + weeklycommittedHours: 1, + timeOffFrom: 1, + timeOffTill: 1, + } + ) + .then((res) => res) + .catch((e) => {}); + } else if (userRole == "Administrator") { + // All users except Owner and Core Team + const excludedRoles = ["Core Team", "Owner"]; + teamMembers = await userProfile + .find( + { isActive: true, role: { $nin: excludedRoles } }, + { + role: 1, + firstName: 1, + lastName: 1, + weeklycommittedHours: 1, + timeOffFrom: 1, + timeOffFrom: 1, + } + ) + .then((res) => res) + .catch((e) => {}); + } else { + // 'Core Team', 'Owner' //All users + teamMembers = await userProfile + .find( + { isActive: true }, + { + role: 1, + firstName: 1, + lastName: 1, + weeklycommittedHours: 1, + timeOffFrom: 1, + timeOffTill: 1, + } + ) + .then((res) => res) + .catch((e) => {}); + } + + teamMemberIds = teamMembers.map((member) => member._id); + + const timeEntries = await timeentry.find({ + dateOfWork: { + $gte: pdtstart, + $lte: pdtend, }, - ]); + personId: { $in: teamMemberIds }, + }); + + const timeEntryByPerson = {}; + timeEntries.map((timeEntry) => { + const personIdStr = timeEntry.personId.toString(); + + if (timeEntryByPerson[personIdStr] == null) { + timeEntryByPerson[personIdStr] = { + tangibleSeconds: 0, + intangibleSeconds: 0, + totalSeconds: 0, + }; + } + + if (timeEntry.isTangible === true) { + timeEntryByPerson[personIdStr].tangibleSeconds += + timeEntry.totalSeconds; + } + timeEntryByPerson[personIdStr].totalSeconds += timeEntry.totalSeconds; + }); + + const teamMemberTasks = await Task.find( + { "resources.userID": { $in: teamMemberIds } }, + { "resources.profilePic": 0 } + ).populate({ + path: "wbsId", + select: "projectId", + }); + const teamMemberTaskIds = teamMemberTasks.map((task) => task._id); + const teamMemberTaskNotifications = await TaskNotification.find({ + taskId: { $in: teamMemberTaskIds }, + }); + + const taskNotificationByTaskNdUser = []; + teamMemberTaskNotifications.map((teamMemberTaskNotification) => { + const taskIdStr = teamMemberTaskNotification.taskId.toString(); + const userIdStr = teamMemberTaskNotification.userId.toString(); + const taskNdUserID = `${taskIdStr},${userIdStr}`; + + if (taskNotificationByTaskNdUser[taskNdUserID]) { + taskNotificationByTaskNdUser[taskNdUserID].push( + teamMemberTaskNotification + ); + } else { + taskNotificationByTaskNdUser[taskNdUserID] = [ + teamMemberTaskNotification, + ]; + } + }); + + const taskByPerson = []; + + teamMemberTasks.map((teamMemberTask) => { + const projId = teamMemberTask.wbsId?.projectId; + const _teamMemberTask = { ...teamMemberTask._doc }; + _teamMemberTask.projectId = projId; + const taskIdStr = _teamMemberTask._id.toString(); + + teamMemberTask.resources.map((resource) => { + const resourceIdStr = resource.userID.toString(); + const taskNdUserID = `${taskIdStr},${resourceIdStr}`; + _teamMemberTask.taskNotifications = + taskNotificationByTaskNdUser[taskNdUserID] || []; + if (taskByPerson[resourceIdStr]) { + taskByPerson[resourceIdStr].push(_teamMemberTask); + } else { + taskByPerson[resourceIdStr] = [_teamMemberTask]; + } + }); + }); + + const teamMemberTasksData = []; + teamMembers.map((teamMember) => { + const obj = { + personId: teamMember._id, + role: teamMember.role, + name: `${teamMember.firstName} ${teamMember.lastName}`, + weeklycommittedHours: teamMember.weeklycommittedHours, + timeOffFrom: teamMember.timeOffFrom || null, + timeOffTill: teamMember.timeOffTill || null, + totaltangibletime_hrs: + timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / + 3600 || 0, + totaltime_hrs: + timeEntryByPerson[teamMember._id.toString()]?.totalSeconds / 3600 || + 0, + tasks: taskByPerson[teamMember._id.toString()] || [], + }; + teamMemberTasksData.push(obj); + }); + + return teamMemberTasksData; + + // return myteam.aggregate([ + // { + // $match: { + // _id: userId, + // }, + // }, + // { + // $unwind: '$myteam', + // }, + // { + // $project: { + // _id: 0, + // personId: '$myteam._id', + // name: '$myteam.fullName', + // role: 1, + // }, + // }, + // // have personId, name, role + // { + // $lookup: { + // from: 'userProfiles', + // localField: 'personId', + // foreignField: '_id', + // as: 'persondata', + // }, + // }, + // { + // $match: { + // // dashboard tasks user roles hierarchy + // $or: [ + // { + // role: { $in: ['Owner', 'Core Team'] }, + // }, + // { + // $and: [ + // { + // role: 'Administrator', + // }, + // { 'persondata.0.role': { $nin: ['Owner', 'Administrator'] } }, + // ], + // }, + // { + // $and: [ + // { + // role: { $in: ['Manager', 'Mentor'] }, + // }, + // { + // 'persondata.0.role': { + // $nin: ['Manager', 'Mentor', 'Core Team', 'Administrator', 'Owner'], + // }, + // }, + // ], + // }, + // { 'persondata.0._id': userId }, + // { 'persondata.0.role': 'Volunteer' }, + // { 'persondata.0.isVisible': true }, + // ], + // }, + // }, + // { + // $project: { + // personId: 1, + // name: 1, + // weeklycommittedHours: { + // $sum: [ + // { + // $arrayElemAt: ['$persondata.weeklycommittedHours', 0], + // }, + // { + // $ifNull: [{ $arrayElemAt: ['$persondata.missedHours', 0] }, 0], + // }, + // ], + // }, + // role: 1, + // }, + // }, + // { + // $lookup: { + // from: 'timeEntries', + // localField: 'personId', + // foreignField: 'personId', + // as: 'timeEntryData', + // }, + // }, + // { + // $project: { + // personId: 1, + // name: 1, + // weeklycommittedHours: 1, + // timeEntryData: { + // $filter: { + // input: '$timeEntryData', + // as: 'timeentry', + // cond: { + // $and: [ + // { + // $gte: ['$$timeentry.dateOfWork', pdtstart], + // }, + // { + // $lte: ['$$timeentry.dateOfWork', pdtend], + // }, + // ], + // }, + // }, + // }, + // role: 1, + // }, + // }, + // { + // $unwind: { + // path: '$timeEntryData', + // preserveNullAndEmptyArrays: true, + // }, + // }, + // { + // $project: { + // personId: 1, + // name: 1, + // weeklycommittedHours: 1, + // totalSeconds: { + // $cond: [ + // { + // $gte: ['$timeEntryData.totalSeconds', 0], + // }, + // '$timeEntryData.totalSeconds', + // 0, + // ], + // }, + // isTangible: { + // $cond: [ + // { + // $gte: ['$timeEntryData.totalSeconds', 0], + // }, + // '$timeEntryData.isTangible', + // false, + // ], + // }, + // role: 1, + // }, + // }, + // { + // $addFields: { + // tangibletime: { + // $cond: [ + // { + // $eq: ['$isTangible', true], + // }, + // '$totalSeconds', + // 0, + // ], + // }, + // }, + // }, + // { + // $group: { + // _id: { + // personId: '$personId', + // weeklycommittedHours: '$weeklycommittedHours', + // name: '$name', + // role: '$role', + // }, + // totalSeconds: { + // $sum: '$totalSeconds', + // }, + // tangibletime: { + // $sum: '$tangibletime', + // }, + // }, + // }, + // { + // $project: { + // _id: 0, + // personId: '$_id.personId', + // name: '$_id.name', + // weeklycommittedHours: '$_id.weeklycommittedHours', + // totaltime_hrs: { + // $divide: ['$totalSeconds', 3600], + // }, + // totaltangibletime_hrs: { + // $divide: ['$tangibletime', 3600], + // }, + // role: '$_id.role', + // }, + // }, + // { + // $lookup: { + // from: 'tasks', + // localField: 'personId', + // foreignField: 'resources.userID', + // as: 'tasks', + // }, + // }, + // { + // $project: { + // tasks: { + // resources: { + // profilePic: 0, + // }, + // }, + // }, + // }, + // { + // $unwind: { + // path: '$tasks', + // preserveNullAndEmptyArrays: true, + // }, + // }, + // { + // $lookup: { + // from: 'wbs', + // localField: 'tasks.wbsId', + // foreignField: '_id', + // as: 'projectId', + // }, + // }, + // { + // $addFields: { + // 'tasks.projectId': { + // $cond: [ + // { $ne: ['$projectId', []] }, + // { $arrayElemAt: ['$projectId', 0] }, + // '$tasks.projectId', + // ], + // }, + // }, + // }, + // { + // $project: { + // projectId: 0, + // tasks: { + // projectId: { + // _id: 0, + // isActive: 0, + // modifiedDatetime: 0, + // wbsName: 0, + // createdDatetime: 0, + // __v: 0, + // }, + // }, + // }, + // }, + // { + // $addFields: { + // 'tasks.projectId': '$tasks.projectId.projectId', + // }, + // }, + // { + // $lookup: { + // from: 'taskNotifications', + // localField: 'tasks._id', + // foreignField: 'taskId', + // as: 'tasks.taskNotifications', + // }, + // }, + // { + // $group: { + // _id: '$personId', + // tasks: { + // $push: '$tasks', + // }, + // data: { + // $first: '$$ROOT', + // }, + // }, + // }, + // { + // $addFields: { + // 'data.tasks': { + // $filter: { + // input: '$tasks', + // as: 'task', + // cond: { $ne: ['$$task', {}] }, + // }, + // }, + // }, + // }, + // { + // $replaceRoot: { + // newRoot: '$data', + // }, + // }, + // ]); }; const getTasksForSingleUser = function (userId) { const pdtstart = moment() @@ -381,6 +561,9 @@ const taskHelper = function () { { $lte: ["$$timeentry.dateOfWork", pdtend], }, + { + $in: ["$$timeentry.entryType", ["default", null]], + }, ], }, }, From b81b0a15340148a6378ce6aa920e39bfe01a76b2 Mon Sep 17 00:00:00 2001 From: Shiwani Rajagopalan Date: Wed, 6 Dec 2023 17:16:44 -0500 Subject: [PATCH 263/272] added timeOffFrom and timeOffTill fields to mongoDB --- src/controllers/reasonSchedulingController.js | 171 ++++---- src/helpers/dashboardhelper.js | 374 ++++++++++-------- src/models/userProfile.js | 104 +++-- 3 files changed, 387 insertions(+), 262 deletions(-) diff --git a/src/controllers/reasonSchedulingController.js b/src/controllers/reasonSchedulingController.js index 6f872f338..4d56c5a5e 100644 --- a/src/controllers/reasonSchedulingController.js +++ b/src/controllers/reasonSchedulingController.js @@ -1,23 +1,19 @@ - -const moment = require('moment-timezone'); -const UserModel = require('../models/userProfile'); -const ReasonModel = require('../models/reason'); -const emailSender = require('../utilities/emailSender'); - +const moment = require("moment-timezone"); +const UserModel = require("../models/userProfile"); +const ReasonModel = require("../models/reason"); +const emailSender = require("../utilities/emailSender"); const postReason = async (req, res) => { try { const { userId, requestor, reasonData } = req.body; const newDate = moment - .tz(reasonData.date, 'America/Los_Angeles') - .startOf('day'); - const currentDate = moment - .tz('America/Los_Angeles') - .startOf('day'); + .tz(reasonData.date, "America/Los_Angeles") + .startOf("day"); + const currentDate = moment.tz("America/Los_Angeles").startOf("day"); // error case 0 - if (moment.tz(reasonData.date, 'America/Los_Angeles').day() !== 0) { + if (moment.tz(reasonData.date, "America/Los_Angeles").day() !== 0) { return res.status(400).json({ message: "You must choose the Sunday YOU'LL RETURN as your date. This is so your reason ends up as a note on that blue square.", @@ -27,19 +23,19 @@ const postReason = async (req, res) => { if (newDate.isBefore(currentDate)) { return res.status(400).json({ - message: 'You should select a date that is yet to come', + message: "You should select a date that is yet to come", errorCode: 7, }); } if (!reasonData.message) { return res.status(400).json({ - message: 'You must provide a reason.', + message: "You must provide a reason.", errorCode: 6, }); } - // Commented this condition to make reason scheduler available to all the users. + // Commented this condition to make reason scheduler available to all the users. // error case 1 // if (requestor.role !== 'Owner' && requestor.role !== 'Administrator') { // return res.status(403).json({ @@ -54,15 +50,61 @@ const postReason = async (req, res) => { // error case 2 if (!foundUser) { return res.status(404).json({ - message: 'User not found', + message: "User not found", errorCode: 2, }); } + // new changes + + if ( + foundUser.hasOwnProperty("timeOffFrom") && + foundUser.hasOwnProperty("timeOffTill") + ) { + if (currentDate >= foundUser.timeOffTill) { + await UserModel.findOneAndUpdate( + { + _id: userId, + }, + { + $set: { + timeOffFrom: currentDate, + timeOffTill: newDate, + }, + } + ); + } else { + await UserModel.findOneAndUpdate( + { + _id: userId, + }, + { + $set: { + timeOffTill: newDate, + }, + } + ); + } + } else { + await UserModel.findOneAndUpdate( + { + _id: userId, + }, + { + $set: { + timeOffFrom: currentDate, + timeOffTill: newDate, + }, + } + ); + } + + // + const foundReason = await ReasonModel.findOne({ date: moment - .tz(reasonData.date, 'America/Los_Angeles') - .startOf('day') + .tz(reasonData.date, "America/Los_Angeles") + .startOf("day") .toISOString(), userId, }); @@ -70,14 +112,14 @@ const postReason = async (req, res) => { // error case 3 if (foundReason) { return res.status(403).json({ - message: 'The reason must be unique to the date', + message: "The reason must be unique to the date", errorCode: 3, }); } const savingDate = moment - .tz(reasonData.date, 'America/Los_Angeles') - .startOf('day') + .tz(reasonData.date, "America/Los_Angeles") + .startOf("day") .toISOString(); const newReason = new ReasonModel({ @@ -86,14 +128,13 @@ const postReason = async (req, res) => { userId, }); - // await newReason.save(); - const savedData = await newReason.save(); + const savedData = await newReason.save(); if (savedData) { // Upon clicking the "Save" button in the Blue Square Reason Scheduler, an email will be automatically sent to the user and Jae. - const subject = `Blue Square Reason for ${foundUser.firstName} ${foundUser.lastName} has been set`; + const subject = `Blue Square Reason for ${foundUser.firstName} ${foundUser.lastName} has been set`; - const emailBody = `

Hi !

+ const emailBody = `

Hi !

This email is to let you know that ${foundUser.firstName} ${foundUser.lastName} has set their Blue Square Reason.

@@ -103,21 +144,20 @@ const postReason = async (req, res) => {

Thank you,
One Community

`; + // 1 hardcoded email- emailSender('@gmail.com', subject, emailBody, null, null); - // 1 hardcoded email- emailSender('@gmail.com', subject, emailBody, null, null); - - // 2 user email - - emailSender(`${foundUser.email}`, subject, emailBody, null, null); + // 2 user email - + emailSender(`${foundUser.email}`, subject, emailBody, null, null); - // 3 - user email and hardcoded email ( After PR approval hardcode Jae's email) - // emailSender(`${foundUser.email},@gmail.com`, subject, emailBody, null, null); - } + // 3 - user email and hardcoded email ( After PR approval hardcode Jae's email) + // emailSender(`${foundUser.email},@gmail.com`, subject, emailBody, null, null); + } return res.sendStatus(200); } catch (error) { console.log(error); return res.status(400).json({ - errMessage: 'Something went wrong', + errMessage: "Something went wrong", }); } }; @@ -140,7 +180,7 @@ const getAllReasons = async (req, res) => { // error case 2 if (!foundUser) { return res.status(404).json({ - message: 'User not found', + message: "User not found", }); } @@ -154,7 +194,7 @@ const getAllReasons = async (req, res) => { } catch (error) { console.log(error); return res.status(400).json({ - errMessage: 'Something went wrong while fetching the user', + errMessage: "Something went wrong while fetching the user", }); } }; @@ -178,24 +218,24 @@ const getSingleReason = async (req, res) => { // error case 2 if (!foundUser) { return res.status(404).json({ - message: 'User not found', + message: "User not found", errorCode: 2, }); } const foundReason = await ReasonModel.findOne({ date: moment - .tz(queryDate, 'America/Los_Angeles') - .startOf('day') + .tz(queryDate, "America/Los_Angeles") + .startOf("day") .toISOString(), userId, }); if (!foundReason) { return res.status(200).json({ - reason: '', - date: '', - userId: '', + reason: "", + date: "", + userId: "", isSet: false, }); } @@ -204,7 +244,7 @@ const getSingleReason = async (req, res) => { } catch (error) { console.log(error); return res.status(400).json({ - message: 'Something went wrong while fetching single reason', + message: "Something went wrong while fetching single reason", }); } }; @@ -225,7 +265,7 @@ const patchReason = async (req, res) => { if (!reasonData.message) { return res.status(400).json({ - message: 'You must provide a reason.', + message: "You must provide a reason.", errorCode: 6, }); } @@ -235,22 +275,22 @@ const patchReason = async (req, res) => { // error case 2 if (!foundUser) { return res.status(404).json({ - message: 'User not found', + message: "User not found", errorCode: 2, }); } const foundReason = await ReasonModel.findOne({ date: moment - .tz(reasonData.date, 'America/Los_Angeles') - .startOf('day') + .tz(reasonData.date, "America/Los_Angeles") + .startOf("day") .toISOString(), userId, }); // error case 4 if (!foundReason) { return res.status(404).json({ - message: 'Reason not found', + message: "Reason not found", errorCode: 4, }); } @@ -260,9 +300,9 @@ const patchReason = async (req, res) => { const savedData = await foundReason.save(); if (savedData) { // Upon clicking the "Save" button in the Blue Square Reason Scheduler, an email will be automatically sent to the user and Jae. - const subject = `Blue Square Reason for ${foundUser.firstName} ${foundUser.lastName} has been updated`; + const subject = `Blue Square Reason for ${foundUser.firstName} ${foundUser.lastName} has been updated`; - const emailBody = `

Hi !

+ const emailBody = `

Hi !

This email is to let you know that ${foundUser.firstName} ${foundUser.lastName} has updated their Blue Square Reason.

@@ -272,22 +312,21 @@ const patchReason = async (req, res) => {

Thank you,
One Community

`; + // 1 hardcoded email- emailSender('@gmail.com', subject, emailBody, null, null); - // 1 hardcoded email- emailSender('@gmail.com', subject, emailBody, null, null); + // 2 user email - + emailSender(`${foundUser.email}`, subject, emailBody, null, null); - // 2 user email - - emailSender(`${foundUser.email}`, subject, emailBody, null, null); - - // 3 - user email and hardcoded email ( After PR approval hardcode Jae's email) - // emailSender(`${foundUser.email},@gmail.com`, subject, emailBody, null, null); - } + // 3 - user email and hardcoded email ( After PR approval hardcode Jae's email) + // emailSender(`${foundUser.email},@gmail.com`, subject, emailBody, null, null); + } return res.status(200).json({ - message: 'Reason Updated!', + message: "Reason Updated!", }); } catch (error) { return res.status(400).json({ - message: 'something went wrong while patching the reason', + message: "something went wrong while patching the reason", }); } }; @@ -298,10 +337,10 @@ const deleteReason = async (req, res) => { const { userId } = req.params; // error case 1 - if (requestor.role !== 'Owner' && requestor.role !== 'Administrator') { + if (requestor.role !== "Owner" && requestor.role !== "Administrator") { return res.status(403).json({ message: - 'You must be an Owner or Administrator to schedule a reason for a Blue Square', + "You must be an Owner or Administrator to schedule a reason for a Blue Square", errorCode: 1, }); } @@ -311,21 +350,21 @@ const deleteReason = async (req, res) => { // error case 2 if (!foundUser) { return res.status(404).json({ - message: 'User not found', + message: "User not found", errorCode: 2, }); } const foundReason = await ReasonModel.findOne({ date: moment - .tz(reasonData.date, 'America/Los_Angeles') - .startOf('day') + .tz(reasonData.date, "America/Los_Angeles") + .startOf("day") .toISOString(), }); if (!foundReason) { return res.status(404).json({ - message: 'Reason not found', + message: "Reason not found", errorCode: 4, }); } @@ -333,13 +372,13 @@ const deleteReason = async (req, res) => { foundReason.remove((err) => { if (err) { return res.status(500).json({ - message: 'Error while deleting document', + message: "Error while deleting document", errorCode: 5, }); } return res.status(200).json({ - message: 'Document deleted', + message: "Document deleted", }); }); } catch (error) {} diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index 9bedb0e8f..a200a0095 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -1,28 +1,27 @@ -const moment = require('moment-timezone'); -const mongoose = require('mongoose'); -const userProfile = require('../models/userProfile'); -const timeentry = require('../models/timeentry'); -const myTeam = require('../helpers/helperModels/myTeam'); -const team = require('../models/team'); - +const moment = require("moment-timezone"); +const mongoose = require("mongoose"); +const userProfile = require("../models/userProfile"); +const timeentry = require("../models/timeentry"); +const myTeam = require("../helpers/helperModels/myTeam"); +const team = require("../models/team"); const dashboardhelper = function () { const personaldetails = function (userId) { return userProfile.findById( userId, - '_id firstName lastName role profilePic badgeCollection', + "_id firstName lastName role profilePic badgeCollection" ); }; const getOrgData = async function () { const pdtstart = moment() - .tz('America/Los_Angeles') - .startOf('week') - .format('YYYY-MM-DD'); + .tz("America/Los_Angeles") + .startOf("week") + .format("YYYY-MM-DD"); const pdtend = moment() - .tz('America/Los_Angeles') - .endOf('week') - .format('YYYY-MM-DD'); + .tz("America/Los_Angeles") + .endOf("week") + .format("YYYY-MM-DD"); /** * Previous aggregate pipeline had two issues: @@ -41,40 +40,43 @@ const dashboardhelper = function () { $gte: 1, }, role: { - $ne: 'Mentor', + $ne: "Mentor", }, }, }, { $lookup: { - from: 'timeEntries', - localField: '_id', - foreignField: 'personId', - as: 'timeEntryData', + from: "timeEntries", + localField: "_id", + foreignField: "personId", + as: "timeEntryData", }, }, { $project: { - personId: '$_id', + personId: "$_id", name: 1, weeklycommittedHours: 1, role: 1, timeEntryData: { $filter: { - input: '$timeEntryData', - as: 'timeentry', + input: "$timeEntryData", + as: "timeentry", cond: { $and: [ { - $gte: ['$$timeentry.dateOfWork', pdtstart], + $gte: ["$$timeentry.dateOfWork", pdtstart], }, { - $lte: ['$$timeentry.dateOfWork', pdtend], + $lte: ["$$timeentry.dateOfWork", pdtend], }, { $not: [ { - $in: ['$$timeentry.entryType', ['person', 'team', 'project']], + $in: [ + "$$timeentry.entryType", + ["person", "team", "project"], + ], }, ], }, @@ -86,7 +88,7 @@ const dashboardhelper = function () { }, { $unwind: { - path: '$timeEntryData', + path: "$timeEntryData", preserveNullAndEmptyArrays: true, }, }, @@ -97,27 +99,27 @@ const dashboardhelper = function () { totalSeconds: { $cond: [ { - $gte: ['$timeEntryData.totalSeconds', 0], + $gte: ["$timeEntryData.totalSeconds", 0], }, - '$timeEntryData.totalSeconds', + "$timeEntryData.totalSeconds", 0, ], }, tangibletime: { $cond: [ { - $eq: ['$timeEntryData.isTangible', true], + $eq: ["$timeEntryData.isTangible", true], }, - '$timeEntryData.totalSeconds', + "$timeEntryData.totalSeconds", 0, ], }, intangibletime: { $cond: [ { - $eq: ['$timeEntryData.isTangible', false], + $eq: ["$timeEntryData.isTangible", false], }, - '$timeEntryData.totalSeconds', + "$timeEntryData.totalSeconds", 0, ], }, @@ -126,17 +128,17 @@ const dashboardhelper = function () { { $group: { _id: { - personId: '$personId', - weeklycommittedHours: '$weeklycommittedHours', + personId: "$personId", + weeklycommittedHours: "$weeklycommittedHours", }, time_hrs: { - $sum: { $divide: ['$totalSeconds', 3600] }, + $sum: { $divide: ["$totalSeconds", 3600] }, }, tangibletime_hrs: { - $sum: { $divide: ['$tangibletime', 3600] }, + $sum: { $divide: ["$tangibletime", 3600] }, }, intangibletime_hrs: { - $sum: { $divide: ['$intangibletime', 3600] }, + $sum: { $divide: ["$intangibletime", 3600] }, }, }, }, @@ -144,15 +146,15 @@ const dashboardhelper = function () { $group: { _id: 0, memberCount: { $sum: 1 }, - totalweeklycommittedHours: { $sum: '$_id.weeklycommittedHours' }, + totalweeklycommittedHours: { $sum: "$_id.weeklycommittedHours" }, totaltime_hrs: { - $sum: '$time_hrs', + $sum: "$time_hrs", }, totaltangibletime_hrs: { - $sum: '$tangibletime_hrs', + $sum: "$tangibletime_hrs", }, totalintangibletime_hrs: { - $sum: '$intangibletime_hrs', + $sum: "$intangibletime_hrs", }, }, }, @@ -163,55 +165,93 @@ const dashboardhelper = function () { const getLeaderboard = async function (userId) { const userid = mongoose.Types.ObjectId(userId); - const userById = await userProfile.findOne({ _id: userid, isActive: true }, { role: 1 }) - .then(res => res).catch((e) => {}); + const userById = await userProfile + .findOne({ _id: userid, isActive: true }, { role: 1 }) + .then((res) => res) + .catch((e) => {}); if (userById == null) return null; const userRole = userById.role; const pdtstart = moment() - .tz('America/Los_Angeles') - .startOf('week') - .format('YYYY-MM-DD'); + .tz("America/Los_Angeles") + .startOf("week") + .format("YYYY-MM-DD"); const pdtend = moment() - .tz('America/Los_Angeles') - .endOf('week') - .format('YYYY-MM-DD'); + .tz("America/Los_Angeles") + .endOf("week") + .format("YYYY-MM-DD"); let teamMemberIds = [userid]; let teamMembers = []; - if (userRole != 'Administrator' && userRole != 'Owner' && userRole != 'Core Team') // Manager , Mentor , Volunteer ... , Show only team members - { - const teamsResult = await team.find({ 'members.userId': { $in: [userid] } }, { members: 1 }) - .then(res => res).catch((e) => {}); + if ( + userRole != "Administrator" && + userRole != "Owner" && + userRole != "Core Team" + ) { + // Manager , Mentor , Volunteer ... , Show only team members + const teamsResult = await team + .find({ "members.userId": { $in: [userid] } }, { members: 1 }) + .then((res) => res) + .catch((e) => {}); teamsResult.map((_myTeam) => { _myTeam.members.map((teamMember) => { - if (!teamMember.userId.equals(userid)) teamMemberIds.push(teamMember.userId); - }); + if (!teamMember.userId.equals(userid)) + teamMemberIds.push(teamMember.userId); + }); }); - teamMembers = await userProfile.find({ _id: { $in: teamMemberIds }, isActive: true }, + teamMembers = await userProfile + .find( + { _id: { $in: teamMemberIds }, isActive: true }, { - role: 1, firstName: 1, lastName: 1, isVisible: 1, weeklycommittedHours: 1, weeklySummaries: 1, -}) - .then(res => res).catch((e) => {}); - } else if (userRole == 'Administrator') { // All users except Owner and Core Team - const excludedRoles = ['Core Team', 'Owner']; - teamMembers = await userProfile.find({ isActive: true, role: { $nin: excludedRoles } }, + role: 1, + firstName: 1, + lastName: 1, + isVisible: 1, + weeklycommittedHours: 1, + weeklySummaries: 1, + } + ) + .then((res) => res) + .catch((e) => {}); + } else if (userRole == "Administrator") { + // All users except Owner and Core Team + const excludedRoles = ["Core Team", "Owner"]; + teamMembers = await userProfile + .find( + { isActive: true, role: { $nin: excludedRoles } }, { - role: 1, firstName: 1, lastName: 1, isVisible: 1, weeklycommittedHours: 1, weeklySummaries: 1, -}) - .then(res => res).catch((e) => {}); - } else { // 'Core Team', 'Owner' //All users - teamMembers = await userProfile.find({ isActive: true }, + role: 1, + firstName: 1, + lastName: 1, + isVisible: 1, + weeklycommittedHours: 1, + weeklySummaries: 1, + } + ) + .then((res) => res) + .catch((e) => {}); + } else { + // 'Core Team', 'Owner' //All users + teamMembers = await userProfile + .find( + { isActive: true }, { - role: 1, firstName: 1, lastName: 1, isVisible: 1, weeklycommittedHours: 1, weeklySummaries: 1, -}) - .then(res => res).catch((e) => {}); - } + role: 1, + firstName: 1, + lastName: 1, + isVisible: 1, + weeklycommittedHours: 1, + weeklySummaries: 1, + } + ) + .then((res) => res) + .catch((e) => {}); + } - teamMemberIds = teamMembers.map(member => member._id); + teamMemberIds = teamMembers.map((member) => member._id); const timeEntries = await timeentry.find({ dateOfWork: { @@ -225,36 +265,56 @@ const dashboardhelper = function () { timeEntries.map((timeEntry) => { const personIdStr = timeEntry.personId.toString(); - if (timeEntryByPerson[personIdStr] == null) { timeEntryByPerson[personIdStr] = { tangibleSeconds: 0, intangibleSeconds: 0, totalSeconds: 0 }; } + if (timeEntryByPerson[personIdStr] == null) { + timeEntryByPerson[personIdStr] = { + tangibleSeconds: 0, + intangibleSeconds: 0, + totalSeconds: 0, + }; + } if (timeEntry.isTangible === true) { - timeEntryByPerson[personIdStr].tangibleSeconds += timeEntry.totalSeconds; + timeEntryByPerson[personIdStr].tangibleSeconds += + timeEntry.totalSeconds; } else { - timeEntryByPerson[personIdStr].intangibleSeconds += timeEntry.totalSeconds; + timeEntryByPerson[personIdStr].intangibleSeconds += + timeEntry.totalSeconds; } timeEntryByPerson[personIdStr].totalSeconds += timeEntry.totalSeconds; }); - const leaderBoardData = []; teamMembers.map((teamMember) => { - const obj = { - personId: teamMember._id, - role: teamMember.role, - name: `${teamMember.firstName } ${ teamMember.lastName}`, - isVisible: teamMember.isVisible, - hasSummary: teamMember.weeklySummaries?.length > 0 ? teamMember.weeklySummaries[0].summary != '' : false, - weeklycommittedHours: teamMember.weeklycommittedHours, - totaltangibletime_hrs: ((timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / 3600) || 0), - totalintangibletime_hrs: ((timeEntryByPerson[teamMember._id.toString()]?.intangibleSeconds / 3600) || 0), - totaltime_hrs: ((timeEntryByPerson[teamMember._id.toString()]?.totalSeconds / 3600) || 0), - percentagespentintangible: - (timeEntryByPerson[teamMember._id.toString()] && timeEntryByPerson[teamMember._id.toString()]?.totalSeconds != 0 && timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds != 0) - ? (timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / timeEntryByPerson[teamMember._id.toString()]?.totalSeconds) * 100 - : 0, - }; - leaderBoardData.push(obj); + const obj = { + personId: teamMember._id, + role: teamMember.role, + name: `${teamMember.firstName} ${teamMember.lastName}`, + isVisible: teamMember.isVisible, + hasSummary: + teamMember.weeklySummaries?.length > 0 + ? teamMember.weeklySummaries[0].summary != "" + : false, + weeklycommittedHours: teamMember.weeklycommittedHours, + totaltangibletime_hrs: + timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / + 3600 || 0, + totalintangibletime_hrs: + timeEntryByPerson[teamMember._id.toString()]?.intangibleSeconds / + 3600 || 0, + totaltime_hrs: + timeEntryByPerson[teamMember._id.toString()]?.totalSeconds / 3600 || + 0, + percentagespentintangible: + timeEntryByPerson[teamMember._id.toString()] && + timeEntryByPerson[teamMember._id.toString()]?.totalSeconds != 0 && + timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds != 0 + ? (timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / + timeEntryByPerson[teamMember._id.toString()]?.totalSeconds) * + 100 + : 0, + }; + leaderBoardData.push(obj); }); const sortedLBData = leaderBoardData.sort((a, b) => { @@ -532,14 +592,14 @@ const dashboardhelper = function () { const getUserLaborData = async function (userId) { try { const pdtStart = moment() - .tz('America/Los_Angeles') - .startOf('week') - .format('YYYY-MM-DD'); + .tz("America/Los_Angeles") + .startOf("week") + .format("YYYY-MM-DD"); const pdtEnd = moment() - .tz('America/Los_Angeles') - .endOf('week') - .format('YYYY-MM-DD'); + .tz("America/Los_Angeles") + .endOf("week") + .format("YYYY-MM-DD"); const user = await userProfile.findById({ _id: userId, @@ -550,7 +610,7 @@ const dashboardhelper = function () { $gte: pdtStart, $lte: pdtEnd, }, - entryType: { $in: ['default', null] }, + entryType: { $in: ["default", null] }, personId: userId, }); @@ -570,7 +630,7 @@ const dashboardhelper = function () { personId: userId, role: user.role, isVisible: user.isVisible, - hasSummary: user.weeklySummaries[0].summary !== '', + hasSummary: user.weeklySummaries[0].summary !== "", weeklycommittedHours: user.weeklycommittedHours, name: `${user.firstName} ${user.lastName}`, totaltime_hrs: (tangibleSeconds + intangibleSeconds) / 3600, @@ -583,8 +643,8 @@ const dashboardhelper = function () { } catch (err) { return [ { - personId: 'error', - name: 'Error Error', + personId: "error", + name: "Error Error", totaltime_hrs: 0, totaltangibletime_hrs: 0, totalintangibletime_hrs: 0, @@ -595,8 +655,8 @@ const dashboardhelper = function () { }; const laborthismonth = function (userId, startDate, endDate) { - const fromdate = moment(startDate).format('YYYY-MM-DD'); - const todate = moment(endDate).format('YYYY-MM-DD'); + const fromdate = moment(startDate).format("YYYY-MM-DD"); + const todate = moment(endDate).format("YYYY-MM-DD"); return timeentry.aggregate([ { @@ -612,19 +672,19 @@ const dashboardhelper = function () { { $group: { _id: { - projectId: '$projectId', + projectId: "$projectId", }, labor: { - $sum: '$totalSeconds', + $sum: "$totalSeconds", }, }, }, { $lookup: { - from: 'projects', - localField: '_id.projectId', - foreignField: '_id', - as: 'project', + from: "projects", + localField: "_id.projectId", + foreignField: "_id", + as: "project", }, }, { @@ -633,13 +693,13 @@ const dashboardhelper = function () { projectName: { $ifNull: [ { - $arrayElemAt: ['$project.projectName', 0], + $arrayElemAt: ["$project.projectName", 0], }, - 'Undefined', + "Undefined", ], }, timeSpent_hrs: { - $divide: ['$labor', 3600], + $divide: ["$labor", 3600], }, }, }, @@ -647,8 +707,8 @@ const dashboardhelper = function () { }; const laborthisweek = function (userId, startDate, endDate) { - const fromdate = moment(startDate).format('YYYY-MM-DD'); - const todate = moment(endDate).format('YYYY-MM-DD'); + const fromdate = moment(startDate).format("YYYY-MM-DD"); + const todate = moment(endDate).format("YYYY-MM-DD"); return userProfile.aggregate([ { @@ -664,10 +724,10 @@ const dashboardhelper = function () { }, { $lookup: { - from: 'timeEntries', - localField: '_id', - foreignField: 'personId', - as: 'timeEntryData', + from: "timeEntries", + localField: "_id", + foreignField: "personId", + as: "timeEntryData", }, }, { @@ -675,23 +735,26 @@ const dashboardhelper = function () { weeklycommittedHours: 1, timeEntryData: { $filter: { - input: '$timeEntryData', - as: 'timeentry', + input: "$timeEntryData", + as: "timeentry", cond: { $and: [ { - $eq: ['$$timeentry.isTangible', true], + $eq: ["$$timeentry.isTangible", true], }, { - $gte: ['$$timeentry.dateOfWork', fromdate], + $gte: ["$$timeentry.dateOfWork", fromdate], }, { - $lte: ['$$timeentry.dateOfWork', todate], + $lte: ["$$timeentry.dateOfWork", todate], }, { $not: [ { - $in: ['$$timeentry.entryType', ['person', 'team', 'project']], + $in: [ + "$$timeentry.entryType", + ["person", "team", "project"], + ], }, ], }, @@ -703,27 +766,27 @@ const dashboardhelper = function () { }, { $unwind: { - path: '$timeEntryData', + path: "$timeEntryData", preserveNullAndEmptyArrays: true, }, }, { $group: { _id: { - _id: '$_id', - weeklycommittedHours: '$weeklycommittedHours', + _id: "$_id", + weeklycommittedHours: "$weeklycommittedHours", }, effort: { - $sum: '$timeEntryData.totalSeconds', + $sum: "$timeEntryData.totalSeconds", }, }, }, { $project: { _id: 0, - weeklycommittedHours: '$_id.weeklycommittedHours', + weeklycommittedHours: "$_id.weeklycommittedHours", timeSpent_hrs: { - $divide: ['$effort', 3600], + $divide: ["$effort", 3600], }, }, }, @@ -731,8 +794,8 @@ const dashboardhelper = function () { }; const laborThisWeekByCategory = function (userId, startDate, endDate) { - const fromdate = moment(startDate).format('YYYY-MM-DD'); - const todate = moment(endDate).format('YYYY-MM-DD'); + const fromdate = moment(startDate).format("YYYY-MM-DD"); + const todate = moment(endDate).format("YYYY-MM-DD"); return userProfile.aggregate([ { @@ -748,10 +811,10 @@ const dashboardhelper = function () { }, { $lookup: { - from: 'timeEntries', - localField: '_id', - foreignField: 'personId', - as: 'timeEntryData', + from: "timeEntries", + localField: "_id", + foreignField: "personId", + as: "timeEntryData", }, }, { @@ -759,23 +822,26 @@ const dashboardhelper = function () { weeklycommittedHours: 1, timeEntryData: { $filter: { - input: '$timeEntryData', - as: 'timeentry', + input: "$timeEntryData", + as: "timeentry", cond: { $and: [ { - $eq: ['$$timeentry.isTangible', true], + $eq: ["$$timeentry.isTangible", true], }, { - $gte: ['$$timeentry.dateOfWork', fromdate], + $gte: ["$$timeentry.dateOfWork", fromdate], }, { - $lte: ['$$timeentry.dateOfWork', todate], + $lte: ["$$timeentry.dateOfWork", todate], }, { $not: [ { - $in: ['$$timeentry.entryType', ['person', 'team', 'project']], + $in: [ + "$$timeentry.entryType", + ["person", "team", "project"], + ], }, ], }, @@ -787,37 +853,37 @@ const dashboardhelper = function () { }, { $unwind: { - path: '$timeEntryData', + path: "$timeEntryData", preserveNullAndEmptyArrays: true, }, }, { $group: { - _id: '$timeEntryData.projectId', + _id: "$timeEntryData.projectId", effort: { - $sum: '$timeEntryData.totalSeconds', + $sum: "$timeEntryData.totalSeconds", }, }, }, { $lookup: { - from: 'projects', - localField: '_id', - foreignField: '_id', - as: 'project', + from: "projects", + localField: "_id", + foreignField: "_id", + as: "project", }, }, { $unwind: { - path: '$project', + path: "$project", preserveNullAndEmptyArrays: true, }, }, { $group: { - _id: '$project.category', + _id: "$project.category", effort: { - $sum: '$effort', + $sum: "$effort", }, }, }, @@ -825,7 +891,7 @@ const dashboardhelper = function () { $project: { _id: 1, timeSpent_hrs: { - $divide: ['$effort', 3600], + $divide: ["$effort", 3600], }, }, }, diff --git a/src/models/userProfile.js b/src/models/userProfile.js index 8a8de2e18..762b61c02 100644 --- a/src/models/userProfile.js +++ b/src/models/userProfile.js @@ -1,9 +1,9 @@ -const mongoose = require('mongoose'); -const moment = require('moment-timezone'); +const mongoose = require("mongoose"); +const moment = require("moment-timezone"); const { Schema } = mongoose; -const validate = require('mongoose-validator'); -const bcrypt = require('bcryptjs'); +const validate = require("mongoose-validator"); +const bcrypt = require("bcryptjs"); const SALT_ROUNDS = 10; const nextDay = new Date(); @@ -15,11 +15,12 @@ const userProfileSchema = new Schema({ required: true, validate: { validator(v) { - const passwordregex = /(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/; + const passwordregex = + /(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/; return passwordregex.test(v); }, message: - '{VALUE} is not a valid password!password should be at least 8 charcaters long with uppercase, lowercase and number/special char.', + "{VALUE} is not a valid password!password should be at least 8 charcaters long with uppercase, lowercase and number/special char.", }, }, isActive: { type: Boolean, required: true, default: true }, @@ -47,7 +48,9 @@ const userProfileSchema = new Schema({ type: String, required: true, unique: true, - validate: [validate({ validator: 'isEmail', message: 'Email address is invalid' })], + validate: [ + validate({ validator: "isEmail", message: "Email address is invalid" }), + ], }, weeklycommittedHours: { type: Number, default: 10 }, weeklycommittedHoursHistory: [ @@ -60,13 +63,15 @@ const userProfileSchema = new Schema({ createdDate: { type: Date, required: true, default: nextDay }, lastModifiedDate: { type: Date, required: true, default: Date.now() }, reactivationDate: { type: Date }, - personalLinks: [{ _id: Schema.Types.ObjectId, Name: String, Link: { type: String } }], + personalLinks: [ + { _id: Schema.Types.ObjectId, Name: String, Link: { type: String } }, + ], adminLinks: [{ _id: Schema.Types.ObjectId, Name: String, Link: String }], - teams: [{ type: mongoose.SchemaTypes.ObjectId, ref: 'team' }], - projects: [{ type: mongoose.SchemaTypes.ObjectId, ref: 'project' }], + teams: [{ type: mongoose.SchemaTypes.ObjectId, ref: "team" }], + projects: [{ type: mongoose.SchemaTypes.ObjectId, ref: "project" }], badgeCollection: [ { - badge: { type: mongoose.SchemaTypes.ObjectId, ref: 'badge' }, + badge: { type: mongoose.SchemaTypes.ObjectId, ref: "badge" }, count: { type: Number, default: 0 }, earnedDate: { type: Array, default: [] }, lastModified: { type: Date, required: true, default: Date.now() }, @@ -79,20 +84,25 @@ const userProfileSchema = new Schema({ ], profilePic: { type: String }, infringements: [ - { date: { type: String, required: true }, description: { type: String, required: true } }, + { + date: { type: String, required: true }, + description: { type: String, required: true }, + }, ], location: { - userProvided: { type: String, default: '' }, + userProvided: { type: String, default: "" }, coords: { - lat: { type: Number, default: '' }, - lng: { type: Number, default: '' }, + lat: { type: Number, default: "" }, + lng: { type: Number, default: "" }, }, - country: { type: String, default: '' }, - city: { type: String, default: '' }, - + country: { type: String, default: "" }, + city: { type: String, default: "" }, }, oldInfringements: [ - { date: { type: String, required: true }, description: { type: String, required: true } }, + { + date: { type: String, required: true }, + description: { type: String, required: true }, + }, ], privacySettings: { blueSquares: { type: Boolean, default: true }, @@ -104,7 +114,7 @@ const userProfileSchema = new Schema({ dueDate: { type: Date, required: true, - default: moment().tz('America/Los_Angeles').endOf('week'), + default: moment().tz("America/Los_Angeles").endOf("week"), }, summary: { type: String }, uploadDate: { type: Date }, @@ -134,17 +144,17 @@ const userProfileSchema = new Schema({ category: { type: String, enum: [ - 'Food', - 'Energy', - 'Housing', - 'Education', - 'Society', - 'Economics', - 'Stewardship', - 'Other', - 'Unspecified', + "Food", + "Energy", + "Housing", + "Education", + "Society", + "Economics", + "Stewardship", + "Other", + "Unspecified", ], - default: 'Other', + default: "Other", }, hrs: { type: Number, default: 0 }, }, @@ -152,48 +162,58 @@ const userProfileSchema = new Schema({ savedTangibleHrs: [Number], timeEntryEditHistory: [ { - date: { type: Date, required: true, default: moment().tz('America/Los_Angeles').toDate() }, + date: { + type: Date, + required: true, + default: moment().tz("America/Los_Angeles").toDate(), + }, initialSeconds: { type: Number, required: true }, newSeconds: { type: Number, required: true }, }, ], weeklySummaryNotReq: { type: Boolean, default: false }, - timeZone: { type: String, required: true, default: 'America/Los_Angeles' }, + timeZone: { type: String, required: true, default: "America/Los_Angeles" }, isVisible: { type: Boolean, default: false }, weeklySummaryOption: { type: String }, - bioPosted: { type: String, default: 'default' }, + bioPosted: { type: String, default: "default" }, isFirstTimelog: { type: Boolean, default: true }, teamCode: { type: String, - default: '', + default: "", validate: { validator(v) { const teamCoderegex = /^([a-zA-Z]-[a-zA-Z]{3}|[a-zA-Z]{5})$|^$/; return teamCoderegex.test(v); }, - message: - 'Please enter a code in the format of A-AAA or AAAAA', + message: "Please enter a code in the format of A-AAA or AAAAA", }, }, infoCollections: [ { areaName: { type: String }, areaContent: { type: String }, - }], + }, + ], + timeOffFrom: { type: Date, default: undefined }, + timeOffTill: { type: Date, default: undefined }, }); -userProfileSchema.pre('save', function (next) { +userProfileSchema.pre("save", function (next) { const user = this; - if (!user.isModified('password')) return next(); + if (!user.isModified("password")) return next(); return bcrypt .genSalt(SALT_ROUNDS) - .then(result => bcrypt.hash(user.password, result)) + .then((result) => bcrypt.hash(user.password, result)) .then((hash) => { user.password = hash; return next(); }) - .catch(error => next(error)); + .catch((error) => next(error)); }); -module.exports = mongoose.model('userProfile', userProfileSchema, 'userProfiles'); +module.exports = mongoose.model( + "userProfile", + userProfileSchema, + "userProfiles" +); From 02ba9860461b0e01b15bc68c0b89fa14bb2817df Mon Sep 17 00:00:00 2001 From: Shiwani Rajagopalan Date: Sun, 17 Dec 2023 14:16:00 -0500 Subject: [PATCH 264/272] added timeOffFrom and timeOffTill to taskHelper --- src/helpers/taskHelper.js | 420 +++++++++++++++++++++----------------- 1 file changed, 237 insertions(+), 183 deletions(-) diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index 800d1ee6b..fc6a331b3 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -1,149 +1,207 @@ -const moment = require('moment-timezone'); -const mongoose = require('mongoose'); -const userProfile = require('../models/userProfile'); -const timeentry = require('../models/timeentry'); -const myTeam = require('../helpers/helperModels/myTeam'); -const team = require('../models/team'); -const Task = require('../models/task'); -const TaskNotification = require('../models/taskNotification'); -const Wbs = require('../models/wbs'); +const moment = require("moment-timezone"); +const mongoose = require("mongoose"); +const userProfile = require("../models/userProfile"); +const timeentry = require("../models/timeentry"); +const myTeam = require("../helpers/helperModels/myTeam"); +const team = require("../models/team"); +const Task = require("../models/task"); +const TaskNotification = require("../models/taskNotification"); +const Wbs = require("../models/wbs"); const taskHelper = function () { const getTasksForTeams = async function (userId) { const userid = mongoose.Types.ObjectId(userId); - const userById = await userProfile.findOne({ _id: userid, isActive: true }, { - role: 1, firstName: 1, lastName: 1, role: 1, isVisible: 1, weeklycommittedHours: 1, weeklySummaries: 1, -}) - .then(res => res).catch((e) => {}); + const userById = await userProfile + .findOne( + { _id: userid, isActive: true }, + { + role: 1, + firstName: 1, + lastName: 1, + role: 1, + isVisible: 1, + weeklycommittedHours: 1, + weeklySummaries: 1, + } + ) + .then((res) => res) + .catch((e) => {}); if (userById == null) return null; const userRole = userById.role; const pdtstart = moment() - .tz('America/Los_Angeles') - .startOf('week') - .format('YYYY-MM-DD'); + .tz("America/Los_Angeles") + .startOf("week") + .format("YYYY-MM-DD"); const pdtend = moment() - .tz('America/Los_Angeles') - .endOf('week') - .format('YYYY-MM-DD'); + .tz("America/Los_Angeles") + .endOf("week") + .format("YYYY-MM-DD"); - let teamMemberIds = [userid]; - let teamMembers = []; + let teamMemberIds = [userid]; + let teamMembers = []; - if (userRole != 'Administrator' && userRole != 'Owner' && userRole != 'Core Team') // Manager , Mentor , Volunteer ... , Show only team members - { - const teamsResult = await team.find({ 'members.userId': { $in: [userid] } }, { members: 1 }) - .then(res => res).catch((e) => {}); + if ( + userRole != "Administrator" && + userRole != "Owner" && + userRole != "Core Team" + ) { + // Manager , Mentor , Volunteer ... , Show only team members + const teamsResult = await team + .find({ "members.userId": { $in: [userid] } }, { members: 1 }) + .then((res) => res) + .catch((e) => {}); - teamsResult.map((_myTeam) => { - _myTeam.members.map((teamMember) => { - if (!teamMember.userId.equals(userid)) teamMemberIds.push(teamMember.userId); - }); - }); + teamsResult.map((_myTeam) => { + _myTeam.members.map((teamMember) => { + if (!teamMember.userId.equals(userid)) + teamMemberIds.push(teamMember.userId); + }); + }); - teamMembers = await userProfile.find({ _id: { $in: teamMemberIds }, isActive: true }, - { - role: 1, firstName: 1, lastName: 1, weeklycommittedHours: 1, -}) - .then(res => res).catch((e) => {}); - } else if (userRole == 'Administrator') { // All users except Owner and Core Team - const excludedRoles = ['Core Team', 'Owner']; - teamMembers = await userProfile.find({ isActive: true, role: { $nin: excludedRoles } }, - { - role: 1, firstName: 1, lastName: 1, weeklycommittedHours: 1, -}) - .then(res => res).catch((e) => {}); - } else { // 'Core Team', 'Owner' //All users - teamMembers = await userProfile.find({ isActive: true }, - { - role: 1, firstName: 1, lastName: 1, weeklycommittedHours: 1, -}) - .then(res => res).catch((e) => {}); - } + teamMembers = await userProfile + .find( + { _id: { $in: teamMemberIds }, isActive: true }, + { + role: 1, + firstName: 1, + lastName: 1, + weeklycommittedHours: 1, + } + ) + .then((res) => res) + .catch((e) => {}); + } else if (userRole == "Administrator") { + // All users except Owner and Core Team + const excludedRoles = ["Core Team", "Owner"]; + teamMembers = await userProfile + .find( + { isActive: true, role: { $nin: excludedRoles } }, + { + role: 1, + firstName: 1, + lastName: 1, + weeklycommittedHours: 1, + } + ) + .then((res) => res) + .catch((e) => {}); + } else { + // 'Core Team', 'Owner' //All users + teamMembers = await userProfile + .find( + { isActive: true }, + { + role: 1, + firstName: 1, + lastName: 1, + weeklycommittedHours: 1, + } + ) + .then((res) => res) + .catch((e) => {}); + } - teamMemberIds = teamMembers.map(member => member._id); + teamMemberIds = teamMembers.map((member) => member._id); - const timeEntries = await timeentry.find({ - dateOfWork: { - $gte: pdtstart, - $lte: pdtend, - }, - personId: { $in: teamMemberIds }, - }); + const timeEntries = await timeentry.find({ + dateOfWork: { + $gte: pdtstart, + $lte: pdtend, + }, + personId: { $in: teamMemberIds }, + }); - const timeEntryByPerson = {}; - timeEntries.map((timeEntry) => { - const personIdStr = timeEntry.personId.toString(); + const timeEntryByPerson = {}; + timeEntries.map((timeEntry) => { + const personIdStr = timeEntry.personId.toString(); - if (timeEntryByPerson[personIdStr] == null) { timeEntryByPerson[personIdStr] = { tangibleSeconds: 0, intangibleSeconds: 0, totalSeconds: 0 }; } + if (timeEntryByPerson[personIdStr] == null) { + timeEntryByPerson[personIdStr] = { + tangibleSeconds: 0, + intangibleSeconds: 0, + totalSeconds: 0, + }; + } - if (timeEntry.isTangible === true) { - timeEntryByPerson[personIdStr].tangibleSeconds += timeEntry.totalSeconds; - } - timeEntryByPerson[personIdStr].totalSeconds += timeEntry.totalSeconds; - }); + if (timeEntry.isTangible === true) { + timeEntryByPerson[personIdStr].tangibleSeconds += + timeEntry.totalSeconds; + } + timeEntryByPerson[personIdStr].totalSeconds += timeEntry.totalSeconds; + }); - const teamMemberTasks = await Task.find({ 'resources.userID': { $in: teamMemberIds } }, { 'resources.profilePic': 0 }) - .populate({ - path: 'wbsId', - select: 'projectId', - }); - const teamMemberTaskIds = teamMemberTasks.map(task => task._id); - const teamMemberTaskNotifications = await TaskNotification.find({ taskId: { $in: teamMemberTaskIds } }); + const teamMemberTasks = await Task.find( + { "resources.userID": { $in: teamMemberIds } }, + { "resources.profilePic": 0 } + ).populate({ + path: "wbsId", + select: "projectId", + }); + const teamMemberTaskIds = teamMemberTasks.map((task) => task._id); + const teamMemberTaskNotifications = await TaskNotification.find({ + taskId: { $in: teamMemberTaskIds }, + }); - const taskNotificationByTaskNdUser = []; - teamMemberTaskNotifications.map((teamMemberTaskNotification) => { - const taskIdStr = teamMemberTaskNotification.taskId.toString(); - const userIdStr = teamMemberTaskNotification.userId.toString(); - const taskNdUserID = `${taskIdStr},${userIdStr}`; + const taskNotificationByTaskNdUser = []; + teamMemberTaskNotifications.map((teamMemberTaskNotification) => { + const taskIdStr = teamMemberTaskNotification.taskId.toString(); + const userIdStr = teamMemberTaskNotification.userId.toString(); + const taskNdUserID = `${taskIdStr},${userIdStr}`; - if (taskNotificationByTaskNdUser[taskNdUserID]) { - taskNotificationByTaskNdUser[taskNdUserID].push(teamMemberTaskNotification); - } else { - taskNotificationByTaskNdUser[taskNdUserID] = [teamMemberTaskNotification]; - } - }); + if (taskNotificationByTaskNdUser[taskNdUserID]) { + taskNotificationByTaskNdUser[taskNdUserID].push( + teamMemberTaskNotification + ); + } else { + taskNotificationByTaskNdUser[taskNdUserID] = [ + teamMemberTaskNotification, + ]; + } + }); - const taskByPerson = []; + const taskByPerson = []; - teamMemberTasks.map((teamMemberTask) => { - const projId = teamMemberTask.wbsId?.projectId; - const _teamMemberTask = { ...teamMemberTask._doc }; - _teamMemberTask.projectId = projId; - const taskIdStr = _teamMemberTask._id.toString(); + teamMemberTasks.map((teamMemberTask) => { + const projId = teamMemberTask.wbsId?.projectId; + const _teamMemberTask = { ...teamMemberTask._doc }; + _teamMemberTask.projectId = projId; + const taskIdStr = _teamMemberTask._id.toString(); - teamMemberTask.resources.map((resource) => { - const resourceIdStr = resource.userID.toString(); - const taskNdUserID = `${taskIdStr},${resourceIdStr}`; - _teamMemberTask.taskNotifications = taskNotificationByTaskNdUser[taskNdUserID] || []; - if (taskByPerson[resourceIdStr]) { - taskByPerson[resourceIdStr].push(_teamMemberTask); - } else { - taskByPerson[resourceIdStr] = [_teamMemberTask]; - } - }); + teamMemberTask.resources.map((resource) => { + const resourceIdStr = resource.userID.toString(); + const taskNdUserID = `${taskIdStr},${resourceIdStr}`; + _teamMemberTask.taskNotifications = + taskNotificationByTaskNdUser[taskNdUserID] || []; + if (taskByPerson[resourceIdStr]) { + taskByPerson[resourceIdStr].push(_teamMemberTask); + } else { + taskByPerson[resourceIdStr] = [_teamMemberTask]; + } }); - + }); const teamMemberTasksData = []; teamMembers.map((teamMember) => { - const obj = { - personId: teamMember._id, - role: teamMember.role, - name: `${teamMember.firstName } ${ teamMember.lastName}`, - weeklycommittedHours: teamMember.weeklycommittedHours, - totaltangibletime_hrs: ((timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / 3600) || 0), - totaltime_hrs: ((timeEntryByPerson[teamMember._id.toString()]?.totalSeconds / 3600) || 0), - tasks: taskByPerson[teamMember._id.toString()] || [], - }; - teamMemberTasksData.push(obj); + const obj = { + personId: teamMember._id, + role: teamMember.role, + name: `${teamMember.firstName} ${teamMember.lastName}`, + weeklycommittedHours: teamMember.weeklycommittedHours, + totaltangibletime_hrs: + timeEntryByPerson[teamMember._id.toString()]?.tangibleSeconds / + 3600 || 0, + totaltime_hrs: + timeEntryByPerson[teamMember._id.toString()]?.totalSeconds / 3600 || + 0, + tasks: taskByPerson[teamMember._id.toString()] || [], + }; + teamMemberTasksData.push(obj); }); - return teamMemberTasksData; - // return myteam.aggregate([ // { // $match: { @@ -429,13 +487,13 @@ const taskHelper = function () { }; const getTasksForSingleUser = function (userId) { const pdtstart = moment() - .tz('America/Los_Angeles') - .startOf('week') - .format('YYYY-MM-DD'); + .tz("America/Los_Angeles") + .startOf("week") + .format("YYYY-MM-DD"); const pdtend = moment() - .tz('America/Los_Angeles') - .endOf('week') - .format('YYYY-MM-DD'); + .tz("America/Los_Angeles") + .endOf("week") + .format("YYYY-MM-DD"); return userProfile.aggregate([ { $match: { @@ -444,20 +502,16 @@ const taskHelper = function () { }, { $project: { - personId: '$_id', - role: '$role', + personId: "$_id", + role: "$role", name: { - $concat: [ - '$firstName', - ' ', - '$lastName', - ], + $concat: ["$firstName", " ", "$lastName"], }, weeklycommittedHours: { $sum: [ - '$weeklycommittedHours', + "$weeklycommittedHours", { - $ifNull: ['$missedHours', 0], + $ifNull: ["$missedHours", 0], }, ], }, @@ -465,10 +519,10 @@ const taskHelper = function () { }, { $lookup: { - from: 'timeEntries', - localField: 'personId', - foreignField: 'personId', - as: 'timeEntryData', + from: "timeEntries", + localField: "personId", + foreignField: "personId", + as: "timeEntryData", }, }, { @@ -479,18 +533,18 @@ const taskHelper = function () { role: 1, timeEntryData: { $filter: { - input: '$timeEntryData', - as: 'timeentry', + input: "$timeEntryData", + as: "timeentry", cond: { $and: [ { - $gte: ['$$timeentry.dateOfWork', pdtstart], + $gte: ["$$timeentry.dateOfWork", pdtstart], }, { - $lte: ['$$timeentry.dateOfWork', pdtend], + $lte: ["$$timeentry.dateOfWork", pdtend], }, { - $in: ['$$timeentry.entryType', ['default', null]], + $in: ["$$timeentry.entryType", ["default", null]], }, ], }, @@ -500,7 +554,7 @@ const taskHelper = function () { }, { $unwind: { - path: '$timeEntryData', + path: "$timeEntryData", preserveNullAndEmptyArrays: true, }, }, @@ -513,18 +567,18 @@ const taskHelper = function () { totalSeconds: { $cond: [ { - $gte: ['$timeEntryData.totalSeconds', 0], + $gte: ["$timeEntryData.totalSeconds", 0], }, - '$timeEntryData.totalSeconds', + "$timeEntryData.totalSeconds", 0, ], }, isTangible: { $cond: [ { - $gte: ['$timeEntryData.totalSeconds', 0], + $gte: ["$timeEntryData.totalSeconds", 0], }, - '$timeEntryData.isTangible', + "$timeEntryData.isTangible", false, ], }, @@ -535,9 +589,9 @@ const taskHelper = function () { tangibletime: { $cond: [ { - $eq: ['$isTangible', true], + $eq: ["$isTangible", true], }, - '$totalSeconds', + "$totalSeconds", 0, ], }, @@ -546,40 +600,40 @@ const taskHelper = function () { { $group: { _id: { - personId: '$personId', - weeklycommittedHours: '$weeklycommittedHours', - name: '$name', - role: '$role', + personId: "$personId", + weeklycommittedHours: "$weeklycommittedHours", + name: "$name", + role: "$role", }, totalSeconds: { - $sum: '$totalSeconds', + $sum: "$totalSeconds", }, tangibletime: { - $sum: '$tangibletime', + $sum: "$tangibletime", }, }, }, { $project: { _id: 0, - personId: '$_id.personId', - name: '$_id.name', - weeklycommittedHours: '$_id.weeklycommittedHours', - role: '$_id.role', + personId: "$_id.personId", + name: "$_id.name", + weeklycommittedHours: "$_id.weeklycommittedHours", + role: "$_id.role", totaltime_hrs: { - $divide: ['$totalSeconds', 3600], + $divide: ["$totalSeconds", 3600], }, totaltangibletime_hrs: { - $divide: ['$tangibletime', 3600], + $divide: ["$tangibletime", 3600], }, }, }, { $lookup: { - from: 'tasks', - localField: 'personId', - foreignField: 'resources.userID', - as: 'tasks', + from: "tasks", + localField: "personId", + foreignField: "resources.userID", + as: "tasks", }, }, { @@ -593,25 +647,25 @@ const taskHelper = function () { }, { $unwind: { - path: '$tasks', + path: "$tasks", preserveNullAndEmptyArrays: true, }, }, { $lookup: { - from: 'wbs', - localField: 'tasks.wbsId', - foreignField: '_id', - as: 'projectId', + from: "wbs", + localField: "tasks.wbsId", + foreignField: "_id", + as: "projectId", }, }, { $addFields: { - 'tasks.projectId': { + "tasks.projectId": { $cond: [ - { $ne: ['$projectId', []] }, - { $arrayElemAt: ['$projectId', 0] }, - '$tasks.projectId', + { $ne: ["$projectId", []] }, + { $arrayElemAt: ["$projectId", 0] }, + "$tasks.projectId", ], }, }, @@ -633,40 +687,40 @@ const taskHelper = function () { }, { $addFields: { - 'tasks.projectId': '$tasks.projectId.projectId', + "tasks.projectId": "$tasks.projectId.projectId", }, }, { $lookup: { - from: 'taskNotifications', - localField: 'tasks._id', - foreignField: 'taskId', - as: 'tasks.taskNotifications', + from: "taskNotifications", + localField: "tasks._id", + foreignField: "taskId", + as: "tasks.taskNotifications", }, }, { $group: { - _id: '$personId', - tasks: { $push: '$tasks' }, + _id: "$personId", + tasks: { $push: "$tasks" }, data: { - $first: '$$ROOT', + $first: "$$ROOT", }, }, }, { $addFields: { - 'data.tasks': { + "data.tasks": { $filter: { - input: '$tasks', - as: 'task', - cond: { $ne: ['$$task', {}] }, + input: "$tasks", + as: "task", + cond: { $ne: ["$$task", {}] }, }, }, }, }, { $replaceRoot: { - newRoot: '$data', + newRoot: "$data", }, }, ]); @@ -674,7 +728,7 @@ const taskHelper = function () { const getUserProfileFirstAndLastName = function (userId) { return userProfile.findById(userId).then((results) => { if (!results) { - return ' '; + return " "; } return `${results.firstName} ${results.lastName}`; }); From c26046ec38728b000962cfd42dd7c71ca1fe24c1 Mon Sep 17 00:00:00 2001 From: Shiwani Rajagopalan Date: Sun, 17 Dec 2023 14:55:58 -0500 Subject: [PATCH 265/272] added timeOffFrom and timeOffTill to reportHelper --- src/helpers/reporthelper.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/helpers/reporthelper.js b/src/helpers/reporthelper.js index 3826aa8ed..eac0a71a1 100644 --- a/src/helpers/reporthelper.js +++ b/src/helpers/reporthelper.js @@ -121,7 +121,13 @@ const reporthelper = function () { }, }, teamCode: { - $ifNull: ['$teamCode', ''], + $ifNull: ["$teamCode", ""], + }, + timeOffFrom: { + $ifNull: ["$timeOffFrom", null], + }, + timeOffTill: { + $ifNull: ["$timeOffTill", null], }, role: 1, weeklySummaries: { From a153942136a951dde7b4503a58f52218087ffe33 Mon Sep 17 00:00:00 2001 From: Shiwani Rajagopalan Date: Mon, 18 Dec 2023 14:32:17 -0500 Subject: [PATCH 266/272] updated dashboardhelper and taskHelper to add timeOffFrom anf timeOffTill for individual task and leaderboard data --- src/helpers/dashboardhelper.js | 2 ++ src/helpers/taskHelper.js | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index a200a0095..0482f4252 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -638,6 +638,8 @@ const dashboardhelper = function () { totalintangibletime_hrs: intangibleSeconds / 3600, percentagespentintangible: (intangibleSeconds / tangibleSeconds) * 100, + timeOffFrom: user.timeOffFrom, + timeOffTill: user.timeOffTill, }, ]; } catch (err) { diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index fc6a331b3..6d5449bc8 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -515,6 +515,12 @@ const taskHelper = function () { }, ], }, + timeOffFrom: { + $ifNull: ["$timeOffFrom", null], + }, + timeOffTill: { + $ifNull: ["$timeOffTill", null], + }, }, }, { @@ -530,6 +536,8 @@ const taskHelper = function () { personId: 1, name: 1, weeklycommittedHours: 1, + timeOffFrom: 1, + timeOffTill: 1, role: 1, timeEntryData: { $filter: { @@ -563,6 +571,8 @@ const taskHelper = function () { personId: 1, name: 1, weeklycommittedHours: 1, + timeOffFrom: 1, + timeOffTill: 1, role: 1, totalSeconds: { $cond: [ @@ -602,6 +612,8 @@ const taskHelper = function () { _id: { personId: "$personId", weeklycommittedHours: "$weeklycommittedHours", + timeOffFrom: "$timeOffFrom", + timeOffTill: "$timeOffTill", name: "$name", role: "$role", }, @@ -619,6 +631,8 @@ const taskHelper = function () { personId: "$_id.personId", name: "$_id.name", weeklycommittedHours: "$_id.weeklycommittedHours", + timeOffFrom: "$_id.timeOffFrom", + timeOffTill: "$_id.timeOffTill", role: "$_id.role", totaltime_hrs: { $divide: ["$totalSeconds", 3600], From f484767ccef78e1e8e6118f8323003241c9daa1d Mon Sep 17 00:00:00 2001 From: Shiwani Rajagopalan Date: Mon, 18 Dec 2023 17:50:04 -0500 Subject: [PATCH 267/272] modified the array representation for timeOffFrom and TimeOffTill to a value instead of array --- src/helpers/dashboardhelper.js | 265 +++++++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+) diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index 0482f4252..e6d5118f6 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -258,6 +258,7 @@ const dashboardhelper = function () { $gte: pdtstart, $lte: pdtend, }, +<<<<<<< HEAD personId: { $in: teamMemberIds }, }); @@ -582,6 +583,270 @@ const dashboardhelper = function () { // }, // }, // ]); +======= + { + $unwind: "$myteam", + }, + { + $project: { + _id: 0, + role: 1, + personId: "$myteam._id", + name: "$myteam.fullName", + }, + }, + { + $lookup: { + from: "userProfiles", + localField: "personId", + foreignField: "_id", + as: "persondata", + }, + }, + { + $match: { + // leaderboard user roles hierarchy + $or: [ + { + role: { $in: ["Owner", "Core Team"] }, + }, + { + $and: [ + { + role: "Administrator", + }, + { "persondata.0.role": { $nin: ["Owner", "Administrator"] } }, + ], + }, + { + $and: [ + { + role: { $in: ["Manager", "Mentor"] }, + }, + { + "persondata.0.role": { + $nin: [ + "Manager", + "Mentor", + "Core Team", + "Administrator", + "Owner", + ], + }, + }, + ], + }, + { "persondata.0._id": userId }, + { "persondata.0.role": "Volunteer" }, + { "persondata.0.isVisible": true }, + ], + }, + }, + { + $project: { + personId: 1, + name: 1, + role: { + $arrayElemAt: ["$persondata.role", 0], + }, + isVisible: { + $arrayElemAt: ["$persondata.isVisible", 0], + }, + hasSummary: { + $ne: [ + { + $arrayElemAt: [ + { + $arrayElemAt: ["$persondata.weeklySummaries.summary", 0], + }, + 0, + ], + }, + "", + ], + }, + weeklycommittedHours: { + $sum: [ + { + $arrayElemAt: ["$persondata.weeklycommittedHours", 0], + }, + { + $ifNull: [{ $arrayElemAt: ["$persondata.missedHours", 0] }, 0], + }, + ], + }, + timeOffFrom: { + $ifNull: [{ $arrayElemAt: ["$persondata.timeOffFrom", 0] }, null], + }, + timeOffTill: { + $ifNull: [{ $arrayElemAt: ["$persondata.timeOffTill", 0] }, null], + }, + }, + }, + { + $lookup: { + from: "timeEntries", + localField: "personId", + foreignField: "personId", + as: "timeEntryData", + }, + }, + { + $project: { + personId: 1, + name: 1, + role: 1, + isVisible: 1, + hasSummary: 1, + weeklycommittedHours: 1, + timeOffFrom: 1, + timeOffTill: 1, + timeEntryData: { + $filter: { + input: "$timeEntryData", + as: "timeentry", + cond: { + $and: [ + { + $gte: ["$$timeentry.dateOfWork", pdtstart], + }, + { + $lte: ["$$timeentry.dateOfWork", pdtend], + }, + ], + }, + }, + }, + }, + }, + { + $unwind: { + path: "$timeEntryData", + preserveNullAndEmptyArrays: true, + }, + }, + { + $project: { + personId: 1, + name: 1, + role: 1, + isVisible: 1, + hasSummary: 1, + weeklycommittedHours: 1, + timeOffFrom: 1, + timeOffTill: 1, + totalSeconds: { + $cond: [ + { + $gte: ["$timeEntryData.totalSeconds", 0], + }, + "$timeEntryData.totalSeconds", + 0, + ], + }, + isTangible: { + $cond: [ + { + $gte: ["$timeEntryData.totalSeconds", 0], + }, + "$timeEntryData.isTangible", + false, + ], + }, + }, + }, + { + $addFields: { + tangibletime: { + $cond: [ + { + $eq: ["$isTangible", true], + }, + "$totalSeconds", + 0, + ], + }, + intangibletime: { + $cond: [ + { + $eq: ["$isTangible", false], + }, + "$totalSeconds", + 0, + ], + }, + }, + }, + { + $group: { + _id: { + personId: "$personId", + weeklycommittedHours: "$weeklycommittedHours", + timeOffFrom: "$timeOffFrom", + timeOffTill: "$timeOffTill", + name: "$name", + role: "$role", + isVisible: "$isVisible", + hasSummary: "$hasSummary", + }, + totalSeconds: { + $sum: "$totalSeconds", + }, + tangibletime: { + $sum: "$tangibletime", + }, + intangibletime: { + $sum: "$intangibletime", + }, + }, + }, + { + $project: { + _id: 0, + personId: "$_id.personId", + name: "$_id.name", + role: "$_id.role", + isVisible: "$_id.isVisible", + hasSummary: "$_id.hasSummary", + weeklycommittedHours: "$_id.weeklycommittedHours", + totaltime_hrs: { + $divide: ["$totalSeconds", 3600], + }, + totaltangibletime_hrs: { + $divide: ["$tangibletime", 3600], + }, + totalintangibletime_hrs: { + $divide: ["$intangibletime", 3600], + }, + percentagespentintangible: { + $cond: [ + { + $eq: ["$totalSeconds", 0], + }, + 0, + { + $multiply: [ + { + $divide: ["$tangibletime", "$totalSeconds"], + }, + 100, + ], + }, + ], + }, + timeOffFrom: "$_id.timeOffFrom", + timeOffTill: "$_id.timeOffTill", + }, + }, + { + $sort: { + totaltangibletime_hrs: -1, + name: 1, + role: 1, + }, + }, + ]); +>>>>>>> 367abce (modified the array representation for timeOffFrom and TimeOffTill to a value instead of array) }; /** From a956753af7579b5049338493273f19cefb419f0d Mon Sep 17 00:00:00 2001 From: Shiwani99 <78906820+Shiwani99@users.noreply.github.com> Date: Mon, 18 Dec 2023 18:53:26 -0500 Subject: [PATCH 268/272] Added comments to reasonSchedulingController.js --- src/controllers/reasonSchedulingController.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/controllers/reasonSchedulingController.js b/src/controllers/reasonSchedulingController.js index 4d56c5a5e..63dc51fed 100644 --- a/src/controllers/reasonSchedulingController.js +++ b/src/controllers/reasonSchedulingController.js @@ -55,12 +55,13 @@ const postReason = async (req, res) => { }); } - // new changes + // conditions added to check if timeOffFrom and timeOffTill fields existed if ( foundUser.hasOwnProperty("timeOffFrom") && foundUser.hasOwnProperty("timeOffTill") ) { + // if currentDate is greater than or equal to the last timeOffTill date then both the fields will be updated if (currentDate >= foundUser.timeOffTill) { await UserModel.findOneAndUpdate( { @@ -74,6 +75,7 @@ const postReason = async (req, res) => { } ); } else { + // else only timeOffTill will be updated await UserModel.findOneAndUpdate( { _id: userId, @@ -86,6 +88,7 @@ const postReason = async (req, res) => { ); } } else { + // if both the fields are not present then these fields will be added to mongoDB for that user await UserModel.findOneAndUpdate( { _id: userId, From 6346f4a40093db72230a5a4a673b50a3bd3324be Mon Sep 17 00:00:00 2001 From: Shiwani Rajagopalan Date: Mon, 8 Jan 2024 06:04:11 -0500 Subject: [PATCH 269/272] fixed issues with rebasing current branch with development and added timeOffFrom and timeOffTill to the new aggregation in dashboard and task helper --- package-lock.json | 106 ++++++------- src/helpers/dashboardhelper.js | 273 +-------------------------------- src/helpers/taskHelper.js | 10 ++ 3 files changed, 71 insertions(+), 318 deletions(-) diff --git a/package-lock.json b/package-lock.json index ff66994e8..ecce49ec7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1568,7 +1568,7 @@ "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, "@types/mime": { @@ -1729,7 +1729,7 @@ "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, "array-includes": { "version": "3.1.6", @@ -2768,7 +2768,7 @@ "bcryptjs": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", - "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" + "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" }, "bignumber.js": { "version": "9.0.2", @@ -2863,7 +2863,7 @@ "buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" }, "buffer-from": { "version": "1.1.2", @@ -2995,7 +2995,7 @@ "clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==" }, "clone-deep": { "version": "4.0.1", @@ -3039,12 +3039,12 @@ "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "concat-stream": { "version": "1.6.2", @@ -3100,7 +3100,7 @@ "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "core-js": { "version": "3.21.1", @@ -3253,7 +3253,7 @@ "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "electron-to-chromium": { "version": "1.4.81", @@ -3269,7 +3269,7 @@ "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" }, "es-abstract": { "version": "1.19.1", @@ -3350,7 +3350,7 @@ "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "escape-string-regexp": { "version": "1.0.5", @@ -4264,7 +4264,7 @@ "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, "event-target-shim": { "version": "5.0.1", @@ -4445,7 +4445,7 @@ "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, "fast-text-encoding": { @@ -4575,7 +4575,7 @@ "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" }, "fs-readdir-recursive": { "version": "1.1.0", @@ -4585,7 +4585,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "fsevents": { "version": "2.3.2", @@ -4968,7 +4968,7 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true }, "indent-string": { @@ -4980,7 +4980,7 @@ "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "requires": { "once": "^1.3.0", "wrappy": "1" @@ -5085,7 +5085,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" }, "is-glob": { "version": "4.0.3", @@ -5187,13 +5187,13 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" }, "js-tokens": { "version": "4.0.0", @@ -5231,7 +5231,7 @@ "json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, "json5": { @@ -5552,7 +5552,7 @@ "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" }, "lodash.merge": { "version": "4.6.2", @@ -5729,7 +5729,7 @@ "lru_map": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", - "integrity": "sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0=" + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==" }, "make-dir": { "version": "2.1.0", @@ -5743,7 +5743,7 @@ "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" }, "memory-pager": { "version": "1.5.0", @@ -5754,7 +5754,7 @@ "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" }, "merge-stream": { "version": "2.0.0", @@ -5765,7 +5765,7 @@ "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" }, "micromatch": { "version": "4.0.5", @@ -5945,7 +5945,7 @@ "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, "negotiator": { @@ -6085,7 +6085,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" }, "object-inspect": { "version": "1.12.0", @@ -6804,7 +6804,7 @@ "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "requires": { "wrappy": "1" } @@ -6834,7 +6834,7 @@ "os-shim": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz", - "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=", + "integrity": "sha512-jd0cvB8qQ5uVt0lvCIexBaROw1KyKm5sbulg2fWOHjETisuCzWyt+eTZKEMs8v6HwzoGs8xik26jg7eCM6pS+A==", "dev": true }, "p-limit": { @@ -6879,7 +6879,7 @@ "parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==" }, "parseurl": { "version": "1.3.3", @@ -6894,7 +6894,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" }, "path-key": { "version": "3.1.1", @@ -6910,7 +6910,7 @@ "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, "picocolors": { "version": "1.0.0", @@ -6957,7 +6957,7 @@ "pre-commit": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/pre-commit/-/pre-commit-1.2.2.tgz", - "integrity": "sha1-287g7p3nI15X95xW186UZBpp7sY=", + "integrity": "sha512-qokTiqxD6GjODy5ETAIgzsRgnBWWQHQH2ghy86PU7mIn/wuWeTwF3otyNQZxWBwVn8XNr8Tdzj/QfUXpH+gRZA==", "dev": true, "requires": { "cross-spawn": "^5.0.1", @@ -6968,7 +6968,7 @@ "cross-spawn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", "dev": true, "requires": { "lru-cache": "^4.0.1", @@ -6979,7 +6979,7 @@ "which": { "version": "1.2.14", "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", - "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "integrity": "sha512-16uPglFkRPzgiUXYMi1Jf8Z5EzN1iB4V0ZtMXcHZnwsBtQhhHeCqoWw7tsUY42hJGNDWtUsVLTjakIa5BgAxCw==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -7021,7 +7021,7 @@ "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", "dev": true }, "pstree.remy": { @@ -7499,7 +7499,7 @@ "sparse-bitfield": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", "optional": true, "requires": { "memory-pager": "^1.0.2" @@ -7508,7 +7508,7 @@ "spawn-sync": { "version": "1.0.15", "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", - "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=", + "integrity": "sha512-9DWBgrgYZzNghseho0JOuh+5fg9u6QWhAWa51QC7+U5rCheZ/j1DrEZnyE0RBBRqZ9uEXGPgSSM0nky6burpVw==", "dev": true, "requires": { "concat-stream": "^1.4.7", @@ -7903,7 +7903,7 @@ "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true }, "strip-final-newline": { @@ -7934,19 +7934,19 @@ "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" }, "to-regex-range": { "version": "5.0.1", @@ -7973,7 +7973,7 @@ "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "tsconfig-paths": { "version": "3.14.2", @@ -8091,7 +8091,7 @@ "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "dev": true }, "unbox-primitive": { @@ -8138,7 +8138,7 @@ "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" }, "uri-js": { "version": "4.4.1", @@ -8152,17 +8152,17 @@ "url-template": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", - "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" + "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==" }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" }, "uuid": { "version": "3.4.0", @@ -8185,17 +8185,17 @@ "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -8313,7 +8313,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "ws": { "version": "8.8.1", diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index e6d5118f6..9335a67c4 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -212,6 +212,8 @@ const dashboardhelper = function () { isVisible: 1, weeklycommittedHours: 1, weeklySummaries: 1, + timeOffFrom: 1, + timeOffTill: 1, } ) .then((res) => res) @@ -229,6 +231,8 @@ const dashboardhelper = function () { isVisible: 1, weeklycommittedHours: 1, weeklySummaries: 1, + timeOffFrom: 1, + timeOffTill: 1, } ) .then((res) => res) @@ -245,6 +249,8 @@ const dashboardhelper = function () { isVisible: 1, weeklycommittedHours: 1, weeklySummaries: 1, + timeOffFrom: 1, + timeOffTill: 1, } ) .then((res) => res) @@ -258,7 +264,6 @@ const dashboardhelper = function () { $gte: pdtstart, $lte: pdtend, }, -<<<<<<< HEAD personId: { $in: teamMemberIds }, }); @@ -314,6 +319,8 @@ const dashboardhelper = function () { timeEntryByPerson[teamMember._id.toString()]?.totalSeconds) * 100 : 0, + timeOffFrom: teamMember.timeOffFrom || null, + timeOffTill: teamMember.timeOffTill || null, }; leaderBoardData.push(obj); }); @@ -583,270 +590,6 @@ const dashboardhelper = function () { // }, // }, // ]); -======= - { - $unwind: "$myteam", - }, - { - $project: { - _id: 0, - role: 1, - personId: "$myteam._id", - name: "$myteam.fullName", - }, - }, - { - $lookup: { - from: "userProfiles", - localField: "personId", - foreignField: "_id", - as: "persondata", - }, - }, - { - $match: { - // leaderboard user roles hierarchy - $or: [ - { - role: { $in: ["Owner", "Core Team"] }, - }, - { - $and: [ - { - role: "Administrator", - }, - { "persondata.0.role": { $nin: ["Owner", "Administrator"] } }, - ], - }, - { - $and: [ - { - role: { $in: ["Manager", "Mentor"] }, - }, - { - "persondata.0.role": { - $nin: [ - "Manager", - "Mentor", - "Core Team", - "Administrator", - "Owner", - ], - }, - }, - ], - }, - { "persondata.0._id": userId }, - { "persondata.0.role": "Volunteer" }, - { "persondata.0.isVisible": true }, - ], - }, - }, - { - $project: { - personId: 1, - name: 1, - role: { - $arrayElemAt: ["$persondata.role", 0], - }, - isVisible: { - $arrayElemAt: ["$persondata.isVisible", 0], - }, - hasSummary: { - $ne: [ - { - $arrayElemAt: [ - { - $arrayElemAt: ["$persondata.weeklySummaries.summary", 0], - }, - 0, - ], - }, - "", - ], - }, - weeklycommittedHours: { - $sum: [ - { - $arrayElemAt: ["$persondata.weeklycommittedHours", 0], - }, - { - $ifNull: [{ $arrayElemAt: ["$persondata.missedHours", 0] }, 0], - }, - ], - }, - timeOffFrom: { - $ifNull: [{ $arrayElemAt: ["$persondata.timeOffFrom", 0] }, null], - }, - timeOffTill: { - $ifNull: [{ $arrayElemAt: ["$persondata.timeOffTill", 0] }, null], - }, - }, - }, - { - $lookup: { - from: "timeEntries", - localField: "personId", - foreignField: "personId", - as: "timeEntryData", - }, - }, - { - $project: { - personId: 1, - name: 1, - role: 1, - isVisible: 1, - hasSummary: 1, - weeklycommittedHours: 1, - timeOffFrom: 1, - timeOffTill: 1, - timeEntryData: { - $filter: { - input: "$timeEntryData", - as: "timeentry", - cond: { - $and: [ - { - $gte: ["$$timeentry.dateOfWork", pdtstart], - }, - { - $lte: ["$$timeentry.dateOfWork", pdtend], - }, - ], - }, - }, - }, - }, - }, - { - $unwind: { - path: "$timeEntryData", - preserveNullAndEmptyArrays: true, - }, - }, - { - $project: { - personId: 1, - name: 1, - role: 1, - isVisible: 1, - hasSummary: 1, - weeklycommittedHours: 1, - timeOffFrom: 1, - timeOffTill: 1, - totalSeconds: { - $cond: [ - { - $gte: ["$timeEntryData.totalSeconds", 0], - }, - "$timeEntryData.totalSeconds", - 0, - ], - }, - isTangible: { - $cond: [ - { - $gte: ["$timeEntryData.totalSeconds", 0], - }, - "$timeEntryData.isTangible", - false, - ], - }, - }, - }, - { - $addFields: { - tangibletime: { - $cond: [ - { - $eq: ["$isTangible", true], - }, - "$totalSeconds", - 0, - ], - }, - intangibletime: { - $cond: [ - { - $eq: ["$isTangible", false], - }, - "$totalSeconds", - 0, - ], - }, - }, - }, - { - $group: { - _id: { - personId: "$personId", - weeklycommittedHours: "$weeklycommittedHours", - timeOffFrom: "$timeOffFrom", - timeOffTill: "$timeOffTill", - name: "$name", - role: "$role", - isVisible: "$isVisible", - hasSummary: "$hasSummary", - }, - totalSeconds: { - $sum: "$totalSeconds", - }, - tangibletime: { - $sum: "$tangibletime", - }, - intangibletime: { - $sum: "$intangibletime", - }, - }, - }, - { - $project: { - _id: 0, - personId: "$_id.personId", - name: "$_id.name", - role: "$_id.role", - isVisible: "$_id.isVisible", - hasSummary: "$_id.hasSummary", - weeklycommittedHours: "$_id.weeklycommittedHours", - totaltime_hrs: { - $divide: ["$totalSeconds", 3600], - }, - totaltangibletime_hrs: { - $divide: ["$tangibletime", 3600], - }, - totalintangibletime_hrs: { - $divide: ["$intangibletime", 3600], - }, - percentagespentintangible: { - $cond: [ - { - $eq: ["$totalSeconds", 0], - }, - 0, - { - $multiply: [ - { - $divide: ["$tangibletime", "$totalSeconds"], - }, - 100, - ], - }, - ], - }, - timeOffFrom: "$_id.timeOffFrom", - timeOffTill: "$_id.timeOffTill", - }, - }, - { - $sort: { - totaltangibletime_hrs: -1, - name: 1, - role: 1, - }, - }, - ]); ->>>>>>> 367abce (modified the array representation for timeOffFrom and TimeOffTill to a value instead of array) }; /** diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index 6d5449bc8..8347a56ef 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -22,6 +22,8 @@ const taskHelper = function () { isVisible: 1, weeklycommittedHours: 1, weeklySummaries: 1, + timeOffFrom: 1, + timeOffTill: 1, } ) .then((res) => res) @@ -68,6 +70,8 @@ const taskHelper = function () { firstName: 1, lastName: 1, weeklycommittedHours: 1, + timeOffFrom: 1, + timeOffTill: 1, } ) .then((res) => res) @@ -83,6 +87,8 @@ const taskHelper = function () { firstName: 1, lastName: 1, weeklycommittedHours: 1, + timeOffFrom: 1, + timeOffTill: 1, } ) .then((res) => res) @@ -97,6 +103,8 @@ const taskHelper = function () { firstName: 1, lastName: 1, weeklycommittedHours: 1, + timeOffFrom: 1, + timeOffTill: 1, } ) .then((res) => res) @@ -196,6 +204,8 @@ const taskHelper = function () { timeEntryByPerson[teamMember._id.toString()]?.totalSeconds / 3600 || 0, tasks: taskByPerson[teamMember._id.toString()] || [], + timeOffFrom: teamMember.timeOffFrom || null, + timeOffTill: teamMember.timeOffTill || null, }; teamMemberTasksData.push(obj); }); From 2f362910ce36b623aff3ddfe2ce02d2353153e74 Mon Sep 17 00:00:00 2001 From: Shiwani Rajagopalan Date: Mon, 8 Jan 2024 07:22:46 -0500 Subject: [PATCH 270/272] resolved errors after merge conflicts --- src/controllers/reasonSchedulingController.js | 11 +--------- src/helpers/dashboardhelper.js | 21 ++++++++++--------- src/helpers/taskHelper.js | 15 ------------- 3 files changed, 12 insertions(+), 35 deletions(-) diff --git a/src/controllers/reasonSchedulingController.js b/src/controllers/reasonSchedulingController.js index 4fce71b3a..a76dcf4a2 100644 --- a/src/controllers/reasonSchedulingController.js +++ b/src/controllers/reasonSchedulingController.js @@ -11,9 +11,6 @@ const postReason = async (req, res) => { .tz(reasonData.date, "America/Los_Angeles") .startOf("day"); const currentDate = moment.tz("America/Los_Angeles").startOf("day"); - .tz(reasonData.date, "America/Los_Angeles") - .startOf("day"); - const currentDate = moment.tz("America/Los_Angeles").startOf("day"); // error case 0 if (moment.tz(reasonData.date, "America/Los_Angeles").day() !== 0) { @@ -38,7 +35,6 @@ const postReason = async (req, res) => { }); } - // Commented this condition to make reason scheduler available to all the users. // error case 1 // if (requestor.role !== 'Owner' && requestor.role !== 'Administrator') { @@ -160,7 +156,6 @@ const postReason = async (req, res) => { // emailSender(`${foundUser.email},@gmail.com`, subject, emailBody, null, null); } - return res.sendStatus(200); } catch (error) { console.log(error); @@ -307,11 +302,9 @@ const patchReason = async (req, res) => { const savedData = await foundReason.save(); if (savedData) { - // Upon clicking the "Save" button in the Blue Square Reason Scheduler, an email will be automatically sent to the user and Jae. const subject = `Blue Square Reason for ${foundUser.firstName} ${foundUser.lastName} has been updated`; - const emailBody = `

Hi !

const emailBody = `

Hi !

This email is to let you know that ${foundUser.firstName} ${foundUser.lastName} has updated their Blue Square Reason.

@@ -331,7 +324,6 @@ const patchReason = async (req, res) => { // emailSender(`${foundUser.email},@gmail.com`, subject, emailBody, null, null); } - return res.status(200).json({ message: "Reason Updated!", message: "Reason Updated!", @@ -348,13 +340,12 @@ const deleteReason = async (req, res) => { const { reasonData, requestor } = req.body; const { userId } = req.params; - // error case 1 if (requestor.role !== "Owner" && requestor.role !== "Administrator") { return res.status(403).json({ message: "You must be an Owner or Administrator to schedule a reason for a Blue Square", - "You must be an Owner or Administrator to schedule a reason for a Blue Square", + errorCode: 1, }); } diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index 2babef0b2..9f172dd2a 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -174,20 +174,17 @@ const dashboardhelper = function () { .then((res) => res) .catch((e) => {}); - if (userById == null) return null; const userRole = userById.role; const pdtstart = moment() .tz("America/Los_Angeles") .startOf("week") .format("YYYY-MM-DD"); + + const pdtend = moment() .tz("America/Los_Angeles") - .startOf("week") + .endOf("week") .format("YYYY-MM-DD"); - const pdtend = moment() - .tz('America/Los_Angeles') - .endOf('week') - .format('YYYY-MM-DD'); let teamMemberIds = [userid]; let teamMembers = []; @@ -210,9 +207,6 @@ const dashboardhelper = function () { }); }); - teamMembers = await userProfile - .find( - { _id: { $in: teamMemberIds }, isActive: true }, teamMembers = await userProfile .find( { _id: { $in: teamMemberIds }, isActive: true }, @@ -235,6 +229,7 @@ const dashboardhelper = function () { teamMembers = await userProfile .find( { isActive: true, role: { $nin: excludedRoles } }, + { role: 1, firstName: 1, lastName: 1, @@ -300,7 +295,13 @@ const dashboardhelper = function () { timeEntries.map((timeEntry) => { const personIdStr = timeEntry.personId.toString(); - if (timeEntryByPerson[personIdStr] == null) { timeEntryByPerson[personIdStr] = { tangibleSeconds: 0, intangibleSeconds: 0, totalSeconds: 0 }; } + if (timeEntryByPerson[personIdStr] == null) { + timeEntryByPerson[personIdStr] = { + tangibleSeconds: 0, + intangibleSeconds: 0, + totalSeconds: 0, + }; + } if (timeEntry.isTangible === true) { timeEntryByPerson[personIdStr].tangibleSeconds += diff --git a/src/helpers/taskHelper.js b/src/helpers/taskHelper.js index 0d26b96bb..372c960dd 100644 --- a/src/helpers/taskHelper.js +++ b/src/helpers/taskHelper.js @@ -40,25 +40,10 @@ const taskHelper = function () { .tz("America/Los_Angeles") .endOf("week") .format("YYYY-MM-DD"); - .tz("America/Los_Angeles") - .endOf("week") - .format("YYYY-MM-DD"); let teamMemberIds = [userid]; let teamMembers = []; - let teamMemberIds = [userid]; - let teamMembers = []; - if ( - userRole != "Administrator" && - userRole != "Owner" && - userRole != "Core Team" - ) { - // Manager , Mentor , Volunteer ... , Show only team members - const teamsResult = await team - .find({ "members.userId": { $in: [userid] } }, { members: 1 }) - .then((res) => res) - .catch((e) => {}); if ( userRole != "Administrator" && userRole != "Owner" && From bd9a1500299a597190de07ff4eb38e6ef4b2ef77 Mon Sep 17 00:00:00 2001 From: Shiwani Rajagopalan Date: Mon, 8 Jan 2024 07:26:38 -0500 Subject: [PATCH 271/272] resolved errors in userProfile.js after conflicts --- src/models/userProfile.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/models/userProfile.js b/src/models/userProfile.js index 8f5e23d2c..aaa3923f5 100644 --- a/src/models/userProfile.js +++ b/src/models/userProfile.js @@ -1,13 +1,9 @@ const mongoose = require("mongoose"); const moment = require("moment-timezone"); -const mongoose = require("mongoose"); -const moment = require("moment-timezone"); const { Schema } = mongoose; const validate = require("mongoose-validator"); const bcrypt = require("bcryptjs"); -const validate = require("mongoose-validator"); -const bcrypt = require("bcryptjs"); const SALT_ROUNDS = 10; const nextDay = new Date(); From b03f597e8d3cb2bf59adbaad42d2f15262a6c81f Mon Sep 17 00:00:00 2001 From: Vishala Ramasamy Date: Wed, 10 Jan 2024 16:23:36 -0800 Subject: [PATCH 272/272] Lb view hier. for Admins --- src/helpers/dashboardhelper.js | 40 +--------------------------------- 1 file changed, 1 insertion(+), 39 deletions(-) diff --git a/src/helpers/dashboardhelper.js b/src/helpers/dashboardhelper.js index 9f172dd2a..8df4f6c9d 100644 --- a/src/helpers/dashboardhelper.js +++ b/src/helpers/dashboardhelper.js @@ -223,46 +223,8 @@ const dashboardhelper = function () { ) .then((res) => res) .catch((e) => {}); - } else if (userRole == "Administrator") { - // All users except Owner and Core Team - const excludedRoles = ["Core Team", "Owner"]; - teamMembers = await userProfile - .find( - { isActive: true, role: { $nin: excludedRoles } }, - { - role: 1, - firstName: 1, - lastName: 1, - isVisible: 1, - weeklycommittedHours: 1, - weeklySummaries: 1, - timeOffFrom: 1, - timeOffTill: 1, - } - ) - .then((res) => res) - .catch((e) => {}); - } else if (userRole == "Administrator") { - // All users except Owner and Core Team - const excludedRoles = ["Core Team", "Owner"]; - teamMembers = await userProfile - .find( - { isActive: true, role: { $nin: excludedRoles } }, - { - role: 1, - firstName: 1, - lastName: 1, - isVisible: 1, - weeklycommittedHours: 1, - weeklySummaries: 1, - timeOffFrom: 1, - timeOffTill: 1, - } - ) - .then((res) => res) - .catch((e) => {}); } else { - // 'Core Team', 'Owner' //All users + // 'Core Team', 'Owner' , 'Admin' //Show All users teamMembers = await userProfile .find( { isActive: true },