Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
47cc03a
feat(reports): add finalWeekIndex for inactive users
Neeraj-Kondaveeti Oct 24, 2025
839d32d
feat: Add organizer field to Event model
pavanputti Dec 6, 2025
58ae3e6
feat: Add organizerLogo field to Event model
pavanputti Dec 7, 2025
908bb1a
feat: add KIInventoryItems schema and add items
bhanuanishakkineni Jan 22, 2026
296353c
feat: create get items and update items endpoints
bhanuanishakkineni Jan 24, 2026
2812b72
feat: add getPreservedStock and updateNextHarvest
bhanuanishakkineni Jan 24, 2026
fe1941e
Merge branch 'development' into bhanuanish-kitchenandinventory-invent…
bhanuanishakkineni Feb 4, 2026
0f5f0b0
fix: HGN Totals mismatch with Acitve Volunteers Count
sohailuddinsyed Feb 8, 2026
a9e5fe5
fix: align mentor count with dashboard 0 hrs total
sohailuddinsyed Feb 15, 2026
3e03df4
feat: add test endpoint for setting user teamCode
sayali-2308 Feb 19, 2026
7c2c88d
feat: add user state indicator backend - controller, models, routes
sayali-2308 Feb 26, 2026
d58e0ed
fix: resolve SonarCloud security and maintainability issues in userSt…
sayali-2308 Feb 26, 2026
bf9b7ed
fix: resolve all SonarCloud issues in userStateController
sayali-2308 Feb 26, 2026
597fe1d
fix: resolve SonarCloud NoSQL injection blockers using ObjectId valid…
sayali-2308 Feb 27, 2026
b67d869
fix: explicitly reassign user fields to resolve remaining SonarCloud …
sayali-2308 Feb 27, 2026
a082e5a
fix: break taint chain for SonarCloud L87 blocker in createCatalog
sayali-2308 Feb 27, 2026
f165bff
fix: use codePointAt and explicit casting to resolve SonarCloud issues
sayali-2308 Mar 5, 2026
2104c7b
feat: add PR grading config model, controller, and routes for dynamic…
sayali-2308 Mar 6, 2026
358c4e2
fix(recipients): Fixed Weekly Summary Email Recipients UI + Functiona…
DiyaWadhwani Mar 13, 2026
8b8eec1
Merge pull request #2101 from OneCommunityGlobal/Diya_Fix_WeeklySumma…
one-community Mar 13, 2026
a318f6a
Merge pull request #1943 from OneCommunityGlobal/siva/fix-organizer-n…
one-community Mar 14, 2026
9220c5a
Merge pull request #2088 from OneCommunityGlobal/Sayali_PR_Grading_Cr…
one-community Mar 16, 2026
dd0e4fc
Merge pull request #2074 from OneCommunityGlobal/Sayali_User_State_In…
one-community Mar 16, 2026
6c969e0
Merge pull request #1850 from OneCommunityGlobal/Neeraj_Create_Way_To…
one-community Mar 20, 2026
d96644b
Merge branch 'development' into bhanuanish-kitchenandinventory-invent…
bhanuanishakkineni Mar 20, 2026
29a68c8
fix: Fixed UserProfile delete reflect in Teams page
DiyaWadhwani Mar 20, 2026
c8ada9f
Merge pull request #2018 from OneCommunityGlobal/bhanuanish-kitchenan…
one-community Mar 20, 2026
8d7f7f9
Merge pull request #2048 from OneCommunityGlobal/Sohail-mentor-count-…
one-community Mar 23, 2026
1019b2a
Merge pull request #2035 from OneCommunityGlobal/Sohail-Active-Volunt…
one-community Mar 23, 2026
b0aab23
Merge pull request #2060 from OneCommunityGlobal/Sayali_Add_Member_Co…
one-community Mar 24, 2026
75f8097
Merge pull request #2113 from OneCommunityGlobal/Diya_Dix_TeamPageUI
one-community Mar 24, 2026
622b99e
chore: add puppeteer browser install step
Mar 24, 2026
17be92d
Merge pull request #2117 from OneCommunityGlobal/sundar/totalOrgEmail
one-community Mar 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
"serve": "babel-node src/server.js",
"prepare-macos-linux": "husky install && chmod ug+x .husky/* && chmod ug+x .git/hooks/*",
"prepare": "husky install",
"install": "npm install --ignore-scripts sharp"
"install": "npm install --ignore-scripts sharp",
"postinstall": "npx puppeteer browsers install chrome"
},
"author": "AK",
"license": "ISC",
Expand Down
3 changes: 3 additions & 0 deletions src/app.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
const express = require('express');
const Sentry = require('@sentry/node');
const testRoutes = require('./routes/testRoutes');

Check warning on line 3 in src/app.js

View workflow job for this annotation

