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

SIMSBIOHUB-223: Observations Prototype #1097

Merged
merged 75 commits into from
Sep 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
876e34c
Initial Prototype Development
jeznorth Sep 5, 2023
84a67fb
UI Prototype Development - Adding Sampling Sites
jeznorth Sep 7, 2023
53978d9
WIP
jeznorth Sep 8, 2023
6ad7243
WIP
jeznorth Sep 8, 2023
88525d9
split up prototype to new components
KjartanE Sep 12, 2023
195db7b
SIMSBIOHUB-223: Create Observations table component
curtisupshall Sep 15, 2023
da4037a
Merge branch 'dev' into observations-prototype
curtisupshall Sep 15, 2023
32e81aa
Merge branch 'observations-prototype' into SIMSBIOHUB-223
curtisupshall Sep 15, 2023
860f07d
SIMSBIOHUB-223: Pluralize row text
curtisupshall Sep 15, 2023
9bbd025
SIMSBIOHUB-223: Create Observations context
curtisupshall Sep 18, 2023
9f24526
SIMSBIOHUB-223: Use observationContext to store table data
curtisupshall Sep 18, 2023
dc98ebc
SIMSBIOHUB-223: Fixed data fetching
curtisupshall Sep 18, 2023
06b6093
SIMSBIOHBUB-223: Relinquish edit state
curtisupshall Sep 19, 2023
1b94578
SIMSBIOHUB-223: Update table behaviour
curtisupshall Sep 19, 2023
d21f203
SIMSBIOHUB-223: Remove focus loss condition
curtisupshall Sep 19, 2023
627e1c8
Merge branch 'dev' into observations-prototype
curtisupshall Sep 19, 2023
270e823
Merge branch 'observations-prototype' into SIMSBIOHUB-223
curtisupshall Sep 19, 2023
e5de264
SIMSBIOHUB-223: Refactor prototype components
curtisupshall Sep 20, 2023
46b75dd
SIMSBIOHUB-223: More experimental changes
curtisupshall Sep 20, 2023
29ca080
SIMSBIOHUB-223: Use MUI datagrid API ref (experimental)
curtisupshall Sep 22, 2023
b2f7e39
SIMSBIOHUB-223: Changes
curtisupshall Sep 22, 2023
e62e9c9
SIMSBIOHUB-223: use updateRows method; updated data fetching
curtisupshall Sep 22, 2023
783c656
SIMSBIOHUB-223: Save/Cancel behaviour
curtisupshall Sep 22, 2023
10a18ba
SIMSBIOHUB-223: Observations migrations
curtisupshall Sep 25, 2023
810070f
SIMSBIOHUB-223: Added observation getter/setter endpoint
curtisupshall Sep 25, 2023
2d70a70
SIMSBIOHUB-223: Added endpoint logic
curtisupshall Sep 26, 2023
5aa3a32
SIMSBIOHUB-223: Insert records WIP
curtisupshall Sep 26, 2023
c4eb8b2
SISMBIOHUB-223: Added debug log
curtisupshall Sep 26, 2023
315e1f0
SIMSBIOHUB-223: Lint fix; SQL fixes
curtisupshall Sep 26, 2023
834640b
SIMSBIOHUB-223: Update datagrid and sql table to use discrete date an…
curtisupshall Sep 26, 2023
53fc02f
SIMSBIOHUB-223: createNewRecord update
curtisupshall Sep 26, 2023
9a715d9
SIMSBIOHUB-223: table updates
curtisupshall Sep 26, 2023
ef1ab23
Improve error handler
NickPhura Sep 26, 2023
4275aa9
Fix observation put endpoint type
NickPhura Sep 26, 2023
4d336ea
Add cast to datagrid type to resolve typing issue (better solution?)
NickPhura Sep 26, 2023
0dac9c8
SIMSBIOHUB-223: Update migration; some SQL WIP
curtisupshall Sep 26, 2023
79f570e
Merge branch 'dev' into observations-prototype
curtisupshall Sep 26, 2023
a61d298
SIMSBIOHUB-223: Some PR changes
curtisupshall Sep 26, 2023
fe9f71d
SIMSBIOHUB-223: SQL insertion working
curtisupshall Sep 26, 2023
ef51ccd
SIMSBIOUB-223: endpoint valiation WIP
curtisupshall Sep 26, 2023
ef09b56
Fix taxonomy api types.
NickPhura Sep 27, 2023
fd35625
WIP datagrid autocomplete for taxonomy
NickPhura Sep 27, 2023
c759317
SIMSBIOHUB-223: improved data fetching
curtisupshall Sep 27, 2023
b1d86d2
Merge branch 'observations-prototype' of github.com:bcgov/biohubbc in…
curtisupshall Sep 27, 2023
9202e09
SIMSBIOHUB-223: Fix merge import error
curtisupshall Sep 27, 2023
3169a5a
Remove WIP taxonomy autocomplete components
NickPhura Sep 27, 2023
5c34a1f
SIMSBIOHUB-223: Temp remove specieName
curtisupshall Sep 27, 2023
0d2393c
Merge branch 'observations-prototype' of github.com:bcgov/biohubbc in…
curtisupshall Sep 27, 2023
6871c3f
SIMSBIOHUB-223: Working record updating
curtisupshall Sep 27, 2023
188b7d7
SIMSBIOHUB-223: Replace speciesName with wldtaxonomic_units
curtisupshall Sep 27, 2023
b85728c
SIMSBIOHUB-223: Removed temp demo fetching; fixed observation_time ty…
curtisupshall Sep 27, 2023
5736615
SIMSBIOHUB-223: Working record creation and subsequent updating
curtisupshall Sep 27, 2023
51c9070
SIMSBIOHUB-223: Code cleanup
curtisupshall Sep 27, 2023
7839ab2
Merge branch 'dev' into observations-prototype
curtisupshall Sep 27, 2023
befa082
SISMBIOHUB-223: Lint fix; ignore-skip
curtisupshall Sep 27, 2023
7f1e4fb
SIMSBIOHUB-223: Remove prototype stuff
curtisupshall Sep 27, 2023
b67d561
SISMBIOHUB-223: Removed http-error change; added test boilerplate
curtisupshall Sep 27, 2023
2270851
SISMBIOHUB-223: Added new service and repo methods
curtisupshall Sep 28, 2023
fe52de4
Add observation repository tests.
NickPhura Sep 28, 2023
6bc2044
SIMSBIOHUB-223: Removed extra Manage Observations button from SurveyO…
curtisupshall Sep 28, 2023
446507c
Add observation service tests
NickPhura Sep 28, 2023
cb193e0
SIMSBIOHUB-223: Added req/res validation testing for PUT
curtisupshall Sep 28, 2023
46a5399
Merge branch 'observations-prototype' of github.com:bcgov/biohubbc in…
curtisupshall Sep 28, 2023
93cb861
SIMSBIOHUB-223: Finish endpoint testing
curtisupshall Sep 28, 2023
0ccc4d2
SIMSBIOHUB-223: lint fix
curtisupshall Sep 28, 2023
1201c1a
SIMSBIOHUB-223: Added mechanism for determining if rows are unsaved
curtisupshall Sep 28, 2023
1feb57f
fixed upset data loaders
al-rosenthal Sep 28, 2023
e2d8be4
SIMSBIOHUB-223: Fix some bugs; PR comments. WIP
curtisupshall Sep 28, 2023
8435c9c
Fix dataloader isMounted
NickPhura Sep 28, 2023
8f140da
Merge branch 'observations-prototype' of github.com:bcgov/biohubbc in…
curtisupshall Sep 28, 2023
977d4c9
Merge branch 'observations-prototype' of github.com:bcgov/biohubbc in…
curtisupshall Sep 28, 2023
fbbf327
SIMSBIOHUB-223: Updated latitude and longitude data types from float …
curtisupshall Sep 29, 2023
ca2d9fe
SIMSBIOHUB-223: More PR changes
curtisupshall Sep 29, 2023
40998e2
Merge branch 'dev' into observations-prototype
NickPhura Sep 29, 2023
c093844
Merge branch 'dev' into observations-prototype
NickPhura Sep 29, 2023
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

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,342 @@
import { SchemaObject } from 'ajv';
import { RequestHandler } from 'express';
import { Operation } from 'express-openapi';
import { PROJECT_PERMISSION, SYSTEM_ROLE } from '../../../../../../constants/roles';
import { getDBConnection } from '../../../../../../database/db';
import { InsertObservation, UpdateObservation } from '../../../../../../repositories/observation-repository';
import { authorizeRequestHandler } from '../../../../../../request-handlers/security/authorization';
import { ObservationService } from '../../../../../../services/observation-service';
import { getLogger } from '../../../../../../utils/logger';

