Skip to content

Backend work for Smart Room Booking & Clash Detection#233

Open
gmarav05 wants to merge 8 commits intoOpenLake:mainfrom
gmarav05:main
Open

Backend work for Smart Room Booking & Clash Detection#233
gmarav05 wants to merge 8 commits intoOpenLake:mainfrom
gmarav05:main

Conversation

@gmarav05
Copy link

@gmarav05 gmarav05 commented Feb 25, 2026


name: " Pull Request"
about: Propose and submit changes to the project for review
title: "PR: [Brief Description of Changes]"
labels: ""
assignees: harshitap1305, sakshi1755

Related Issue


Changes Introduced

  • Added: Room and RoomBooking schemas, controller, and routes for room management, booking, clash detection, and status updates.
  • Fixed: N/A
  • Updated: Registered new routes in backend server, added sample room seeding logic.
  • Removed: N/A

Why This Change?

  • Problem: No centralized room booking system; manual clash detection was error-prone.
  • Solution: Introduces robust backend for booking rooms, automatic clash detection, and admin approval workflow.
  • Impact: Streamlines event coordination, prevents double-booking, and improves admin workflow.

Screenshots / Video (if applicable)

Before After

Testing

  • Ran unit tests and all passed (npm test in the relevant directory).
  • Manually tested the following scenarios:
    • Test Case 1: [Describe steps + Expected Result]
    • Test Case 2: [Describe steps + Expected Result]
  • Tested on different browsers (Chrome, Firefox) for UI changes.
  • Verified there are no new console warnings or errors.

Documentation Updates

  • Updated the README.md with new instructions.
  • Added clear code comments where logic is complex.
  • N/A

Checklist

  • I have created a new branch for this PR (git checkout -b feature/my-amazing-feature).
  • I have starred the repository.
  • My code follows the project's coding style and conventions.
  • My commit messages are clear and follow the project's guidelines.
  • I have performed a self-review of my own code.
  • I have added tests that prove my fix is effective or that my feature works.
  • All new and existing tests passed locally with my changes.
  • This PR introduces no breaking changes (or they are clearly documented).

Deployment Notes

  • Requires a database migration/schema update.
  • Requires new environment variables to be set.
  • N/A

💬 Additional Notes

  • [Add any other context or information here.]

Summary by CodeRabbit

  • New Features

    • Room management: create and view rooms with capacity, location, amenities, unique IDs and role-based creation controls.
    • Room booking: reserve rooms for date/time with same-day enforcement, automatic conflict detection, and populated booking details.
    • Availability & live status: per-day booking lists and real-time occupied/available status including current event info.
    • Booking administration: approve/reject bookings with overlap checks; cancel bookings with role-based permissions.
  • Chores

    • Added sample rooms and seeding for room-related data.

@vercel
Copy link

vercel bot commented Feb 25, 2026

@gmarav05 is attempting to deploy a commit to the openlake's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 25, 2026

Important

Review skipped

This PR was authored by the user configured for CodeRabbit reviews. CodeRabbit does not review PRs authored by this user. It's recommended to use a dedicated user account to post CodeRabbit review feedback.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2d1821ea-31b0-4fe9-840e-fac3a08b0bcb

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

Adds Room and RoomBooking Mongoose models, a new roomBookingController with full room and booking REST handlers, an Express router mounted at /api/rooms, seed updates to populate/clear rooms, and small session/CORS changes in backend/index.js.

Changes

Cohort / File(s) Summary
Models
backend/models/schema.js
Added Room and RoomBooking Mongoose models, room_id generation, enums, timestamps, compound index, and exported the new models.
Controller
backend/controllers/roomBookingController.js
New controller implementing room and booking handlers (createRoom, getAllRooms, getRoomById, bookRoom, getAvailability, updateBookingStatus, cancelBooking, getBookings), helpers for day bounds/id resolution/occupancy, transactional clash detection, and mapped HTTP errors (400/404/409/500).
Routes
backend/routes/roomBooking.js
New Express router wiring endpoints to controller methods; applies isAuthenticated and authorizeRole on protected routes; includes legacy adapters and exports router.
App Integration
backend/index.js
Mounted room routes at app.use("/api/rooms", roomBookingRoutes); changed CORS origin to http://localhost:3000; simplified session cookie settings (saveUninitialized: true, secure: false, sameSite: "lax", httpOnly: true).
Seeding
backend/seed.js
Imported Room/RoomBooking; added sampleRooms and seedRooms(); extended clearData() to remove room-related docs; adjusted seeding order and formatting.
Auth config
backend/models/passportConfig.js
Changed Passport serialization to store only user.id, updated deserializeUser to load via User.findById(id) and handle missing users with done(null, false).

