Skip to content

Commit df4e99c

Browse files
Merge pull request #2206 from OneCommunityGlobal/development
Backend Release to Main [3.05]
2 parents 1f9349f + bef6dba commit df4e99c

33 files changed

Lines changed: 1549 additions & 1790 deletions

src/app.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ app.use(Sentry.Handlers.requestHandler());
1515
require('./startup/compression')(app);
1616
require('./startup/cors')(app);
1717
require('./startup/bodyParser')(app);
18-
require('./startup/session')(app); // Add session before middleware and routes
18+
require('./startup/session')(app); // Add session before middleware and routes
1919

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

src/controllers/bmdashboard/bmEquipmentController.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ const bmEquipmentController = (BuildingEquipment) => {
298298
}
299299

300300
if (!mongoose.Types.ObjectId.isValid(createdBy)) {
301-
console.error('Invalid createdBy ID:', createdBy);
301+
console.error('Invalid createdBy ID');
302302
return res.status(400).send({
303303
error: 'Invalid user ID format. Please log in again.',
304304
details: `Expected a valid MongoDB ObjectId, got: ${createdBy}`,
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
const calendarController = function (CalendarEvent, ProcessingProject) {
2+
const getCalendarEvents = async (req, res) => {
3+
try {
4+
const { month, year, module: moduleFilter } = req.query;
5+
6+
if (!month || !year) {
7+
return res.status(400).send({ error: 'Month and year query parameters are required.' });
8+
}
9+
10+
const monthNum = Number.parseInt(month, 10);
11+
const yearNum = Number.parseInt(year, 10);
12+
13+
if (Number.isNaN(monthNum) || Number.isNaN(yearNum) || monthNum < 1 || monthNum > 12) {
14+
return res.status(400).send({ error: 'Invalid month or year value.' });
15+
}
16+
17+
// Build date range: start of month to end of month
18+
const startDate = new Date(yearNum, monthNum - 1, 1);
19+
const endDate = new Date(yearNum, monthNum, 0, 23, 59, 59, 999);
20+
21+
// Build query from validated primitives only — never spread user-controlled data
22+
const safeQuery = {
23+
scheduled_date: { $gte: startDate, $lte: endDate },
24+
};
25+
26+
const validModules = ['garden', 'orchard', 'animals', 'kitchen'];
27+
28+
if (moduleFilter && !validModules.includes(moduleFilter)) {
29+
return res.status(400).send({
30+
error: `Invalid module. Must be one of: ${validModules.join(', ')}`,
31+
});
32+
}
33+
34+
let events = [];
35+
36+
if (moduleFilter === 'kitchen') {
37+
// Query kitchen events from ProcessingProject collection
38+
const kitchenProjects = await ProcessingProject.find(safeQuery).sort({
39+
scheduled_date: 1,
40+
});
41+
events = kitchenProjects.map((project) => ({
42+
_id: project._id,
43+
title: project.item_name,
44+
module: 'kitchen',
45+
event_type: project.process_name,
46+
scheduled_date: project.scheduled_date,
47+
description: '',
48+
assigned_to: '',
49+
related_item: project.item_name,
50+
status: 'scheduled',
51+
}));
52+
} else if (moduleFilter) {
53+
// Look up the module from the whitelist — never use raw user value in query
54+
const safeModule = validModules.find((m) => m === moduleFilter);
55+
events = await CalendarEvent.find({ ...safeQuery, module: safeModule }).sort({
56+
scheduled_date: 1,
57+
});
58+
} else {
59+
// No filter: query all modules in parallel
60+
const [calendarEvents, kitchenProjects] = await Promise.all([
61+
CalendarEvent.find(safeQuery).sort({ scheduled_date: 1 }),
62+
ProcessingProject.find(safeQuery).sort({ scheduled_date: 1 }),
63+
]);
64+
65+
const normalizedKitchen = kitchenProjects.map((project) => ({
66+
_id: project._id,
67+
title: project.item_name,
68+
module: 'kitchen',
69+
event_type: project.process_name,
70+
scheduled_date: project.scheduled_date,
71+
description: '',
72+
assigned_to: '',
73+
related_item: project.item_name,
74+
status: 'scheduled',
75+
}));
76+
77+
events = [...calendarEvents, ...normalizedKitchen];
78+
79+
// Sort merged results by scheduled_date
80+
events.sort((a, b) => new Date(a.scheduled_date) - new Date(b.scheduled_date));
81+
}
82+
83+
return res.status(200).send({ events });
84+
} catch (err) {
85+
// eslint-disable-next-line no-console
86+
console.error('Error fetching calendar events:', err);
87+
return res.status(500).send({ error: 'Internal Server Error' });
88+
}
89+
};
90+
91+
const createEvent = async (req, res) => {
92+
try {
93+
const {
94+
title,
95+
module: eventModule,
96+
event_type,
97+
scheduled_date,
98+
description,
99+
assigned_to,
100+
related_item,
101+
status,
102+
} = req.body;
103+
104+
if (!title || !eventModule || !event_type || !scheduled_date) {
105+
return res.status(400).send({
106+
error: 'Title, module, event_type, and scheduled_date are required.',
107+
});
108+
}
109+
110+
const validModules = ['garden', 'orchard', 'animals', 'kitchen'];
111+
if (!validModules.includes(eventModule)) {
112+
return res.status(400).send({
113+
error: `Invalid module. Must be one of: ${validModules.join(', ')}`,
114+
});
115+
}
116+
117+
const event = new CalendarEvent({
118+
title,
119+
module: eventModule,
120+
event_type,
121+
scheduled_date,
122+
description,
123+
assigned_to,
124+
related_item,
125+
status,
126+
});
127+
128+
await event.save();
129+
return res.status(201).send(event);
130+
} catch (err) {
131+
// eslint-disable-next-line no-console
132+
console.error('Error creating calendar event:', err);
133+
return res.status(500).send({ error: 'Internal Server Error' });
134+
}
135+
};
136+
137+
const deleteEvent = async (req, res) => {
138+
try {
139+
const { id } = req.params;
140+
141+
const event = await CalendarEvent.findById(id);
142+
if (!event) {
143+
return res.status(404).send({ error: 'Event not found.' });
144+
}
145+
146+
await CalendarEvent.findByIdAndDelete(id);
147+
return res.status(200).send({ message: 'Event successfully deleted.' });
148+
} catch (err) {
149+
// eslint-disable-next-line no-console
150+
console.error('Error deleting calendar event:', err);
151+
return res.status(500).send({ error: 'Internal Server Error' });
152+
}
153+
};
154+
155+
return {
156+
getCalendarEvents,
157+
createEvent,
158+
deleteEvent,
159+
};
160+
};
161+
162+
module.exports = calendarController;
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
const cullingController = function (CullingEvent) {
2+
const postEvent = async (req, res) => {
3+
try {
4+
const { name, related_to, count, purpose, notes, scheduled_date } = req.body;
5+
6+
if (!name || !related_to || !count || !purpose || !scheduled_date) {
7+
return res.status(400).send({
8+
error: 'Name, related_to, count, purpose, and scheduled_date are required.',
9+
});
10+
}
11+
12+
const validModules = ['Garden', 'Orchard', 'Animals'];
13+
if (!validModules.includes(related_to)) {
14+
return res.status(400).send({
15+
error: `Invalid related_to value. Must be one of: ${validModules.join(', ')}`,
16+
});
17+
}
18+
19+
const event = new CullingEvent({
20+
name,
21+
related_to,
22+
count,
23+
purpose,
24+
notes,
25+
scheduled_date,
26+
});
27+
28+
await event.save();
29+
return res.status(201).send(event);
30+
} catch (err) {
31+
// eslint-disable-next-line no-console
32+
console.error('Error creating culling event:', err);
33+
return res.status(500).send({ error: 'Internal Server Error' });
34+
}
35+
};
36+
37+
const getEvents = async (req, res) => {
38+
try {
39+
const events = await CullingEvent.find().sort({ scheduled_date: 1 });
40+
return res.status(200).send(events);
41+
} catch (err) {
42+
// eslint-disable-next-line no-console
43+
console.error('Error fetching culling events:', err);
44+
return res.status(500).send({ error: 'Internal Server Error' });
45+
}
46+
};
47+
48+
return {
49+
postEvent,
50+
getEvents,
51+
};
52+
};
53+
54+
module.exports = cullingController;
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
const harvestingController = function (HarvestingEvent) {
2+
const postEvent = async (req, res) => {
3+
try {
4+
const { name, related_to, type, expected_date, yield: yieldAmount } = req.body;
5+
6+
if (!name || !related_to || !type || !expected_date) {
7+
return res.status(400).send({
8+
error: 'Name, related_to, type, and expected_date are required.',
9+
});
10+
}
11+
12+
const validModules = ['Garden', 'Orchard', 'Animals'];
13+
if (!validModules.includes(related_to)) {
14+
return res.status(400).send({
15+
error: `Invalid related_to value. Must be one of: ${validModules.join(', ')}`,
16+
});
17+
}
18+
19+
const validTypes = ['garden harvesting', 'orchard harvesting'];
20+
if (!validTypes.includes(type)) {
21+
return res.status(400).send({
22+
error: `Invalid type value. Must be one of: ${validTypes.join(', ')}`,
23+
});
24+
}
25+
26+
const event = new HarvestingEvent({
27+
name,
28+
related_to,
29+
type,
30+
expected_date,
31+
yield: yieldAmount,
32+
});
33+
34+
await event.save();
35+
return res.status(201).send(event);
36+
} catch (err) {
37+
// eslint-disable-next-line no-console
38+
console.error('Error creating harvesting event:', err);
39+
return res.status(500).send({ error: 'Internal Server Error' });
40+
}
41+
};
42+
43+
const getEvents = async (req, res) => {
44+
try {
45+
const { type } = req.query;
46+
const VALID_TYPES = ['garden harvesting', 'orchard harvesting'];
47+
48+
if (type && !VALID_TYPES.includes(type)) {
49+
return res.status(400).send({
50+
error: `Invalid type filter. Must be one of: ${VALID_TYPES.join(', ')}`,
51+
});
52+
}
53+
54+
// Build query from whitelisted values only — never from raw user input
55+
const matchedType = VALID_TYPES.find((t) => t === type);
56+
const query = matchedType ? { type: matchedType } : {};
57+
58+
const events = await HarvestingEvent.find(query).sort({ expected_date: 1 });
59+
return res.status(200).send(events);
60+
} catch (err) {
61+
// eslint-disable-next-line no-console
62+
console.error('Error fetching harvesting events:', err);
63+
return res.status(500).send({ error: 'Internal Server Error' });
64+
}
65+
};
66+
67+
return {
68+
postEvent,
69+
getEvents,
70+
};
71+
};
72+
73+
module.exports = harvestingController;

src/controllers/lbdashboard/bidsController.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,13 @@ const bidsController = function (Bids) {
8080

8181
const paypalCheckoutNowLink = ordDetails?.links.find((u) => u.href.includes('checkoutnow'));
8282
const newBidsData = {
83-
...req.body,
83+
listingId: req.body.listingId,
84+
termsAgreed: req.body.termsAgreed,
85+
email: req.body.email,
86+
startDate: req.body.startDate,
87+
endDate: req.body.endDate,
88+
biddingHistory: req.body.biddingHistory,
89+
phone: req.body.phone,
8490
userId: userExists._id,
8591
paypalOrderId: ordDetails?.id,
8692
paypalCheckoutNowLink: paypalCheckoutNowLink?.href,
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
const plantingController = function (PlantingEvent) {
2+
const postEvent = async (req, res) => {
3+
try {
4+
const { name, related_to, count, date, location } = req.body;
5+
6+
if (!name || !related_to || !count || !date || !location) {
7+
return res.status(400).send({
8+
error: 'Name, related_to, count, date, and location are required.',
9+
});
10+
}
11+
12+
const validModules = ['Garden', 'Orchard', 'Animals'];
13+
if (!validModules.includes(related_to)) {
14+
return res.status(400).send({
15+
error: `Invalid related_to value. Must be one of: ${validModules.join(', ')}`,
16+
});
17+
}
18+
19+
const event = new PlantingEvent({
20+
name,
21+
related_to,
22+
count,
23+
date,
24+
location,
25+
});
26+
27+
await event.save();
28+
return res.status(201).send(event);
29+
} catch (err) {
30+
// eslint-disable-next-line no-console
31+
console.error('Error creating planting event:', err);
32+
return res.status(500).send({ error: 'Internal Server Error' });
33+
}
34+
};
35+
36+
const getEvents = async (req, res) => {
37+
try {
38+
const events = await PlantingEvent.find().sort({ date: 1 });
39+
return res.status(200).send(events);
40+
} catch (err) {
41+
// eslint-disable-next-line no-console
42+
console.error('Error fetching planting events:', err);
43+
return res.status(500).send({ error: 'Internal Server Error' });
44+
}
45+
};
46+
47+
return {
48+
postEvent,
49+
getEvents,
50+
};
51+
};
52+
53+
module.exports = plantingController;

0 commit comments

Comments
 (0)