Skip to content

Commit b7b305f

Browse files
committed
Fixed a lot of bugs
1 parent a54a4c8 commit b7b305f

File tree

8 files changed

+281
-76
lines changed

8 files changed

+281
-76
lines changed

course-matrix/backend/src/controllers/eventsController.ts

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -482,20 +482,22 @@ export default {
482482
});
483483
}
484484

485-
const { data: courseEventData, error: courseEventError } =
486-
await supabase
487-
.schema("timetable")
488-
.from("course_events")
489-
.select("*")
490-
.eq("id", id)
491-
.eq("user_id", user_id)
492-
.eq("calendar_id", calendar_id)
493-
.maybeSingle();
494-
495-
if (courseEventData.calendar_id !== timetableData.id) {
496-
return res.status(400).json({
497-
error: "Restriction id does not belong to the provided calendar id",
498-
});
485+
if (!old_offering_id && !new_offering_id) {
486+
const { data: courseEventData, error: courseEventError } =
487+
await supabase
488+
.schema("timetable")
489+
.from("course_events")
490+
.select("*")
491+
.eq("id", id)
492+
.eq("user_id", user_id)
493+
.eq("calendar_id", calendar_id)
494+
.maybeSingle();
495+
496+
if (courseEventData.calendar_id !== timetableData.id) {
497+
return res.status(400).json({
498+
error: "Restriction id does not belong to the provided calendar id",
499+
});
500+
}
499501
}
500502

501503
const courseEventName = `${newofferingData.code} - ${newofferingData.meeting_section}`;
@@ -714,16 +716,19 @@ export default {
714716
if (courseEventError)
715717
return res.status(400).json({ error: courseEventError.message });
716718

717-
if (!courseEventData || courseEventData.length === 0) {
718-
return res
719-
.status(400)
720-
.json({ error: "Provided note ID is invalid or does not exist" });
721-
}
722719

723-
if (courseEventData.calendar_id !== timetableData.id) {
724-
return res.status(400).json({
725-
error: "Restriction id does not belong to the provided calendar id",
726-
});
720+
if (!offering_id) {
721+
if (!courseEventData || courseEventData.length === 0) {
722+
return res
723+
.status(400)
724+
.json({ error: "Provided note ID is invalid or does not exist" });
725+
}
726+
727+
if (courseEventData.calendar_id !== timetableData.id) {
728+
return res.status(400).json({
729+
error: "Restriction id does not belong to the provided calendar id",
730+
});
731+
}
727732
}
728733

729734
//Build the delete query
@@ -741,14 +746,13 @@ export default {
741746
deleteQuery = deleteQuery.eq("id", id);
742747
}
743748

744-
const { error: deleteError } = await deleteQuery
749+
const { data: deleteData, error: deleteError } = await deleteQuery
745750
.eq("calendar_id", calendar_id)
746751
.eq("user_id", user_id)
747752
.select("*");
748753
if (deleteError)
749754
return res.status(400).json({ error: deleteError.message });
750-
751-
return res.status(200).send("Event successfully deleted");
755+
return res.status(200).json("Event successfully deleted");
752756
} else if (event_type === "user") {
753757
//Validate note availability
754758
const { data: userEventData, error: userEventError } = await supabase

course-matrix/backend/src/controllers/offeringsController.ts

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,92 @@ import { supabase } from "../db/setupDb";
44
import { generateWeeklyCourseEvents } from "./eventsController";
55

66
export default {
7+
/**
8+
* Get a list of offering events based on offering ids, semester start date, and semester end date.
9+
*
10+
* @param {Request} req - The request object containing query parameters.
11+
* @param {Response} res - The response object to send the offering events data.
12+
* @returns {Promise<Response>} - The response object with the offering events data.
13+
*/
14+
getOfferingEvents: asyncHandler(async (req: Request, res: Response) => {
15+
const { offering_ids, semester_start_date, semester_end_date } = req.query;
16+
17+
// Retrieve the authenticated user
18+
const user_id = (req as any).user.id;
19+
20+
// Check if semester start and end dates are provided
21+
if (!semester_start_date || !semester_end_date) {
22+
return res.status(400).json({
23+
error: "Semester start and end dates are required.",
24+
});
25+
}
26+
27+
if (!offering_ids) {
28+
return res.status(200).json([]); // Return an empty array if no offering_ids are provided
29+
}
30+
31+
const offering_ids_array = (offering_ids as string).split(",");
32+
let eventsToInsert: any[] = [];
33+
34+
const promises = offering_ids_array.map(async (offering_id) => {
35+
// Get the offering data
36+
const { data: offeringData, error: offeringError } = await supabase
37+
.schema("course")
38+
.from("offerings")
39+
.select("*")
40+
.eq("id", offering_id)
41+
.maybeSingle();
42+
43+
if (offeringError) {
44+
return res.status(400).json({ error: offeringError.message });
45+
}
46+
47+
if (!offeringData || offeringData.length === 0) {
48+
return res.status(400).json({
49+
error: "Invalid offering_id or course offering not found.",
50+
});
51+
}
52+
53+
// Generate event details
54+
const courseEventName = ` ${offeringData.code} - ${offeringData.meeting_section} `;
55+
let courseDay = offeringData.day;
56+
let courseStartTime = offeringData.start;
57+
let courseEndTime = offeringData.end;
58+
59+
// Some offerings do not have a day, start time, or end time in the database, so we set default values
60+
if (!courseDay || !courseStartTime || !courseEndTime) {
61+
courseDay = "MO";
62+
courseStartTime = "08:00:00";
63+
courseEndTime = "09:00:00";
64+
}
65+
66+
const mockCalendarId = "1";
67+
const events = generateWeeklyCourseEvents(
68+
user_id,
69+
courseEventName,
70+
courseDay,
71+
courseStartTime,
72+
courseEndTime,
73+
mockCalendarId,
74+
offering_id as string,
75+
semester_start_date as string,
76+
semester_end_date as string,
77+
);
78+
eventsToInsert = [...eventsToInsert, ...events];
79+
});
80+
81+
await Promise.all(promises);
82+
83+
if (eventsToInsert.length === 0) {
84+
return res.status(400).json({
85+
error: "Failed to generate course events",
86+
});
87+
}
88+
89+
// Return the generated events
90+
return res.status(200).json(eventsToInsert);
91+
}),
92+
793
/**
894
* Get a list of offerings based on course code and semester.
995
*
@@ -15,7 +101,24 @@ export default {
15101
try {
16102
const { course_code, semester } = req.query;
17103

18-
let offeringsQuery = supabase
104+
let offeringsQuery;
105+
106+
// If course code or semester is not provided, return all offerings
107+
if (!course_code || !semester) {
108+
offeringsQuery = supabase
109+
.schema("course")
110+
.from("offerings")
111+
.select();
112+
113+
const { data: offeringsData, error: offeringsError } =
114+
await offeringsQuery;
115+
116+
const offerings = offeringsData || [];
117+
118+
return res.status(200).json(offerings);
119+
}
120+
121+
offeringsQuery = supabase
19122
.schema("course")
20123
.from("offerings")
21124
.select()

course-matrix/backend/src/routes/courseRouter.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ coursesRouter.get(
3333
*/
3434
departmentsRouter.get("/", authHandler, departmentsController.getDepartments);
3535

36+
/**
37+
* Route to get a list of events for an offering.
38+
* @route GET /events/:offering_id
39+
* @middleware authHandler - Middleware to check if the user is authenticated.
40+
*/
41+
offeringsRouter.get(
42+
"/events",
43+
authHandler,
44+
offeringsController.getOfferingEvents,
45+
);
46+
3647
/**
3748
* Route to get a list of offerings.
3849
* @route GET /

course-matrix/frontend/src/api/eventsApiSlice.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { data } from "react-router-dom";
21
import { apiSlice } from "./baseApiSlice";
32
import { EVENTS_URL } from "./config";
43

@@ -44,9 +43,10 @@ export const eventsApiSlice = apiSlice.injectEndpoints({
4443
invalidatesTags: ["Event"],
4544
}),
4645
deleteEvent: builder.mutation({
47-
query: (id) => ({
48-
url: `${EVENTS_URL}/${id}`,
46+
query: (data) => ({
47+
url: `${EVENTS_URL}/${data.id}`,
4948
method: "DELETE",
49+
params: data,
5050
headers: {
5151
"Content-Type": "application/json",
5252
Accept: "application/json, text/plain, */*",

course-matrix/frontend/src/api/offeringsApiSlice.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,19 @@ import { OFFERINGS_URL } from "./config";
44
// Endpoints for /api/offerings
55
export const offeringsApiSlice = apiSlice.injectEndpoints({
66
endpoints: (builder) => ({
7+
getOfferingEvents: builder.query({
8+
query: (params) => ({
9+
url: `${OFFERINGS_URL}/events`,
10+
method: "GET",
11+
params: params,
12+
headers: {
13+
"Content-Type": "application/json",
14+
Accept: "application/json, text/plain, */*",
15+
},
16+
providesTags: ["OfferingEvents"],
17+
credentials: "include",
18+
}),
19+
}),
720
getOfferings: builder.query({
821
query: (params) => ({
922
url: `${OFFERINGS_URL}`,
@@ -20,4 +33,5 @@ export const offeringsApiSlice = apiSlice.injectEndpoints({
2033
}),
2134
});
2235

23-
export const { useGetOfferingsQuery } = offeringsApiSlice;
36+
export const { useGetOfferingsQuery, useGetOfferingEventsQuery } =
37+
offeringsApiSlice;

0 commit comments

Comments
 (0)