Sequence Diagram(s)

sequenceDiagram
    actor Client
    participant Routes as /api/rooms Router
    participant Controller as roomBookingController
    participant Models as Room & RoomBooking Models
    participant DB as Database

    Client->>Routes: POST /api/rooms/book (payload)
    Routes->>Controller: bookRoom(req)
    Controller->>Models: resolve room id (Room.findOne / findById)
    Models->>DB: query Room
    DB-->>Models: room doc
    Models-->>Controller: room
    Controller->>Models: query existing bookings (day bounds, statuses)
    Models->>DB: query RoomBooking (overlap check)
    DB-->>Models: matching bookings[]
    Models-->>Controller: bookings (maybe conflict)
    alt Conflict detected
        Controller-->>Routes: 409 Conflict (conflicting booking)
        Routes-->>Client: 409
    else No conflict
        Controller->>DB: begin transaction
        Controller->>Models: update Room.updated_at
        Controller->>Models: create RoomBooking
        Models->>DB: insert booking
        DB-->>Models: created booking
        Controller->>DB: commit
        Controller-->>Routes: 201 Created (booking)
        Routes-->>Client: 201
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through schemas, routes, and seed,
I checked the times so bookings succeed,
Conflicts caught, roles trimmed, and rooms named true,
Now halls report when someone’s in view —
A tiny hop, a code carrot for you.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Out of Scope Changes check ❓ Inconclusive Most changes align with issue #231; however, modifications to CORS origin (hardcoded localhost), session middleware, and Passport serialization appear tangential to the core room booking requirements. Clarify whether CORS/session/Passport changes in backend/index.js and backend/models/passportConfig.js are necessary for the room booking feature or represent separate concerns requiring separate PRs.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately describes the main changes: backend implementation of smart room booking with clash detection features.
Description check ✅ Passed The PR description follows the template structure with Related Issue, Changes Introduced, Why This Change sections completed; however, Testing and Documentation Update checklists remain unchecked with placeholder content.
Linked Issues check ✅ Passed The PR implements core requirements from issue #231: room schemas, GET /room endpoints for all/individual rooms with status/occupancy detection, and clash detection for bookings. All major coding requirements are addressed.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/controllers/roomBookingController.js`:
- Around line 65-66: The populated bookedBy user documents are exposing full
user data; update both populate calls (the one using
RoomBooking.find(...).populate('room event bookedBy') and the similar populate
at lines ~121-122) to restrict fields by using the object form: populate({ path:
'bookedBy', select: '_id name email' }) (or whichever minimal safe fields your
User model exposes), e.g., replace the string 'bookedBy' with the object
selector so only safe user fields are returned while keeping room and event
populations unchanged.
- Around line 19-23: getAllRooms currently returns only static Room docs from
Room.find and must be extended to include live status fields (status,
current_event, occupied_until). After fetching rooms in getAllRooms, retrieve
live occupancy data (from your RoomStatus/Occupancy store or service) for each
room (e.g., via RoomStatus.findOne({ roomId }) or
RoomStatusService.getStatus(room.id)), merge those fields into each room object,
and then send the augmented array with res.json; perform the per-room lookups
concurrently with Promise.all to avoid serial waits and handle missing status
records by supplying sensible defaults.
- Around line 31-39: The clash logic in the RoomBooking.findOne query ignores
the booking date and doesn’t validate time ranges; update the controller to
first validate that startTime < endTime (reject requests where startTime >=
endTime) and then include the booking date in the query (e.g., filter by date or
by combining date+time) so only bookings on the same date are checked; keep the
existing room: roomId and status: { $in: ['Pending','Approved'] } filters and
use the same overlap condition ({ startTime: { $lt: endTime }, endTime: { $gt:
startTime } }) but applied together with date to prevent cross-day matches.
- Around line 77-84: Before updating to 'Approved', load the target booking (use
RoomBooking.findById(id)) to get its room and time window, then if status ===
'Approved' run a query for any other booking with status 'Approved' for the same
room that overlaps the target booking's start/end (e.g. findOne({ _id: { $ne: id
}, room: booking.room, status: 'Approved', $or: [{ start: { $lt: booking.end,
$gte: booking.start } }, { end: { $gt: booking.start, $lte: booking.end } }, {
start: { $lte: booking.start }, end: { $gte: booking.end } }] }) ) and if one
exists return a 409/conflict; only then perform the update
(RoomBooking.findByIdAndUpdate or findOneAndUpdate). Ensure you reference
RoomBooking.findById and RoomBooking.findByIdAndUpdate in the change.