GitHub Actions / Lint Check

There should be no empty line between import groups

const app = express();
const logger = require('./startup/logger');
const globalErrorHandler = require('./utilities/errorHandling/globalErrorHandler');

Check warning on line 7 in src/app.js

View workflow job for this annotation

GitHub Actions / Lint Check

There should be no empty line between import groups
// const experienceRoutes = require('./routes/applicantAnalyticsRoutes');

logger.init();
Expand All @@ -15,6 +16,8 @@
require('./startup/cors')(app);
require('./startup/bodyParser')(app);

app.use('/api/test', testRoutes);

const helpFeedbackRouter = require('./routes/helpFeedbackRouter');
const helpRequestRouter = require('./routes/helpRequestRouter');

Expand Down
167 changes: 167 additions & 0 deletions src/controllers/kitchenandinventory/KIInventoryController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
const KIInventoryItem = require('../../models/kitchenandinventory/KIInventoryItems');

const KIInventoryController = () => {
const addItem = async (req, res) => {
const {
name,
storedQuantity,
unit,
type,
monthlyUsage,
category,
expiryDate,
location,
onsite,
reorderAt,
lastHarvestDate,
nextHarvestDate,
nextHarvestQuantity,
} = req.body;
const newItem = new KIInventoryItem({
name,
storedQuantity,
presentQuantity: storedQuantity,
unit,
type,
monthlyUsage,
category,
expiryDate,
location,
onsite,
reorderAt,
lastHarvestDate,
nextHarvestDate,
nextHarvestQuantity,
});
try {
const savedItem = await newItem.save();
res.status(201).json({
message: 'Inventory item added successfully',
data: savedItem,
});
} catch (error) {
res.status(400).json({ message: error.message });
}
};
const getItems = async (req, res) => {
try {
const items = await KIInventoryItem.find(null, { __v: 0 }).lean().sort({ createdAt: -1 });
res.status(200).json({ message: 'All Items fetched successfully.', data: items });
} catch (err) {
res.status(400).json({ message: 'Something went wrong while fetching items.' });
}
};
const getItemsByCategory = async (req, res) => {
const { category } = req.params;
try {
const items = await KIInventoryItem.find({ category }, { __v: 0 })
.lean()
.sort({ createdAt: -1 });
res.status(200).json({ message: 'Items fetched successfully.', data: items });
} catch (err) {
res.status(400).json({ message: 'Something went wrong while fetching items.' });
}
};
const getPreservedStock = async (req, res) => {
const oneyearFromNow = new Date();
oneyearFromNow.setFullYear(oneyearFromNow.getFullYear() + 1);
try {
const items = await KIInventoryItem.find(
{ category: 'INGREDIENT', expiryDate: { $gte: oneyearFromNow } },
{ __v: 0 },
)
.lean()
.sort({ presentQuantity: -1 });
res.status(200).json({ message: 'Preserved stock items fetched successfully.', data: items });
} catch (err) {
res
.status(400)
.json({ message: 'Something went wrong while fetching preserved stock items.' });
}
};
const updateOnUsage = async (req, res) => {
const { itemId, usedQuantity } = req.body;
if (usedQuantity <= 0) {
return res.status(400).json({ message: 'Used quantity must be greater than zero.' });
}
try {
const item = await KIInventoryItem.findById(itemId);
if (!item) {
return res.status(404).json({ message: 'Item not found.' });
}
if (item.expiryDate < new Date()) {
return res.status(400).json({ message: `This item was expired on ${item.expiryDate}` });
}
let present = item.presentQuantity;
present -= usedQuantity;
if (present < 0) {
present = 0;
}
item.presentQuantity = present;
item.updatedAt = new Date();
await item.save();
res.status(200).json({ message: 'Item usage updated successfully.', data: item });
} catch (err) {
res.status(400).json({ message: err.message });
}
};
const updateStoredQuantity = async (req, res) => {
const { itemId, addedQuantity, newExpiry } = req.body;
if (addedQuantity <= 0) {
return res.status(400).json({ message: 'Added quantity must be greater than zero.' });
}
if (newExpiry && new Date(newExpiry) < new Date()) {
return res.status(400).json({ message: 'New expiry date must be a future date.' });
}
try {
const item = await KIInventoryItem.findById(itemId);
if (!item) {
return res.status(404).json({ message: 'Item not found.' });
}
if (item.presentQuantity === 0 || item.expiryDate < new Date()) {
item.storedQuantity = addedQuantity;
item.presentQuantity = 0;
} else {
item.storedQuantity += addedQuantity;
}
item.presentQuantity += addedQuantity;
if (newExpiry) {
item.expiryDate = newExpiry;
}
item.updatedAt = new Date();
await item.save();
res.status(200).json({ message: 'Stored quantity updated successfully.', data: item });
} catch (err) {
res.status(400).json({ message: err.message });
}
};
const updateNextHarvest = async (req, res) => {
const { itemId, lastHarvestSuccess, nextHarvestDate, nextHarvestQuantity } = req.body;
try {
const item = await KIInventoryItem.findById(itemId);
if (!item) {
return res.status(404).json({ message: 'Item not found.' });
}
if (lastHarvestSuccess) {
item.lastHarvestDate = item.nextHarvestDate;
}
item.nextHarvestDate = nextHarvestDate;
item.nextHarvestQuantity = nextHarvestQuantity;
item.updatedAt = new Date();
await item.save();
res.status(200).json({ message: 'Next harvest details updated successfully.', data: item });
} catch (err) {
res.status(400).json({ message: err.message });
}
};
return {
addItem,
getItems,
getItemsByCategory,
getPreservedStock,
updateOnUsage,
updateStoredQuantity,
updateNextHarvest,
};
};
module.exports = KIInventoryController;
63 changes: 63 additions & 0 deletions src/controllers/prAnalytics/prGradingConfigController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
const prGradingConfigController = function (PRGradingConfig) {
const getAllConfigs = async (req, res) => {
try {
const configs = await PRGradingConfig.find().sort({ createdAt: -1 });
res.status(200).json(configs);
} catch (err) {
res.status(500).json({ error: 'Failed to fetch configurations', details: err.message });
}
};

const createConfig = async (req, res) => {
try {
const { teamName, reviewerCount, testDataType, reviewerNames, notes } = req.body;

if (!teamName || !reviewerCount || !testDataType) {
return res
.status(400)
.json({ error: 'teamName, reviewerCount, and testDataType are required.' });
}

if (typeof reviewerCount !== 'number' || reviewerCount < 1) {
return res.status(400).json({ error: 'reviewerCount must be a positive number.' });
}

const existing = await PRGradingConfig.findOne({ teamName: teamName.trim() });
if (existing) {
return res
.status(409)
.json({ error: `A configuration with team name "${teamName}" already exists.` });
}

const newConfig = new PRGradingConfig({
teamName: teamName.trim(),
reviewerCount,
testDataType,
reviewerNames: reviewerNames || [],
notes: notes || '',
});

const saved = await newConfig.save();
res.status(201).json(saved);
} catch (err) {
res.status(500).json({ error: 'Failed to create configuration', details: err.message });
}
};

const deleteConfig = async (req, res) => {
try {
const { id } = req.params;
const deleted = await PRGradingConfig.findByIdAndDelete(id);
if (!deleted) {
return res.status(404).json({ error: 'Configuration not found.' });
}
res.status(200).json({ message: 'Configuration deleted successfully.' });
} catch (err) {
res.status(500).json({ error: 'Failed to delete configuration', details: err.message });
}
};

return { getAllConfigs, createConfig, deleteConfig };
};

