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

Add environmental variables & sampling methods to standards page #1325

Merged
merged 27 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c7b17b7
initial commit from transferring otu of method-standards
LouisThedroux Jul 18, 2024
46e1f10
quick div to box fix for header not showing
LouisThedroux Jul 18, 2024
5327db5
Moving components around based off of Mac's suggestions.
LouisThedroux Jul 18, 2024
1be615f
update standards page layout
mauberti-bc Jul 24, 2024
02fb583
mock method data
mauberti-bc Jul 24, 2024
bfc3798
merge dev
mauberti-bc Jul 24, 2024
3521fbb
environment standards
mauberti-bc Jul 25, 2024
a6df334
Merge branch 'dev' of github.com:bcgov/biohubbc into double-standards
mauberti-bc Jul 25, 2024
ff84b21
add backend tests
mauberti-bc Jul 25, 2024
01232a4
replace getApiUserDBConnection with getDBConnection temporarily
mauberti-bc Jul 25, 2024
b4747da
lots of changes, MethodStandards Card and results, API path, sessions…
LouisThedroux Jul 31, 2024
00cf5fa
formatting, fixing SQL, adding unit chip
LouisThedroux Aug 1, 2024
66855f3
some fies to font, color, chevrons, chip etc
LouisThedroux Aug 2, 2024
aabd1e3
simplify standard cards
mauberti-bc Aug 6, 2024
bd4b2c8
Merge branch 'dev' into double-standards
mauberti-bc Aug 6, 2024
e74c10a
write tests
mauberti-bc Aug 6, 2024
9303735
Merge branch 'double-standards' of github.com:bcgov/biohubbc into dou…
mauberti-bc Aug 6, 2024
34eea75
species standards loading state
mauberti-bc Aug 6, 2024
5f39c35
fix missing keys
mauberti-bc Aug 6, 2024
dcc2676
shade of grey
mauberti-bc Aug 6, 2024
36db879
Merge branch 'dev' into double-standards
MacQSL Aug 7, 2024
cfafec3
ignore-skip
MacQSL Aug 7, 2024
25a20ba
fix: removed bad import from merge conflict
MacQSL Aug 7, 2024
253ef45
remove security from standards endpoints & address PR comments
mauberti-bc Aug 8, 2024
2d8f3a4
Merge branch 'dev' into double-standards
mauberti-bc Aug 10, 2024
c07bced
Merge branch 'dev' into double-standards
mauberti-bc Aug 15, 2024
86f9a2e
Merge branch 'dev' into double-standards
mauberti-bc Aug 19, 2024
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
53 changes: 53 additions & 0 deletions api/src/models/standards-view.ts
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 }[];
}
137 changes: 137 additions & 0 deletions api/src/openapi/schemas/standards.ts
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: {
mauberti-bc marked this conversation as resolved.
Show resolved Hide resolved
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 }
}
}
}
}
}
}
}
};
89 changes: 89 additions & 0 deletions api/src/paths/standards/environment/index.test.ts
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');
}
});
});
});
83 changes: 83 additions & 0 deletions api/src/paths/standards/environment/index.ts
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();
}
};
}
Loading