In `@backend/models/schema.js`:
- Around line 648-666: The roomSchema is missing the API-required fields room_id
and allowed_roles; update the mongoose roomSchema to add a room_id field
(String, required, unique — generated if absent via a default function or a
pre('save') hook using UUID logic) and an allowed_roles field (Array of String,
required or with a sensible default like []), and ensure any creation/update
code that constructs Room documents (e.g., create handlers or Model.create
usages) no longer omit room_id so responses match the API contract; keep the
symbol name roomSchema and adjust indexes/validation as needed.

In `@backend/routes/roomBooking.js`:
- Around line 11-13: The route paths are incorrect: change router.get('/rooms',
isAuthenticated, roomBookingController.getAllRooms) to router.get('/',
isAuthenticated, roomBookingController.getAllRooms) so the mounted /api/rooms
yields GET /api/rooms; add a new parameterized route router.get('/:room_id',
isAuthenticated, roomBookingController.getRoomById) (or the appropriate
controller method that returns room details/status) to expose GET
/api/rooms/:room_id; also update the other similar occurrence (the one around
line 35) to use '/' or '/:room_id' instead of duplicating "rooms". Ensure the
referenced controller method name matches an exported function in
roomBookingController.

In `@backend/seed.js`:
- Around line 26-31: The seedRooms function is defined but never invoked, so
sampleRooms are not inserted; call seedRooms from the main seeding flow (for
example inside the top-level async seed/run function or after other seed calls)
or add it to the Promise.all/await chain that runs other seed helpers so it
executes during seeding; locate the seedRooms function and ensure the script
invokes seedRooms() (or exports and calls it where other seeds like
seedUsers/seedBookings are executed) so rooms get inserted on a fresh seed.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 64a42c1 and a0bccbc.

📒 Files selected for processing (5)
  • backend/controllers/roomBookingController.js
  • backend/index.js
  • backend/models/schema.js
  • backend/routes/roomBooking.js
  • backend/seed.js

@harshitap1305 harshitap1305 self-requested a review March 2, 2026 14:50
@harshitap1305
Copy link
Member

@gmarav05 fix the clash detection algorithm and other bugs in the PR

@gmarav05
Copy link
Author

Yeah sure i am currently working on that only. i will send it by eod.

@gmarav05
Copy link
Author

@harshitap1305 Can you check if any changes are required also can you please check again with the Coderabbit? Just In case i am missing something.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (1)
backend/seed.js (1)

1147-1147: Remove the second seedRooms() pass.

Line 1147 deletes and recreates every Room after the rest of the seed flow has finished. That regenerates room _ids and will orphan any room-linked seed data as soon as this script starts creating RoomBooking rows or other room references.

♻️ Proposed fix
     await seedEvents();
     await seedAchievements();
     await seedFeedbacks();
