diff --git a/backend/src/components/utils.js b/backend/src/components/utils.js index aaf0e636..65ff6c26 100644 --- a/backend/src/components/utils.js +++ b/backend/src/components/utils.js @@ -274,6 +274,38 @@ function addDistrictLabels(jsonData, districtList) { return nonPubliclyAvailableCodes; } + function addFundingGroups(schools, fundingGroups) { + try { + // Process each school in the array + const schoolsWithFunding = schools.map(school => { + // Find the corresponding funding group by mincode + const matchingFundingGroup = fundingGroups.find(fundingGroup => + fundingGroup.mincode === school.mincode + ); + + // Add fundingGroupCode to the school + if (matchingFundingGroup) { + Object.assign(school, { + fundingGroupCode: matchingFundingGroup.fundingGroupCode, + }); + } else { + // If mincode is not found in fundingGroups, add null values + Object.assign(school, { + fundingGroupCode: null, + }); + } + + return school; + }); + + 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.'); @@ -377,4 +409,4 @@ function addDistrictLabels(jsonData, districtList) { return school; }); } - module.exports = {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}; \ No newline at end of file diff --git a/backend/src/config/index.js b/backend/src/config/index.js index c9737a49..477991ae 100644 --- a/backend/src/config/index.js +++ b/backend/src/config/index.js @@ -31,6 +31,7 @@ nconf.defaults({ maxAge: +process.env.SESSION_MAX_AGE }, instituteAPIURL: process.env.INSTITUTE_API_URL, + schoolsAPIURL: process.env.SCHOOLS_API_URL, instituteAPITokenExpiry: process.env.INSTITUTE_API_EXPIRY, clearFilesKey: process.env.CLEAR_FILES_KEY }, diff --git a/backend/src/routes/district-router.js b/backend/src/routes/district-router.js index a8e16b51..3897fc2c 100644 --- a/backend/src/routes/district-router.js +++ b/backend/src/routes/district-router.js @@ -7,21 +7,8 @@ const axios = require("axios"); const fs = require("fs"); const path = require("path"); const { checkToken } = require("../components/auth"); -const { listCache } = require("../components/cache"); -const { - 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); @@ -394,12 +381,13 @@ async function getDistrict(req, res) { }); const contactTypeCodes = await getDistrictCodes(req); - const schoolCategoryCodes = await listCache.get("categoryCodes"); - const facilityCodes = await listCache.get("facilityCodes"); - 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 = getNonPublicContactTypeCodes(contactTypeCodes); + + const districtDataPublic = removeContacts( districtDataResponse.data, nonPublicContactTypeCodes @@ -420,40 +408,9 @@ async function getDistrict(req, res) { 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"] - ); - - 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); - - // 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 - ); - } - ); - + 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 districtJSON = { districtData: districtDataPublicWithLabels, districtSchools: filteredSchoolsResponse, diff --git a/backend/src/routes/institute-router.js b/backend/src/routes/institute-router.js index 1e766d83..5507b8a6 100644 --- a/backend/src/routes/institute-router.js +++ b/backend/src/routes/institute-router.js @@ -38,8 +38,33 @@ router.get("/district/list", checkToken, getDistrictList); router.get("/district/contact/*", checkToken, getDistrictContactsAPI); router.get("/create-cache", checkToken, createCache); router.get("/category-codes", checkToken, getCategoryCodes); + 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`, + { + headers: { Authorization: `Bearer ${req.accessToken}` }, + } + ); + listCache.set("fundingGroups", fundingGroupsResponse.data); + res.json(fundingGroupsResponse.data); + } catch (error) { + const statusCode = error.response ? error.response.status : 500; + log.error("getFunding Groups Error", statusCode, error.message); + res.status(statusCode).send(error.message); + } + } else { + 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 @@ -243,7 +268,6 @@ async function createCache(req, res) { log.error("getCodesList Error", statusCode, error.message); res.status(statusCode).send(error.message); } - listCache.set("codesList", codes); } res.status(200).json({ success: true }); @@ -287,14 +311,13 @@ async function getContactTypeCodes(req, res) { districtContactTypeCodes: removeFieldsByCriteria(districtContactTypeCodesResponse.data,[{ fieldToRemove: "publiclyAvailable", value: false }]), schoolContactTypeCodes: removeFieldsByCriteria(schoolContactTypeCodesResponse.data,[{ fieldToRemove: "publiclyAvailable", value: false }]), }; - res.json(codes); listCache.set("codesList", { codesList: codes }); + res.json(codes); } catch (error) { const statusCode = error.response ? error.response.status : 500; log.error("getContactCodeList Error", statusCode, error.message); res.status(statusCode).send(error.message); } - listCache.set("codesList", codes); } else { const cachedCodeList = await listCache.get("codesList"); res.json(cachedCodeList); diff --git a/backend/src/routes/school-router.js b/backend/src/routes/school-router.js index 1ede7c29..b6908bed 100644 --- a/backend/src/routes/school-router.js +++ b/backend/src/routes/school-router.js @@ -4,7 +4,21 @@ const log = require("../components/logger"); const config = require("../config/index"); const axios = require("axios"); -const { filterRemoveByField, filterByField, filterByExpiryDate, filterIncludeByField, getArrayofPubliclyAvailableCodes, normalizeJsonObject, createSchoolCache, addDistrictLabels, formatGrades, sortJSONBySchoolCode, rearrangeAndRelabelObjectProperties, filterByPubliclyAvailableCodes} = require("../components/utils"); +const { + filterRemoveByField, + filterByField, + filterByExpiryDate, + filterIncludeByField, + getArrayofPubliclyAvailableCodes, + normalizeJsonObject, + createSchoolCache, + addDistrictLabels, + formatGrades, + sortJSONBySchoolCode, + rearrangeAndRelabelObjectProperties, + filterByPubliclyAvailableCodes, + addFundingGroups +} = require("../components/utils"); const { checkToken } = require("../components/auth"); const { schoolCache, listCache, codeCache } = require("../components/cache"); @@ -14,152 +28,295 @@ router.get("/all-contacts/:schoolCategory", checkToken, getAllSchools); router.get("/:schoolId", checkToken, getSchool); async function getSchool(req, res) { - const {schoolId} = req.params; - const contactTypeCodes= await listCache.get("codesList") - const url = `${config.get( - "server:instituteAPIURL" - )}/institute/school/` + schoolId; - axios - .get(url, { headers: { Authorization: `Bearer ${req.accessToken}` } }) - .then((response) => { - //const openSchoolList = createList(response.data, openSchoolListOptions); - const schoolGrades = [{"schoolGradeCode":"KINDHALF","label":"Kindergarten Half","description":"Kindergarten half","displayOrder":1,"effectiveDate":"2020-01-01T00:00:00","expiryDate":"2099-12-31T00:00:00"},{"schoolGradeCode":"KINDFULL","label":"Kindergarten Full","description":"Kindergarten full","displayOrder":2,"effectiveDate":"2020-01-01T00:00:00","expiryDate":"2099-12-31T00:00:00"},{"schoolGradeCode":"GRADE01","label":"Grade 1","description":"First grade","displayOrder":3,"effectiveDate":"2020-01-01T00:00:00","expiryDate":"2099-12-31T00:00:00"},{"schoolGradeCode":"GRADE02","label":"Grade 2","description":"Second grade","displayOrder":4,"effectiveDate":"2020-01-01T00:00:00","expiryDate":"2099-12-31T00:00:00"},{"schoolGradeCode":"GRADE03","label":"Grade 3","description":"Third grade","displayOrder":5,"effectiveDate":"2020-01-01T00:00:00","expiryDate":"2099-12-31T00:00:00"},{"schoolGradeCode":"GRADE04","label":"Grade 4","description":"Fourth grade","displayOrder":6,"effectiveDate":"2020-01-01T00:00:00","expiryDate":"2099-12-31T00:00:00"},{"schoolGradeCode":"GRADE05","label":"Grade 5","description":"Fifth grade","displayOrder":7,"effectiveDate":"2020-01-01T00:00:00","expiryDate":"2099-12-31T00:00:00"},{"schoolGradeCode":"GRADE06","label":"Grade 6","description":"Sixth grade","displayOrder":8,"effectiveDate":"2020-01-01T00:00:00","expiryDate":"2099-12-31T00:00:00"},{"schoolGradeCode":"GRADE07","label":"Grade 7","description":"Seventh grade","displayOrder":9,"effectiveDate":"2020-01-01T00:00:00","expiryDate":"2099-12-31T00:00:00"},{"schoolGradeCode":"ELEMUNGR","label":"Elementary Ungraded","description":"Elementary ungraded","displayOrder":10,"effectiveDate":"2020-01-01T00:00:00","expiryDate":"2099-12-31T00:00:00"},{"schoolGradeCode":"GRADE08","label":"Grade 8","description":"Eighth grade","displayOrder":11,"effectiveDate":"2020-01-01T00:00:00","expiryDate":"2099-12-31T00:00:00"},{"schoolGradeCode":"GRADE09","label":"Grade 9","description":"Ninth grade","displayOrder":12,"effectiveDate":"2020-01-01T00:00:00","expiryDate":"2099-12-31T00:00:00"},{"schoolGradeCode":"GRADE10","label":"Grade 10","description":"Tenth grade","displayOrder":13,"effectiveDate":"2020-01-01T00:00:00","expiryDate":"2099-12-31T00:00:00"},{"schoolGradeCode":"GRADE11","label":"Grade 11","description":"Eleventh grade","displayOrder":14,"effectiveDate":"2020-01-01T00:00:00","expiryDate":"2099-12-31T00:00:00"},{"schoolGradeCode":"GRADE12","label":"Grade 12","description":"Twelfth grade","displayOrder":15,"effectiveDate":"2020-01-01T00:00:00","expiryDate":"2099-12-31T00:00:00"},{"schoolGradeCode":"SECUNGR","label":"Secondary Ungraded","description":"Secondary ungraded","displayOrder":16,"effectiveDate":"2020-01-01T00:00:00","expiryDate":"2099-12-31T00:00:00"}] - const schoolData = response.data; + const { schoolId } = req.params; + const contactTypeCodes = await listCache.get("codesList"); + const fundingGroups = await listCache.get("fundingGroups"); - const includedFields = ['label', 'description']; - schoolData.contacts = normalizeJsonObject(schoolData.contacts, contactTypeCodes.codesList.schoolContactTypeCodes, 'schoolContactTypeCode', (info) => info.publiclyAvailable === true, includedFields); - - schoolData.contacts = filterByPubliclyAvailableCodes(schoolData.contacts, "schoolContactTypeCode", getArrayofPubliclyAvailableCodes(contactTypeCodes.codesList.schoolContactTypeCodes, "schoolContactTypeCode")) - schoolData.contacts = filterByExpiryDate(schoolData.contacts) - const formattedGrades = formatGrades(schoolData.grades, schoolGrades); - const schoolWithFormattedGrades = { ...schoolData, ...formattedGrades }; - res.json(schoolWithFormattedGrades); - }) - .catch((e) => { - log.error( - "getSchools Error", - e.response ? e.response.status : e.message - ); - }); + const url = + `${config.get("server:instituteAPIURL")}/institute/school/` + schoolId; + axios + .get(url, { headers: { Authorization: `Bearer ${req.accessToken}` } }) + .then((response) => { + const schoolGrades = [ + { + schoolGradeCode: "KINDHALF", + label: "Kindergarten Half", + description: "Kindergarten half", + displayOrder: 1, + effectiveDate: "2020-01-01T00:00:00", + expiryDate: "2099-12-31T00:00:00", + }, + { + schoolGradeCode: "KINDFULL", + label: "Kindergarten Full", + description: "Kindergarten full", + displayOrder: 2, + effectiveDate: "2020-01-01T00:00:00", + expiryDate: "2099-12-31T00:00:00", + }, + { + schoolGradeCode: "GRADE01", + label: "Grade 1", + description: "First grade", + displayOrder: 3, + effectiveDate: "2020-01-01T00:00:00", + expiryDate: "2099-12-31T00:00:00", + }, + { + schoolGradeCode: "GRADE02", + label: "Grade 2", + description: "Second grade", + displayOrder: 4, + effectiveDate: "2020-01-01T00:00:00", + expiryDate: "2099-12-31T00:00:00", + }, + { + schoolGradeCode: "GRADE03", + label: "Grade 3", + description: "Third grade", + displayOrder: 5, + effectiveDate: "2020-01-01T00:00:00", + expiryDate: "2099-12-31T00:00:00", + }, + { + schoolGradeCode: "GRADE04", + label: "Grade 4", + description: "Fourth grade", + displayOrder: 6, + effectiveDate: "2020-01-01T00:00:00", + expiryDate: "2099-12-31T00:00:00", + }, + { + schoolGradeCode: "GRADE05", + label: "Grade 5", + description: "Fifth grade", + displayOrder: 7, + effectiveDate: "2020-01-01T00:00:00", + expiryDate: "2099-12-31T00:00:00", + }, + { + schoolGradeCode: "GRADE06", + label: "Grade 6", + description: "Sixth grade", + displayOrder: 8, + effectiveDate: "2020-01-01T00:00:00", + expiryDate: "2099-12-31T00:00:00", + }, + { + schoolGradeCode: "GRADE07", + label: "Grade 7", + description: "Seventh grade", + displayOrder: 9, + effectiveDate: "2020-01-01T00:00:00", + expiryDate: "2099-12-31T00:00:00", + }, + { + schoolGradeCode: "ELEMUNGR", + label: "Elementary Ungraded", + description: "Elementary ungraded", + displayOrder: 10, + effectiveDate: "2020-01-01T00:00:00", + expiryDate: "2099-12-31T00:00:00", + }, + { + schoolGradeCode: "GRADE08", + label: "Grade 8", + description: "Eighth grade", + displayOrder: 11, + effectiveDate: "2020-01-01T00:00:00", + expiryDate: "2099-12-31T00:00:00", + }, + { + schoolGradeCode: "GRADE09", + label: "Grade 9", + description: "Ninth grade", + displayOrder: 12, + effectiveDate: "2020-01-01T00:00:00", + expiryDate: "2099-12-31T00:00:00", + }, + { + schoolGradeCode: "GRADE10", + label: "Grade 10", + description: "Tenth grade", + displayOrder: 13, + effectiveDate: "2020-01-01T00:00:00", + expiryDate: "2099-12-31T00:00:00", + }, + { + schoolGradeCode: "GRADE11", + label: "Grade 11", + description: "Eleventh grade", + displayOrder: 14, + effectiveDate: "2020-01-01T00:00:00", + expiryDate: "2099-12-31T00:00:00", + }, + { + schoolGradeCode: "GRADE12", + label: "Grade 12", + description: "Twelfth grade", + displayOrder: 15, + effectiveDate: "2020-01-01T00:00:00", + expiryDate: "2099-12-31T00:00:00", + }, + { + schoolGradeCode: "SECUNGR", + label: "Secondary Ungraded", + description: "Secondary ungraded", + displayOrder: 16, + effectiveDate: "2020-01-01T00:00:00", + expiryDate: "2099-12-31T00:00:00", + }, + ]; + const schoolData = response.data; + + const includedFields = ["label", "description"]; + schoolData.contacts = normalizeJsonObject( + schoolData.contacts, + contactTypeCodes.codesList.schoolContactTypeCodes, + "schoolContactTypeCode", + (info) => info.publiclyAvailable === true, + includedFields + ); + + schoolData.contacts = filterByPubliclyAvailableCodes( + schoolData.contacts, + "schoolContactTypeCode", + getArrayofPubliclyAvailableCodes( + contactTypeCodes.codesList.schoolContactTypeCodes, + "schoolContactTypeCode" + ) + ); + schoolData.contacts = filterByExpiryDate(schoolData.contacts); + const formattedGrades = formatGrades(schoolData.grades, schoolGrades); + const schoolWithFormattedGrades = [{ ...schoolData, ...formattedGrades }]; + + const schoolsWithFundingGroups = addFundingGroups(schoolWithFormattedGrades, fundingGroups) + res.json(schoolsWithFundingGroups[0]); + + }) + .catch((e) => { + log.error("getSchools Error", e.response ? e.response.status : e.message); + }); } async function getAllSchoolMailing(req, res) { - const allSchools = await getAllSchools(req,res) - res.json(allSchools) - + const allSchools = await getAllSchools(req, res); + res.json(allSchools); } async function getAllSchools(req, res) { - const {schoolCategory} = req.params - const contactTypeCodes= await listCache.get("codesList") + const { schoolCategory } = req.params; + const contactTypeCodes = await listCache.get("codesList"); let params = []; - if (await !schoolCache.has("openschoollist" + schoolCategory)) { - let currentDate = new Date().toISOString().substring(0, 19) - params = [ - - { - condition: 'AND', - searchCriteriaList: [ - { - key: "openedDate", - operation: "lte", - value: currentDate, - valueType: "DATE_TIME", - condition: "AND", - } - ], - }, - { - condition: 'AND', - searchCriteriaList: [ - { - key: "closedDate", - operation: "eq", - value: null, - valueType: "STRING", - condition: "OR", - }, - { - key: "closedDate", - operation: "gte", - value: currentDate, - valueType: "DATE_TIME", - condition: "OR", - }, - ], - }, - { - condition: 'AND', - searchCriteriaList: [ - { - key: "schoolCategoryCode", - operation: "neq", - value: "FED_BAND", - valueType: "STRING", - condition: "AND", - }, - { - key: "facilityTypeCode", - operation: "neq", - value: "SUMMER", - valueType: "STRING", - condition: "AND", - }, - ], - } - ]; - const jsonString = JSON.stringify(params); - const encodedParams = encodeURIComponent(jsonString); - const districtList = await listCache.get("districtlist") - const schoolGrades = await codeCache.get("gradelist"); - const schoolCategoryCodes = await listCache.get("categoryCodes"); - const facilityCodes = await listCache.get("facilityCodes"); - const url = `${config.get( - "server:instituteAPIURL" - )}/institute/school/paginated?pageSize=4000&searchCriteriaList=${encodedParams}`; - axios - .get(url, { headers: { Authorization: `Bearer ${req.accessToken}` } }) - .then((response) => { - - const propertyOrder = [ - - { property: "districtNumber", label: "District Number" }, - { property: "mincode", label: "School Code" }, - { property: "displayName", label: "School Name" }, - { property: "mailing_addressLine1", label: "Address" }, - { property: "mailing_city", label: "City" }, - { property: "mailing_provinceCode", label: "Province" }, - { property: "mailing_postal", label: "Postal Code" }, - // { property: "principalTitle", label: "Principal Title" }, - { property: "firstName", label: "Principal First Name" }, - { property: "lastName", label: "Principal Last Name" }, - { property: "facilityTypeCode", label: "Type" }, - { property: "facilityTypeCode_description", label: "Type" }, - { property: "schoolCategoryCode_description", label: "School Category" }, - // { property: "gradeRange", label: "Grade Range" }, - // { property: "fundingGroups", label: "Funding Group(s)" }, - { property: "phoneNumber", label: "Phone" }, - { property: "faxNumber", label: "Fax" }, - { property: "email", label: "Email" }, - { property: "KINDHALF", label: "Kindergarten Half Enrollment" }, - { property: "KINDFULL", label: "Kindergarten Full Enrollment" }, - { property: "GRADE01", label: "Grade 1 Enrollment" }, - { property: "GRADE02", label: "Grade 2 Enrollment" }, - { property: "GRADE03", label: "Grade 3 Enrollment" }, - { property: "GRADE04", label: "Grade 4 Enrollment" }, - { property: "GRADE05", label: "Grade 5 Enrollment" }, - { property: "GRADE06", label: "Grade 6 Enrollment" }, - { property: "GRADE07", label: "Grade 7 Enrollment" }, - { property: "GRADE08", label: "Grade 8 Enrollment" }, - { property: "GRADE09", label: "Grade 9 Enrollment" }, - { property: "GRADE10", label: "Grade 10 Enrollment" }, - { property: "GRADE11", label: "Grade 11 Enrollment" }, - { property: "GRADE12", label: "Grade 12 Enrollment" } - + let currentDate = new Date().toISOString().substring(0, 19); + params = [ + { + condition: "AND", + searchCriteriaList: [ + { + key: "openedDate", + operation: "lte", + value: currentDate, + valueType: "DATE_TIME", + condition: "AND", + }, + ], + }, + { + condition: "AND", + searchCriteriaList: [ + { + key: "closedDate", + operation: "eq", + value: null, + valueType: "STRING", + condition: "OR", + }, + { + key: "closedDate", + operation: "gte", + value: currentDate, + valueType: "DATE_TIME", + condition: "OR", + }, + ], + }, + { + condition: "AND", + searchCriteriaList: [ + { + key: "schoolCategoryCode", + operation: "neq", + value: "FED_BAND", + valueType: "STRING", + condition: "AND", + }, + { + key: "facilityTypeCode", + operation: "neq", + value: "SUMMER", + valueType: "STRING", + condition: "AND", + }, + ], + }, + ]; + const jsonString = JSON.stringify(params); + const encodedParams = encodeURIComponent(jsonString); + const districtList = await listCache.get("districtlist"); + const schoolGrades = await codeCache.get("gradelist"); + const schoolCategoryCodes = await listCache.get("categoryCodes"); + const fundingGroups = await listCache.get("fundingGroups"); + const facilityCodes = await listCache.get("facilityCodes"); + const url = `${config.get( + "server:instituteAPIURL" + )}/institute/school/paginated?pageSize=4000&searchCriteriaList=${encodedParams}`; + axios + .get(url, { headers: { Authorization: `Bearer ${req.accessToken}` } }) + .then((response) => { + const propertyOrder = [ + { property: "districtNumber", label: "District Number" }, + { property: "mincode", label: "School Code" }, + { property: "displayName", label: "School Name" }, + { property: "mailing_addressLine1", label: "Address" }, + { property: "mailing_city", label: "City" }, + { property: "mailing_provinceCode", label: "Province" }, + { property: "mailing_postal", label: "Postal Code" }, + { property: "physical_addressLine1", label: "Physical Address" }, + { property: "physical_city", label: "Physical City" }, + { property: "physical_provinceCode", label: "Physical Province" }, + { property: "physical_postal", label: "Physical Postal Code" }, + { property: "firstName", label: "Principal First Name" }, + { property: "lastName", label: "Principal Last Name" }, + { property: "facilityTypeCode", label: "Type" }, + { property: "facilityTypeCode_description", label: "Type" }, + { + property: "schoolCategoryCode_description", + label: "School Category", + }, + // { property: "gradeRange", label: "Grade Range" }, + // { property: "fundingGroups", label: "Funding Group(s)" }, + { property: "phoneNumber", label: "Phone" }, + { property: "faxNumber", label: "Fax" }, + { property: "email", label: "Email" }, + { property: "KINDHALF", label: "Kindergarten Half Enrollment" }, + { property: "KINDFULL", label: "Kindergarten Full Enrollment" }, + { property: "GRADE01", label: "Grade 1 Enrollment" }, + { property: "GRADE02", label: "Grade 2 Enrollment" }, + { property: "GRADE03", label: "Grade 3 Enrollment" }, + { property: "GRADE04", label: "Grade 4 Enrollment" }, + { property: "GRADE05", label: "Grade 5 Enrollment" }, + { property: "GRADE06", label: "Grade 6 Enrollment" }, + { property: "GRADE07", label: "Grade 7 Enrollment" }, + { property: "GRADE08", label: "Grade 8 Enrollment" }, + { property: "GRADE09", label: "Grade 9 Enrollment" }, + { property: "GRADE10", label: "Grade 10 Enrollment" }, + { property: "GRADE11", label: "Grade 11 Enrollment" }, + { property: "GRADE12", label: "Grade 12 Enrollment" }, + { property: "fundingGroupCode", label: "Funding Group" }, ]; const mailingListpropertyOrder = [ - { property: "districtNumber", label: "District Number" }, { property: "mincode", label: "School Code" }, { property: "displayName", label: "School Name" }, @@ -170,66 +327,104 @@ async function getAllSchools(req, res) { { property: "physical_addressLine1", label: "Courier Address" }, { property: "physical_city", label: "Courier City" }, { property: "physical_provinceCode", label: "Courier Province" }, - { property: "physical_postal", label: "Courier Postal Code" }, + { property: "physical_postal", label: "Courier Postal Code" }, { property: "phoneNumber", label: "Phone" }, - - ]; - - const openSchoolListWithDistrictLabels = addDistrictLabels(response.data, districtList) - let openSchoolList = sortJSONBySchoolCode(createSchoolCache(openSchoolListWithDistrictLabels.content, schoolGrades)); - let openSchoolMailingList = [...openSchoolList]; - - openSchoolList = normalizeJsonObject(openSchoolList, schoolCategoryCodes, 'schoolCategoryCode', null, ['label','description']); - openSchoolList = normalizeJsonObject(openSchoolList, facilityCodes, 'facilityTypeCode', null, ['label','description']); + ]; + const openSchoolListWithDistrictLabels = addDistrictLabels( + response.data, + districtList + ); + let openSchoolListSorted = sortJSONBySchoolCode( + createSchoolCache( + openSchoolListWithDistrictLabels.content, + schoolGrades + ) + ); + openSchoolList = addFundingGroups(openSchoolListSorted, fundingGroups) + let openSchoolMailingList = [...openSchoolList]; + + openSchoolList = normalizeJsonObject( + openSchoolList, + schoolCategoryCodes, + "schoolCategoryCode", + null, + ["label", "description"] + ); + + openSchoolList = normalizeJsonObject( + openSchoolList, + facilityCodes, + "facilityTypeCode", + null, + ["label", "description"] + ); openSchoolList.forEach((currentElement, index, array) => { - const rearrangedElement = rearrangeAndRelabelObjectProperties(currentElement, propertyOrder); + const rearrangedElement = rearrangeAndRelabelObjectProperties( + currentElement, + propertyOrder + ); array[index] = rearrangedElement; }); - openSchoolList = filterRemoveByField(openSchoolList,"District Number", ["098","102","103", ""]) - + openSchoolList = filterRemoveByField( + openSchoolList, + "District Number", + ["098", "102", "103", ""] + ); + openSchoolMailingList.forEach((currentElement, index, array) => { - const rearrangedElement = rearrangeAndRelabelObjectProperties(currentElement, mailingListpropertyOrder); + const rearrangedElement = rearrangeAndRelabelObjectProperties( + currentElement, + mailingListpropertyOrder + ); array[index] = rearrangedElement; - }); - openSchoolMailingList = filterRemoveByField(openSchoolMailingList,"District Number", ["098","102","103", ""]) - - + }); + openSchoolMailingList = filterRemoveByField( + openSchoolMailingList, + "District Number", + ["098", "102", "103", ""] + ); - const openINDEPENDSchoolList = filterIncludeByField(openSchoolList, "School Category", ["Independent School"] ); - schoolCache.set("openschoollistINDEPEND", openINDEPENDSchoolList); - - const openPUBLICSchoolList = filterIncludeByField(openSchoolList, "School Category", ["Public School"] ); - schoolCache.set("openschoollistPUBLIC", openPUBLICSchoolList); - - schoolCache.set("openschoollistALL", openSchoolList); - schoolCache.set("openschoollistALLMAILING", openSchoolMailingList); + const openINDEPENDSchoolList = filterIncludeByField( + openSchoolList, + "School Category", + ["Independent School", "Independent First Nations School"] + ); + schoolCache.set("openschoollistINDEPEND", openINDEPENDSchoolList); - if(schoolCategory== "INDEPEND"){ - res.json(openINDEPENDSchoolList); - }else if(schoolCategory== "PUBLIC"){ - res.json(openPUBLICSchoolList); - }else if(schoolCategory== "ALL"){ - res.json(openSchoolList); - } - else if(schoolCategory== "ALLMAILING"){ - res.json(openSchoolMailingList); - } - - - log.info(req.url); - }) - .catch((e) => { - log.error( - "getAllSchoolsList Error", - e.response ? e.response.status : e.message - ); - }); + const openPUBLICSchoolList = filterIncludeByField( + openSchoolList, + "School Category", + ["Public School"] + ); + schoolCache.set("openschoollistPUBLIC", openPUBLICSchoolList); + + schoolCache.set("openschoollistALL", openSchoolList); + schoolCache.set("openschoollistALLMAILING", openSchoolMailingList); + if (schoolCategory == "INDEPEND") { + res.json(openINDEPENDSchoolList); + } else if (schoolCategory == "PUBLIC") { + res.json(openPUBLICSchoolList); + } else if (schoolCategory == "ALL") { + res.json(openSchoolList); + } else if (schoolCategory == "ALLMAILING") { + res.json(openSchoolMailingList); + } + + log.info(req.url); + }) + .catch((e) => { + log.error( + "getAllSchoolsList Error", + e.response ? e.response.status : e.message + ); + }); } else { - const openSchoolList = await schoolCache.get("openschoollist" + schoolCategory); + const openSchoolList = await schoolCache.get( + "openschoollist" + schoolCategory + ); res.json(openSchoolList); } } -module.exports = router; - +module.exports = router; \ No newline at end of file diff --git a/backend/src/routes/search-router.js b/backend/src/routes/search-router.js index 5bf8b929..85b9b8ba 100644 --- a/backend/src/routes/search-router.js +++ b/backend/src/routes/search-router.js @@ -8,15 +8,18 @@ const fs = require("fs"); const path = require("path"); const { checkToken } = require("../components/auth"); const { listCache } = require("../components/cache"); -const {appendMailingAddressDetailsAndRemoveAddresses, rearrangeAndRelabelObjectProperties, sortByProperty} = require("../components/utils.js") +const {addFundingGroups, appendMailingAddressDetailsAndRemoveAddresses, rearrangeAndRelabelObjectProperties, sortByProperty} = require("../components/utils.js") //Batch Routes router.get("/*", checkToken, getSearchResults) async function getSearchResults(req, res) { - + const fundingGroups = await listCache.get("fundingGroups") const url = `${config.get("server:instituteAPIURL")}`+ req.url; axios .get(url, { headers: { Authorization: `Bearer ${req.accessToken}` } }) .then((response) => { + const results = response.data.content; + const resultsWithFundingGroups = addFundingGroups(results, fundingGroups); + response.data.content = resultsWithFundingGroups; res.json(response.data); }) .catch((e) => { diff --git a/frontend/src/components/common/DisplayAlert.vue b/frontend/src/components/common/DisplayAlert.vue index 2b5f8acf..e2735140 100644 --- a/frontend/src/components/common/DisplayAlert.vue +++ b/frontend/src/components/common/DisplayAlert.vue @@ -4,8 +4,10 @@ The information on this page is provided by schools and districts through the Education Data Exchange (EDX). - Learn more.Learn more. +
If you represent an Independent School or Independent Authority and have not yet been + onboarded to EDX, please email + Independent Schools Office to + update your contact information. diff --git a/frontend/src/types/types.d.ts b/frontend/src/types/types.d.ts index d59e444c..14ac2fa1 100644 --- a/frontend/src/types/types.d.ts +++ b/frontend/src/types/types.d.ts @@ -131,6 +131,7 @@ export interface School { grades: Grade[]; contacts: SchoolContact[]; addresses: Address[]; + fundingGroupCode: string; notes?: []; } diff --git a/frontend/src/views/ContactsView.vue b/frontend/src/views/ContactsView.vue index 23c01c65..16a9b3e2 100644 --- a/frontend/src/views/ContactsView.vue +++ b/frontend/src/views/ContactsView.vue @@ -55,6 +55,12 @@ const transformContactForDownload = (inputData: any) => { email: item.email })) } +const filterOutYukon = (inputData: any) => { + return inputData.filter( + (contact: { districtId: string }) => + contact.districtId !== '54396317-b444-063d-779e-e4d42ff7634f' + ) +} const searchContact = async () => { // Filter contacts based on selected filters let currentDate = new Date().toISOString().substring(0, 19) @@ -65,6 +71,27 @@ const searchContact = async () => { } ] if (selectedContactType.value) { + params[0].searchCriteriaList.push({ + key: 'expiryDate', + operation: 'eq', + value: null, + valueType: 'STRING', + condition: 'OR' + }) + params[0].searchCriteriaList.push({ + key: 'expiryDate', + operation: 'gte', + value: currentDate, + valueType: 'DATE_TIME', + condition: 'OR' + }) + params[0].searchCriteriaList.push({ + key: 'effectiveDate', + operation: 'lte', + value: currentDate, + valueType: 'DATE_TIME', + condition: 'AND' + }) params[0].searchCriteriaList.push({ key: 'districtContactTypeCode', operation: 'eq', @@ -72,11 +99,26 @@ const searchContact = async () => { valueType: 'STRING', condition: 'AND' }) + } else { params[0].searchCriteriaList.push({ key: 'expiryDate', operation: 'eq', value: null, valueType: 'STRING', + condition: 'OR' + }) + params[0].searchCriteriaList.push({ + key: 'expiryDate', + operation: 'gte', + value: currentDate, + valueType: 'DATE_TIME', + condition: 'OR' + }) + params[0].searchCriteriaList.push({ + key: 'effectiveDate', + operation: 'lte', + value: currentDate, + valueType: 'DATE_TIME', condition: 'AND' }) } @@ -89,7 +131,8 @@ const searchContact = async () => { } try { const searchResults = await InstituteService.searchContactByType(req) - filteredContacts.value = transformContactForDownload(searchResults.data.content) + const yukonFilteredContacts = filterOutYukon(searchResults.data.content) + filteredContacts.value = transformContactForDownload(yukonFilteredContacts) results.value = searchResults.data.totalElements // Update current page and total pages totalPages.value = searchResults.data.totalPages diff --git a/frontend/src/views/DistrictView.vue b/frontend/src/views/DistrictView.vue index 514f8ec7..24ad010f 100644 --- a/frontend/src/views/DistrictView.vue +++ b/frontend/src/views/DistrictView.vue @@ -137,7 +137,8 @@ onMounted(async () => { 'Phone Number': item.phoneNumber, Fax: item.faxNumber, Email: item.email, - Website: item.website + Website: item.website, + 'Funding Group': item.fundingGroupCode } }) filteredContacts.value = contacts.value.map((item: any) => { diff --git a/frontend/src/views/SchoolSearchView.vue b/frontend/src/views/SchoolSearchView.vue index 874878d1..fe65454d 100644 --- a/frontend/src/views/SchoolSearchView.vue +++ b/frontend/src/views/SchoolSearchView.vue @@ -331,6 +331,10 @@ onBeforeMount(async () => { + + Funding
+ Group: {{ item.fundingGroupCode }}
+
diff --git a/frontend/src/views/SchoolView.vue b/frontend/src/views/SchoolView.vue index b0b7046e..60137c67 100644 --- a/frontend/src/views/SchoolView.vue +++ b/frontend/src/views/SchoolView.vue @@ -172,6 +172,7 @@ onBeforeMount(async () => { filteredContacts.value[i].GRADE11 = response.data.GRADE11 filteredContacts.value[i].GRADE12 = response.data.GRADE12 } + downloadContacts.value = transformContactForDownload(filteredContacts.value) } } @@ -259,6 +260,10 @@ function goToDistrict() { + + Funding:
+ Group: {{ schoolData.value.fundingGroupCode }}
+