Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Intake form - advanced mapping component #205

Draft
wants to merge 1 commit into
base: release/mapping
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/environments/values.dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ config:
SERVER_OIDC_AUTHORITY: https://dev.loginproxy.gov.bc.ca/auth/realms/standard
SERVER_OIDC_IDENTITYKEY: idir_user_guid,bceid_user_guid,github_id
SERVER_OIDC_PUBLICKEY: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuy7zfh2ZgpDV5mH/aXyLDTddZK81rGakJcTy4KvCNOkDDxt1KAhW02lmbCo8YhHCOzjNZBp1+Vi6QiMRgBqAe2GTPZYEiV70aXfROGZe3Nvwcjbtki6HoyRte3SpqLJEIPL2F+hjJkw1UPGnjPTWZkEx9p74b9i3BjuE8RnjJ0Sza2MWw83zoQUZEJRGiopSL0yuVej6t2LO2btVdVf7QuZfPt9ehkcQYlPKpVvJA+pfeqPAdnNt7OjEIeYxinjurZr8Z04hz8UhkRefcWlSbFzFQYmL7O7iArjW0bsSvq8yNUd5r0KCOQkFduwZy26yTzTxj8OLFT91fEmbBBl4rQIDAQAB
SERVER_OPENMAPS_APIPATH: https://openmaps.gov.bc.ca
SERVER_PORT: "8080"
SERVER_SSO_APIPATH: https://api.loginproxy.gov.bc.ca/api/v1
SERVER_SSO_TOKENURL: https://loginproxy.gov.bc.ca/auth/realms/standard/protocol/openid-connect/token
Expand Down
1 change: 1 addition & 0 deletions .github/environments/values.prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ config:
SERVER_OIDC_AUTHORITY: https://loginproxy.gov.bc.ca/auth/realms/standard
SERVER_OIDC_IDENTITYKEY: idir_user_guid,bceid_user_guid
SERVER_OIDC_PUBLICKEY: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmHiuPKOkpkq4GXN1ktr23rJtDl6Vdu/Y37ZAd3PnQ8/IDfAODvy1Y81aAUZicKe9egolv+OTRANN3yOg+TAbRhkeXLE5p/473EK0aQ0NazTCuWo6Am3oDQ7Yt8x0pw56/qcLtkTuXNyo5EnVV2Z2BzCnnaL31JOhyitolku0DNT6GDoRBmT4o2ItqEVHk5nM25cf1t2zbwI2790W6if1B2qVRkxxivS8tbH7nYC61Is3XCPockKptkH22cm2ZQJmtYd5sZKuXaGsvtyzHmn8/l0Kd1xnHmUu4JNuQ67YiNZGu3hOkrF0Js3BzAk1Qm4kvYRaxbJFCs/qokLZ4Z0W9wIDAQAB
SERVER_OPENMAPS_APIPATH: https://openmaps.gov.bc.ca
SERVER_PORT: "8080"
SERVER_SSO_APIPATH: https://api.loginproxy.gov.bc.ca/api/v1
SERVER_SSO_TOKENURL: https://loginproxy.gov.bc.ca/auth/realms/standard/protocol/openid-connect/token
Expand Down
1 change: 1 addition & 0 deletions .github/environments/values.test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ config:
SERVER_OIDC_AUTHORITY: https://test.loginproxy.gov.bc.ca/auth/realms/standard
SERVER_OIDC_IDENTITYKEY: idir_user_guid,bceid_user_guid
SERVER_OIDC_PUBLICKEY: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiFdv9GA83uHuy8Eu9yiZHGGF9j6J8t7FkbcpaN81GDjwbjsIJ0OJO9dKRAx6BAtTC4ubJTBJMPvQER5ikOhIeBi4o25fg61jpgsU6oRZHkCXc9gX6mrjMjbsPaf3/bjjYxP5jicBDJQeD1oRa24+tiGggoQ7k6gDEN+cRYqqNpzC/GQbkUPk8YsgroncEgu8ChMh/3ERsLV2zorchMANUq76max16mHrhtWIQxrb/STpSt4JuSlUzzBV/dcXjJe5gywZHe0jAutFhNqjHzHdgyaC4RAd3eYQo+Kl/JOgy2AZrnx+CiPmvOJKe9tAW4k4H087ng8aVE40v4HW/FEbnwIDAQAB
SERVER_OPENMAPS_APIPATH: https://openmaps.gov.bc.ca
SERVER_PORT: "8080"
SERVER_SSO_APIPATH: https://api.loginproxy.gov.bc.ca/api/v1
SERVER_SSO_TOKENURL: https://loginproxy.gov.bc.ca/auth/realms/standard/protocol/openid-connect/token
Expand Down
8 changes: 6 additions & 2 deletions app/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,16 @@ app.use(
new URL(config.get('frontend.geocoder.apiPath')).origin,
new URL(config.get('frontend.orgbook.apiPath')).origin
],
'img-src': ["'self'", 'data:', new URL(config.get('frontend.openStreetMap.apiPath')).origin] // eslint-disable-line