const defaultLog = getLogger('/api/project/{projectId}/survey/{surveyId}/observation');

export const GET: Operation = [
authorizeRequestHandler((req) => {
return {
or: [
{
validProjectPermissions: [
PROJECT_PERMISSION.COORDINATOR,
PROJECT_PERMISSION.COLLABORATOR,
PROJECT_PERMISSION.OBSERVER
],
projectId: Number(req.params.projectId),
discriminator: 'ProjectPermission'
},
{
validSystemRoles: [SYSTEM_ROLE.DATA_ADMINISTRATOR],
discriminator: 'SystemRole'
}
]
};
}),
getSurveyObservations()
];

export const PUT: Operation = [
authorizeRequestHandler((req) => {
return {
or: [
{
validProjectPermissions: [PROJECT_PERMISSION.COORDINATOR, PROJECT_PERMISSION.COLLABORATOR],
projectId: Number(req.params.projectId),
discriminator: 'ProjectPermission'
},
{
validSystemRoles: [SYSTEM_ROLE.DATA_ADMINISTRATOR],
discriminator: 'SystemRole'
}
]
};
}),
insertUpdateSurveyObservations()
];

const surveyObservationsResponseSchema: SchemaObject = {
title: 'Survey get response object, for view purposes',
type: 'object',
nullable: true,
required: ['surveyObservations'],
properties: {
surveyObservations: {
type: 'array',
items: {
type: 'object',
required: [
'survey_observation_id',
'wldtaxonomic_units_id',
'latitude',
'longitude',
'count',
'observation_date',
'observation_time',
'create_user',
'create_date',
'update_user',
'update_date',
'revision_count'
],
properties: {
survey_observation_id: {
type: 'integer'
},
wldtaxonomic_units_id: {
type: 'integer'
},
latitude: {
type: 'number'
},
longitude: {
type: 'number'
},
count: {
type: 'integer'
},
observation_date: {
type: 'string'
},
observation_time: {
type: 'string'
},
create_date: {
oneOf: [{ type: 'object' }, { type: 'string', format: 'date' }],
description: 'ISO 8601 date string for the project start date'
},
create_user: {
type: 'integer',
minimum: 1
},
update_date: {
oneOf: [{ type: 'object' }, { type: 'string', format: 'date' }],
description: 'ISO 8601 date string for the project start date',
nullable: true
},
update_user: {
type: 'integer',
minimum: 1,
nullable: true
},
revision_count: {
type: 'integer',
minimum: 0
}
}
}
}
}
};

