diff --git a/server/controllers/__tests__/courseCtrlHelpers.test.js b/server/controllers/__tests__/courseCtrlHelpers.test.js index 44182c64..83bbc181 100644 --- a/server/controllers/__tests__/courseCtrlHelpers.test.js +++ b/server/controllers/__tests__/courseCtrlHelpers.test.js @@ -1,4 +1,8 @@ -import { calculateInitiallySelectedSemester, generateSelectedSemesterBasedOnDate } from '../courseCtrlHelpers' +import { + calculateInitiallySelectedSemester, + generateSelectedSemesterBasedOnDate, + isValidCourseCode, +} from '../courseCtrlHelpers' const activeSemesters = [ { @@ -149,4 +153,30 @@ describe('courseCtrlHelpers', () => { expect(generateSelectedSemesterBasedOnDate(new Date('2024-12-01'))).toBe(expectedSemester) }) }) + + describe('isValidCourseCode', () => { + test.each([null, undefined])('returns false if given courseCode is %s', courseCode => { + expect(isValidCourseCode(courseCode)).toBe(false) + }) + test.each(['', '1', '12', 123, '1234', 'asdfg'])( + 'returns false if given courseCode is shorter than 6 characters: %s', + courseCode => { + expect(isValidCourseCode(courseCode)).toBe(false) + } + ) + + test.each(['12345678', 'SF1523423490234'])( + 'returns false if given courseCode is longer than 7 characters: %s', + courseCode => { + expect(isValidCourseCode(courseCode)).toBe(false) + } + ) + + test.each(['123456', 123456, '1234567', 1234567])( + 'returns true if given courseCode has length of 6 or 7 characters: %s', + courseCode => { + expect(isValidCourseCode(courseCode)).toBe(true) + } + ) + }) }) diff --git a/server/controllers/courseCtrl.js b/server/controllers/courseCtrl.js index a33275ca..b5995de0 100644 --- a/server/controllers/courseCtrl.js +++ b/server/controllers/courseCtrl.js @@ -14,11 +14,13 @@ const { getServerSideFunctions } = require('../utils/serverSideRendering') const { INFORM_IF_IMPORTANT_INFO_IS_MISSING } = require('../util/constants') const { getFilteredData: getFilteredData } = require('../apiCalls/filteredData') const { createCourseWebContext } = require('../util/webContextUtil') -const { calculateInitiallySelectedSemester } = require('./courseCtrlHelpers') +const { HttpError } = require('../HttpError') +const { calculateInitiallySelectedSemester, isValidCourseCode } = require('./courseCtrlHelpers') const extractUpperCaseCourseCodeOrThrow = req => { const { courseCode } = req.params - if (!courseCode) throw new Error('Missing parameter courseCode') + if (!courseCode) throw new HttpError(400, 'Missing parameter courseCode') + if (!isValidCourseCode(courseCode)) throw new HttpError(400, `Invalid course code: ${courseCode}`) return courseCode.toUpperCase() } @@ -82,14 +84,14 @@ const getLanguageOrDefault = res => languageUtils.getLanguage(res) || 'sv' /* COURSE PAGE SETTINGS AND RENDERING */ /* ****************************************************************************** */ async function getIndex(req, res, next) { - const courseCode = extractUpperCaseCourseCodeOrThrow(req) - const language = getLanguageOrDefault(res) + try { + const courseCode = extractUpperCaseCourseCodeOrThrow(req) + const language = getLanguageOrDefault(res) - const klaroAnalyticsConsentCookie = extractKlaroAnalyticsCookie(req) + const klaroAnalyticsConsentCookie = extractKlaroAnalyticsCookie(req) - const { getCompressedData, renderStaticPage } = getServerSideFunctions() + const { getCompressedData, renderStaticPage } = getServerSideFunctions() - try { const startSemesterFromQuery = extractStartSemesterFromQuery(req) const memoList = await getMemoList(courseCode) @@ -142,7 +144,7 @@ async function getIndex(req, res, next) { breadcrumbsList, }) } catch (err) { - const errorCodesThatShouldNotBeLogged = [403, 404] + const errorCodesThatShouldNotBeLogged = [400, 403, 404] let statusCode if (err.response) { statusCode = err.response.status diff --git a/server/controllers/courseCtrlHelpers.js b/server/controllers/courseCtrlHelpers.js index be88339b..e56a2e31 100644 --- a/server/controllers/courseCtrlHelpers.js +++ b/server/controllers/courseCtrlHelpers.js @@ -54,8 +54,19 @@ const parseOrSetEmpty = (value, language, setEmpty = false) => { return value ? value : emptyText } +const VALID_COURSE_CODE_LENGTHS = [6, 7] + +/** + * + * + * @param {string} courseCode + * @returns true if the given courseCode has a length of 6 or 7 characters + */ +const isValidCourseCode = courseCode => !!courseCode && VALID_COURSE_CODE_LENGTHS.includes(courseCode.toString().length) + module.exports = { calculateInitiallySelectedSemester, generateSelectedSemesterBasedOnDate, parseOrSetEmpty, + isValidCourseCode, }