Skip to content

Commit d10be0b

Browse files
committed
Integrate Timetable Create and Update
1 parent 8de4414 commit d10be0b

File tree

12 files changed

+1376
-630
lines changed

12 files changed

+1376
-630
lines changed

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

Lines changed: 148 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -5,100 +5,159 @@ import { supabase } from "../db/setupDb";
55
const DEFAULT_COURSE_LIMIT = 1000;
66

77
export default {
8-
/**
9-
* Get a list of courses based on various query parameters.
10-
*
11-
* @param {Request} req - The request object containing query parameters.
12-
* @param {Response} res - The response object to send the filtered courses.
13-
* @returns {Promise<Response>} - The response object with the filtered courses.
14-
*/
15-
getCourses: asyncHandler(async (req: Request, res: Response) => {
16-
try {
17-
// Get the query parameters
18-
const {
19-
limit,
20-
search,
21-
semester,
22-
breadthRequirement,
23-
creditWeight,
24-
department,
25-
yearLevel,
26-
} = req.query;
8+
/**
9+
* Get a list of courses based on various query parameters.
10+
*
11+
* @param {Request} req - The request object containing query parameters.
12+
* @param {Response} res - The response object to send the filtered courses.
13+
* @returns {Promise<Response>} - The response object with the filtered courses.
14+
*/
15+
getCourses: asyncHandler(async (req: Request, res: Response) => {
16+
try {
17+
// Get the query parameters
18+
const {
19+
limit,
20+
search,
21+
semester,
22+
breadthRequirement,
23+
creditWeight,
24+
department,
25+
yearLevel,
26+
} = req.query;
2727

28-
// Query the courses, offerings tables from the database
29-
let coursesQuery = supabase
30-
.schema("course")
31-
.from("courses")
32-
.select()
33-
.limit(Number(limit || DEFAULT_COURSE_LIMIT));
28+
// Query the courses, offerings tables from the database
29+
let coursesQuery = supabase
30+
.schema("course")
31+
.from("courses")
32+
.select()
33+
.limit(Number(limit || DEFAULT_COURSE_LIMIT));
3434

35-
if ((search as string)?.trim()) {
36-
coursesQuery = coursesQuery.or(
37-
`code.ilike.%${search}%,name.ilike.%${search}%`,
38-
);
39-
}
40-
let offeringsQuery = supabase.schema("course").from("offerings").select();
35+
if ((search as string)?.trim()) {
36+
coursesQuery = coursesQuery.or(
37+
`code.ilike.%${search}%,name.ilike.%${search}%`
38+
);
39+
}
40+
let offeringsQuery = supabase.schema("course").from("offerings").select();
4141

42-
// Get the data and errors from the queries
43-
const { data: coursesData, error: coursesError } = await coursesQuery;
44-
const { data: offeringsData, error: offeringsError } =
45-
await offeringsQuery;
42+
// Get the data and errors from the queries
43+
const { data: coursesData, error: coursesError } = await coursesQuery;
44+
const { data: offeringsData, error: offeringsError } =
45+
await offeringsQuery;
4646

47-
// Set the courses and offerings data
48-
const courses = coursesData || [];
49-
const offerings = offeringsData || [];
47+
// Set the courses and offerings data
48+
const courses = coursesData || [];
49+
const offerings = offeringsData || [];
5050

51-
// Create a map of course codes to semesters.
52-
const courseCodesToSemestersMap: { [key: string]: string[] } = {};
53-
offerings.forEach((offering) => {
54-
const courseCode = offering.code;
55-
const semester = offering.offering;
56-
if (courseCodesToSemestersMap[courseCode]) {
57-
courseCodesToSemestersMap[courseCode].push(semester);
58-
} else {
59-
courseCodesToSemestersMap[courseCode] = [semester];
60-
}
61-
});
51+
// Create a map of course codes to semesters.
52+
const courseCodesToSemestersMap: { [key: string]: string[] } = {};
53+
offerings.forEach((offering) => {
54+
const courseCode = offering.code;
55+
const semester = offering.offering;
56+
if (courseCodesToSemestersMap[courseCode]) {
57+
courseCodesToSemestersMap[courseCode].push(semester);
58+
} else {
59+
courseCodesToSemestersMap[courseCode] = [semester];
60+
}
61+
});
6262

63-
// Filter the courses based on the breadth requirement, credit weight, semester, department, and year level
64-
let filteredCourses = courses;
65-
if (breadthRequirement) {
66-
filteredCourses = filteredCourses.filter((course) => {
67-
return course.breadth_requirement === breadthRequirement;
68-
});
69-
}
70-
if (creditWeight) {
71-
filteredCourses = filteredCourses.filter((course) => {
72-
const courseCreditWeight =
73-
course.code[course.code.length - 2] === "H" ? 0.5 : 1;
74-
return courseCreditWeight === Number(creditWeight);
75-
});
76-
}
77-
if (semester) {
78-
filteredCourses = filteredCourses.filter((course) => {
79-
return courseCodesToSemestersMap[course.code]?.includes(
80-
semester as string,
81-
);
82-
});
83-
}
84-
if (department) {
85-
filteredCourses = filteredCourses.filter((course) => {
86-
const courseDepartment = course.code.substring(0, 3);
87-
return courseDepartment === department;
88-
});
89-
}
90-
if (yearLevel) {
91-
filteredCourses = filteredCourses.filter((course) => {
92-
const courseYearLevel =
93-
course.code.charCodeAt(3) - "A".charCodeAt(0) + 1;
94-
return courseYearLevel === Number(yearLevel);
95-
});
96-
}
63+
// Filter the courses based on the breadth requirement, credit weight, semester, department, and year level
64+
let filteredCourses = courses;
65+
if (breadthRequirement) {
66+
filteredCourses = filteredCourses.filter((course) => {
67+
return course.breadth_requirement === breadthRequirement;
68+
});
69+
}
70+
if (creditWeight) {
71+
filteredCourses = filteredCourses.filter((course) => {
72+
const courseCreditWeight =
73+
course.code[course.code.length - 2] === "H" ? 0.5 : 1;
74+
return courseCreditWeight === Number(creditWeight);
75+
});
76+
}
77+
if (semester) {
78+
filteredCourses = filteredCourses.filter((course) => {
79+
return courseCodesToSemestersMap[course.code]?.includes(
80+
semester as string
81+
);
82+
});
83+
}
84+
if (department) {
85+
filteredCourses = filteredCourses.filter((course) => {
86+
const courseDepartment = course.code.substring(0, 3);
87+
return courseDepartment === department;
88+
});
89+
}
90+
if (yearLevel) {
91+
filteredCourses = filteredCourses.filter((course) => {
92+
const courseYearLevel =
93+
course.code.charCodeAt(3) - "A".charCodeAt(0) + 1;
94+
return courseYearLevel === Number(yearLevel);
95+
});
96+
}
9797

98-
// Return the filtered courses
99-
return res.status(200).send(filteredCourses);
100-
} catch (err) {
101-
return res.status(500).send({ err });
102-
}
103-
}),
98+
// Return the filtered courses
99+
return res.status(200).send(filteredCourses);
100+
} catch (err) {
101+
return res.status(500).send({ err });
102+
}
103+
}),
104+
105+
/**
106+
* Gets the total number of sections for a list of courses.
107+
*
108+
* @param {Request} req - The request object containing query parameters.
109+
* @param {Response} res - The response object to send the total number of sections.
110+
* @returns {Promise<Response>} - The response object with the total number of sections.
111+
*
112+
*/
113+
getNumberOfSections: asyncHandler(async (req: Request, res: Response) => {
114+
try {
115+
const { course_ids, semester } = req.query;
116+
117+
if (!course_ids || !semester) {
118+
return res.status(400).send({
119+
error: "Missing required parameters: course_ids, semester",
120+
});
121+
}
122+
123+
const course_ids_array = (course_ids as string).split(",");
124+
125+
let totalNumberOfCourseSections = 0;
126+
const promises = course_ids_array.map(async (course_id) => {
127+
const { data: courseOfferingsData, error: courseOfferingsError } =
128+
await supabase
129+
.schema("course")
130+
.from("offerings")
131+
.select()
132+
.eq("course_id", course_id)
133+
.eq("offering", semester);
134+
135+
const offerings = courseOfferingsData || [];
136+
137+
const hasLectures = offerings.some((offering) =>
138+
offering.meeting_section.startsWith("LEC")
139+
);
140+
const hasTutorials = offerings.some((offering) =>
141+
offering.meeting_section.startsWith("TUT")
142+
);
143+
const hasPracticals = offerings.some((offering) =>
144+
offering.meeting_section.startsWith("PRA")
145+
);
146+
if (hasLectures) {
147+
totalNumberOfCourseSections += 1;
148+
}
149+
if (hasTutorials) {
150+
totalNumberOfCourseSections += 1;
151+
}
152+
if (hasPracticals) {
153+
totalNumberOfCourseSections += 1;
154+
}
155+
});
156+
157+
await Promise.all(promises);
158+
return res.status(200).send({ totalNumberOfCourseSections });
159+
} catch (err) {
160+
return res.status(500).send({ err });
161+
}
162+
}),
104163
};

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { start } from "repl";
1616
* @returns An array of event objects ready to be inserted.
1717
*/
1818

19-
function getNextWeekDayOccurance(targetDay: string): string {
19+
export function getNextWeekDayOccurance(targetDay: string): string {
2020
//Map weekday code to JS day number
2121
const weekdayMap: { [key: string]: number } = {
2222
SU: 0,
@@ -45,7 +45,7 @@ function getNextWeekDayOccurance(targetDay: string): string {
4545
return today.toISOString().split("T")[0];
4646
}
4747

48-
function generateWeeklyCourseEvents(
48+
export function generateWeeklyCourseEvents(
4949
user_id: string,
5050
courseEventName: string,
5151
courseDay: string,

0 commit comments

Comments
 (0)