From 26eaaa254bf78d2d0d3bbc634e6c7630ce82ee8d Mon Sep 17 00:00:00 2001 From: Xiao Tan Date: Thu, 15 Jun 2023 15:33:57 -0700 Subject: [PATCH 01/17] 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 95a5386820bc38e7374f2fcf68e1ee489abfa6a3 Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Tue, 29 Aug 2023 12:14:47 +0800 Subject: [PATCH 02/17] 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 03/17] 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 65f675eb60fc6de9f35274f9c4a67477596456ad Mon Sep 17 00:00:00 2001 From: navneeeth Date: Fri, 22 Sep 2023 19:25:14 -0700 Subject: [PATCH 04/17] 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 05/17] 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 b69dd8beb4916b15ac9eb7756bf499a18426782b Mon Sep 17 00:00:00 2001 From: abdelmounaim lallouache Date: Thu, 28 Sep 2023 19:13:38 -0500 Subject: [PATCH 06/17] 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 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 07/17] 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 08/17] 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 09/17] 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 10/17] 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 60a1fa2348c3a790b3b5c59b3297a41d6074ddb7 Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Tue, 3 Oct 2023 12:46:33 +0800 Subject: [PATCH 11/17] 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 12/17] 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 1e096f26a066587f7eea80e771894ecce4a3f50d Mon Sep 17 00:00:00 2001 From: Jerry Ren Date: Wed, 4 Oct 2023 15:11:44 -0400 Subject: [PATCH 13/17] 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 b7201d5b0a0d542510c1ed2178db7bf6da6312da Mon Sep 17 00:00:00 2001 From: AriaYu927 Date: Thu, 5 Oct 2023 16:27:37 +0800 Subject: [PATCH 14/17] 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 1782d7446115509e54cd88f431be62f78334106a Mon Sep 17 00:00:00 2001 From: Aaron Persaud Date: Sat, 7 Oct 2023 23:53:33 -0400 Subject: [PATCH 15/17] 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 545a2582263748f4ea2e8f3d1ff80215d6fdf2d4 Mon Sep 17 00:00:00 2001 From: wang9hu Date: Tue, 10 Oct 2023 13:42:53 -0700 Subject: [PATCH 16/17] 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 17/17] 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/**/*" + ] } }
First Name: