Skip to content

Commit

Permalink
Merge branch 'development' into Xiao-F-Create-way-for-owner-to-edit-u…
Browse files Browse the repository at this point in the history
…pdate-ChatGPT-prompt-text
  • Loading branch information
tsunami776 committed Jan 5, 2024
2 parents 403ca74 + fcf86f5 commit ce8d244
Show file tree
Hide file tree
Showing 60 changed files with 3,403 additions and 1,985 deletions.
7 changes: 4 additions & 3 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lts/fermium
18 changes: 17 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
195 changes: 135 additions & 60 deletions src/controllers/badgeController.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
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 logger = require('../startup/logger');

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;
}

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,
Expand All @@ -26,8 +29,32 @@ 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());
return moment(currentDate).tz('America/Los_Angeles').format('MMM-DD-YY');
};

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;
}
Expand All @@ -39,63 +66,100 @@ 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]) {
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
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,
);
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) {
res.status(500).send(`Internal Error: Badge Collection. ${ err.message}`);
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((err) => {
logger.logException(err);
res.status(500).send('Internal Error: Unable to save the record.');
});
});
};

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;
Expand All @@ -104,19 +168,31 @@ 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;
Expand All @@ -129,7 +205,6 @@ const badgeController = function (Badge) {
// store onto Azure and return url
}


const data = {
badgeName: req.body.name || req.body.badgeName,
description: req.body.description,
Expand Down
19 changes: 19 additions & 0 deletions src/controllers/bmdashboard/bmInventoryTypeController.js
Original file line number Diff line number Diff line change
@@ -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;
Loading

0 comments on commit ce8d244

Please sign in to comment.