diff --git a/.github/workflows/build-n-deploy-backend-to-ocp-dev.yml b/.github/workflows/build-n-deploy-backend-to-ocp-dev.yml index a8ea8b52..28bb0752 100644 --- a/.github/workflows/build-n-deploy-backend-to-ocp-dev.yml +++ b/.github/workflows/build-n-deploy-backend-to-ocp-dev.yml @@ -204,6 +204,6 @@ jobs: oc rollout status dc/${{ env.IMAGE_NAME }} - name: ZAP Scan - uses: zaproxy/action-full-scan@v0.3.0 + uses: zaproxy/action-full-scan@v0.10.0 with: target: "https://${{ env.HOST_ROUTE }}" diff --git a/.github/workflows/deploy-to.openshift-prod.yml b/.github/workflows/deploy-to.openshift-prod.yml index a3d155a9..7b33dddd 100644 --- a/.github/workflows/deploy-to.openshift-prod.yml +++ b/.github/workflows/deploy-to.openshift-prod.yml @@ -143,6 +143,6 @@ jobs: oc rollout status dc/${{ env.IMAGE_NAME }} - name: ZAP Scan - uses: zaproxy/action-full-scan@v0.3.0 + uses: zaproxy/action-full-scan@v0.10.0 with: target: "https://${{ env.HOST_ROUTE }}" diff --git a/.github/workflows/deploy-to.openshift-test.yml b/.github/workflows/deploy-to.openshift-test.yml index fbdd2460..47dbbd26 100644 --- a/.github/workflows/deploy-to.openshift-test.yml +++ b/.github/workflows/deploy-to.openshift-test.yml @@ -143,6 +143,6 @@ jobs: oc rollout status dc/${{ env.IMAGE_NAME }} - name: ZAP Scan - uses: zaproxy/action-full-scan@v0.3.0 + uses: zaproxy/action-full-scan@v0.10.0 with: target: "https://${{ env.HOST_ROUTE }}" diff --git a/backend/src/components/utils.js b/backend/src/components/utils.js index ea0f424f..7796d3e2 100644 --- a/backend/src/components/utils.js +++ b/backend/src/components/utils.js @@ -1,21 +1,20 @@ const ALLOWED_FILENAMES = new Set([ - - 'districtcontacts', - 'districtmailing', - 'publicschoolcontacts', - 'independentschoolcontacts', - 'allschoolcontacts', - 'allschoolmailing', - 'authoritycontacts', - 'authoritymailing', - 'offshoreschoolrepresentatives' + "districtcontacts", + "districtmailing", + "publicschoolcontacts", + "independentschoolcontacts", + "allschoolcontacts", + "allschoolmailing", + "authoritycontacts", + "authoritymailing", + "offshoreschoolrepresentatives", // Add more allowed filepaths as needed ]); const ALLOWED_SCHOOLCATEGORYCODES = new Set([ - 'PUBLIC', - 'INDEPEND', - 'OFFSHORE' + "PUBLIC", + "INDEPEND", + "OFFSHORE", // Add more allowed filepaths as needed ]); function isAllowedSchoolCategory(category) { @@ -31,17 +30,17 @@ function createList(list, options = {}) { fieldToInclude = null, // Updated option name valueToInclude = null, // Updated option name sortFunction = null, - sortField = null + sortField = null, } = options; const filteredList = list .filter(function (item) { // Change the condition from removal to inclusion - return (!fieldToInclude || item[fieldToInclude] === valueToInclude); + return !fieldToInclude || item[fieldToInclude] === valueToInclude; }) .map(function (item) { const itemData = {}; - fields.forEach(field => { + fields.forEach((field) => { itemData[field] = item[field]; }); return itemData; @@ -58,7 +57,6 @@ function createList(list, options = {}) { }); } - return filteredList; } function removeFieldsByCriteria(inputData, criteria) { @@ -79,355 +77,434 @@ function removeFieldsByCriteria(inputData, criteria) { } function appendMailingAddressDetailsAndRemoveAddresses(data) { if (data && data.addresses && data.addresses.length > 0) { - const physicalAddress = data.addresses.find(address => address.addressTypeCode === 'PHYSICAL'); - if (physicalAddress) { - // Extract specific name-value pairs from the mailing address - const { addressLine1, addressLine2, city, postal, provinceCode, countryCode } = physicalAddress; - - // Add these name-value pairs to the original district object - data.physicalAddressLine1 = addressLine1; - data.physicalAddressLine2 = addressLine2; - data.physicalCity = city; - data.physicalPostal = postal; - data.physicalProvinceCode = provinceCode; - data.physicalCountryCode = countryCode; - - // Remove the "addresses" property - - } - const courierAddress = data.addresses.find(address => address.addressTypeCode === 'MAILING'); - if (courierAddress) { - // Extract specific name-value pairs from the mailing address - const { addressLine1, addressLine2, city, postal, provinceCode, countryCode } = courierAddress; - - // Add these name-value pairs to the original district object - data.mailingAddressLine1 = addressLine1; - data.mailingAddressLine2 = addressLine2; - data.mailingCity = city; - data.mailingPostal = postal; - data.mailingProvinceCode = provinceCode; - data.mailingCountryCode = countryCode; - - // Remove the "addresses" property - } - delete data.addresses; - delete data.contacts; - } -} -function addDistrictLabels(jsonData, districtList) { - if (jsonData.content && Array.isArray(jsonData.content)) { - jsonData.content.forEach(dataItem => { - const district = districtList.find(item => item.districtId === dataItem.districtId); - if (district) { - dataItem.districtNumber = district.districtNumber; - dataItem.districtName = district.displayName; - } - }); + const physicalAddress = data.addresses?.find( + (address) => address.addressTypeCode === "PHYSICAL" + ); + if (physicalAddress) { + // Extract specific name-value pairs from the mailing address + const { + addressLine1, + addressLine2, + city, + postal, + provinceCode, + countryCode, + } = physicalAddress; + + // Add these name-value pairs to the original district object + data.physicalAddressLine1 = addressLine1; + data.physicalAddressLine2 = addressLine2; + data.physicalCity = city; + data.physicalPostal = postal; + data.physicalProvinceCode = provinceCode; + data.physicalCountryCode = countryCode; + + // Remove the "addresses" property } - return jsonData - } - - function districtNumberSort(a, b) { - // Convert the strings to numbers for comparison - const numA = parseInt(a, 10); - const numB = parseInt(b, 10); - - if (numA < numB) { - return -1; + const courierAddress = data.addresses?.find( + (address) => address.addressTypeCode === "MAILING" + ); + if (courierAddress) { + // Extract specific name-value pairs from the mailing address + const { + addressLine1, + addressLine2, + city, + postal, + provinceCode, + countryCode, + } = courierAddress; + + // Add these name-value pairs to the original district object + data.mailingAddressLine1 = addressLine1; + data.mailingAddressLine2 = addressLine2; + data.mailingCity = city; + data.mailingPostal = postal; + data.mailingProvinceCode = provinceCode; + data.mailingCountryCode = countryCode; + + // Remove the "addresses" property } - if (numA > numB) { - return 1; - } - return 0; + delete data.addresses; + delete data.contacts; } - function formatGrades(grades, schoolGrades) { - const result = {}; - - // Create a set of all school grade codes from the provided grades - const gradeCodesSet = new Set(grades.map(grade => grade.schoolGradeCode)); - - // Include all school grade codes in the result object - for (const grade of grades) { - result[grade.schoolGradeCode] = "Y"; - } - - // Set the value to "N" for school grade codes not in the provided grades - for (const grade of schoolGrades) { - if (!gradeCodesSet.has(grade.schoolGradeCode)) { - result[grade.schoolGradeCode] = "N"; +} +function addDistrictLabels(jsonData, districtList) { + if (jsonData.content && Array.isArray(jsonData.content)) { + jsonData.content.forEach((dataItem) => { + const district = districtList?.find( + (item) => item.districtId === dataItem.districtId + ); + if (district) { + dataItem.districtNumber = district.districtNumber; + dataItem.districtName = district.displayName; } - } - - return result; - } - - function sortJSONByDistrictNumber(districts) { - return districts.slice().sort((a, b) => { - const districtNumberA = a['District Number'] || ''; - const districtNumberB = b['District Number'] || ''; - return districtNumberA.localeCompare(districtNumberB, undefined, { numeric: true, sensitivity: 'base' }); }); } - function sortJSONBySchoolCode(schools) { - return schools.slice().sort((a, b) => { - const schoolCodeA = a.mincode || ''; - const schoolCodeB = b.mincode || ''; - return schoolCodeA.localeCompare(schoolCodeB, undefined, { numeric: true, sensitivity: 'base' }); - }); - } + return jsonData; +} - function sortByProperty(arr, propertyName, options = { numeric: true, sensitivity: 'base' }) { - return arr.slice().sort((a, b) => { - const valueA = a[propertyName] || ''; - const valueB = b[propertyName] || ''; - return valueA.localeCompare(valueB, undefined, options); - }); - } - - function rearrangeAndRelabelObjectProperties(object, propertyList) { - const reorderedObject = {}; - propertyList.forEach((propertyInfo) => { - const prop = propertyInfo.property; - const label = propertyInfo.label; - reorderedObject[label] = object.hasOwnProperty(prop) ? object[prop] : ""; - }); - return reorderedObject; - } +function districtNumberSort(a, b) { + // Convert the strings to numbers for comparison + const numA = parseInt(a, 10); + const numB = parseInt(b, 10); - function normalizeJsonObject(sourceArray, referenceArray, matchKey, condition, includeFields) { - return sourceArray.map((item) => { - const matchingItem = referenceArray.find( - (info) => info[matchKey] === item[matchKey] && (!condition || condition(info)) - ); - if (matchingItem) { - return { - ...item, - ...includeFields.reduce((result, field) => { - result[matchKey + "_" + field] = matchingItem[field]; - return result; - }, {}), - }; - } - return item; - }); + if (numA < numB) { + return -1; } - function filterRemoveByField(data, field, valuesToExclude) { - return data.filter(item => !valuesToExclude.includes(item[field])); + if (numA > numB) { + return 1; } - function filterIncludeByField(data, field, valuesToInclude) { - return data.filter(item => valuesToInclude.includes(item[field])); - } - - function filterByPubliclyAvailableCodes(jsonArray, fieldName, publicCodes) { - // Filter the array based on the condition - const filteredArray = jsonArray.filter(item => { - // Extract the field value (or use an empty string if the field is not present) - const fieldValue = item[fieldName] || ''; - - // Check if the fieldValue exactly matches any string from the stringsToRemove array - return publicCodes.includes(fieldValue); - }); - - return filteredArray; + return 0; +} +function formatGrades(grades, schoolGrades) { + const result = {}; + + // Create a set of all school grade codes from the provided grades + const gradeCodesSet = new Set(grades.map((grade) => grade.schoolGradeCode)); + + // Include all school grade codes in the result object + for (const grade of grades) { + result[grade.schoolGradeCode] = "Y"; } - function filterByField(jsonArray, fieldName, stringsToRemove) { - // Filter the array based on the condition - const filteredArray = jsonArray.filter(item => { - // Extract the field value (or use an empty string if the field is not present) - const fieldValue = item[fieldName] || ''; - - // Check if the fieldValue exactly matches any string from the stringsToRemove array - return !stringsToRemove.includes(fieldValue); - }); - - return filteredArray; + + // Set the value to "N" for school grade codes not in the provided grades + for (const grade of schoolGrades) { + if (!gradeCodesSet.has(grade.schoolGradeCode)) { + result[grade.schoolGradeCode] = "N"; + } } - function filterByOpenedAndClosedDate(data){ - const currentDate = new Date(); - - return data.filter(item => { - const closedDate = item.closedDate ? new Date(item.closedDate) : null; - const openedDate = item.openedDate ? new Date(item.openedDate) : null; - - return (closedDate === null && currentDate > openedDate) || (currentDate < closedDate && currentDate > openedDate) ; + + return result; +} + +function sortJSONByDistrictNumber(districts) { + return districts.slice().sort((a, b) => { + const districtNumberA = a["District Number"] || ""; + const districtNumberB = b["District Number"] || ""; + return districtNumberA.localeCompare(districtNumberB, undefined, { + numeric: true, + sensitivity: "base", }); - } - function filterByExpiryDate(data) { - const currentDate = new Date(); - - return data.filter(item => { - const expiryDate = item.expiryDate ? new Date(item.expiryDate) : null; - const effectiveDate = item.effectiveDate ? new Date(item.effectiveDate) : null; - - return (expiryDate === null && currentDate > effectiveDate) || (currentDate < expiryDate && currentDate > effectiveDate) ; + }); +} +function sortJSONBySchoolCode(schools) { + return schools.slice().sort((a, b) => { + const schoolCodeA = a.mincode || ""; + const schoolCodeB = b.mincode || ""; + return schoolCodeA.localeCompare(schoolCodeB, undefined, { + numeric: true, + sensitivity: "base", }); - } - function getArrayofNonPubliclyAvailableCodes(codes, field) { - if (!Array.isArray(codes)) { - throw new Error('Invalid input. Expecting an array of objects.'); - } - - // Filter out objects where "publiclyAvailable" is false - const nonPubliclyAvailableCodes = codes - .filter(item => item && item.publiclyAvailable !== true) - .map(item => item[field]); - - return nonPubliclyAvailableCodes; - } - function addFundingGroups(schools, fundingGroups) { - try { - // Process each school in the array - const schoolsWithFunding = schools.map(school => { - // Find all matching funding groups by mincode - const matchingFundingGroups = fundingGroups.filter(fundingGroup => - fundingGroup.mincode === school.mincode - ); - - const schoolWithFunding = { - ...school, - primaryK3: "", // Replace with an appropriate default value - elementary47: "", // Replace with an appropriate default value - juniorSecondary810: "", // Replace with an appropriate default value - seniorSecondary1112: "" // Replace with an appropriate default value - }; - - // Iterate through the matching funding groups - matchingFundingGroups.forEach(matchingFundingGroup => { - // Access the fundingGroupCode and fundingSubCode properties - const fundingGroupCode = matchingFundingGroup.fundingGroupCode; - const fundingSubCode = matchingFundingGroup.fundingGroupSubCode; - - // Check the fundingSubCode and update the school information - switch (fundingSubCode) { - case "01": - schoolWithFunding.primaryK3 = fundingGroupCode; - break; - case "04": - schoolWithFunding.elementary47 = fundingGroupCode; - break; - case "08": - schoolWithFunding.juniorSecondary810 = fundingGroupCode; - break; - case "11": - schoolWithFunding.seniorSecondary1112 = fundingGroupCode; - break; - default: - break; - } - }); - - return schoolWithFunding; - }); + }); +} - return schoolsWithFunding; - } catch (error) { - // Handle the error here, you can log it or perform other actions - console.error("An error occurred in addFundingGroups:", error); - // Optionally, you can rethrow the error if needed - throw error; - } +function sortByProperty( + arr, + propertyName, + options = { numeric: true, sensitivity: "base" } +) { + return arr.slice().sort((a, b) => { + const valueA = a[propertyName] || ""; + const valueB = b[propertyName] || ""; + return valueA.localeCompare(valueB, undefined, options); + }); +} + +function rearrangeAndRelabelObjectProperties(object, propertyList) { + const reorderedObject = {}; + propertyList.forEach((propertyInfo) => { + const prop = propertyInfo.property; + const label = propertyInfo.label; + reorderedObject[label] = object.hasOwnProperty(prop) ? object[prop] : ""; + }); + return reorderedObject; } - function getArrayofPubliclyAvailableCodes(codes, field) { - if (!Array.isArray(codes)) { - throw new Error('Invalid input. Expecting an array of objects.'); + +function normalizeJsonObject( + sourceArray, + referenceArray, + matchKey, + condition, + includeFields +) { + return sourceArray.map((item) => { + const matchingItem = referenceArray?.find( + (info) => + info[matchKey] === item[matchKey] && (!condition || condition(info)) + ); + if (matchingItem) { + return { + ...item, + ...includeFields.reduce((result, field) => { + result[matchKey + "_" + field] = matchingItem[field]; + return result; + }, {}), + }; } - - // Filter out objects where "publiclyAvailable" is true - const publiclyAvailableCodes = codes - .filter(item => item && item.publiclyAvailable === true) - .map(item => item[field]); - - return publiclyAvailableCodes; + return item; + }); +} +function filterRemoveByField(data, field, valuesToExclude) { + return data.filter((item) => !valuesToExclude.includes(item[field])); +} +function filterIncludeByField(data, field, valuesToInclude) { + return data.filter((item) => valuesToInclude.includes(item[field])); +} + +function filterByPubliclyAvailableCodes(jsonArray, fieldName, publicCodes) { + // Filter the array based on the condition + const filteredArray = jsonArray.filter((item) => { + // Extract the field value (or use an empty string if the field is not present) + const fieldValue = item[fieldName] || ""; + + // Check if the fieldValue exactly matches any string from the stringsToRemove array + return publicCodes.includes(fieldValue); + }); + + return filteredArray; +} +function filterByField(jsonArray, fieldName, stringsToRemove) { + // Filter the array based on the condition + const filteredArray = jsonArray.filter((item) => { + // Extract the field value (or use an empty string if the field is not present) + const fieldValue = item[fieldName] || ""; + + // Check if the fieldValue exactly matches any string from the stringsToRemove array + return !stringsToRemove.includes(fieldValue); + }); + + return filteredArray; +} +function filterByOpenedAndClosedDate(data) { + const currentDate = new Date(); + + return data.filter((item) => { + const closedDate = item.closedDate ? new Date(item.closedDate) : null; + const openedDate = item.openedDate ? new Date(item.openedDate) : null; + + return ( + (closedDate === null && currentDate > openedDate) || + (currentDate < closedDate && currentDate > openedDate) + ); + }); +} +function filterByExpiryDate(data) { + const currentDate = new Date(); + + return data.filter((item) => { + const expiryDate = item.expiryDate ? new Date(item.expiryDate) : null; + const effectiveDate = item.effectiveDate + ? new Date(item.effectiveDate) + : null; + + return ( + (expiryDate === null && currentDate > effectiveDate) || + (currentDate < expiryDate && currentDate > effectiveDate) + ); + }); +} +function getArrayofNonPubliclyAvailableCodes(codes, field) { + if (!Array.isArray(codes)) { + throw new Error("Invalid input. Expecting an array of objects."); } - function createSchoolCache(schoolData, schoolGrades) { - // Preload convertedGrades with schoolGrades.schoolGradeCode and set the value to "N" + // Filter out objects where "publiclyAvailable" is false + const nonPubliclyAvailableCodes = codes + .filter((item) => item && item.publiclyAvailable !== true) + .map((item) => item[field]); - // Map over each school object - return schoolData.map((school) => { - const convertedGrades = {}; - schoolGrades.forEach((grade) => { - convertedGrades[grade.schoolGradeCode] = "N"; - }); + return nonPubliclyAvailableCodes; +} +function addFundingGroups(schools, fundingGroups) { + try { + // Process each school in the array + const schoolsWithFunding = schools.map((school) => { + // Find all matching funding groups by mincode + const matchingFundingGroups = fundingGroups.filter( + (fundingGroup) => fundingGroup.mincode === school.mincode + ); - const addressFields = { - mailing: {}, - physical: {}, + const schoolWithFunding = { + ...school, + primaryK3: "", // Replace with an appropriate default value + elementary47: "", // Replace with an appropriate default value + juniorSecondary810: "", // Replace with an appropriate default value + seniorSecondary1112: "", // Replace with an appropriate default value }; - // Loop through the grades and set the value to "Y" for each grade - school.grades.forEach((grade) => { - convertedGrades[grade.schoolGradeCode] = "Y"; + // Iterate through the matching funding groups + matchingFundingGroups.forEach((matchingFundingGroup) => { + // Access the fundingGroupCode and fundingSubCode properties + const fundingGroupCode = matchingFundingGroup.fundingGroupCode; + const fundingSubCode = matchingFundingGroup.fundingGroupSubCode; + + // Check the fundingSubCode and update the school information + switch (fundingSubCode) { + case "01": + schoolWithFunding.primaryK3 = fundingGroupCode; + break; + case "04": + schoolWithFunding.elementary47 = fundingGroupCode; + break; + case "08": + schoolWithFunding.juniorSecondary810 = fundingGroupCode; + break; + case "11": + schoolWithFunding.seniorSecondary1112 = fundingGroupCode; + break; + default: + break; + } }); - // Extract and format principal contact information if it exists - const principalContact = school.contacts.find((contact) => contact.schoolContactTypeCode === "PRINCIPAL"); - if (principalContact) { - school.firstName = principalContact.firstName; - school.lastName = principalContact.lastName; - - - } + return schoolWithFunding; + }); - // Loop through addresses and update the fields based on addressTypeCode - school.addresses.forEach((address) => { - if (address.addressTypeCode === "MAILING") { - Object.keys(address).forEach((field) => { - // Exclude the specified fields - if (![ - "createUser", - "updateUser", - "createDate", - "updateDate", - "schoolAddressId", - "schoolId", - "addressTypeCode" - ].includes(field)) { - addressFields.mailing[`mailing_${field}`] = address[field]; - } - }); - } else if (address.addressTypeCode === "PHYSICAL") { - Object.keys(address).forEach((field) => { - if (![ - "createUser", - "updateUser", - "createDate", - "updateDate", - "schoolAddressId", - "schoolId", - "addressTypeCode" - ].includes(field)) { - addressFields.mailing[`physical_${field}`] = address[field]; - } - }); - } - }); + return schoolsWithFunding; + } catch (error) { + // Handle the error here, you can log it or perform other actions + console.error("An error occurred in addFundingGroups:", error); + // Optionally, you can rethrow the error if needed + throw error; + } +} +function getArrayofPubliclyAvailableCodes(codes, field) { + if (!Array.isArray(codes)) { + throw new Error("Invalid input. Expecting an array of objects."); + } + + // Filter out objects where "publiclyAvailable" is true + const publiclyAvailableCodes = codes + .filter((item) => item && item.publiclyAvailable === true) + .map((item) => item[field]); + + return publiclyAvailableCodes; +} +function createSchoolCache(schoolData, schoolGrades) { + // Preload convertedGrades with schoolGrades.schoolGradeCode and set the value to "N" + + // Map over each school object + return schoolData.map((school) => { + const convertedGrades = {}; + schoolGrades.forEach((grade) => { + convertedGrades[grade.schoolGradeCode] = "N"; + }); + + const addressFields = { + mailing: {}, + physical: {}, + }; + + // Loop through the grades and set the value to "Y" for each grade + school.grades.forEach((grade) => { + convertedGrades[grade.schoolGradeCode] = "Y"; + }); + + // Extract and format principal contact information if it exists + const principalContact = school.contacts?.find( + (contact) => contact.schoolContactTypeCode === "PRINCIPAL" + ); + if (principalContact) { + school.firstName = principalContact.firstName; + school.lastName = principalContact.lastName; + } - // Concatenate neighborhoodLearningTypeCode into a single string - const nlc = school.neighborhoodLearning.map(learning => learning.neighborhoodLearningTypeCode).join(' | '); - - // Merge the address fields and nlc into the school object - Object.assign(school, convertedGrades, addressFields.mailing, addressFields.physical, { nlc }); - - // Remove the original grades property and the updated address object - delete school.grades; - delete school.addresses; - delete school.neighborhoodLearning; - delete school.createUser; - delete school.updateUser; - delete school.updateDate; - delete school.createDate; - delete school.schoolId; - delete school.openedDate; - delete school.closedDate; - delete school.notes; - delete school.schoolMove.createUser; - delete school.schoolMove; - - // Remove the contacts property - delete school.contacts; - - return school; + // Loop through addresses and update the fields based on addressTypeCode + school.addresses.forEach((address) => { + if (address.addressTypeCode === "MAILING") { + Object.keys(address).forEach((field) => { + // Exclude the specified fields + if ( + ![ + "createUser", + "updateUser", + "createDate", + "updateDate", + "schoolAddressId", + "schoolId", + "addressTypeCode", + ].includes(field) + ) { + addressFields.mailing[`mailing_${field}`] = address[field]; + } + }); + } else if (address.addressTypeCode === "PHYSICAL") { + Object.keys(address).forEach((field) => { + if ( + ![ + "createUser", + "updateUser", + "createDate", + "updateDate", + "schoolAddressId", + "schoolId", + "addressTypeCode", + ].includes(field) + ) { + addressFields.mailing[`physical_${field}`] = address[field]; + } + }); + } }); + + // Concatenate neighborhoodLearningTypeCode into a single string + const nlc = school.neighborhoodLearning + .map((learning) => learning.neighborhoodLearningTypeCode) + .join(" | "); + + // Merge the address fields and nlc into the school object + Object.assign( + school, + convertedGrades, + addressFields.mailing, + addressFields.physical, + { nlc } + ); + + // Remove the original grades property and the updated address object + delete school.grades; + delete school.addresses; + delete school.neighborhoodLearning; + delete school.createUser; + delete school.updateUser; + delete school.updateDate; + delete school.createDate; + delete school.schoolId; + delete school.openedDate; + delete school.closedDate; + delete school.notes; + delete school.schoolMove.createUser; + delete school.schoolMove; + + // Remove the contacts property + delete school.contacts; + + return school; + }); } - module.exports = {addFundingGroups, filterByOpenedAndClosedDate, filterByPubliclyAvailableCodes, getArrayofPubliclyAvailableCodes, filterByExpiryDate, filterRemoveByField,filterIncludeByField, sortByProperty,getArrayofNonPubliclyAvailableCodes,filterByField,appendMailingAddressDetailsAndRemoveAddresses,sortJSONBySchoolCode,sortJSONByDistrictNumber,normalizeJsonObject, removeFieldsByCriteria, createList, isSafeFilePath,isAllowedSchoolCategory, addDistrictLabels, districtNumberSort, createSchoolCache, formatGrades, rearrangeAndRelabelObjectProperties}; \ No newline at end of file +module.exports = { + addFundingGroups, + filterByOpenedAndClosedDate, + filterByPubliclyAvailableCodes, + getArrayofPubliclyAvailableCodes, + filterByExpiryDate, + filterRemoveByField, + filterIncludeByField, + sortByProperty, + getArrayofNonPubliclyAvailableCodes, + filterByField, + appendMailingAddressDetailsAndRemoveAddresses, + sortJSONBySchoolCode, + sortJSONByDistrictNumber, + normalizeJsonObject, + removeFieldsByCriteria, + createList, + isSafeFilePath, + isAllowedSchoolCategory, + addDistrictLabels, + districtNumberSort, + createSchoolCache, + formatGrades, + rearrangeAndRelabelObjectProperties, +}; diff --git a/backend/src/routes/district-router.js b/backend/src/routes/district-router.js index 8df54a90..9f6751fa 100644 --- a/backend/src/routes/district-router.js +++ b/backend/src/routes/district-router.js @@ -7,8 +7,22 @@ const axios = require("axios"); const fs = require("fs"); const path = require("path"); const { checkToken } = require("../components/auth"); -const { listCache} = require("../components/cache"); -const {addFundingGroups, getArrayofPubliclyAvailableCodes,filterRemoveByField, filterByExpiryDate, getArrayofNonPubliclyAvailableCodes, filterByField,appendMailingAddressDetailsAndRemoveAddresses, rearrangeAndRelabelObjectProperties, addDistrictLabels, normalizeJsonObject, sortJSONByDistrictNumber, removeFieldsByCriteria, filterByPubliclyAvailableCodes} = require("../components/utils.js") +const { listCache } = require("../components/cache"); +const { + addFundingGroups, + getArrayofPubliclyAvailableCodes, + filterRemoveByField, + filterByExpiryDate, + getArrayofNonPubliclyAvailableCodes, + filterByField, + appendMailingAddressDetailsAndRemoveAddresses, + rearrangeAndRelabelObjectProperties, + addDistrictLabels, + normalizeJsonObject, + sortJSONByDistrictNumber, + removeFieldsByCriteria, + filterByPubliclyAvailableCodes, +} = require("../components/utils.js"); //Batch Routes router.get("/all-contacts", checkToken, getAllDistrictContacts); @@ -33,7 +47,7 @@ function addContactTypeLabels(districtDataResponse, nonPublicContactTypeCodes) { Array.isArray(updatedDistrictData.contacts) ) { updatedDistrictData.contacts.forEach((contact) => { - const matchingType = nonPublicContactTypeCodes.find( + const matchingType = nonPublicContactTypeCodes?.find( (codeObj) => codeObj.districtContactTypeCode === contact.districtContactTypeCode ); @@ -79,7 +93,7 @@ async function getDistrictCodes(req) { return districtCodeList; } catch (e) { log.error( - "getDistrictList Error", + "getDistrictCodesList Error", e.response ? e.response.status : e.message ); } @@ -236,7 +250,6 @@ async function getAllDistrictContacts(req, res) { async function getAllDistrictMailing(req, res) { const districtList = await listCache.get("districtlist"); - const contactTypeCodes = await listCache.get("codesList"); const propertyOrder = [ { property: "districtId_districtNumber", label: "District Number" }, @@ -309,13 +322,11 @@ async function getAllDistrictMailing(req, res) { const contentByDistrict = sortJSONByDistrictNumber(content); res.json(contentByDistrict); - //res.json(districtContactsReorderedAndRelabeled ); } catch (e) { log.error("getData Error", e.response ? e.response.status : e.message); } } -//api/v1/institute/district/12342525 async function getDistrict(req, res) { const { id } = req.params; @@ -381,13 +392,14 @@ async function getDistrict(req, res) { }); const contactTypeCodes = await getDistrictCodes(req); - const schoolCategoryCodes = await listCache.get("categoryCodes") - const facilityCodes = await listCache.get("facilityCodes") - const fundingGroups = await listCache.get("fundingGroups") - const districtContactCodeTypes = await listCache.get("codesList") - const nonPublicContactTypeCodes = getNonPublicContactTypeCodes(contactTypeCodes); - - + const schoolCategoryCodes = await listCache.get("categoryCodes"); + const facilityCodes = await listCache.get("facilityCodes"); + const fundingGroups = await listCache.get("fundingGroups"); + const districtContactCodeTypes = await listCache.get("codesList"); + const nonPublicContactTypeCodes = await getNonPublicContactTypeCodes( + contactTypeCodes + ); + const districtDataPublic = removeContacts( districtDataResponse.data, nonPublicContactTypeCodes @@ -396,40 +408,56 @@ async function getDistrict(req, res) { districtDataPublic, contactTypeCodes ); - districtDataPublicWithLabels.contacts = filterByPubliclyAvailableCodes( - districtDataPublicWithLabels.contacts, - "districtContactTypeCode", - getArrayofPubliclyAvailableCodes( - districtContactCodeTypes.codesList.districtContactTypeCodes, - "districtContactTypeCode" - ) - ); - districtDataPublicWithLabels.contacts = filterByExpiryDate( - districtDataPublicWithLabels.contacts - ); - - districtSchoolsResponse.data.content = normalizeJsonObject(districtSchoolsResponse.data.content, schoolCategoryCodes, "schoolCategoryCode", null, ["label", "description"]); - districtSchoolsResponse.data.content = normalizeJsonObject(districtSchoolsResponse.data.content, facilityCodes, "faciltyTypeCode", null, ["label", "description"]); - districtSchoolsResponse.data.content = addFundingGroups(districtSchoolsResponse.data.content, fundingGroups) + if (!!districtContactCodeTypes) { + districtDataPublicWithLabels.contacts = filterByPubliclyAvailableCodes( + districtDataPublicWithLabels.contacts, + "districtContactTypeCode", + getArrayofPubliclyAvailableCodes( + districtContactCodeTypes.codesList.districtContactTypeCodes, + "districtContactTypeCode" + ) + ); + districtDataPublicWithLabels.contacts = filterByExpiryDate( + districtDataPublicWithLabels.contacts + ); + districtSchoolsResponse.data.content = normalizeJsonObject( + districtSchoolsResponse.data.content, + schoolCategoryCodes, + "schoolCategoryCode", + null, + ["label", "description"] + ); + districtSchoolsResponse.data.content = normalizeJsonObject( + districtSchoolsResponse.data.content, + facilityCodes, + "faciltyTypeCode", + null, + ["label", "description"] + ); + districtSchoolsResponse.data.content = addFundingGroups( + districtSchoolsResponse.data.content, + fundingGroups + ); + } - const today = new Date(); - const filteredSchoolsResponse = districtSchoolsResponse.data.content.filter( - (obj) => { - // if openedDate is a valid date is less than today, keep the object - const openedDate = new Date(obj.openedDate); + const today = new Date(); + const filteredSchoolsResponse = districtSchoolsResponse.data.content.filter( + (obj) => { + // if openedDate is a valid date is less than today, keep the object + const openedDate = new Date(obj.openedDate); - // If closedDate is a valid date greater than today, keep the object - const closedDate = new Date(obj.closedDate); + // If closedDate is a valid date greater than today, keep the object + const closedDate = new Date(obj.closedDate); - // return obj IF closedDate does not exist OR is after than current date - // AND openedDate exists AND is before current date - return ( - (!obj.closedDate || closedDate > today) && - obj.openedDate && - openedDate < today - ); - } - ); + // return obj IF closedDate does not exist OR is after than current date + // AND openedDate exists AND is before current date + return ( + (!obj.closedDate || closedDate > today) && + obj.openedDate && + openedDate < today + ); + } + ); const districtJSON = { districtData: districtDataPublicWithLabels, districtSchools: filteredSchoolsResponse, diff --git a/backend/src/routes/institute-router.js b/backend/src/routes/institute-router.js index 2b0ebf95..fb7b4c2f 100644 --- a/backend/src/routes/institute-router.js +++ b/backend/src/routes/institute-router.js @@ -5,28 +5,69 @@ const config = require("../config/index"); const axios = require("axios"); const { checkToken } = require("../components/auth"); -const {filterByOpenedAndClosedDate, formatGrades, removeFieldsByCriteria, createList, addDistrictLabels, districtNumberSort, isAllowedSchoolCategory, filterRemoveByField, filterByField } = require("../components/utils"); +const { + filterByOpenedAndClosedDate, + formatGrades, + removeFieldsByCriteria, + createList, + addDistrictLabels, + districtNumberSort, + isAllowedSchoolCategory, + filterRemoveByField, + filterByField, +} = require("../components/utils"); const { listCache, codeCache } = require("../components/cache"); -const schoolListOptions = { fields: ["mincode", "displayName", "schoolId", "closedDate", "openedDate","schoolCategoryCode"], fieldToInclude: null, valueToInclude: null, sortField: "mincode" }; -const districtListOptions = { fields: ["displayName", "districtId","districtNumber", "closedDate"] ,fieldToInclude: "districtStatusCode", valueToInclude: "ACTIVE", sortField: "districtNumber"}; -const authorityListOptions = { fields: ["displayName", "authorityNumber","independentAuthorityId", "closedDate", "opendDate"], sortField: "authorityNumber" }; -const openSchoolListOptions = { fields: [ - "schoolId", - "districtId", - "mincode", - "schoolNumber", - "faxNumber", - "phoneNumber", - "email", - "website", - "displayName", - "schoolCategoryCode", - "facilityTypeCode", - "openedDate", - "closedDate", - "districtNumber" -],fieldToInclude: "closedDate", valueToInclude: null, sortField: "mincode" }; +const schoolListOptions = { + fields: [ + "mincode", + "displayName", + "schoolId", + "closedDate", + "openedDate", + "schoolCategoryCode", + ], + fieldToInclude: null, + valueToInclude: null, + sortField: "mincode", +}; +const districtListOptions = { + fields: ["displayName", "districtId", "districtNumber", "closedDate"], + fieldToInclude: "districtStatusCode", + valueToInclude: "ACTIVE", + sortField: "districtNumber", +}; +const authorityListOptions = { + fields: [ + "displayName", + "authorityNumber", + "independentAuthorityId", + "closedDate", + "opendDate", + ], + sortField: "authorityNumber", +}; +const openSchoolListOptions = { + fields: [ + "schoolId", + "districtId", + "mincode", + "schoolNumber", + "faxNumber", + "phoneNumber", + "email", + "website", + "displayName", + "schoolCategoryCode", + "facilityTypeCode", + "openedDate", + "closedDate", + "districtNumber", + ], + fieldToInclude: "closedDate", + valueToInclude: null, + sortField: "mincode", +}; //Batch Routes router.get("/contact-type-codes", checkToken, getContactTypeCodes); @@ -43,19 +84,16 @@ router.get("/*", checkToken, getInstituteAPI); async function createCache(req, res) { if (await !listCache.has("fundingGroups")) { - //const codes = []; - try { const fundingGroupsResponse = await axios.get( - `${config.get( - "server:schoolsAPIURL" - )}/schools/fundingGroups`, + `${config.get("server:schoolsAPIURL")}/schools/fundingGroups`, { headers: { Authorization: `Bearer ${req.accessToken}` }, } ); listCache.set("fundingGroups", fundingGroupsResponse.data); res.json(fundingGroupsResponse.data); + log.info("cached funding groups - ", req.url); } catch (error) { const statusCode = error.response ? error.response.status : 500; log.error("getFunding Groups Error", statusCode, error.message); @@ -65,52 +103,32 @@ async function createCache(req, res) { const cachedFundingGroupList = await listCache.get("fundingGroups"); res.json(cachedFundingGroupList); } - if (await !listCache.has("districtlist")) { - const url = `${config.get("server:instituteAPIURL")}/institute/district`; // Update the URL according to your API endpoint - axios - .get(url, { headers: { Authorization: `Bearer ${req.accessToken}` } }) - .then((response) => { - const filteredNonbBCDistrictList = response.data.filter(district => ["098","102", "103"].includes(district.districtNumber)); - const filteredDistrictList = response.data.filter(district => !["098","102", "103"].includes(district.districtNumber)); - const districtList = createList(filteredDistrictList, districtListOptions); - const nonBCdistrictList = createList(filteredNonbBCDistrictList, districtListOptions); - listCache.set("nonbcdistrictlist", nonBCdistrictList); - listCache.set("districtlist", districtList); - res.json(districtList); - log.info(req.url); - }) - .catch((e) => { - log.error( - "getDistrictList Error", - e.response ? e.response.status : e.message - ); - }); - } - if (!listCache.has("categoryCodes")) { - //const codes = []; - + if (await !listCache.has("categoryCodes")) { try { const categoryCodesResponse = await axios.get( - `${config.get( - "server:instituteAPIURL" - )}/institute/category-codes`, + `${config.get("server:instituteAPIURL")}/institute/category-codes`, { headers: { Authorization: `Bearer ${req.accessToken}` }, } ); - - categoryCodesResponse.data = filterRemoveByField(categoryCodesResponse.data,"schoolCategoryCode", ["FED_BAND","POST_SEC","YUKON"]) + + categoryCodesResponse.data = filterRemoveByField( + categoryCodesResponse.data, + "schoolCategoryCode", + ["FED_BAND", "POST_SEC", "YUKON"] + ); listCache.set("categoryCodes", categoryCodesResponse.data); - + log.info("cached category codes - ", req.url); } catch (error) { const statusCode = error.response ? error.response.status : 500; log.error("Category Code Caching Error", statusCode, error.message); res.status(statusCode).send(error.message); } - } else{ + } else { const categoryCodes = await listCache.get("categoryCodes"); - res.json(categoryCodes) + res.json(categoryCodes); + log.info("fetched category codes - ", req.url); } if (await !codeCache.has("gradelist")) { const url = `${config.get("server:instituteAPIURL")}/institute/grade-codes`; // Update the URL according to your API endpoint @@ -118,103 +136,81 @@ async function createCache(req, res) { .get(url, { headers: { Authorization: `Bearer ${req.accessToken}` } }) .then((response) => { const gradeCodes = response.data; - + codeCache.set("gradelist", gradeCodes); - log.info(req.url); + log.info("cached grade list - ", req.url); }) .catch((e) => { log.error( - "getDistrictList Error", + "getGradeList Error", e.response ? e.response.status : e.message ); }); } else { const gradeCodes = await codeCache.get("gradelist"); res.json(gradeCodes); + log.info("fetched grade list - ", req.url); } - if (!listCache.has("categoryCodes")) { - //const codes = []; - - try { - const categoryCodesResponse = await axios.get( - `${config.get( - "server:instituteAPIURL" - )}/institute/category-codes`, - { - headers: { Authorization: `Bearer ${req.accessToken}` }, - } - ); - - categoryCodesResponse.data = filterRemoveByField(categoryCodesResponse.data,"schoolCategoryCode", ["FED_BAND","POST_SEC","YUKON"]) - listCache.set("categoryCodes", categoryCodesResponse.data); - - } catch (error) { - const statusCode = error.response ? error.response.status : 500; - log.error("Category Code Caching Error", statusCode, error.message); - res.status(statusCode).send(error.message); - } - } - if (!listCache.has("facilityCodes")) { - //const codes = []; - try { const facilityCodesResponse = await axios.get( - `${config.get( - "server:instituteAPIURL" - )}/institute/facility-codes`, + `${config.get("server:instituteAPIURL")}/institute/facility-codes`, { headers: { Authorization: `Bearer ${req.accessToken}` }, } ); listCache.set("facilityCodes", facilityCodesResponse.data); + log.info("cached facility codes - ", req.url); } catch (error) { const statusCode = error.response ? error.response.status : 500; log.error("Faility Code Caching Error", statusCode, error.message); res.status(statusCode).send(error.message); } - } + } if (!listCache.has("districtAddresses")) { - //const codes = []; - try { const districtsResponse = await axios.get( - `${config.get("server:instituteAPIURL")}/institute/district/paginated?pageSize=200`, + `${config.get( + "server:instituteAPIURL" + )}/institute/district/paginated?pageSize=200`, { headers: { Authorization: `Bearer ${req.accessToken}` }, } ); - + districtsResponse.data.content.forEach((district) => { district.addresses.forEach((address) => { - if (address.addressTypeCode === "MAILING") { Object.keys(address).forEach((field) => { // Exclude the specified fields - if (![ - "createUser", - "updateUser", - "createDate", - "updateDate", - "schoolAddressId", - "schoolId", - "addressTypeCode" - ].includes(field)) { + if ( + ![ + "createUser", + "updateUser", + "createDate", + "updateDate", + "schoolAddressId", + "schoolId", + "addressTypeCode", + ].includes(field) + ) { district[`mailing_${field}`] = address[field]; } }); } else if (address.addressTypeCode === "PHYSICAL") { Object.keys(address).forEach((field) => { - if (![ - "createUser", - "updateUser", - "createDate", - "updateDate", - "schoolAddressId", - "schoolId", - "addressTypeCode" - ].includes(field)) { + if ( + ![ + "createUser", + "updateUser", + "createDate", + "updateDate", + "schoolAddressId", + "schoolId", + "addressTypeCode", + ].includes(field) + ) { district[`physical_${field}`] = address[field]; } }); @@ -222,16 +218,17 @@ async function createCache(req, res) { }); }); listCache.set("districtAddresses", districtsResponse.data.content); + log.info("cached district addresses - ", req.url); } catch (error) { const statusCode = error.response ? error.response.status : 500; log.error("District Code Caching Error", statusCode, error.message); res.status(statusCode).send(error.message); } - } - + } if (await !listCache.has("codesList")) { try { + log.info("Starting to get codes list"); //MOVE UNTIL I SEE IT const authorityContactTypeCodesResponse = await axios.get( `${config.get( "server:instituteAPIURL" @@ -260,27 +257,35 @@ async function createCache(req, res) { ); const codes = { - authorityContactTypeCodes: removeFieldsByCriteria(authorityContactTypeCodesResponse.data, [{ fieldToRemove: "publiclyAvailable", value: false }]), - districtContactTypeCodes: removeFieldsByCriteria(districtContactTypeCodesResponse.data,[{ fieldToRemove: "publiclyAvailable", value: false }]), - schoolContactTypeCodes: removeFieldsByCriteria(schoolContactTypeCodesResponse.data,[{ fieldToRemove: "publiclyAvailable", value: false }]), + authorityContactTypeCodes: removeFieldsByCriteria( + authorityContactTypeCodesResponse.data, + [{ fieldToRemove: "publiclyAvailable", value: false }] + ), + districtContactTypeCodes: removeFieldsByCriteria( + districtContactTypeCodesResponse.data, + [{ fieldToRemove: "publiclyAvailable", value: false }] + ), + schoolContactTypeCodes: removeFieldsByCriteria( + schoolContactTypeCodesResponse.data, + [{ fieldToRemove: "publiclyAvailable", value: false }] + ), }; - res.json(codes); + // res.json(codes); listCache.set("codesList", { codesList: codes }); + log.info("cached codes list - ", req.url); } catch (error) { const statusCode = error.response ? error.response.status : 500; + log.error(e); log.error("getCodesList Error", statusCode, error.message); res.status(statusCode).send(error.message); } } + // res acts like a return res.status(200).json({ success: true }); - } - async function getContactTypeCodes(req, res) { if (await !listCache.has("codesList")) { - //const codes = []; - try { const authorityContactTypeCodesResponse = await axios.get( `${config.get( @@ -310,9 +315,18 @@ async function getContactTypeCodes(req, res) { ); const codes = { - authorityContactTypeCodes: removeFieldsByCriteria(authorityContactTypeCodesResponse.data, [{ fieldToRemove: "publiclyAvailable", value: false }]), - districtContactTypeCodes: removeFieldsByCriteria(districtContactTypeCodesResponse.data,[{ fieldToRemove: "publiclyAvailable", value: false }]), - schoolContactTypeCodes: removeFieldsByCriteria(schoolContactTypeCodesResponse.data,[{ fieldToRemove: "publiclyAvailable", value: false }]), + authorityContactTypeCodes: removeFieldsByCriteria( + authorityContactTypeCodesResponse.data, + [{ fieldToRemove: "publiclyAvailable", value: false }] + ), + districtContactTypeCodes: removeFieldsByCriteria( + districtContactTypeCodesResponse.data, + [{ fieldToRemove: "publiclyAvailable", value: false }] + ), + schoolContactTypeCodes: removeFieldsByCriteria( + schoolContactTypeCodesResponse.data, + [{ fieldToRemove: "publiclyAvailable", value: false }] + ), }; listCache.set("codesList", { codesList: codes }); res.json(codes); @@ -327,67 +341,72 @@ async function getContactTypeCodes(req, res) { } } async function getOffshoreSchoolList(req, res) { - - let currentDate = new Date().toISOString().substring(0, 19) + let currentDate = new Date().toISOString().substring(0, 19); const params = [ { - condition: 'AND', + condition: "AND", searchCriteriaList: [ { - key: 'schoolCategoryCode', - operation: 'eq', + key: "schoolCategoryCode", + operation: "eq", value: "OFFSHORE", - valueType: 'STRING', - condition: 'AND' + valueType: "STRING", + condition: "AND", }, { - key: 'openedDate', - operation: 'lte', + key: "openedDate", + operation: "lte", value: currentDate, - valueType: 'DATE_TIME', - condition: 'AND' - } - ] + valueType: "DATE_TIME", + condition: "AND", + }, + ], }, { - condition: 'AND', + condition: "AND", searchCriteriaList: [ { - key: 'closedDate', - operation: 'eq', + key: "closedDate", + operation: "eq", value: null, - valueType: 'STRING', - condition: 'OR' + valueType: "STRING", + condition: "OR", }, { - key: 'closedDate', - operation: 'gte', + key: "closedDate", + operation: "gte", value: currentDate, - valueType: 'DATE_TIME', - condition: 'OR' - } - ] - } + valueType: "DATE_TIME", + condition: "OR", + }, + ], + }, ]; - const jsonString = JSON.stringify(params) - const encodedParams = encodeURIComponent(jsonString) - - + const jsonString = JSON.stringify(params); + const encodedParams = encodeURIComponent(jsonString); if (await !listCache.has("offshoreschoollist")) { - const url = `${config.get('server:instituteAPIURL')}/institute/school/paginated?pageSize=1000&pageNumber=0&searchCriteriaList=${encodedParams}`; + const url = `${config.get( + "server:instituteAPIURL" + )}/institute/school/paginated?pageSize=1000&pageNumber=0&searchCriteriaList=${encodedParams}`; axios .get(url, { headers: { Authorization: `Bearer ${req.accessToken}` } }) .then((response) => { const offshoreSchoolList = response.data.content; - const schoolGrades = codeCache.get("gradelist"); - + const schoolGrades = codeCache.get("gradelist"); + for (let i = 0; i < offshoreSchoolList.length; i++) { - const formattedGrades = formatGrades(offshoreSchoolList[i].grades, schoolGrades); - offshoreSchoolList[i] = { ...offshoreSchoolList[i], ...formattedGrades }; + const formattedGrades = formatGrades( + offshoreSchoolList[i].grades, + schoolGrades + ); + offshoreSchoolList[i] = { + ...offshoreSchoolList[i], + ...formattedGrades, + }; // Now you can use the updated offshoreSchoolList[i] object as needed - } + } res.json(offshoreSchoolList); listCache.set("offshoreschoollist", offshoreSchoolList); log.info(req.url); @@ -404,41 +423,44 @@ async function getOffshoreSchoolList(req, res) { } } async function getAuthorityList(req, res) { - if (await !listCache.has("authoritylist")) { - - let currentDate = new Date().toISOString().substring(0, 19) + let currentDate = new Date().toISOString().substring(0, 19); const params = [ { condition: null, searchCriteriaList: [ { - key: 'closedDate', - operation: 'eq', + key: "closedDate", + operation: "eq", value: null, - valueType: 'STRING', - condition: 'OR' + valueType: "STRING", + condition: "OR", }, { - key: 'closedDate', - operation: 'gte', + key: "closedDate", + operation: "gte", value: currentDate, - valueType: 'DATE_TIME', - condition: 'OR' - } - ] - } + valueType: "DATE_TIME", + condition: "OR", + }, + ], + }, ]; - - const jsonString = JSON.stringify(params) - const encodedParams = encodeURIComponent(jsonString) - - const url = `${config.get('server:instituteAPIURL')}/institute/authority/paginated?pageSize=1000&searchCriteriaList=${encodedParams}`; + + const jsonString = JSON.stringify(params); + const encodedParams = encodeURIComponent(jsonString); + + const url = `${config.get( + "server:instituteAPIURL" + )}/institute/authority/paginated?pageSize=1000&searchCriteriaList=${encodedParams}`; axios .get(url, { headers: { Authorization: `Bearer ${req.accessToken}` } }) .then((response) => { - const authorityList = createList(response.data.content, authorityListOptions); - + const authorityList = createList( + response.data.content, + authorityListOptions + ); + res.json(authorityList); listCache.set("authoritylist", authorityList); log.info(req.url); @@ -455,31 +477,30 @@ async function getAuthorityList(req, res) { } } async function getCategoryCodes(req, res) { - if (!listCache.has("categoryCodes")) { - //const codes = []; - try { const categoryCodesResponse = await axios.get( - `${config.get( - "server:instituteAPIURL" - )}/institute/category-codes`, + `${config.get("server:instituteAPIURL")}/institute/category-codes`, { headers: { Authorization: `Bearer ${req.accessToken}` }, } ); - - categoryCodesResponse.data = filterRemoveByField(categoryCodesResponse.data,"schoolCategoryCode", ["FED_BAND","POST_SEC","YUKON"]) + + categoryCodesResponse.data = filterRemoveByField( + categoryCodesResponse.data, + "schoolCategoryCode", + ["FED_BAND", "POST_SEC", "YUKON"] + ); listCache.set("categoryCodes", categoryCodesResponse.data); - + res.json(categoryCodesResponse.data); } catch (error) { const statusCode = error.response ? error.response.status : 500; log.error("Category Code Caching Error", statusCode, error.message); res.status(statusCode).send(error.message); } - } else{ + } else { const categoryCodes = await listCache.get("categoryCodes"); - res.json(categoryCodes) + res.json(categoryCodes); } } async function getSchoolList(req, res) { @@ -488,9 +509,24 @@ async function getSchoolList(req, res) { axios .get(url, { headers: { Authorization: `Bearer ${req.accessToken}` } }) .then((response) => { - const openSchools = filterByOpenedAndClosedDate(response.data) - const validSchoolCategories = filterByField(openSchools, "schoolCategoryCode", ["POST_SEC", "YUKON", "SUMMER", "FED_BAND"]) - const validSchoolFacilities = filterByField(validSchoolCategories, "facilityTypeCode", ['PROVINCIAL','DIST_CONT','ELEC_DELIV','POST_SEC','JUSTB4PRO','SUMMER']) + const openSchools = filterByOpenedAndClosedDate(response.data); + const validSchoolCategories = filterByField( + openSchools, + "schoolCategoryCode", + ["POST_SEC", "YUKON", "SUMMER", "FED_BAND"] + ); + const validSchoolFacilities = filterByField( + validSchoolCategories, + "facilityTypeCode", + [ + "PROVINCIAL", + "DIST_CONT", + "ELEC_DELIV", + "POST_SEC", + "JUSTB4PRO", + "SUMMER", + ] + ); const schoolList = createList(validSchoolFacilities, schoolListOptions); res.json(schoolList); listCache.set("schoollist", schoolList); @@ -514,10 +550,20 @@ async function getDistrictList(req, res) { .get(url, { headers: { Authorization: `Bearer ${req.accessToken}` } }) .then((response) => { //const districtList = response.data; - const filteredNonbBCDistrictList = response.data.filter(district => ["098","102", "103"].includes(district.districtNumber)); - const filteredDistrictList = response.data.filter(district => !["098","102", "103"].includes(district.districtNumber)); - const districtList = createList(filteredDistrictList, districtListOptions); - const nonBCdistrictList = createList(filteredNonbBCDistrictList, districtListOptions); + const filteredNonbBCDistrictList = response.data.filter((district) => + ["098", "102", "103"].includes(district.districtNumber) + ); + const filteredDistrictList = response.data.filter( + (district) => !["098", "102", "103"].includes(district.districtNumber) + ); + const districtList = createList( + filteredDistrictList, + districtListOptions + ); + const nonBCdistrictList = createList( + filteredNonbBCDistrictList, + districtListOptions + ); listCache.set("nonbcdistrictlist", nonBCdistrictList); listCache.set("districtlist", districtList); res.json(districtList); @@ -525,7 +571,7 @@ async function getDistrictList(req, res) { }) .catch((e) => { log.error( - "getDistrictList Error", + "getDistrictList Error (getDistrictList)", e.response ? e.response.status : e.message ); }); @@ -552,19 +598,21 @@ async function getDistrictContactsAPI(req, res) { const url = `${config.get("server:instituteAPIURL")}/institute` + req.url; const districtList = await listCache.get("districtlist"); - const nonBCDistrictList = await listCache.get("nonbcdistrictlist"); + const nonBCDistrictList = await listCache.get("nonbcdistrictlist"); axios .get(url, { headers: { Authorization: `Bearer ${req.accessToken}` } }) .then((response) => { if (req.url.includes("/district/contact/paginated")) { const jsonData = addDistrictLabels(response.data, districtList); - - jsonData.content = jsonData.content.filter(contact => { + + jsonData.content = jsonData.content.filter((contact) => { // Check if districtId is not undefined, empty, or null - return contact.districtNumber !== undefined - && contact.districtNumber !== "" - && contact.districtNumber !== null; - }); + return ( + contact.districtNumber !== undefined && + contact.districtNumber !== "" && + contact.districtNumber !== null + ); + }); res.json(jsonData); } else { res.json(response.data); @@ -582,7 +630,7 @@ async function getGradeCodes(req, res) { .get(url, { headers: { Authorization: `Bearer ${req.accessToken}` } }) .then((response) => { const gradeCodes = response.data; - + codeCache.set("gradelist", gradeCodes); res.json(gradeCodes); log.info(req.url); diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 64419e25..7cc84069 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -9,7 +9,7 @@ const data = ref([]) // Placeholder for the received data const appStore = useAppStore() onBeforeMount(async () => { - await appStore.setCodes() + await appStore.setCodes() //calls /create-cache await appStore.setDistricts() await appStore.setAuthorityList() await appStore.setSchoolList() diff --git a/frontend/src/assets/main.css b/frontend/src/assets/main.css index c438d8ca..59a5f718 100644 --- a/frontend/src/assets/main.css +++ b/frontend/src/assets/main.css @@ -1,35 +1,39 @@ @import './base.css'; #app { - max-width: 1280px; - margin: 0 auto; - padding: 0rem; font-family: 'BCSans', 'Noto Sans', Verdana, Arial, sans-serif; font-weight: normal; } +#main { + max-width: 1280px; + padding: 0rem; +} + a { color: #2a6496; } +div.v-application__wrap { + min-height: 100vh; /* override dvh property */ +} + +.full-width { + margin-left: calc(-1*(100vw - 1024px)/2); + margin-right: calc(-1*(100vw - 1024px)/2); +} + /** Need to look at how CSS is loaded in since Vuetify defaults are overriding our custom CSS. Fixing this now could risk delaying other releases, so we will have to wait on this one - SF **/ .v-alert, .v-alert--variant-outlined { border-radius: 8px !important; } -@media (max-width: 768px) { - #app { - min-width: 1130px; /* Adjust as needed */ - padding: 0; /* Adjust as needed */ - } - - .full-width { - margin: 0 calc(-1*(100vw - 768px)/2); - padding: 0 calc((100vw - 768px)/2); - background-color: red; - } +.v-breadcrumbs-item--disabled { + opacity: 1; + font-weight: bold; } + .school-search{ margin-left:175px } @@ -38,7 +42,7 @@ Fixing this now could risk delaying other releases, so we will have to wait on t } .breadcrumbs { margin: 0 -40em; - padding-left: 40em !important; + padding-left: 40em; } /* styles button to look like links */ @@ -49,10 +53,12 @@ button.link-btn, .link-btn .v-btn__content { } .territorial-acknowledgement { - background-color: #494949; - color: #fff; - border-bottom: 3px solid #FCBA19; - border-top: 3px solid #FCBA19; + background-color: #292929; + color: #faf9f8; + font-size: 14px; + line-height: 21px; + border-bottom: 4px solid #FCBA19; + border-top: 4px solid #FCBA19; } .v-toolbar__extension { @@ -63,6 +69,40 @@ button.link-btn, .link-btn .v-btn__content { .v-btn-align-left { justify-content: normal !important; } + +@media (max-width: 1024px) { + .full-width { + margin-left: unset; + margin-right: unset; + } +} + +@media (max-width: 960px) { + #app { + /* min-width: 600px; */ + padding: 0; /* Adjust as needed */ + } + + .breadcrumbs { + margin: 0; + padding-left: 12px; + } + + h1 span.institute-name { + font-size: 1.5rem; + font-weight: bold; + } + + /* + * wraps button text as long as the class 'wrap' is added to v-btn component + * This is a workaround since a text wrap option is not available for buttons in Vuetify + */ + .wrap .v-btn__content { + white-space: pre-wrap; +} + +} + @media (hover: hover) { a:hover { background-color: #0000; @@ -82,11 +122,14 @@ button.link-btn, .link-btn .v-btn__content { #app { display: grid; - padding: 0; + padding: 0!important; + margin: 0 auto; } - .full-width { - margin: 0 calc(-1*(100vw - 1024px)/2); - padding: 0 calc((100vw - 1024px)/2); - } -} + /* .full-width { + position: relative; + width: 100vw; + left: calc(-1*(100vw - 1280px)/2); + padding: 0!important; + } */ +} \ No newline at end of file diff --git a/frontend/src/components/AuthoritySelect.vue b/frontend/src/components/AuthoritySelect.vue index 747f11dd..7309103a 100644 --- a/frontend/src/components/AuthoritySelect.vue +++ b/frontend/src/components/AuthoritySelect.vue @@ -19,46 +19,43 @@ function goToAuthority() { } }) } - -function downloadAuthorityMailing() { - alert('TODO - Implement authority mailing download') -} -function downloadAuthorityContacts() { - alert('TODO - Implement authority contacts download') -}