-    await seedRooms();
 
     console.log("\n✅ Seeding completed successfully!");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/seed.js` at line 1147, The script calls seedRooms() twice causing
rooms to be recreated and orphaning room-linked data; remove the second
invocation (the await seedRooms(); near the end of the file) so rooms are only
seeded once, and verify no other duplicate calls to seedRooms remain (ensure
RoomBooking or other room-referencing seeding runs after the single seedRooms()
call).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/controllers/roomBookingController.js`:
- Around line 190-198: The handler currently returns the flat room document
enriched with occupancy fields (via Room.findById, SAFE_ROOM_SELECT,
buildRoomStatusMap, enrichRoom) but must return the room-detail shape required
by GET /room/:room_id: wrap the response into the detail payload by constructing
schedule: { start, end } from the occupancy/statusMap data and metadata: {
capacity, features } from the room document (instead of the flat keys), then
return res.json(detailPayload); update the code around Room.findById/enrichRoom
to build and return this detailPayload object (preserving existing values but
reshaping to the detail contract).
- Around line 62-89: buildRoomStatusMap currently only queries RoomBooking and
ignores active Event-only occupancies; update it to also query the Event model
for events whose startTime <= now < endTime for the given roomIds (use the same
SAFE_EVENT_SELECT projection) and merge those results into the returned
statusMap so rooms with active events (even without a RoomBooking) are marked
status: "occupied" with current_event and occupied_until populated; ensure you
reference the existing variables/function name buildRoomStatusMap,
SAFE_EVENT_SELECT, and RoomBooking when implementing the additional Event query
and merge logic.
- Around line 91-97: The code returns the undocumented status string "available"
for empty rooms; update enrichRoom (function enrichRoom) to return "vacant"
instead of "available" in its fallback status and similarly change the
create-room response logic (the create-room response branch that currently emits
"available") to emit "vacant" so the API matches the documented enum ("vacant" |
"occupied"); ensure the three fallback fields (status, current_event,
occupied_until) keep the same values but with status set to "vacant".
- Around line 276-303: The current read-then-write flow (RoomBooking.findOne ...
then new RoomBooking ... booking.save) is TOCTOU-prone; wrap the check+insert in
a MongoDB transaction (start a session, run RoomBooking.findOne with { session
}, abort if clash, then insert/save the new RoomBooking with the same session
and commit) so the check and write are atomic and serialized; apply the same
transactional pattern to the other create/approve flow that also uses
RoomBooking.findOne and booking.save (the second block referenced in the
comment) so concurrent requests cannot both pass the check and double-book a
room.
- Around line 371-375: After retrieving the booking with
RoomBooking.findById(id) in the roomBookingController handler, restrict further
review/approval to only bookings with status "Pending": check booking.status (or
the enum used) and if it's not "Pending" return an error response (e.g., 400/409
with a clear message like "Only pending bookings can be reviewed") so
Cancelled/Rejected/Completed bookings cannot be resurrected; update any related
logic that assumes reviewable bookings and add/adjust tests to cover non-pending
status rejection.

In `@backend/routes/roomBooking.js`:
- Around line 22-27: The POST /bookings route is incorrectly blocked by the
authorizeRole(ROLE_GROUPS.ADMIN) middleware so non-admins cannot submit booking
requests; remove the authorizeRole(ROLE_GROUPS.ADMIN) middleware from the
router.post that registers roomBookingController.bookRoom (leave isAuthenticated
in place) so the controller's own room.allowed_roles and bookedBy logic can
enforce permissions and create pending requests; apply the same removal for the
other booking-creation route that uses authorizeRole(ROLE_GROUPS.ADMIN) (the
second occurrence mentioned) while keeping admin-only middleware on routes that
truly require admin privileges.

---

Nitpick comments:
In `@backend/seed.js`:
- Line 1147: The script calls seedRooms() twice causing rooms to be recreated
and orphaning room-linked data; remove the second invocation (the await
seedRooms(); near the end of the file) so rooms are only seeded once, and verify
no other duplicate calls to seedRooms remain (ensure RoomBooking or other
room-referencing seeding runs after the single seedRooms() call).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: eecdffb9-7715-4cdc-a2c5-4911886ea9c0

📥 Commits

Reviewing files that changed from the base of the PR and between 3528b0f and 0b1621f.

📒 Files selected for processing (4)
  • backend/controllers/roomBookingController.js
  • backend/models/schema.js
  • backend/routes/roomBooking.js
  • backend/seed.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/models/schema.js

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
backend/models/passportConfig.js (1)

68-75: Add explicit null check in deserializeUser for better clarity and robustness.

While the isAuthenticated middleware prevents requests with null users from reaching route handlers, explicitly handling the case where a user is deleted from the database but their session persists makes the code more defensive and intent-clear. This prevents any potential edge cases in session management.

