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

Upload summary results #549

Merged
merged 22 commits into from
Sep 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
c76ad41
can get a record in the db and get a sensible response
anissa-agahchen Sep 20, 2021
40ac169
Merge branch 'dev' of https://github.com/bcgov/biohubbc into uploadSu…
anissa-agahchen Sep 21, 2021
8ac38b4
Merge branch 'dev' of https://github.com/bcgov/biohubbc into uploadSu…
anissa-agahchen Sep 22, 2021
e11c0d9
WIP
anissa-agahchen Sep 22, 2021
e317299
Merge branch 'dev' of https://github.com/bcgov/biohubbc into uploadSu…
anissa-agahchen Sep 23, 2021
7de57e3
Merge branch 'dev' of https://github.com/bcgov/biohubbc into uploadSu…
anissa-agahchen Sep 23, 2021
b983387
with error
anissa-agahchen Sep 24, 2021
2366226
upload and display of summary results is showing
anissa-agahchen Sep 24, 2021
7d8f80c
clean up
anissa-agahchen Sep 24, 2021
b109065
Merge branch 'dev' of https://github.com/bcgov/biohubbc into uploadSu…
anissa-agahchen Sep 24, 2021
013d0e0
fixes and tests
anissa-agahchen Sep 27, 2021
74fc97b
clean up
anissa-agahchen Sep 27, 2021
1559e36
fix ObservationCSV test to work with props
anissa-agahchen Sep 27, 2021
fca66b1
clean up
anissa-agahchen Sep 27, 2021
46088cd
lint-fix
anissa-agahchen Sep 27, 2021
8841ca5
update dependencies
anissa-agahchen Sep 27, 2021
b0b49f9
added tests
anissa-agahchen Sep 27, 2021
ff500ff
addressed feedback
anissa-agahchen Sep 27, 2021
69cd8df
clean up
anissa-agahchen Sep 27, 2021
fbdaacc
clean up
anissa-agahchen Sep 27, 2021
79ac585
code smell
anissa-agahchen Sep 27, 2021
930c110
Merge branch 'dev' of https://github.com/bcgov/biohubbc into uploadSu…
anissa-agahchen Sep 27, 2021
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
2 changes: 2 additions & 0 deletions api/src/models/survey-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export class GetViewSurveyDetailsData {
completion_status: string;
publish_date: string;
occurrence_submission_id: number;
summary_results_submission_id: number;

constructor(surveyDetailsData?: any) {
defaultLog.debug({ label: 'GetViewSurveyDetailsData', message: 'params', surveyDetailsData });
Expand Down Expand Up @@ -72,6 +73,7 @@ export class GetViewSurveyDetailsData {

this.id = surveyDataItem?.id ?? null;
this.occurrence_submission_id = surveyDataItem?.occurrence_submission_id ?? null;
this.summary_results_submission_id = surveyDataItem?.summary_results_submission_id ?? null;
this.survey_name = surveyDataItem?.name || '';
this.survey_purpose = surveyDataItem?.objectives || '';
this.focal_species = (focalSpeciesList.length && focalSpeciesList.filter((item: string | number) => !!item)) || [];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
'use strict';

import { RequestHandler } from 'express';
import { Operation } from 'express-openapi';
import { SYSTEM_ROLE } from '../../../../../../constants/roles';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import * as upload from './upload';

chai.use(sinonChai);

describe('uploadSubmission', () => {
describe('uploadObservationSubmission', () => {
afterEach(() => {
sinon.restore();
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import chai, { expect } from 'chai';
import { describe } from 'mocha';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';
import * as summarySubmission from './get';
import * as db from '../../../../../../../database/db';
import * as survey_summary_queries from '../../../../../../../queries/survey/survey-summary-queries';
import SQL from 'sql-template-strings';

chai.use(sinonChai);

describe('getSummarySubmission', () => {
const dbConnectionObj = {
systemUserId: () => {
return null;
},
open: async () => {
// do nothing
},
release: () => {
// do nothing
},
commit: async () => {
// do nothing
},
rollback: async () => {
// do nothing
},
query: async () => {
// do nothing
}
};

const sampleReq = {
keycloak_token: {},
body: {},
params: {
projectId: 1,
surveyId: 1
}
} as any;

let actualResult: any = null;

const sampleRes = {
status: () => {
return {
json: (result: any) => {
actualResult = result;
}
};
}
};

afterEach(() => {
sinon.restore();
});

it('should throw a 400 error when no surveyId is provided', async () => {
sinon.stub(db, 'getDBConnection').returns(dbConnectionObj);

try {
const result = summarySubmission.getSurveySummarySubmission();
await result(
{ ...sampleReq, params: { ...sampleReq.params, surveyId: null } },
(null as unknown) as any,
(null as unknown) as any
);
expect.fail();
} catch (actualError) {
expect(actualError.status).to.equal(400);
expect(actualError.message).to.equal('Missing required path param `surveyId`');
}
});

it('should throw a 400 error when no sql statement returned for getLatestSurveySummarySubmissionSQL', async () => {
sinon.stub(db, 'getDBConnection').returns({
...dbConnectionObj,
systemUserId: () => {
return 20;
}
});

sinon.stub(survey_summary_queries, 'getLatestSurveySummarySubmissionSQL').returns(null);

try {
const result = summarySubmission.getSurveySummarySubmission();

await result(sampleReq, (null as unknown) as any, (null as unknown) as any);
expect.fail();
} catch (actualError) {
expect(actualError.status).to.equal(400);
expect(actualError.message).to.equal('Failed to build getLatestSurveySummarySubmissionSQLStatement statement');
}
});

it('should return a summary submission, on success', async () => {
const mockQuery = sinon.stub();

mockQuery.resolves({
rows: [
{
id: 13,
file_name: 'file.xlsx'
}
]
});

sinon.stub(db, 'getDBConnection').returns({
...dbConnectionObj,
systemUserId: () => {
return 20;
},
query: mockQuery
});

sinon.stub(survey_summary_queries, 'getLatestSurveySummarySubmissionSQL').returns(SQL`something`);

const result = summarySubmission.getSurveySummarySubmission();

await result(sampleReq, sampleRes as any, (null as unknown) as any);

expect(actualResult).to.be.eql({
id: 13,
fileName: 'file.xlsx'
});
});

it('should return null if the survey has no summary submission, on success', async () => {
const mockQuery = sinon.stub();

mockQuery.resolves({ rows: undefined });

sinon.stub(db, 'getDBConnection').returns({
...dbConnectionObj,
systemUserId: () => {
return 20;
},
query: mockQuery
});

sinon.stub(survey_summary_queries, 'getLatestSurveySummarySubmissionSQL').returns(SQL`something`);

const result = summarySubmission.getSurveySummarySubmission();

await result(sampleReq, sampleRes as any, (null as unknown) as any);

expect(actualResult).to.be.null;
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
'use strict';

import { RequestHandler } from 'express';
import { Operation } from 'express-openapi';
import { SYSTEM_ROLE } from '../../../../../../../constants/roles';
import { getDBConnection } from '../../../../../../../database/db';
import { HTTP400 } from '../../../../../../../errors/CustomError';
import { getLatestSurveySummarySubmissionSQL } from '../../../../../../../queries/survey/survey-summary-queries';
import { getLogger } from '../../../../../../../utils/logger';

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

export const GET: Operation = [getSurveySummarySubmission()];

GET.apiDoc = {
description: 'Fetches an summary occurrence submission for a survey.',
tags: ['summary_submission'],
security: [
{
Bearer: [SYSTEM_ROLE.SYSTEM_ADMIN, SYSTEM_ROLE.PROJECT_ADMIN]
}
],
parameters: [
{
in: 'path',
name: 'projectId',
schema: {
type: 'number'
},
required: true
},
{
in: 'path',
name: 'surveyId',
schema: {
type: 'number'
},
required: true
}
],
responses: {
200: {
description: 'Summary submission get response.',
content: {
'application/json': {
schema: {
type: 'object',
properties: {
id: {
type: 'number'
},
fileName: {
description: 'The file name of the submission',
type: 'string'
}
}
}
}
}
},
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 getSurveySummarySubmission(): RequestHandler {
return async (req, res) => {
defaultLog.debug({ label: 'Get a survey summary result', message: 'params', req_params: req.params });

if (!req.params.surveyId) {
throw new HTTP400('Missing required path param `surveyId`');
}

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

try {
const getSurveySummarySubmissionSQLStatement = getLatestSurveySummarySubmissionSQL(Number(req.params.surveyId));

if (!getSurveySummarySubmissionSQLStatement) {
throw new HTTP400('Failed to build getLatestSurveySummarySubmissionSQLStatement statement');
}

await connection.open();

const summarySubmissionData = await connection.query(
getSurveySummarySubmissionSQLStatement.text,
getSurveySummarySubmissionSQLStatement.values
);

if (!summarySubmissionData || !summarySubmissionData.rows || !summarySubmissionData.rows[0]) {
return res.status(200).json(null);
}

await connection.commit();

const getSummarySubmissionData =
{
id: summarySubmissionData.rows[0].id,
fileName: summarySubmissionData.rows[0].file_name
} || null;

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