From c84a565f0a6050281becfe4deacb79ec71751af4 Mon Sep 17 00:00:00 2001 From: PeanutPiglet Date: Wed, 14 Oct 2026 20:51:21 -0400 Subject: [PATCH 1/7] add timetableSessions settings to config --- config.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config.yaml b/config.yaml index 7f2e22ac2..77f820e0e 100644 --- a/config.yaml +++ b/config.yaml @@ -13,6 +13,10 @@ genCssPath: "./public/style/" # URLs timetableUrl: "https://ttb.utoronto.ca/" timetableApiUrl: "https://api.easi.utoronto.ca/ttb/getPageableCourses" +timetableSessions: + - "20269" + - "20271" + - "20269-20271" fasCalendarUrl: "https://artsci.calendar.utoronto.ca/" programsUrl: "https://artsci.calendar.utoronto.ca/listing-program-subject-areas" From a79ff48f459a445aa1f6254228bf003206324470 Mon Sep 17 00:00:00 2001 From: PeanutPiglet Date: Wed, 14 Oct 2026 20:54:00 -0400 Subject: [PATCH 2/7] refactor createReqBody to use config --- app/Config.hs | 54 +++++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/app/Config.hs b/app/Config.hs index 1319dd591..cc7ed6555 100644 --- a/app/Config.hs +++ b/app/Config.hs @@ -49,6 +49,7 @@ data Config = Config , genCssPathValue :: String , timetableUrlValue :: String , timetableApiUrlValue :: Text + , timetableSessionsValue :: [T.Text] , fasCalendarUrlValue :: String , programsUrlValue :: String , fallStartDateValue :: Day @@ -71,6 +72,7 @@ instance FromJSON Config where <*> obj .: "genCssPath" <*> obj .: "timetableUrl" <*> obj .: "timetableApiUrl" + <*> obj .: "timetableSessions" <*> obj .: "fasCalendarUrl" <*> obj .: "programsUrl" <*> obj .: "fallStartDate" @@ -162,31 +164,33 @@ programsUrl = programsUrlValue <$> loadConfig -- HTTP REQUEST STRINGS -- | Create the body for the HTTP request based on the page -createReqBody :: Int -> Value -createReqBody page = - object - [ "campuses" .= ([] :: [T.Text]) - , "courseCodeAndTitleProps" - .= object - [ "courseCode" .= ("" :: T.Text) - , "courseSectionCode" .= ("" :: T.Text) - , "courseTitle" .= ("" :: T.Text) - , "searchCourseDescription" .= True - ] - , "courseLevels" .= ([] :: [T.Text]) - , "creditWeights" .= ([] :: [T.Text]) - , "dayPreferences" .= ([] :: [T.Text]) - , "deliveryModes" .= ([] :: [T.Text]) - , "departmentProps" .= ([] :: [T.Text]) - , "direction" .= ("asc" :: T.Text) - , "divisions" .= (["ARTSC"] :: [T.Text]) - , "instructor" .= ("" :: T.Text) - , "page" .= page - , "pageSize" .= (300 :: Int) - , "requirementProps" .= ([] :: [T.Text]) - , "sessions" .= (["20269", "20271", "20269-20271"] :: [T.Text]) - , "timePreferences" .= ([] :: [T.Text]) - ] +createReqBody :: Int -> IO Value +createReqBody page = do + sessions <- timetableSessionsValue <$> loadConfig + return $ + object + [ "campuses" .= ([] :: [T.Text]) + , "courseCodeAndTitleProps" + .= object + [ "courseCode" .= ("" :: T.Text) + , "courseSectionCode" .= ("" :: T.Text) + , "courseTitle" .= ("" :: T.Text) + , "searchCourseDescription" .= True + ] + , "courseLevels" .= ([] :: [T.Text]) + , "creditWeights" .= ([] :: [T.Text]) + , "dayPreferences" .= ([] :: [T.Text]) + , "deliveryModes" .= ([] :: [T.Text]) + , "departmentProps" .= ([] :: [T.Text]) + , "direction" .= ("asc" :: T.Text) + , "divisions" .= (["ARTSC"] :: [T.Text]) + , "instructor" .= ("" :: T.Text) + , "page" .= page + , "pageSize" .= (300 :: Int) + , "requirementProps" .= ([] :: [T.Text]) + , "sessions" .= sessions + , "timePreferences" .= ([] :: [T.Text]) + ] -- | The headers for the HTTP request reqHeaders :: RequestHeaders From ce7d24339d907ca2788eaba6ea918543fdf6d906 Mon Sep 17 00:00:00 2001 From: PeanutPiglet Date: Wed, 14 Oct 2026 20:55:53 -0400 Subject: [PATCH 3/7] fix createReqBody usage to unpack IO action --- app/WebParsing/UtsgJsonParser.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/WebParsing/UtsgJsonParser.hs b/app/WebParsing/UtsgJsonParser.hs index d33ca267c..06ece4cd5 100644 --- a/app/WebParsing/UtsgJsonParser.hs +++ b/app/WebParsing/UtsgJsonParser.hs @@ -34,7 +34,7 @@ parseTimetable = do makeRequest :: Int -> IO ByteString makeRequest pageNum = do -- set up the request - let reqBody = createReqBody pageNum + reqBody <- createReqBody pageNum timetableApi <- liftIO timetableApiUrl request <- liftIO $ parseRequest (T.unpack timetableApi) let request' = request{method = "POST", requestBody = RequestBodyLBS $ encode reqBody, requestHeaders = reqHeaders} From 58303d94bf2575562e6f84f844e22a5d05d2c4e9 Mon Sep 17 00:00:00 2001 From: PeanutPiglet Date: Wed, 14 Oct 2026 21:10:53 -0400 Subject: [PATCH 4/7] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c45647f6b..127278024 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ - Refactored backend database `runDb` helper in `app/Config.hs` - Refactored `Database.Tables.MeetTime` into `Models.Meeting` and renamed it to `MeetingParsedData`; consolidated and refactored timetable JSON parsing helpers - Restructured `courseography.cabal` to separate executable from library, extract shared settings, and remove `hlint` +- Refactored `createReqBody` in `app/Config.hs` to use session field from `config.yaml` ## [0.8.1] - 2026-08-10 From a8ae84077a69a0b1c7e7cfc15dc4c78d15126d7b Mon Sep 17 00:00:00 2001 From: PeanutPiglet Date: Sat, 17 Oct 2026 12:02:06 -0400 Subject: [PATCH 5/7] refactor session config location --- app/Config.hs | 4 ++-- config.yaml | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/Config.hs b/app/Config.hs index cc7ed6555..59d4fc2dd 100644 --- a/app/Config.hs +++ b/app/Config.hs @@ -49,9 +49,9 @@ data Config = Config , genCssPathValue :: String , timetableUrlValue :: String , timetableApiUrlValue :: Text - , timetableSessionsValue :: [T.Text] , fasCalendarUrlValue :: String , programsUrlValue :: String + , timetableSessionsValue :: [T.Text] , fallStartDateValue :: Day , fallEndDateValue :: Day , winterStartDateValue :: Day @@ -72,9 +72,9 @@ instance FromJSON Config where <*> obj .: "genCssPath" <*> obj .: "timetableUrl" <*> obj .: "timetableApiUrl" - <*> obj .: "timetableSessions" <*> obj .: "fasCalendarUrl" <*> obj .: "programsUrl" + <*> obj .: "timetableSessions" <*> obj .: "fallStartDate" <*> obj .: "fallEndDate" <*> obj .: "winterStartDate" diff --git a/config.yaml b/config.yaml index 77f820e0e..92b8f7aba 100644 --- a/config.yaml +++ b/config.yaml @@ -13,12 +13,14 @@ genCssPath: "./public/style/" # URLs timetableUrl: "https://ttb.utoronto.ca/" timetableApiUrl: "https://api.easi.utoronto.ca/ttb/getPageableCourses" +fasCalendarUrl: "https://artsci.calendar.utoronto.ca/" +programsUrl: "https://artsci.calendar.utoronto.ca/listing-program-subject-areas" + +# Data Fetching Parameters timetableSessions: - "20269" - "20271" - "20269-20271" -fasCalendarUrl: "https://artsci.calendar.utoronto.ca/" -programsUrl: "https://artsci.calendar.utoronto.ca/listing-program-subject-areas" # Term dates fallStartDate: 2026-09-08 From 8435e031eb1bfb3acf79d44affee4fc219972084 Mon Sep 17 00:00:00 2001 From: PeanutPiglet Date: Sun, 18 Oct 2026 11:56:34 -0400 Subject: [PATCH 6/7] change name convention for config edits --- config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.yaml b/config.yaml index 92b8f7aba..eceb7866b 100644 --- a/config.yaml +++ b/config.yaml @@ -16,7 +16,7 @@ timetableApiUrl: "https://api.easi.utoronto.ca/ttb/getPageableCourses" fasCalendarUrl: "https://artsci.calendar.utoronto.ca/" programsUrl: "https://artsci.calendar.utoronto.ca/listing-program-subject-areas" -# Data Fetching Parameters +# Data fetching parameters timetableSessions: - "20269" - "20271" From 180ba923bea7e9149b775e56058f9e31c6e77a9e Mon Sep 17 00:00:00 2001 From: PeanutPiglet Date: Sun, 18 Oct 2026 12:46:21 -0400 Subject: [PATCH 7/7] adjust createReqBody contract --- app/Config.hs | 59 +++++++++++++++++--------------- app/WebParsing/UtsgJsonParser.hs | 5 +-- 2 files changed, 35 insertions(+), 29 deletions(-) diff --git a/app/Config.hs b/app/Config.hs index 59d4fc2dd..097ee3314 100644 --- a/app/Config.hs +++ b/app/Config.hs @@ -17,6 +17,7 @@ module Config ( timetableApiUrl, fasCalendarUrl, programsUrl, + timetableSessions, createReqBody, reqHeaders, fallStartDate, @@ -161,36 +162,40 @@ fasCalendarUrl = fasCalendarUrlValue <$> loadConfig programsUrl :: IO String programsUrl = programsUrlValue <$> loadConfig +-- DATA FETCHING PARAMETERS + +-- | The sessions field for the timetable API +timetableSessions :: IO [T.Text] +timetableSessions = timetableSessionsValue <$> loadConfig + -- HTTP REQUEST STRINGS -- | Create the body for the HTTP request based on the page -createReqBody :: Int -> IO Value -createReqBody page = do - sessions <- timetableSessionsValue <$> loadConfig - return $ - object - [ "campuses" .= ([] :: [T.Text]) - , "courseCodeAndTitleProps" - .= object - [ "courseCode" .= ("" :: T.Text) - , "courseSectionCode" .= ("" :: T.Text) - , "courseTitle" .= ("" :: T.Text) - , "searchCourseDescription" .= True - ] - , "courseLevels" .= ([] :: [T.Text]) - , "creditWeights" .= ([] :: [T.Text]) - , "dayPreferences" .= ([] :: [T.Text]) - , "deliveryModes" .= ([] :: [T.Text]) - , "departmentProps" .= ([] :: [T.Text]) - , "direction" .= ("asc" :: T.Text) - , "divisions" .= (["ARTSC"] :: [T.Text]) - , "instructor" .= ("" :: T.Text) - , "page" .= page - , "pageSize" .= (300 :: Int) - , "requirementProps" .= ([] :: [T.Text]) - , "sessions" .= sessions - , "timePreferences" .= ([] :: [T.Text]) - ] +createReqBody :: [T.Text] -> Int -> Value +createReqBody sessions page = + object + [ "campuses" .= ([] :: [T.Text]) + , "courseCodeAndTitleProps" + .= object + [ "courseCode" .= ("" :: T.Text) + , "courseSectionCode" .= ("" :: T.Text) + , "courseTitle" .= ("" :: T.Text) + , "searchCourseDescription" .= True + ] + , "courseLevels" .= ([] :: [T.Text]) + , "creditWeights" .= ([] :: [T.Text]) + , "dayPreferences" .= ([] :: [T.Text]) + , "deliveryModes" .= ([] :: [T.Text]) + , "departmentProps" .= ([] :: [T.Text]) + , "direction" .= ("asc" :: T.Text) + , "divisions" .= (["ARTSC"] :: [T.Text]) + , "instructor" .= ("" :: T.Text) + , "page" .= page + , "pageSize" .= (300 :: Int) + , "requirementProps" .= ([] :: [T.Text]) + , "sessions" .= sessions + , "timePreferences" .= ([] :: [T.Text]) + ] -- | The headers for the HTTP request reqHeaders :: RequestHeaders diff --git a/app/WebParsing/UtsgJsonParser.hs b/app/WebParsing/UtsgJsonParser.hs index 06ece4cd5..350590570 100644 --- a/app/WebParsing/UtsgJsonParser.hs +++ b/app/WebParsing/UtsgJsonParser.hs @@ -1,6 +1,6 @@ module WebParsing.UtsgJsonParser (parseTimetable, insertTimetableData) where -import Config (createReqBody, reqHeaders, runDb, timetableApiUrl) +import Config (createReqBody, reqHeaders, runDb, timetableApiUrl, timetableSessions) import Control.Monad.IO.Class (liftIO) import Data.Aeson (Object, decode, encode, (.!=), (.:), (.:?)) import Data.Aeson.Types (Parser, parseMaybe) @@ -34,7 +34,8 @@ parseTimetable = do makeRequest :: Int -> IO ByteString makeRequest pageNum = do -- set up the request - reqBody <- createReqBody pageNum + sessions <- timetableSessions + let reqBody = createReqBody sessions pageNum timetableApi <- liftIO timetableApiUrl request <- liftIO $ parseRequest (T.unpack timetableApi) let request' = request{method = "POST", requestBody = RequestBodyLBS $ encode reqBody, requestHeaders = reqHeaders}