module.exports = prGradingConfigController;
1 change: 1 addition & 0 deletions src/controllers/reportsController.js
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,7 @@ const reportsController = function () {
createdDate: 1,
getWeeklyReport: 1,
permissionGrantedToGetWeeklySummaryReport: 1,
isActive: 1,
},
)
.then((results) => {
Expand Down
35 changes: 34 additions & 1 deletion src/controllers/userProfileController.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const moment_ = require('moment');
const jwt = require('jsonwebtoken');
const userHelper = require('../helpers/userHelper')();
const TimeEntry = require('../models/timeentry');
const Team = require('../models/team');
const logger = require('../startup/logger');
const Badge = require('../models/badge');
// eslint-disable-next-line no-unused-vars
Expand Down Expand Up @@ -477,7 +478,39 @@ const createControllerMethods = function (UserProfile, Project, cache) {
}

if (req.body.teams !== undefined) {
record.teams = Array.from(new Set(req.body.teams));
const updatedTeams = Array.from(new Set(req.body.teams));

// Find teams that were removed
const removedTeams = record.teams.filter(
(teamId) => !updatedTeams.includes(teamId.toString()),
);

// Find teams that were added
const addedTeams = updatedTeams.filter(
(teamId) => !record.teams.map((t) => t.toString()).includes(teamId),
);

// Remove user from Team's members array for each removed team
if (removedTeams.length > 0) {
await Team.updateMany(
{ _id: { $in: removedTeams } },
{ $pull: { members: { userId: mongoose.Types.ObjectId(record._id) } } },
);
}

// Add user to Team's members array for each added team
if (addedTeams.length > 0) {
await Team.updateMany(
{ _id: { $in: addedTeams } },
{
$push: {
members: { userId: mongoose.Types.ObjectId(record._id), addDateTime: new Date() },
},
},
);
}

record.teams = updatedTeams;
}

await updateProjects(req, record);
Expand Down
Loading
Loading