1- import exp from ' constants' ;
2- import { Request , Response } from ' express' ;
1+ import exp from " constants" ;
2+ import { Request , Response } from " express" ;
33
4- import { supabase } from ' ../db/setupDb' ; // Supabase instance for database interactions
5- import asyncHandler from ' ../middleware/asyncHandler' ; // Middleware to handle async route handlers
4+ import { supabase } from " ../db/setupDb" ; // Supabase instance for database interactions
5+ import asyncHandler from " ../middleware/asyncHandler" ; // Middleware to handle async route handlers
66
77// Interface to define the structure of an Offering
88export interface Offering {
@@ -28,29 +28,29 @@ export function createOffering(overrides: Partial<Offering> = {}): Offering {
2828 return {
2929 id : overrides . id ?? - 1 ,
3030 course_id : overrides . course_id ?? - 1 ,
31- meeting_section : overrides . meeting_section ?? ' No Section' ,
32- offering : overrides . offering ?? ' No Offering' ,
33- day : overrides . day ?? ' N/A' ,
34- start : overrides . start ?? ' 00:00:00' ,
35- end : overrides . end ?? ' 00:00:00' ,
36- location : overrides . location ?? ' No Room' ,
31+ meeting_section : overrides . meeting_section ?? " No Section" ,
32+ offering : overrides . offering ?? " No Offering" ,
33+ day : overrides . day ?? " N/A" ,
34+ start : overrides . start ?? " 00:00:00" ,
35+ end : overrides . end ?? " 00:00:00" ,
36+ location : overrides . location ?? " No Room" ,
3737 current : overrides . current ?? - 1 ,
3838 max : overrides . max ?? - 1 ,
3939 is_waitlisted : overrides . is_waitlisted ?? false ,
40- delivery_mode : overrides . delivery_mode ?? ' N/A' ,
41- instructor : overrides . instructor ?? ' N/A' ,
42- notes : overrides . notes ?? ' N/A' ,
43- code : overrides . code ?? ' N/A' ,
40+ delivery_mode : overrides . delivery_mode ?? " N/A" ,
41+ instructor : overrides . instructor ?? " N/A" ,
42+ notes : overrides . notes ?? " N/A" ,
43+ code : overrides . code ?? " N/A" ,
4444 } ;
4545}
4646
4747// Enum to define different types of restrictions for offerings
4848export enum RestrictionType {
49- RestrictBefore = ' Restrict Before' ,
50- RestrictAfter = ' Restrict After' ,
51- RestrictBetween = ' Restrict Between' ,
52- RestrictDay = ' Restrict Day' ,
53- RestrictDaysOff = ' Days Off' ,
49+ RestrictBefore = " Restrict Before" ,
50+ RestrictAfter = " Restrict After" ,
51+ RestrictBetween = " Restrict Between" ,
52+ RestrictDay = " Restrict Day" ,
53+ RestrictDaysOff = " Days Off" ,
5454}
5555
5656// Interface for the restriction object
@@ -79,17 +79,17 @@ export interface OfferingList {
7979// course (LEC, TUT, PRA)
8080export interface CategorizedOfferingList {
8181 course_id : number ;
82- category : ' LEC' | ' TUT' | ' PRA' ;
82+ category : " LEC" | " TUT" | " PRA" ;
8383 offerings : Record < string , Offering [ ] > ;
8484}
8585
8686// Function to fetch offerings from the database for a given course and semester
8787export async function getOfferings ( course_id : number , semester : string ) {
88- let { data : offeringData , error : offeringError } =
89- await supabase . schema ( ' course' )
90- . from ( ' offerings' )
91- . select (
92- `
88+ let { data : offeringData , error : offeringError } = await supabase
89+ . schema ( " course" )
90+ . from ( " offerings" )
91+ . select (
92+ `
9393 id,
9494 course_id,
9595 meeting_section,
@@ -106,9 +106,9 @@ export async function getOfferings(course_id: number, semester: string) {
106106 notes,
107107 code
108108 ` ,
109- )
110- . eq ( ' course_id' , course_id )
111- . eq ( ' offering' , semester ) ;
109+ )
110+ . eq ( " course_id" , course_id )
111+ . eq ( " offering" , semester ) ;
112112
113113 return offeringData ;
114114}
@@ -138,18 +138,16 @@ export async function getMaxDays(restrictions: Restriction[]) {
138138 for ( const restriction of restrictions ) {
139139 if ( restriction . disabled ) continue ;
140140 if ( restriction . type == RestrictionType . RestrictDaysOff ) {
141- return 5 -
142- restriction
143- . numDays ; // Subtract the restricted days from the total days
141+ return 5 - restriction . numDays ; // Subtract the restricted days from the total days
144142 }
145143 }
146- return 5 ; // Default to 5 days if no restrictions
144+ return 5 ; // Default to 5 days if no restrictions
147145}
148146
149147// Function to check if an offering satisfies the restrictions
150148export function isValidOffering (
151- offering : Offering ,
152- restrictions : Restriction [ ] ,
149+ offering : Offering ,
150+ restrictions : Restriction [ ] ,
153151) {
154152 for ( const restriction of restrictions ) {
155153 if ( restriction . disabled ) continue ;
@@ -161,15 +159,17 @@ export function isValidOffering(
161159 break ;
162160
163161 case RestrictionType . RestrictAfter :
164- console . log ( ' ====' ) ;
162+ console . log ( " ====" ) ;
165163 console . log ( offering . end ) ;
166164 console . log ( restriction . endTime ) ;
167165 if ( offering . end > restriction . startTime ) return false ;
168166 break ;
169167
170168 case RestrictionType . RestrictBetween :
171- if ( offering . start < restriction . endTime &&
172- restriction . startTime < offering . end ) {
169+ if (
170+ offering . start < restriction . endTime &&
171+ restriction . startTime < offering . end
172+ ) {
173173 return false ;
174174 }
175175 break ;
@@ -188,16 +188,16 @@ export function isValidOffering(
188188
189189// Function to get valid offerings by filtering them based on the restrictions
190190export async function getValidOfferings (
191- groups : Record < string , Offering [ ] > ,
192- restrictions : Restriction [ ] ,
191+ groups : Record < string , Offering [ ] > ,
192+ restrictions : Restriction [ ] ,
193193) {
194194 const validGroups : Record < string , Offering [ ] > = { } ;
195195
196196 // Loop through each group in the groups object
197197 for ( const [ groupKey , offerings ] of Object . entries ( groups ) ) {
198198 // Check if all offerings in the group are valid
199- const allValid = offerings . every (
200- ( offering ) => isValidOffering ( offering , restrictions ) ,
199+ const allValid = offerings . every ( ( offering ) =>
200+ isValidOffering ( offering , restrictions ) ,
201201 ) ;
202202
203203 // Only add the group to validGroups if all offerings are valid
@@ -212,33 +212,33 @@ export async function getValidOfferings(
212212
213213// Function to categorize offerings into lectures, tutorials, and practicals
214214export async function categorizeValidOfferings (
215- offerings : GroupedOfferingList [ ] ,
215+ offerings : GroupedOfferingList [ ] ,
216216) {
217217 const lst : CategorizedOfferingList [ ] = [ ] ;
218218
219219 for ( const offering of offerings ) {
220220 const lectures : CategorizedOfferingList = {
221221 course_id : offering . course_id ,
222- category : ' LEC' ,
222+ category : " LEC" ,
223223 offerings : { } ,
224224 } ;
225225 const tutorials : CategorizedOfferingList = {
226226 course_id : offering . course_id ,
227- category : ' TUT' ,
227+ category : " TUT" ,
228228 offerings : { } ,
229229 } ;
230230 const practicals : CategorizedOfferingList = {
231231 course_id : offering . course_id ,
232- category : ' PRA' ,
232+ category : " PRA" ,
233233 offerings : { } ,
234234 } ;
235235
236236 for ( const [ meeting_section , offerings ] of Object . entries (
237- offering . groups ,
238- ) ) {
239- if ( meeting_section && meeting_section . startsWith ( ' PRA' ) ) {
237+ offering . groups ,
238+ ) ) {
239+ if ( meeting_section && meeting_section . startsWith ( " PRA" ) ) {
240240 practicals . offerings [ meeting_section ] = offerings ;
241- } else if ( meeting_section && meeting_section . startsWith ( ' TUT' ) ) {
241+ } else if ( meeting_section && meeting_section . startsWith ( " TUT" ) ) {
242242 tutorials . offerings [ meeting_section ] = offerings ;
243243 } else {
244244 lectures . offerings [ meeting_section ] = offerings ;
@@ -260,19 +260,19 @@ export async function canInsert(toInsert: Offering, curList: Offering[]) {
260260 for ( const offering of curList ) {
261261 if ( offering . day == toInsert . day ) {
262262 if ( offering . start < toInsert . end && toInsert . start < offering . end ) {
263- return false ; // Check if the time overlaps
263+ return false ; // Check if the time overlaps
264264 }
265265 }
266266 }
267267
268- return true ; // No conflict found
268+ return true ; // No conflict found
269269}
270270
271271// Function to check if an ever offerings in toInstList can be inserted into
272272// the current list of offerings without conflicts
273273export async function canInsertList (
274- toInsertList : Offering [ ] ,
275- curList : Offering [ ] ,
274+ toInsertList : Offering [ ] ,
275+ curList : Offering [ ] ,
276276) {
277277 console . log ( toInsertList ) ;
278278 return toInsertList . every ( ( x ) => canInsert ( x , curList ) ) ;
@@ -292,12 +292,12 @@ export function getFrequencyTable(arr: Offering[]): Map<string, number> {
292292// Function to generate all valid schedules based on offerings and restrictions
293293
294294export async function getValidSchedules (
295- validSchedules : Offering [ ] [ ] ,
296- courseOfferingsList : CategorizedOfferingList [ ] ,
297- curList : Offering [ ] ,
298- cur : number ,
299- len : number ,
300- maxdays : number ,
295+ validSchedules : Offering [ ] [ ] ,
296+ courseOfferingsList : CategorizedOfferingList [ ] ,
297+ curList : Offering [ ] ,
298+ cur : number ,
299+ len : number ,
300+ maxdays : number ,
301301) {
302302 // Base case: if all courses have been considered
303303 if ( cur == len ) {
@@ -306,7 +306,7 @@ export async function getValidSchedules(
306306 // If the number of unique days is within the allowed limit, add the current
307307 // schedule to the list
308308 if ( freq . size <= maxdays ) {
309- validSchedules . push ( [ ...curList ] ) ; // Push a copy of the current list
309+ validSchedules . push ( [ ...curList ] ) ; // Push a copy of the current list
310310 }
311311 return ;
312312 }
@@ -315,20 +315,20 @@ export async function getValidSchedules(
315315
316316 // Recursively attempt to add offerings for the current course
317317 for ( const [ groupKey , offerings ] of Object . entries (
318- offeringsForCourse . offerings ,
319- ) ) {
318+ offeringsForCourse . offerings ,
319+ ) ) {
320320 if ( await canInsertList ( offerings , curList ) ) {
321321 const count = offerings . length ;
322- curList . push ( ...offerings ) ; // Add offering to the current list
322+ curList . push ( ...offerings ) ; // Add offering to the current list
323323
324324 // Recursively generate schedules for the next course
325325 await getValidSchedules (
326- validSchedules ,
327- courseOfferingsList ,
328- curList ,
329- cur + 1 ,
330- len ,
331- maxdays ,
326+ validSchedules ,
327+ courseOfferingsList ,
328+ curList ,
329+ cur + 1 ,
330+ len ,
331+ maxdays ,
332332 ) ;
333333
334334 // Backtrack: remove the last offering if no valid schedule was found
@@ -345,7 +345,7 @@ export function trim(schedules: Offering[][]) {
345345
346346 const uniqueNumbers = new Set < number > ( ) ;
347347 while ( uniqueNumbers . size < 10 ) {
348- uniqueNumbers . add ( Math . floor ( Math . random ( ) * ( num ) ) ) ;
348+ uniqueNumbers . add ( Math . floor ( Math . random ( ) * num ) ) ;
349349 }
350350 // console.log(uniqueNumbers);
351351 const trim_schedule : Offering [ ] [ ] = [ ] ;
@@ -359,62 +359,66 @@ export default {
359359 generateTimetable : asyncHandler ( async ( req : Request , res : Response ) => {
360360 try {
361361 // Extract event details and course information from the request
362- const { name, date, semester, search, courses, restrictions} = req . body ;
362+ const { name, date, semester, search, courses, restrictions } = req . body ;
363363 const courseOfferingsList : OfferingList [ ] = [ ] ;
364364 const validCourseOfferingsList : GroupedOfferingList [ ] = [ ] ;
365365 const maxdays = await getMaxDays ( restrictions ) ;
366366 const validSchedules : Offering [ ] [ ] = [ ] ;
367367 // Fetch offerings for each course
368368 for ( const course of courses ) {
369- const { id } = course ;
369+ const { id } = course ;
370370 courseOfferingsList . push ( {
371371 course_id : id ,
372372 offerings : ( await getOfferings ( id , semester ) ) ?? [ ] ,
373373 } ) ;
374374 }
375375
376376 const groupedOfferingsList : GroupedOfferingList [ ] =
377- await groupOfferings ( courseOfferingsList ) ;
377+ await groupOfferings ( courseOfferingsList ) ;
378378
379379 // console.log(JSON.stringify(groupedOfferingsList, null, 2));
380380
381381 // Filter out invalid offerings based on the restrictions
382- for ( const { course_id, groups} of groupedOfferingsList ) {
382+ for ( const { course_id, groups } of groupedOfferingsList ) {
383383 validCourseOfferingsList . push ( {
384384 course_id : course_id ,
385385 groups : await getValidOfferings ( groups , restrictions ) ,
386386 } ) ;
387387 }
388388
389389 const categorizedOfferings = await categorizeValidOfferings (
390- validCourseOfferingsList ,
390+ validCourseOfferingsList ,
391391 ) ;
392392
393393 // console.log(typeof categorizedOfferings);
394394 // console.log(JSON.stringify(categorizedOfferings, null, 2));
395395
396396 // Generate valid schedules for the given courses and restrictions
397397 await getValidSchedules (
398- validSchedules ,
399- categorizedOfferings ,
400- [ ] ,
401- 0 ,
402- categorizedOfferings . length ,
403- maxdays ,
398+ validSchedules ,
399+ categorizedOfferings ,
400+ [ ] ,
401+ 0 ,
402+ categorizedOfferings . length ,
403+ maxdays ,
404404 ) ;
405405
406406 // Return error if no valid schedules are found
407407 if ( validSchedules . length === 0 ) {
408- return res . status ( 404 ) . json ( { error : ' No valid schedules found.' } ) ;
408+ return res . status ( 404 ) . json ( { error : " No valid schedules found." } ) ;
409409 }
410410 // Return the valid schedules
411- return res . status ( 200 ) . json (
412- { amount : validSchedules . length , schedules : trim ( validSchedules ) } ) ;
411+ return res
412+ . status ( 200 )
413+ . json ( {
414+ amount : validSchedules . length ,
415+ schedules : trim ( validSchedules ) ,
416+ } ) ;
413417 } catch ( error ) {
414418 // Catch any error and return the error message
415419 const errorMessage =
416- error instanceof Error ? error . message : ' An unknown error occurred' ;
417- return res . status ( 500 ) . send ( { error : errorMessage } ) ;
420+ error instanceof Error ? error . message : " An unknown error occurred" ;
421+ return res . status ( 500 ) . send ( { error : errorMessage } ) ;
418422 }
419423 } ) ,
420424} ;
0 commit comments