-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add environmental variables & sampling methods to standards page (#1325)
* initial commit from transferring otu of method-standards * quick div to box fix for header not showing * Moving components around based off of Mac's suggestions. * update standards page layout * mock method data * environment standards * add backend tests * replace getApiUserDBConnection with getDBConnection temporarily * lots of changes, MethodStandards Card and results, API path, sessions wih Macgregor * formatting, fixing SQL, adding unit chip * some fies to font, color, chevrons, chip etc * simplify standard cards * write tests * species standards loading state * fix missing keys * shade of grey * ignore-skip * fix: removed bad import from merge conflict * remove security from standards endpoints & address PR comments --------- Co-authored-by: Macgregor Aubertin-Young <macgregor.aubertin-young@gov.bc.ca> Co-authored-by: Macgregor Aubertin-Young <108430771+mauberti-bc@users.noreply.github.com> Co-authored-by: Mac Deluca <99926243+MacQSL@users.noreply.github.com> Co-authored-by: Mac Deluca <Mac.Deluca@quartech.com>
- Loading branch information
1 parent
c276f1b
commit d50c70f
Showing
34 changed files
with
1,632 additions
and
395 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { z } from 'zod'; | ||
import { | ||
CBQualitativeMeasurementTypeDefinition, | ||
CBQuantitativeMeasurementTypeDefinition | ||
} from '../services/critterbase-service'; | ||
|
||
const QualitativeMeasurementSchema = z.object({ | ||
name: z.string(), | ||
description: z.string().nullable(), | ||
options: z.array( | ||
z.object({ | ||
name: z.string(), | ||
description: z.string().nullable() | ||
}) | ||
) | ||
}); | ||
|
||
const QuantitativeMeasurementSchema = z.object({ | ||
name: z.string(), | ||
description: z.string().nullable(), | ||
unit: z.string().nullable() | ||
}); | ||
|
||
const MethodAttributesSchema = z.object({ | ||
qualitative: z.array(QualitativeMeasurementSchema), | ||
quantitative: z.array(QuantitativeMeasurementSchema) | ||
}); | ||
|
||
export const EnvironmentStandardsSchema = z.object({ | ||
qualitative: z.array(QualitativeMeasurementSchema), | ||
quantitative: z.array(QuantitativeMeasurementSchema) | ||
}); | ||
|
||
export type EnvironmentStandards = z.infer<typeof EnvironmentStandardsSchema>; | ||
|
||
export const MethodStandardSchema = z.object({ | ||
method_lookup_id: z.number(), | ||
name: z.string(), | ||
description: z.string().nullable(), | ||
attributes: MethodAttributesSchema | ||
}); | ||
|
||
export type MethodStandard = z.infer<typeof MethodStandardSchema>; | ||
|
||
export interface ISpeciesStandards { | ||
tsn: number; | ||
scientificName: string; | ||
measurements: { | ||
quantitative: CBQuantitativeMeasurementTypeDefinition[]; | ||
qualitative: CBQualitativeMeasurementTypeDefinition[]; | ||
}; | ||
markingBodyLocations: { id: string; key: string; value: string }[]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
import { OpenAPIV3 } from 'openapi-types'; | ||
|
||
export const EnvironmentStandardsSchema: OpenAPIV3.SchemaObject = { | ||
type: 'object', | ||
description: | ||
'Environment standards response object showing supported environmental variables and associated information', | ||
additionalProperties: false, | ||
properties: { | ||
qualitative: { | ||
type: 'array', | ||
description: 'Array of qualitative environmental variables', | ||
items: { | ||
type: 'object', | ||
properties: { | ||
name: { | ||
type: 'string', | ||
description: 'Name of the environmental variable' | ||
}, | ||
description: { | ||
type: 'string', | ||
description: 'Description of the environmental variable', | ||
nullable: true | ||
}, | ||
options: { | ||
type: 'array', | ||
description: 'Array of options for the qualitative variable', | ||
items: { | ||
type: 'object', | ||
properties: { | ||
name: { | ||
type: 'string', | ||
description: 'Description of the environmental variable option' | ||
}, | ||
description: { | ||
type: 'string', | ||
description: 'Description of the environmental variable option', | ||
nullable: true | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
quantitative: { | ||
type: 'array', | ||
description: 'Array of quantitative environmental variables', | ||
items: { | ||
type: 'object', | ||
properties: { | ||
name: { | ||
type: 'string', | ||
description: 'Name of the quantitative environmental variable' | ||
}, | ||
description: { | ||
type: 'string', | ||
description: 'Description of the quantitative environmental variable', | ||
nullable: true | ||
}, | ||
unit: { | ||
type: 'string', | ||
description: 'Unit of measurement of the quantitative environmental variable', | ||
nullable: true | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
|
||
export const MethodStandardSchema: OpenAPIV3.SchemaObject = { | ||
type: 'array', | ||
items: { | ||
type: 'object', | ||
additionalProperties: false, | ||
properties: { | ||
method_lookup_id: { type: 'number' }, | ||
name: { type: 'string' }, | ||
description: { type: 'string', nullable: true }, | ||
attributes: { | ||
type: 'object', | ||
additionalProperties: false, | ||
properties: { | ||
qualitative: { | ||
type: 'array', | ||
items: { | ||
type: 'object', | ||
additionalProperties: false, | ||
properties: { | ||
name: { | ||
type: 'string' | ||
}, | ||
description: { | ||
type: 'string', | ||
nullable: true | ||
}, | ||
options: { | ||
type: 'array', | ||
items: { | ||
type: 'object', | ||
additionalProperties: false, | ||
properties: { | ||
name: { | ||
type: 'string' | ||
}, | ||
description: { | ||
type: 'string', | ||
nullable: true | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
quantitative: { | ||
type: 'array', | ||
items: { | ||
type: 'object', | ||
additionalProperties: false, | ||
properties: { | ||
name: { | ||
type: 'string' | ||
}, | ||
description: { | ||
type: 'string', | ||
nullable: true | ||
}, | ||
unit: { type: 'string', nullable: true } | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import chai, { expect } from 'chai'; | ||
import { afterEach, describe, it } from 'mocha'; | ||
import sinon from 'sinon'; | ||
import sinonChai from 'sinon-chai'; | ||
import * as db from '../../../database/db'; | ||
import { HTTPError } from '../../../errors/http-error'; | ||
import { StandardsService } from '../../../services/standards-service'; | ||
import { getMockDBConnection, getRequestHandlerMocks } from '../../../__mocks__/db'; | ||
import { getEnvironmentStandards } from './index'; // Adjust the import path based on your file structure | ||
|
||
chai.use(sinonChai); | ||
|
||
describe('standards/environment', () => { | ||
describe('getEnvironmentStandards', () => { | ||
afterEach(() => { | ||
sinon.restore(); | ||
}); | ||
|
||
it('should retrieve environment standards successfully', async () => { | ||
const mockResponse = { | ||
quantitative: [ | ||
{ name: 'Quantitative Standard 1', description: 'Description 1', unit: 'Unit' }, | ||
{ name: 'Quantitative Standard 2', description: 'Description 2', unit: 'Unit' } | ||
], | ||
qualitative: [ | ||
{ | ||
name: 'Qualitative Standard 1', | ||
description: 'Description 1', | ||
options: [ | ||
{ name: 'Option 1', description: 'Option 1 Description' }, | ||
{ name: 'Option 2', description: 'Option 2 Description' } | ||
] | ||
}, | ||
{ | ||
name: 'Qualitative Standard 2', | ||
description: 'Description 2', | ||
options: [ | ||
{ name: 'Option 3', description: 'Option 3 Description' }, | ||
{ name: 'Option 4', description: 'Option 4 Description' } | ||
] | ||
} | ||
] | ||
}; | ||
|
||
const mockDBConnection = getMockDBConnection(); | ||
|
||
sinon.stub(db, 'getAPIUserDBConnection').returns(mockDBConnection); | ||
|
||
sinon.stub(StandardsService.prototype, 'getEnvironmentStandards').resolves(mockResponse); | ||
|
||
const { mockReq, mockRes, mockNext } = getRequestHandlerMocks(); | ||
|
||
const requestHandler = getEnvironmentStandards(); | ||
|
||
await requestHandler(mockReq, mockRes, mockNext); | ||
|
||
expect(mockRes.status).to.have.been.calledWith(200); | ||
expect(mockRes.json).to.have.been.calledWith(mockResponse); | ||
}); | ||
|
||
it('catches and re-throws error', async () => { | ||
const mockDBConnection = getMockDBConnection({ | ||
open: sinon.stub(), | ||
commit: sinon.stub(), | ||
rollback: sinon.stub(), | ||
release: sinon.stub() | ||
}); | ||
|
||
sinon.stub(db, 'getAPIUserDBConnection').returns(mockDBConnection); | ||
|
||
sinon | ||
.stub(StandardsService.prototype, 'getEnvironmentStandards') | ||
.rejects(new Error('Failed to retrieve environment standards')); | ||
|
||
const { mockReq, mockRes, mockNext } = getRequestHandlerMocks(); | ||
|
||
try { | ||
const requestHandler = getEnvironmentStandards(); | ||
await requestHandler(mockReq, mockRes, mockNext); | ||
expect.fail(); | ||
} catch (actualError) { | ||
expect(mockDBConnection.open).to.have.been.calledOnce; | ||
expect(mockDBConnection.rollback).to.have.been.calledOnce; | ||
expect(mockDBConnection.release).to.have.been.calledOnce; | ||
expect((actualError as HTTPError).message).to.equal('Failed to retrieve environment standards'); | ||
} | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { RequestHandler } from 'express'; | ||
import { Operation } from 'express-openapi'; | ||
import { getAPIUserDBConnection } from '../../../database/db'; | ||
import { EnvironmentStandardsSchema } from '../../../openapi/schemas/standards'; | ||
import { StandardsService } from '../../../services/standards-service'; | ||
import { getLogger } from '../../../utils/logger'; | ||
|
||
const defaultLog = getLogger('paths/projects'); | ||
|
||
export const GET: Operation = [getEnvironmentStandards()]; | ||
|
||
GET.apiDoc = { | ||
description: 'Gets lookup values for environment variables', | ||
tags: ['standards'], | ||
parameters: [ | ||
{ | ||
in: 'query', | ||
name: 'keyword', | ||
required: false, | ||
schema: { | ||
type: 'string', | ||
nullable: true | ||
} | ||
} | ||
], | ||
security: [], | ||
responses: { | ||
200: { | ||
description: 'Environment data standards response object.', | ||
content: { | ||
'application/json': { | ||
schema: EnvironmentStandardsSchema | ||
} | ||
} | ||
}, | ||
400: { | ||
$ref: '#/components/responses/400' | ||
}, | ||
401: { | ||
$ref: '#/components/responses/401' | ||
}, | ||
403: { | ||
$ref: '#/components/responses/403' | ||
}, | ||
500: { | ||
$ref: '#/components/responses/500' | ||
}, | ||
default: { | ||
$ref: '#/components/responses/default' | ||
} | ||
} | ||
}; | ||
|
||
/** | ||
* Get species data standards | ||
* | ||
* @returns {RequestHandler} | ||
*/ | ||
export function getEnvironmentStandards(): RequestHandler { | ||
return async (req, res) => { | ||
const connection = getAPIUserDBConnection(); | ||
|
||
try { | ||
await connection.open(); | ||
|
||
const standardsService = new StandardsService(connection); | ||
|
||
const keyword = (req.query.keyword as string) ?? ''; | ||
|
||
const response = await standardsService.getEnvironmentStandards(keyword); | ||
|
||
await connection.commit(); | ||
|
||
return res.status(200).json(response); | ||
} catch (error) { | ||
defaultLog.error({ label: 'getEnvironmentStandards', message: 'error', error }); | ||
connection.rollback(); | ||
throw error; | ||
} finally { | ||
connection.release(); | ||
} | ||
}; | ||
} |
Oops, something went wrong.