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 87e09f86..84a20527 100644 --- a/backend/src/components/utils.js +++ b/backend/src/components/utils.js @@ -77,7 +77,7 @@ function removeFieldsByCriteria(inputData, criteria) { } function appendMailingAddressDetailsAndRemoveAddresses(data) { if (data && data.addresses && data.addresses.length > 0) { - const physicalAddress = data.addresses.find( + const physicalAddress = data.addresses?.find( (address) => address.addressTypeCode === "PHYSICAL" ); if (physicalAddress) { @@ -101,7 +101,7 @@ function appendMailingAddressDetailsAndRemoveAddresses(data) { // Remove the "addresses" property } - const courierAddress = data.addresses.find( + const courierAddress = data.addresses?.find( (address) => address.addressTypeCode === "MAILING" ); if (courierAddress) { @@ -132,7 +132,7 @@ function appendMailingAddressDetailsAndRemoveAddresses(data) { function addDistrictLabels(jsonData, districtList) { if (jsonData.content && Array.isArray(jsonData.content)) { jsonData.content.forEach((dataItem) => { - const district = districtList.find( + const district = districtList?.find( (item) => item.districtId === dataItem.districtId ); if (district) { @@ -229,7 +229,7 @@ function normalizeJsonObject( includeFields ) { return sourceArray.map((item) => { - const matchingItem = referenceArray.find( + const matchingItem = referenceArray?.find( (info) => info[matchKey] === item[matchKey] && (!condition || condition(info)) ); @@ -402,7 +402,7 @@ function createSchoolCache(schoolData, schoolGrades) { }); // Extract and format principal contact information if it exists - const principalContact = school.contacts.find( + const principalContact = school.contacts?.find( (contact) => contact.schoolContactTypeCode === "PRINCIPAL" ); if (principalContact) { diff --git a/backend/src/routes/district-router.js b/backend/src/routes/district-router.js index 5a26a2e7..01be26d9 100644 --- a/backend/src/routes/district-router.js +++ b/backend/src/routes/district-router.js @@ -47,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 ); @@ -93,7 +93,7 @@ async function getDistrictCodes(req) { return districtCodeList; } catch (e) { log.error( - "getDistrictList Error", + "getDistrictCodesList Error", e.response ? e.response.status : e.message ); } @@ -250,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" }, @@ -323,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; @@ -424,8 +421,9 @@ async function getDistrict(req, res) { const facilityCodes = await listCache.get("facilityCodes"); const fundingGroups = await listCache.get("fundingGroups"); const districtContactCodeTypes = await listCache.get("codesList"); - const nonPublicContactTypeCodes = - getNonPublicContactTypeCodes(contactTypeCodes); + const nonPublicContactTypeCodes = await getNonPublicContactTypeCodes( + contactTypeCodes + ); const districtDataPublic = removeContacts( districtDataResponse.data, @@ -435,36 +433,37 @@ 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( 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') -}