-
Notifications
You must be signed in to change notification settings - Fork 58
Port security, CI and stability fixes from new-test-branch onto main #279
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
63fa189
cc304f5
704424f
c7c3776
db5b1bc
4a947a5
1041ebd
a5bf9bf
68f165c
c2eb330
ad12705
6a57a4c
0627ea1
0b649fd
ecf22cd
aad952a
c490aa0
ebfad24
590658e
b6aea0f
9322477
17d3ae0
d233f28
5261566
f8309b7
402801a
f80438d
c6cb516
94cb110
cda1989
344ebfa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,7 +9,6 @@ const { findEvent } = require("../services/event.service"); | |
| const { findTemplate } = require("../services/template.service"); | ||
| const { getApprovers } = require("../services/user.service"); | ||
| const { | ||
| getOrganization, | ||
| getCoordinatorOrganization, | ||
| } = require("../services/organization.service"); | ||
| const { HttpError } = require("../utils/httpError"); | ||
|
|
@@ -107,7 +106,7 @@ async function createBatch(req, res) { | |
| } | ||
|
|
||
|
|
||
| const newBatch = await CertificateBatch.create({ | ||
| await CertificateBatch.create({ | ||
| title, | ||
| eventId: event._id, | ||
| templateId: template._id, | ||
|
|
@@ -188,6 +187,12 @@ async function editBatch(req, res) { | |
| return res.status(404).json({ message: "Batch not found" }); | ||
| } | ||
|
|
||
| if (batch.initiatedBy.toString() !== id) { | ||
| return res.status(403).json({ | ||
| message: "You are not authorized to edit this batch", | ||
| }); | ||
| } | ||
|
|
||
| Object.assign(batch, validation.data); | ||
|
|
||
| batch.lifecycleStatus = action; | ||
|
|
@@ -271,7 +276,7 @@ async function duplicateBatch(req, res) { | |
| const array = batch.title.split("(Copy)"); | ||
| const count = array.length -1; | ||
| const title = `${array[0]} Copy(${count})`; | ||
| const newBatch = await CertificateBatch.create({ | ||
| await CertificateBatch.create({ | ||
| ...batch.toObject(), | ||
| title: title, | ||
| lifecycleStatus: "Draft", | ||
|
|
@@ -539,6 +544,13 @@ async function approveBatch(req, res) { | |
| }; | ||
| } | ||
|
|
||
| // Final (President) approval: generate certificates BEFORE marking the | ||
| // batch Active/Approved. If generation fails, the batch stays Submitted | ||
| // so the approval can be retried once the cause is fixed. | ||
| if (level === 1) { | ||
| await generateCertificates(batch); | ||
|
Comment on lines
+550
to
+551
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift Coordinate certificate creation with the final state transition.
🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| const updatedBatch = await CertificateBatch.findOneAndUpdate( | ||
| matchQuery, | ||
| update, | ||
|
|
@@ -552,17 +564,11 @@ async function approveBatch(req, res) { | |
| }); | ||
| } | ||
|
|
||
| if (level === 1) { | ||
| // Final (President) approval just happened - generate certificates | ||
| // exactly once, from the freshly-updated, level===2 document. | ||
| await generateCertificates(updatedBatch); | ||
| } | ||
|
|
||
| return res.status(200).json({ | ||
| message: | ||
| level === 0 | ||
| ? "Batch approved by GENSEC. Forwarded to President." | ||
| : "Batch approved successfully. Certificates are being generated.", | ||
| : "Batch approved successfully. Certificates generated.", | ||
| }); | ||
| } catch (err) { | ||
| if (err instanceof HttpError) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -215,7 +215,30 @@ exports.deleteEvent = async (req, res) => { | |
| exports.updateEvent = async (req, res) => { | ||
| try { | ||
| const { eventId } = req.params; | ||
| const updates = req.body; | ||
|
|
||
| const allowedFields = [ | ||
| "title", | ||
| "description", | ||
| "category", | ||
| "type", | ||
| "schedule", | ||
| "registration", | ||
| "budget", | ||
| "status", | ||
| ]; | ||
|
|
||
| const updates = {}; | ||
| for (const field of allowedFields) { | ||
| if (req.body[field] !== undefined) { | ||
| updates[field] = req.body[field]; | ||
| } | ||
| } | ||
|
|
||
| if (Object.keys(updates).length === 0) { | ||
| return res.status(400).json({ | ||
| message: "No editable fields provided", | ||
| }); | ||
| } | ||
|
|
||
| const event = await Event.findByIdAndUpdate( | ||
| eventId, | ||
|
|
@@ -241,7 +264,6 @@ exports.updateEvent = async (req, res) => { | |
|
|
||
| return res.status(500).json({ | ||
| message: "Server error", | ||
| error: err.message, | ||
| }); | ||
| } | ||
| }; | ||
|
|
@@ -450,7 +472,7 @@ exports.registerForEvent = async (req, res) => { | |
|
|
||
|
|
||
| exports.getEventsByRole = async (req, res) => { | ||
| const userRole = req.params.userRole; | ||
| const userRole = req.user.role; | ||
|
|
||
| try { | ||
| let query = {}; | ||
|
|
@@ -465,7 +487,7 @@ exports.getEventsByRole = async (req, res) => { | |
| break; | ||
|
|
||
| case "CLUB_COORDINATOR": { | ||
| const username = req.query.username; | ||
| const username = req.user.username; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Use the coordinator’s contact email for the organizational-unit lookup. If a coordinator’s 🤖 Prompt for AI Agents |
||
|
|
||
| if (!username) { | ||
| return res.status(400).json({ | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
Repository: OpenLake/Student_Database_COSA
Length of output: 6622
🏁 Script executed:
Repository: OpenLake/Student_Database_COSA
Length of output: 21604
🏁 Script executed:
Repository: OpenLake/Student_Database_COSA
Length of output: 5731
Pass the sandbox flags to the approval browser.
generateCertificateslaunches Puppeteer before passing the browser torenderToPdf, so the renderer does not applyPUPPETEER_NO_SANDBOXto that launch. If Chromium cannot use its sandbox, final approval can fail before PDF generation and leave the batch inSubmittedstate. Apply the same conditional launch arguments here.🐛 Suggested fix
🤖 Prompt for AI Agents