Suggested improvement
 passport.deserializeUser(async (id, done) => {
   try {
     let user = await User.findById(id);
+    if (!user) {
+      return done(null, false);
+    }
     done(null, user);
   } catch (err) {
     done(err, null);
   }
 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/models/passportConfig.js` around lines 68 - 75, In
passport.deserializeUser's async callback (the function passed to
passport.deserializeUser) explicitly handle the case where User.findById(id)
returns null: after awaiting User.findById(id) check if user is null and call
done(null, false) (and optionally log a warning) instead of passing null user
into done; leave the try/catch for DB errors unchanged so errors still call
done(err, null).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@backend/models/passportConfig.js`:
- Around line 68-75: In passport.deserializeUser's async callback (the function
passed to passport.deserializeUser) explicitly handle the case where
User.findById(id) returns null: after awaiting User.findById(id) check if user
is null and call done(null, false) (and optionally log a warning) instead of
passing null user into done; leave the try/catch for DB errors unchanged so
errors still call done(err, null).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0e259762-d0e6-48a7-92e7-00306cedd3cb

📥 Commits

Reviewing files that changed from the base of the PR and between 0b1621f and 98387b7.

⛔ Files ignored due to path filters (1)
  • backend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • .husky/pre-commit
  • backend/index.js
  • backend/models/passportConfig.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/index.js

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
backend/routes/roomBooking.js (1)

51-74: Extract the review-role list from a shared constant.

These two arrays duplicate each other and already diverge from the controller's ADMIN_ROLES by omitting ROLES.CLUB_COORDINATOR. Reusing one exported group/constant here would keep room-review permissions from drifting across create/cancel/review paths.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/routes/roomBooking.js` around lines 51 - 74, The duplicated role
array passed into authorizeRole for router.patch and router.put should be
replaced with a single exported constant (e.g., REVIEW_ROLES or reuse the
controller's ADMIN_ROLES) to prevent drift; define and export that shared
constant from a central module (or the controller that already defines
ADMIN_ROLES), import it where the routes are declared, and pass it into
authorizeRole in both router.patch and router.put instead of the inline array
(affecting router.patch, router.put, authorizeRole, and
roomBookingController.updateBookingStatus references).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/controllers/roomBookingController.js`:
- Around line 357-363: Clash detection queries currently only check RoomBooking
(e.g., the RoomBooking.findOne that sets clash) but buildRoomStatusMap treats
Event as occupancy too, so modify the overlap checks (both the initial
create/check block around the clash variable and the approval flow after loading
the booking's room/location) to also query the Event collection for overlapping
events in the same room/time window and treat them as conflicts; when checking
during approval, exclude the Event linked to the current RoomBooking (if any) to
avoid self-conflict. Ensure you mirror the same time/room filtering and the
exclusion of a linked event in both places so bookings cannot be
created/approved over event-only usages.
- Around line 94-105: The venue->room mapping only indexes room.name and
room.room_id but must also index room.location (use the room.location field) so
lookups using Event.schedule.venue will resolve correctly; also when computing
live occupancy exclude cancelled events by adding a filter on the Event query
(or schedule entry) to skip events with a cancelled status/flag (e.g.,
Event.status === 'cancelled' or schedule.cancelled) before counting overlaps.
Update the block that builds venueToRoomId (referencing Room.find and
venueToRoomId) to set venueToRoomId.set(room.location, String(room._id)) and
update the occupancy query code that counts overlapping schedules to filter out
cancelled events (the same change should be applied to the similar mapping/usage
later in the file).

---

Nitpick comments:
In `@backend/routes/roomBooking.js`:
- Around line 51-74: The duplicated role array passed into authorizeRole for
router.patch and router.put should be replaced with a single exported constant
(e.g., REVIEW_ROLES or reuse the controller's ADMIN_ROLES) to prevent drift;
define and export that shared constant from a central module (or the controller
that already defines ADMIN_ROLES), import it where the routes are declared, and
pass it into authorizeRole in both router.patch and router.put instead of the
inline array (affecting router.patch, router.put, authorizeRole, and
roomBookingController.updateBookingStatus references).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b5ec991a-b6f9-46f5-9075-39c182ca36dc

📥 Commits

Reviewing files that changed from the base of the PR and between 98387b7 and 742b265.

📒 Files selected for processing (4)
  • backend/controllers/roomBookingController.js
  • backend/models/passportConfig.js
  • backend/routes/roomBooking.js
  • backend/seed.js
✅ Files skipped from review due to trivial changes (1)
  • backend/seed.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/models/passportConfig.js

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
backend/controllers/roomBookingController.js (2)

651-686: Consider preventing re-cancellation of already cancelled or rejected bookings.

The handler allows setting status to Cancelled regardless of current status. This could allow re-cancelling an already Cancelled or Rejected booking. Consider adding a check similar to updateBookingStatus.

♻️ Optional fix
     if (!booking) {
       return res.status(404).json({ message: "Booking not found" });
     }
+    
+    if (["Cancelled", "Rejected"].includes(booking.status)) {
+      return res.status(409).json({ message: "Booking is already cancelled or rejected." });
+    }
 
     if (
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/controllers/roomBookingController.js` around lines 651 - 686, The
cancelBooking handler currently sets booking.status = "Cancelled"
unconditionally; add a guard like in updateBookingStatus to reject attempts to
cancel when booking.status is already "Cancelled" or "Rejected" (check
booking.status before mutating), returning a 400/appropriate response (e.g.,
res.status(400).json({ message: "Booking already cancelled or rejected" }));
keep existing authorization logic (ADMIN_ROLES, req.user._id) and only update
updated_at and save when the status transition is allowed, then continue to
populate and return responseBooking as before.

5-12: Consider using ROLE_GROUPS.ADMIN from roles.js instead of duplicating.

This ADMIN_ROLES array duplicates ROLE_GROUPS.ADMIN defined in backend/utils/roles.js. Consider importing and reusing it to avoid maintenance drift.

♻️ Proposed refactor
-const { ROLES } = require("../utils/roles");
+const { ROLES, ROLE_GROUPS } = require("../utils/roles");

-const ADMIN_ROLES = [
-  ROLES.PRESIDENT,
-  ROLES.GENSEC_SCITECH,
-  ROLES.GENSEC_ACADEMIC,
-  ROLES.GENSEC_CULTURAL,
-  ROLES.GENSEC_SPORTS,
-  ROLES.CLUB_COORDINATOR,
-];
+const ADMIN_ROLES = ROLE_GROUPS.ADMIN;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/controllers/roomBookingController.js` around lines 5 - 12, The
ADMIN_ROLES array in roomBookingController.js duplicates ROLE_GROUPS.ADMIN from
roles.js; import ROLE_GROUPS (or ROLE_GROUPS.ADMIN) from roles.js and replace
the local hard-coded ADMIN_ROLES definition by referencing ROLE_GROUPS.ADMIN (or
remove ADMIN_ROLES and use ROLE_GROUPS.ADMIN in its call sites), ensuring any
existing uses (e.g., permission checks in roomBookingController) still refer to
the imported group to avoid duplication and maintenance drift.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@backend/controllers/roomBookingController.js`:
- Around line 651-686: The cancelBooking handler currently sets booking.status =
"Cancelled" unconditionally; add a guard like in updateBookingStatus to reject
attempts to cancel when booking.status is already "Cancelled" or "Rejected"
(check booking.status before mutating), returning a 400/appropriate response
(e.g., res.status(400).json({ message: "Booking already cancelled or rejected"
})); keep existing authorization logic (ADMIN_ROLES, req.user._id) and only
update updated_at and save when the status transition is allowed, then continue
to populate and return responseBooking as before.
- Around line 5-12: The ADMIN_ROLES array in roomBookingController.js duplicates
ROLE_GROUPS.ADMIN from roles.js; import ROLE_GROUPS (or ROLE_GROUPS.ADMIN) from
roles.js and replace the local hard-coded ADMIN_ROLES definition by referencing
ROLE_GROUPS.ADMIN (or remove ADMIN_ROLES and use ROLE_GROUPS.ADMIN in its call
sites), ensuring any existing uses (e.g., permission checks in
roomBookingController) still refer to the imported group to avoid duplication
and maintenance drift.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bda0aa32-b4dd-446c-a118-68e0184effe8

📥 Commits

Reviewing files that changed from the base of the PR and between 98387b7 and e5c7333.

📒 Files selected for processing (5)
  • backend/controllers/roomBookingController.js
  • backend/models/passportConfig.js
  • backend/routes/roomBooking.js
  • backend/seed.js
  • backend/utils/roles.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/models/passportConfig.js

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FOSSOVERFLOW-25] feat: Implement Room Status & Details APIs

2 participants