From 9456595502dfcbac9cd20f39b77db36dd363b823 Mon Sep 17 00:00:00 2001 From: z72819ap Date: Wed, 1 Nov 2023 18:27:36 +0000 Subject: [PATCH] split features into separate folders and implement new code replace function --- server/features/_new_feature_doc.md | 21 +++++++ server/features/forcedBreakPoint.js | 36 ++++++++++++ server/features/replaceCodeName.js | 81 +++++++++++++++++++++++++++ server/index.js | 86 ++++++----------------------- 4 files changed, 154 insertions(+), 70 deletions(-) create mode 100644 server/features/_new_feature_doc.md create mode 100644 server/features/forcedBreakPoint.js create mode 100644 server/features/replaceCodeName.js diff --git a/server/features/_new_feature_doc.md b/server/features/_new_feature_doc.md new file mode 100644 index 0000000..51cb716 --- /dev/null +++ b/server/features/_new_feature_doc.md @@ -0,0 +1,21 @@ + + +```js +// your feature +// @author : your github username +// @date : the date you created this file +// @description : a short description of what your feature does +// @params : any parameters your feature needs +// @returns : what your feature returns +// @notes : any notes you want to add + +function run(cal) { + // your code + + return cal +} + +module.exports = { + run, +}; +``` \ No newline at end of file diff --git a/server/features/forcedBreakPoint.js b/server/features/forcedBreakPoint.js new file mode 100644 index 0000000..891d3fa --- /dev/null +++ b/server/features/forcedBreakPoint.js @@ -0,0 +1,36 @@ +// Forcing calenders to update events once a day +// @author : aap9002 +// @date : 01/11/2023 +// @description : once a day between 01:00 and 04:00, force a refresh of the events to restyle any new formatting +// @params : the calender in string format +// @returns : the calender in string format +// @notes : Be aware the time is based on the server time not UTC + +const regex = /^LAST-MODIFIED:.*/gm; + +/** + * Force events to update format once a day + * @param {string} cal + * @returns cal with last modified date time set + */ +function run(cal) { + // once a day between 01:00 and 04:00, force a refresh of the events to restyle any new formatting + // this is as modifications to the event will not be recognised and updated unless the UoM event changes on the timetabling system itself + // so this will manual set the last modified each day to force an update in the calender app + // NB. it will stop doing this at 4 am so any changes in the day will be recognised and updated live + // NB. 3 hour window set as the ICS is set to refresh evert 2 hours, so this should affect all users + const date = new Date(); + const hour = date.getHours(); + if (hour >= 1 && hour <= 4) { + datestr = date.toISOString().split('T')[0]; + datestr = datestr.split('-').join(''); + datestr = "LAST-MODIFIED:" + datestr + "T000000"; + cal = cal.replace(regex, datestr); + } + + return cal; +} + +module.exports = { + run, +}; \ No newline at end of file diff --git a/server/features/replaceCodeName.js b/server/features/replaceCodeName.js new file mode 100644 index 0000000..b1f52aa --- /dev/null +++ b/server/features/replaceCodeName.js @@ -0,0 +1,81 @@ +// Replace course codes +// @author : aap9002 +// @date : 01/11/2023 +// @description : Find and replace course codes with [course names] or [course code and course name] +// @params : the calender in string format +// @returns : the calender in string format + + +const pattern = /SUMMARY:[^\/]*\//g // REGEX to search the ICAL for the course code + +/** + * List unique course names in the string + * @param {string} cal + * @returns List of unique course codes + */ +function parseCourseCodes(cal) { + const uniqueMatches = new Set(); + + let match; + while ((match = pattern.exec(cal)) !== null) { + //console.log(match[0].split(':')[1].split('/')[0]); + uniqueMatches.add(match[0].split(':')[1].split('/')[0]); + } + const uniqueCourseCodesArray = Array.from(uniqueMatches); + return uniqueCourseCodesArray; +} + +/** + * Replace course codes with full course names + * @param {string} cal + * @returns cal with replacements + */ +function replaceCourseCodesWithNames(cal, courses) { + // get unique course codes + let uniqueCourseCodesArray = parseCourseCodes(cal); + + // replace course codes with names + for (let i = 0; i < uniqueCourseCodesArray.length; i++) { + const courseCode = uniqueCourseCodesArray[i]; + try { + const courseName = courses.find(course => course.split(' ')[0] === courseCode).split(' ').slice(1).join(' '); + cal = cal.split(courseCode).join(courseName); + } + catch (e) { + // if the course code is not found in the allCourses.md file, log it + console.log(courseCode + " not found in allCourses.md"); + } + } + + return cal; +} + +/** + * Replace course codes with code and full course names + * @param {string} cal + * @returns cal with replacements + */ +function replaceCourseCodesWithCodeAndNames(cal, courses) { + // get unique course codes + let uniqueCourseCodesArray = parseCourseCodes(cal); + + // replace course codes with names + for (let i = 0; i < uniqueCourseCodesArray.length; i++) { + const courseCode = uniqueCourseCodesArray[i]; + try { + const courseName = courses.find(course => course.split(' ')[0] === courseCode).split(' ').slice(1).join(' '); + cal = cal.split(courseCode).join(courseCode + " " + courseName); + } + catch (e) { + // if the course code is not found in the allCourses.md file, log it + console.log(courseCode + " not found in allCourses.md"); + } + } + + return cal; +} + +module.exports = { + replaceCourseCodesWithNames, + replaceCourseCodesWithCodeAndNames +}; \ No newline at end of file diff --git a/server/index.js b/server/index.js index 37dd435..7364e22 100644 --- a/server/index.js +++ b/server/index.js @@ -3,12 +3,22 @@ const app = express(); const axios = require('axios'); var fs = require('fs'); +/////////////////////////////////////////////// IMPORT FEATURES //////////////////////////////////////////////// + +const syncForcedBreakpoint = require('./features/forcedBreakPoint.js') +const replaceTitle = require('./features/replaceCodeName.js') + + +///////////////////////////////////////////// IMPORT FEATURES END ////////////////////////////////////////////// + + +/////////////////////////////////////////////////// SETUP ///////////////////////////////////////////////////// + // This displays message that the server running and listening to specified port const port = process.env.PORT || 5000; app.listen(port, () => console.log(`Listening on port ${port}`)); var courses = []; // Predefined courses from allCourses.md -const pattern = /SUMMARY:[^\/]*\//g // REGEX to search the ICAL for the course code const validUrlPATTERN = /^https:\/\/scientia-eu-v4-api-d3-02\.azurewebsites\.net\/\/api\/ical\/[0-9a-fA-F-]+\/[0-9a-fA-F-]+\/timetable\.ics$/g; // REGEX for valid uom ics uri @@ -23,6 +33,7 @@ try { console.log('Error:', e.stack); } +////////////////////////////////////////////////// SETUP END /////////////////////////////////////////////////// /////////////////////////////////////////////////// API V1 ///////////////////////////////////////////////////// app.get('/api/v1/:uniqueAPI/tt.ics', function (req, res) { @@ -41,9 +52,10 @@ app.get('/api/v1/:uniqueAPI/tt.ics', function (req, res) { getTimetable(rebuild).then(cal => { if (cal != null) { - // modification steps - cal = replaceCourseCodesWithNames(cal); - cal = syncForcedBreakpoint(cal); + ////// modification steps ////// + cal = replaceTitle.replaceCourseCodesWithNames(cal, courses); + cal = syncForcedBreakpoint.run(cal); + //// modification steps end //// res.writeHead(200, { "Content-Type": "text/calendar", @@ -109,70 +121,4 @@ async function getTimetable(timetableUri) { } } -/** - * List unique course names in the string - * @param {string} cal - * @returns List of unique course codes - */ -function parseCourseCodes(cal) { - const uniqueMatches = new Set(); - - let match; - while ((match = pattern.exec(cal)) !== null) { - //console.log(match[0].split(':')[1].split('/')[0]); - uniqueMatches.add(match[0].split(':')[1].split('/')[0]); - } - const uniqueCourseCodesArray = Array.from(uniqueMatches); - return uniqueCourseCodesArray; -} - -/** - * Replace course codes with full course names - * @param {string} cal - * @returns cal with replacements - */ -function replaceCourseCodesWithNames(cal) { - // get unique course codes - let uniqueCourseCodesArray = parseCourseCodes(cal); - - // replace course codes with names - for (let i = 0; i < uniqueCourseCodesArray.length; i++) { - const courseCode = uniqueCourseCodesArray[i]; - try { - const courseName = courses.find(course => course.split(' ')[0] === courseCode).split(' ').slice(1).join(' '); - cal = cal.split(courseCode).join(courseName); - } - catch (e) { - // if the course code is not found in the allCourses.md file, log it - console.log(courseCode + " not found in allCourses.md"); - } - } - - return cal; -} - -/** - * Force events to update format once a day - * @param {string} cal - * @returns cal with last modified date time set - */ -function syncForcedBreakpoint(cal) { - // once a day between 01:00 and 04:00, force a refresh of the events to restyle any new formatting - // this is as modifications to the event will not be recognised and updated unless the UoM event changes on the timetabling system itself - // so this will manual set the last modified each day to force an update in the calender app - // NB. it will stop doing this at 4 am so any changes in the day will be recognised and updated live - // NB. 3 hour window set as the ICS is set to refresh evert 2 hours, so this should affect all users - const date = new Date(); - const hour = date.getHours(); - if (hour >= 1 && hour <= 4) { - datestr = date.toISOString().split('T')[0]; - datestr = datestr.split('-').join(''); - datestr = "LAST-MODIFIED:" + datestr + "T000000"; - const regex = /^LAST-MODIFIED:.*/gm; - cal = cal.replace(regex, datestr); - } - - return cal; -} - ////////////////////////////////////////////// FUNDAMENTAL METHODS END //////////////////////////////////////////////