'img-src': [
"'self'", // eslint-disable-line
'data:',
new URL(config.get('frontend.openStreetMap.apiPath')).origin
]
}
}
})
);

// Skip if running tests
if (process.env.NODE_ENV !== 'test') {
app.use(httpLogger);
Expand Down
3 changes: 3 additions & 0 deletions app/config/custom-environment-variables.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@
"identityKey": "SERVER_OIDC_IDENTITYKEY",
"publicKey": "SERVER_OIDC_PUBLICKEY"
},
"openMaps": {
"apiPath": "SERVER_OPENMAPS_APIPATH"
},
"port": "SERVER_PORT",
"sso": {
"apiPath": "SERVER_SSO_APIPATH",
Expand Down
26 changes: 26 additions & 0 deletions app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
},
"dependencies": {
"@prisma/client": "^5.17.0",
"@types/proj4": "^2.5.5",
"api-problem": "^9.0.2",
"axios": "^1.7.7",
"compression": "^1.7.4",
Expand All @@ -67,6 +68,7 @@
"jsonwebtoken": "^9.0.2",
"knex": "^3.1.0",
"pg": "^8.12.0",
"proj4": "^2.15.0",
"ts-node": "^10.9.2",
"uuid": "^10.0.0",
"winston": "^3.13.1",
Expand Down
1 change: 1 addition & 0 deletions app/src/controllers/submission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ const controller = {
naturalDisaster: data.location.naturalDisaster,
projectLocation: data.location.projectLocation,
projectLocationDescription: data.location.projectLocationDescription,
geoJSON: data.location.geoJSON,
locationPIDs: data.location.ltsaPIDLookup,
latitude: data.location.latitude,
longitude: data.location.longitude,
Expand Down
30 changes: 30 additions & 0 deletions app/src/db/migrations/20241127000000_016-advanced-map.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* eslint-disable max-len */
import type { Knex } from 'knex';

export async function up(knex: Knex): Promise<void> {
return Promise.resolve()
.then(() =>
knex.schema.alterTable('submission', function (table) {
table.json('geo_json');
})
)
.then(() =>
knex.schema.alterTable('submission', function (table) {
table.text('location_pids_auto');
})
);
}

export async function down(knex: Knex): Promise<void> {
return Promise.resolve() // Drop public schema tables
.then(() =>
knex.schema.alterTable('submission', function (table) {
table.dropColumn('geo_json');
})
)
.then(() =>
knex.schema.alterTable('submission', function (table) {
table.dropColumn('location_pids_auto');
})
);
}
5 changes: 5 additions & 0 deletions app/src/db/models/submission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ export default {
submitted_by: input.submittedBy,
consent_to_feedback: input.consentToFeedback,
location_pids: input.locationPIDs,
location_pids_auto: input.locationPIDsAuto,
company_name_registered: input.companyNameRegistered,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
geo_json: input.geoJSON as any,
single_family_units: input.singleFamilyUnits,
has_rental_units: input.hasRentalUnits,
street_address: input.streetAddress,
Expand Down Expand Up @@ -106,10 +109,12 @@ export default {
submittedAt: input.submitted_at?.toISOString() as string,
submittedBy: input.submitted_by,
locationPIDs: input.location_pids,
locationPIDsAuto: input.location_pids_auto,
consentToFeedback: input.consent_to_feedback,
projectName: input.project_name,
projectDescription: input.project_description,
companyNameRegistered: input.company_name_registered,
geoJSON: input.geo_json,
singleFamilyUnits: input.single_family_units,
hasRentalUnits: input.has_rental_units,
streetAddress: input.street_address,
Expand Down
2 changes: 2 additions & 0 deletions app/src/db/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,8 @@ model submission {
housing_coop_description String?
submission_type String?
consent_to_feedback Boolean @default(false)
geo_json Json? @db.Json
location_pids_auto String?
activity activity @relation(fields: [activity_id], references: [activity_id], onDelete: Cascade, map: "submission_activity_id_foreign")
user user? @relation(fields: [assigned_user_id], references: [user_id], onDelete: Cascade, map: "submission_assigned_user_id_foreign")

Expand Down
8 changes: 8 additions & 0 deletions app/src/routes/v1/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ router.use(
})
);

// router.get('/test', (_req: Request, res: Response) => {
// const url =
// 'https://openmaps.gov.bc.ca/geo/pub/wfs?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&outputFormat=json&typeName=WHSE_CADASTRE.PMBC_PARCEL_FABRIC_POLY_SVW&CQL_FILTER=INTERSECTS(SHAPE,%20POLYGON%20((1193370.672730913%20383239.8324306654,%201193348.609585723%20383168.66953196935,%201193474.1532485012%20383132.9849056583,%201193529.7406295289%20383223.5657357173,%201193370.672730913%20383239.8324306654)))';
// axios.get(url).then(function (response) {
// res.status(200).send(response.data);
// });
// });

/** OpenAPI Docs */
router.get('/', (_req: Request, res: Response) => {
res.send(docs.getDocHTML('v1'));
Expand Down
88 changes: 86 additions & 2 deletions app/src/services/submission.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable no-useless-catch */
import axios from 'axios';
import config from 'config';
import proj4 from 'proj4';

import prisma from '../db/dataConnection';
import { submission } from '../db/models';
Expand All @@ -27,14 +28,96 @@
});
}

/**
* @function openMapsAxios
* Returns an Axios instance for the CHEFS API
* @param {AxiosRequestConfig} options Axios request config options
* @returns {AxiosInstance} An axios instance
*/
function openMapsAxios(options: AxiosRequestConfig = {}): AxiosInstance {
return axios.create({
baseURL: config.get('server.openMaps.apiPath'),
timeout: 10000,
...options
});
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function getPolygonArray(geoJSON: any) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const polygonArray = geoJSON.geometry.coordinates[0].map((c: any) => {
return { lat: c[1], lng: c[0] };
});
return polygonArray;
}

/**
* @function getParcelDataFromPMBC
* DataBC’s Open Web Services
* Accessing geographic data via WMS/WFS
* Services Provided by OCIO - Digital Platforms & Data - Data Systems & Services
* ref: https://docs.geoserver.org/main/en/user/services/wfs/reference.html#getfeature
* ref: https://catalogue.data.gov.bc.ca/dataset/parcelmap-bc-parcel-fabric
* @returns parcel data in JSON
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async function getPIDs(polygon: Array<any>) {
// const { getConfig } = storeToRefs(useConfigStore());
// close polygon by re-adding first point to end of array
// const points = polygon.concat(polygon[0]);

// define the source and destination layer types
// leaflet map layer
const source = proj4.Proj('EPSG:4326'); // gps format of leaflet map
// projection (BC Parcel data layer)
proj4.defs(
'EPSG:3005',
'PROJCS["NAD83 / BC Albers", GEOGCS["NAD83", DATUM["North_American_Datum_1983", SPHEROID["GRS 1980",6378137,298.257222101, AUTHORITY["EPSG","7019"]], TOWGS84[0,0,0,0,0,0,0], AUTHORITY["EPSG","6269"]], PRIMEM["Greenwich",0, AUTHORITY["EPSG","8901"]], UNIT["degree",0.0174532925199433, AUTHORITY["EPSG","9122"]], AUTHORITY["EPSG","4269"]], PROJECTION["Albers_Conic_Equal_Area"], PARAMETER["standard_parallel_1",50], PARAMETER["standard_parallel_2",58.5], PARAMETER["latitude_of_center",45], PARAMETER["longitude_of_center",-126], PARAMETER["false_easting",1000000], PARAMETER["false_northing",0], UNIT["metre",1, AUTHORITY["EPSG","9001"]], AXIS["Easting",EAST], AXIS["Northing",NORTH], AUTHORITY["EPSG","3005"]]'

Check warning on line 75 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (20.x)

This line has a length of 714. Maximum allowed is 120

Check warning on line 75 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (20.x)

This line has a length of 714. Maximum allowed is 120

Check warning on line 75 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (18.x)

This line has a length of 714. Maximum allowed is 120

Check warning on line 75 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (18.x)

This line has a length of 714. Maximum allowed is 120

Check warning on line 75 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (16.x)

This line has a length of 714. Maximum allowed is 120

Check warning on line 75 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (16.x)

This line has a length of 714. Maximum allowed is 120

Check warning on line 75 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (20.x)

This line has a length of 714. Maximum allowed is 120

Check warning on line 75 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (18.x)

This line has a length of 714. Maximum allowed is 120

Check warning on line 75 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (16.x)

This line has a length of 714. Maximum allowed is 120

Check warning on line 75 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (20.x)

This line has a length of 714. Maximum allowed is 120

Check warning on line 75 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (18.x)

This line has a length of 714. Maximum allowed is 120

Check warning on line 75 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (16.x)

This line has a length of 714. Maximum allowed is 120
);
const dest = proj4.Proj('EPSG:3005');

// convert lat/long for WFS query
const result = polygon.map((point) => {
//@ts-expect-error please help
return proj4(source, dest, { x: point.lng, y: point.lat });
});

// built query string for WFS request
let query = '';
result.forEach((point, index, array) => {
query = query.concat(point.x, ' ', point.y);
if (index < array.length - 1) query = query.concat(', ');
});

let params =
'/geo/pub/wfs?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&outputFormat=json&typeName=WHSE_CADASTRE.PMBC_PARCEL_FABRIC_POLY_SVW&CQL_FILTER=INTERSECTS(SHAPE, POLYGON ((query)))';

Check warning on line 93 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (20.x)

This line has a length of 181. Maximum allowed is 120

Check warning on line 93 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (20.x)

This line has a length of 181. Maximum allowed is 120

Check warning on line 93 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (18.x)

This line has a length of 181. Maximum allowed is 120

Check warning on line 93 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (18.x)

This line has a length of 181. Maximum allowed is 120

Check warning on line 93 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (16.x)

This line has a length of 181. Maximum allowed is 120

Check warning on line 93 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (16.x)

This line has a length of 181. Maximum allowed is 120

Check warning on line 93 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (20.x)

This line has a length of 181. Maximum allowed is 120

Check warning on line 93 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (18.x)

This line has a length of 181. Maximum allowed is 120

Check warning on line 93 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (16.x)

This line has a length of 181. Maximum allowed is 120

Check warning on line 93 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (20.x)

This line has a length of 181. Maximum allowed is 120

Check warning on line 93 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (18.x)

This line has a length of 181. Maximum allowed is 120

Check warning on line 93 in app/src/services/submission.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (App) (16.x)

This line has a length of 181. Maximum allowed is 120

params = params.replace('query', query);

// return params;

const response = await openMapsAxios().get(params);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const parcelData = response.data.features?.map((f: any) => f.properties);
// get comma separated PIDs
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const PIDs = parcelData.map((p: any) => p.PID_FORMATTED).join(',');

return PIDs;
}

const service = {
/**
* @function createSubmission
* Creates a new submission
* @returns {Promise<Partial<Submission>>} The result of running the transaction
*/
createSubmission: async (data: Partial<Submission>) => {
const polygonArray = getPolygonArray(data.geoJSON);
const PIDs = await getPIDs(polygonArray);
data.locationPIDsAuto = PIDs;
const response = await prisma.submission.create({
//@ts-expect-error please help
data: { ...submission.toPrismaModel(data as Submission), created_at: data.createdAt, created_by: data.createdBy },
include: {
activity: {
Expand All @@ -48,7 +131,7 @@
}
}
});

//@ts-expect-error please help
return submission.fromPrismaModelWithContact(response);
},

Expand Down Expand Up @@ -352,6 +435,7 @@
updateSubmission: async (data: Submission) => {
try {
const result = await prisma.submission.update({
//@ts-expect-error please help
data: { ...submission.toPrismaModel(data), updated_at: data.updatedAt, updated_by: data.updatedBy },
where: {
submission_id: data.submissionId
Expand All @@ -368,7 +452,7 @@
}
}
});

//@ts-expect-error please help
return submission.fromPrismaModelWithContact(result);
} catch (e: unknown) {
throw e;
Expand Down
3 changes: 3 additions & 0 deletions app/src/types/Submission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ export type Submission = {
submittedAt: string;
submittedBy: string;
locationPIDs: string | null;
locationPIDsAuto: string | null;
companyNameRegistered: string | null;
consentToFeedback: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
geoJSON: any;
projectName: string | null;
projectDescription: string | null;
singleFamilyUnits: string | null;
Expand Down
1 change: 1 addition & 0 deletions app/src/types/SubmissionIntake.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export type SubmissionIntake = {
naturalDisaster?: string;
projectLocation?: string;
projectLocationDescription?: string;
geoJSON?: JSON;
ltsaPIDLookup?: string;
latitude?: number | null;
longitude?: number | null;
Expand Down
2 changes: 2 additions & 0 deletions charts/pcns/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ config:
SERVER_OIDC_IDENTITYKEY: ~
SERVER_OIDC_PUBLICKEY: ~

SERVER_OPENMAPS_APIPATH: ~

SERVER_PORT: "8080"

SERVER_SSO_APIPATH: ~
Expand Down
Loading
Loading