GET.apiDoc = {
description: 'Fetches observation records for the given survey.',
tags: ['observation'],
security: [
{
Bearer: []
}
],
parameters: [
{
in: 'path',
name: 'projectId',
schema: {
type: 'number',
minimum: 1
},
required: true
},
{
in: 'path',
name: 'surveyId',
schema: {
type: 'number',
minimum: 1
},
required: true
}
],
responses: {
200: {
description: 'Survey Observations get response.',
content: {
'application/json': {
schema: { ...surveyObservationsResponseSchema }
}
}
},
400: {
$ref: '#/components/responses/400'
},
401: {
$ref: '#/components/responses/401'
},
403: {
$ref: '#/components/responses/401'
},
500: {
$ref: '#/components/responses/500'
},
default: {
$ref: '#/components/responses/default'
}
}
};

PUT.apiDoc = {
description: 'Fetches observation records for the given survey.',
tags: ['attachments'],
security: [
{
Bearer: []
}
],
parameters: [
{
in: 'path',
name: 'projectId',
required: true
},
{
in: 'path',
name: 'surveyId',
required: true
}
],
requestBody: {
description: 'Survey observation record data',
content: {
'application/json': {
schema: {
type: 'object',
properties: {
surveyObservations: {
curtisupshall marked this conversation as resolved.
Show resolved Hide resolved
description: 'Survey observation reords.',
type: 'array',
items: {
type: 'object',
required: [
'wldtaxonomic_units_id',
'count',
'latitude',
'longitude',
'observation_date',
'observation_time'
],
properties: {
wldtaxonomic_units_id: {
oneOf: [{ type: 'integer' }, { type: 'string' }]
},
count: {
type: 'number'
},
latitude: {
type: 'number'
},
longitude: {
type: 'number'
},
observation_date: {
type: 'string'
},
observation_time: {
type: 'string'
}
}
}
}
}
}
}
}
},
responses: {
200: {
description: 'Upload OK',
content: {
'application/json': {
schema: { ...surveyObservationsResponseSchema }
}
}
},
400: {
$ref: '#/components/responses/400'
},
401: {
$ref: '#/components/responses/401'
},
403: {
$ref: '#/components/responses/401'
},
500: {
$ref: '#/components/responses/500'
},
default: {
$ref: '#/components/responses/default'
}
}
};

export function getSurveyObservations(): RequestHandler {
return async (req, res) => {
const surveyId = Number(req.params.surveyId);

defaultLog.debug({ label: 'getSurveyObservations', surveyId });

const connection = getDBConnection(req['keycloak_token']);

try {
await connection.open();

const observationService = new ObservationService(connection);

const surveyObservations = await observationService.getSurveyObservations(surveyId);
return res.status(200).json({ surveyObservations });
} catch (error) {
defaultLog.error({ label: 'getSurveyObservations', message: 'error', error });
await connection.rollback();
throw error;
} finally {
connection.release();
}
};
}

export function insertUpdateSurveyObservations(): RequestHandler {
return async (req, res) => {
const surveyId = Number(req.params.surveyId);

defaultLog.debug({ label: 'insertUpdateSurveyObservations', surveyId });

const connection = getDBConnection(req['keycloak_token']);

try {
await connection.open();

const observationService = new ObservationService(connection);

// Sanitize all incoming records
const records: (InsertObservation | UpdateObservation)[] = req.body.surveyObservations.map((record: any) => {
return {
survey_observation_id: record.survey_observation_id,
wldtaxonomic_units_id: Number(record.wldtaxonomic_units_id),
latitude: record.latitude,
longitude: record.longitude,
count: record.count,
observation_date: record.observation_date,
observation_time: record.observation_time
};
});

const surveyObservations = await observationService.insertUpdateDeleteSurveyObservations(surveyId, records);

await connection.commit();

return res.status(200).json({ surveyObservations });
} catch (error) {
defaultLog.error({ label: 'insertUpdateSurveyObservations', message: 'error', error });
await connection.rollback();
throw error;
} finally {
connection.release();
}
};
}
Loading