diff --git a/api/src/models/project-view.test.ts b/api/src/models/project-view.test.ts index bf68d2862d..93a54de677 100644 --- a/api/src/models/project-view.test.ts +++ b/api/src/models/project-view.test.ts @@ -2,6 +2,7 @@ import { expect } from 'chai'; import { describe } from 'mocha'; import { COMPLETION_STATUS } from '../constants/status'; import { + GetAttachmentsData, GetCoordinatorData, GetFundingData, GetIUCNClassificationData, @@ -9,7 +10,8 @@ import { GetObjectivesData, GetPartnershipsData, GetPermitData, - GetProjectData + GetProjectData, + GetReportAttachmentsData } from './project-view'; describe('GetProjectData', () => { @@ -110,7 +112,8 @@ describe('GetObjectivesData', () => { const obj = { objectives: 'these are the project objectives', - caveats: 'these are some interesting caveats' + caveats: 'these are some interesting caveats', + revision_count: 'revision' }; before(() => { @@ -124,6 +127,10 @@ describe('GetObjectivesData', () => { it('sets caveats', function () { expect(projectObjectivesData.caveats).to.equal(obj.caveats); }); + + it('sets revision_count', function () { + expect(projectObjectivesData.revision_count).to.equal(obj.revision_count); + }); }); }); @@ -164,7 +171,8 @@ describe('GetCoordinatorData', () => { coordinator_last_name: 'last', coordinator_email_address: 'email@example.com', coordinator_agency_name: 'agency', - coordinator_public: true + coordinator_public: true, + revision_count: 'count' }; before(() => { @@ -190,6 +198,10 @@ describe('GetCoordinatorData', () => { it('sets share_contact_details', function () { expect(projectCoordinatorData.share_contact_details).to.equal('true'); }); + + it('sets revision_count', function () { + expect(projectCoordinatorData.revision_count).to.equal('count'); + }); }); }); @@ -284,11 +296,13 @@ describe('GetLocationData', () => { const locationDataObj = [ { location_description, - geometry + geometry, + revision_count: 'count' }, { location_description, - geometry + geometry, + revision_count: 'count' } ]; @@ -303,6 +317,10 @@ describe('GetLocationData', () => { it('sets the geometry', function () { expect(locationData.geometry).to.eql(geometry); }); + + it('sets revision_count', function () { + expect(locationData.revision_count).to.equal('count'); + }); }); }); @@ -501,3 +519,212 @@ describe('GetPartnershipsData', () => { }); }); }); + +describe('GetAttachmentsData', () => { + describe('No values provided', () => { + let data: GetAttachmentsData; + + before(() => { + data = new GetAttachmentsData((null as unknown) as any[]); + }); + + it('sets attachmentDetails', function () { + expect(data.attachmentDetails).to.eql([]); + }); + }); + + describe('Empty arrays as values provided', () => { + let data: GetAttachmentsData; + + before(() => { + data = new GetAttachmentsData([]); + }); + + it('sets attachmentDetails', function () { + expect(data.attachmentDetails).to.eql([]); + }); + }); + + describe('some attachmentDetails values provided', () => { + let data: GetAttachmentsData; + + const attachmentDetails = [{ file_name: 1 }, { file_name: 2 }]; + + before(() => { + data = new GetAttachmentsData(attachmentDetails); + }); + + it('sets file_name', function () { + expect(data.attachmentDetails).to.eql([ + { + file_name: 1, + file_type: undefined, + title: undefined, + description: undefined, + key: undefined, + file_size: undefined, + is_secure: 'false' + }, + { + file_name: 2, + file_type: undefined, + title: undefined, + description: undefined, + key: undefined, + file_size: undefined, + is_secure: 'false' + } + ]); + }); + }); + + describe('all attachmentDetails values provided', () => { + let data: GetAttachmentsData; + + const attachmentDetails = [ + { + file_name: 1, + file_type: 'type', + title: 'title', + description: 'descript', + security_token: 'key', + file_size: 'file_size', + key: 'key' + }, + { + file_name: 2, + file_type: 'type', + title: 'title', + description: 'descript', + security_token: 'key', + file_size: 'file_size', + key: 'key' + } + ]; + + before(() => { + data = new GetAttachmentsData(attachmentDetails); + }); + + it('sets all fields', function () { + expect(data.attachmentDetails).to.eql([ + { + file_name: 1, + file_type: 'type', + title: 'title', + description: 'descript', + key: '', + file_size: 'file_size', + is_secure: 'true' + }, + { + file_name: 2, + file_type: 'type', + title: 'title', + description: 'descript', + key: '', + file_size: 'file_size', + is_secure: 'true' + } + ]); + }); + }); +}); + +describe('GetReportAttachmentsData', () => { + describe('No values provided', () => { + it('sets attachmentDetails', function () { + const data: GetReportAttachmentsData = new GetReportAttachmentsData((null as unknown) as any[]); + + expect(data.attachmentDetails).to.eql([]); + }); + }); + + describe('Empty arrays as values provided', () => { + it('sets attachmentDetails', function () { + const data: GetReportAttachmentsData = new GetReportAttachmentsData([]); + + expect(data.attachmentDetails).to.eql([]); + }); + }); + + describe('some attachmentDetails asdasdsadsasd values provided', () => { + it('sets file_name', function () { + const attachmentDetails = [{ file_name: 1 }, { file_name: 2 }]; + + const data: GetReportAttachmentsData = new GetReportAttachmentsData(attachmentDetails); + expect(data.attachmentDetails).to.eql([ + { + file_name: 1, + title: undefined, + year: undefined, + description: undefined, + key: undefined, + file_size: undefined, + is_secure: 'false' + }, + { + file_name: 2, + title: undefined, + year: undefined, + description: undefined, + key: undefined, + file_size: undefined, + is_secure: 'false' + } + ]); + }); + }); + + describe('all attachmentDetails values provided', () => { + it('sets all fields', function () { + const attachmentDetails = [ + { + file_name: 1, + title: 'title', + year: '1', + description: 'descript', + security_token: 'key', + file_size: 'size', + key: 'key', + authors: [{ author: 'author' }] + }, + { + file_name: 2, + file_type: 'type', + title: 'title', + year: '2', + description: 'descript', + security_token: 'key', + file_size: 'size', + key: 'key', + authors: [{ author: 'author' }] + } + ]; + const data: GetReportAttachmentsData = new GetReportAttachmentsData(attachmentDetails); + + expect(data.attachmentDetails).to.eql([ + { + file_name: 1, + title: 'title', + year: '1', + description: 'descript', + key: '', + file_size: 'size', + is_secure: 'true', + authors: [{ author: 'author' }] + }, + { + file_name: 2, + title: 'title', + year: '2', + description: 'descript', + key: '', + file_size: 'size', + is_secure: 'true', + authors: [{ author: 'author' }] + } + ]); + }); + }); +}); diff --git a/api/src/models/project-view.ts b/api/src/models/project-view.ts index 64fac7ebdb..052f877b7e 100644 --- a/api/src/models/project-view.ts +++ b/api/src/models/project-view.ts @@ -221,3 +221,84 @@ export class GetPartnershipsData { (stakeholder_partnerships?.length && stakeholder_partnerships.map((item: any) => item.partnership_name)) || []; } } + +interface IGetAttachmentsSource { + file_name: string; + file_type: string; + title: string; + description: string; + key: string; + file_size: string; + is_secure: string; +} + +/** + * Pre-processes GET /projects/{id} attachments data + * + * @export + * @class GetAttachmentsData + */ +export class GetAttachmentsData { + attachmentDetails: IGetAttachmentsSource[]; + + constructor(attachments?: any[]) { + this.attachmentDetails = + (attachments?.length && + attachments.map((item: any) => { + return { + file_name: item.file_name, + file_type: item.file_type, + title: item.title, + description: item.description, + key: item.security_token ? '' : item.key, + file_size: item.file_size, + is_secure: item.security_token ? 'true' : 'false' + }; + })) || + []; + } +} + +interface IGetReportAttachmentsSource { + file_name: string; + title: string; + year: string; + description: string; + key: string; + file_size: string; + is_secure: string; + authors?: { author: string }[]; +} + +/** + * Pre-processes GET /projects/{id} report attachments data + * + * @export + * @class GetReportAttachmentsData + */ +export class GetReportAttachmentsData { + attachmentDetails: IGetReportAttachmentsSource[]; + + constructor(attachments?: any[]) { + this.attachmentDetails = + (attachments?.length && + attachments.map((item: any) => { + const attachmentItem = { + file_name: item.file_name, + title: item.title, + year: item.year, + description: item.description, + key: item.security_token ? '' : item.key, + file_size: item.file_size, + is_secure: item.security_token ? 'true' : 'false' + }; + + if (item.authors?.length) { + attachmentItem['authors'] = item.authors; + } + + return attachmentItem; + })) || + []; + } +} diff --git a/api/src/models/survey-view.test.ts b/api/src/models/survey-view.test.ts index a2012c765e..76422ae2e3 100644 --- a/api/src/models/survey-view.test.ts +++ b/api/src/models/survey-view.test.ts @@ -2,8 +2,10 @@ import { expect } from 'chai'; import { describe } from 'mocha'; import { GetAncillarySpeciesData, + GetAttachmentsData, GetFocalSpeciesData, GetPermitData, + GetReportAttachmentsData, GetSurveyData, GetSurveyFundingSources, GetSurveyLocationData, @@ -31,6 +33,10 @@ describe('GetSurveyData', () => { expect(data.start_date).to.equal(null); }); + it('sets geojson', () => { + expect(data.geometry).to.eql([]); + }); + it('sets biologist_first_name', () => { expect(data.biologist_first_name).to.equal(''); }); @@ -48,7 +54,9 @@ describe('GetSurveyData', () => { end_date: '2020/04/04', start_date: '2020/03/03', lead_first_name: 'first', - lead_last_name: 'last' + geojson: [{ data: 'data' }], + lead_last_name: 'last', + revision_count: 'count' }; before(() => { @@ -67,6 +75,10 @@ describe('GetSurveyData', () => { expect(data.start_date).to.equal(obj.start_date); }); + it('sets geojson', () => { + expect(data.geometry).to.equal(obj.geojson); + }); + it('sets biologist_first_name', () => { expect(data.biologist_first_name).to.equal(obj.lead_first_name); }); @@ -74,6 +86,10 @@ describe('GetSurveyData', () => { it('sets biologist_last_name', () => { expect(data.biologist_last_name).to.equal(obj.lead_last_name); }); + + it('sets revision_count', function () { + expect(data.revision_count).to.equal('count'); + }); }); }); @@ -82,7 +98,7 @@ describe('GetFocalSpeciesData', () => { let data: GetFocalSpeciesData; before(() => { - data = new GetFocalSpeciesData([]); + data = new GetFocalSpeciesData(); }); it('sets focal_species', () => { @@ -121,7 +137,7 @@ describe('GetAncillarySpeciesData', () => { let data: GetAncillarySpeciesData; before(() => { - data = new GetAncillarySpeciesData([]); + data = new GetAncillarySpeciesData(); }); it('sets ancillary_species', () => { @@ -199,7 +215,7 @@ describe('GetSurveyFundingSources', () => { let data: GetSurveyFundingSources; before(() => { - data = new GetSurveyFundingSources([]); + data = new GetSurveyFundingSources(); }); it('sets funding_sources', () => { @@ -434,7 +450,8 @@ describe('GetSurveyPurposeAndMethodologyData', () => { field_method_id: 2, ecological_season_id: 3, vantage_ids: [4, 5], - surveyed_all_areas: true + surveyed_all_areas: true, + revision_count: 'count' }; before(() => { @@ -464,5 +481,218 @@ describe('GetSurveyPurposeAndMethodologyData', () => { it('sets surveyed_all_areas', () => { expect(data.surveyed_all_areas).to.eql('true'); }); + + it('sets revision_count', function () { + expect(data.revision_count).to.equal('count'); + }); + }); +}); + +describe('GetAttachmentsData', () => { + describe('No values provided', () => { + let data: GetAttachmentsData; + + before(() => { + data = new GetAttachmentsData((null as unknown) as any[]); + }); + + it('sets attachmentDetails', function () { + expect(data.attachmentDetails).to.eql([]); + }); + }); + + describe('Empty arrays as values provided', () => { + let data: GetAttachmentsData; + + before(() => { + data = new GetAttachmentsData([]); + }); + + it('sets attachmentDetails', function () { + expect(data.attachmentDetails).to.eql([]); + }); + }); + + describe('some attachmentDetails values provided', () => { + let data: GetAttachmentsData; + + const attachmentDetails = [{ file_name: 1 }, { file_name: 2 }]; + + before(() => { + data = new GetAttachmentsData(attachmentDetails); + }); + + it('sets file_name', function () { + expect(data.attachmentDetails).to.eql([ + { + file_name: 1, + file_type: undefined, + title: undefined, + description: undefined, + key: undefined, + file_size: undefined, + is_secure: 'false' + }, + { + file_name: 2, + file_type: undefined, + title: undefined, + description: undefined, + key: undefined, + file_size: undefined, + is_secure: 'false' + } + ]); + }); + }); + + describe('all attachmentDetails values provided', () => { + let data: GetAttachmentsData; + + const attachmentDetails = [ + { + file_name: 1, + file_type: 'type', + title: 'title', + description: 'descript', + security_token: 'key', + file_size: 'file_size', + key: 'key' + }, + { + file_name: 2, + file_type: 'type', + title: 'title', + description: 'descript', + security_token: 'key', + file_size: 'file_size', + key: 'key' + } + ]; + + before(() => { + data = new GetAttachmentsData(attachmentDetails); + }); + + it('sets all fields', function () { + expect(data.attachmentDetails).to.eql([ + { + file_name: 1, + file_type: 'type', + title: 'title', + description: 'descript', + key: '', + file_size: 'file_size', + is_secure: 'true' + }, + { + file_name: 2, + file_type: 'type', + title: 'title', + description: 'descript', + key: '', + file_size: 'file_size', + is_secure: 'true' + } + ]); + }); + }); +}); + +describe('GetReportAttachmentsData', () => { + describe('No values provided', () => { + it('sets attachmentDetails', function () { + const data: GetReportAttachmentsData = new GetReportAttachmentsData((null as unknown) as any[]); + + expect(data.attachmentDetails).to.eql([]); + }); + }); + + describe('Empty arrays as values provided', () => { + it('sets attachmentDetails', function () { + const data: GetReportAttachmentsData = new GetReportAttachmentsData([]); + + expect(data.attachmentDetails).to.eql([]); + }); + }); + + describe('some attachmentDetails asdasdsadsasd values provided', () => { + it('sets file_name', function () { + const attachmentDetails = [{ file_name: 1 }, { file_name: 2 }]; + + const data: GetReportAttachmentsData = new GetReportAttachmentsData(attachmentDetails); + expect(data.attachmentDetails).to.eql([ + { + file_name: 1, + title: undefined, + year: undefined, + description: undefined, + key: undefined, + file_size: undefined, + is_secure: 'false' + }, + { + file_name: 2, + title: undefined, + year: undefined, + description: undefined, + key: undefined, + file_size: undefined, + is_secure: 'false' + } + ]); + }); + }); + + describe('all attachmentDetails values provided', () => { + it('sets all fields', function () { + const attachmentDetails = [ + { + file_name: 1, + title: 'title', + year: '1', + description: 'descript', + security_token: 'key', + file_size: 'size', + key: 'key', + authors: [{ author: 'author' }] + }, + { + file_name: 2, + file_type: 'type', + title: 'title', + year: '2', + description: 'descript', + security_token: 'key', + file_size: 'size', + key: 'key', + authors: [{ author: 'author' }] + } + ]; + const data: GetReportAttachmentsData = new GetReportAttachmentsData(attachmentDetails); + + expect(data.attachmentDetails).to.eql([ + { + file_name: 1, + title: 'title', + year: '1', + description: 'descript', + key: '', + file_size: 'size', + is_secure: 'true', + authors: [{ author: 'author' }] + }, + { + file_name: 2, + title: 'title', + year: '2', + description: 'descript', + key: '', + file_size: 'size', + is_secure: 'true', + authors: [{ author: 'author' }] + } + ]); + }); }); }); diff --git a/api/src/models/survey-view.ts b/api/src/models/survey-view.ts index 0e37aa72f7..a8751b91cd 100644 --- a/api/src/models/survey-view.ts +++ b/api/src/models/survey-view.ts @@ -166,3 +166,84 @@ export class GetSurveyLocationData { this.geometry = (obj?.geojson?.length && obj.geojson) || []; } } + +interface IGetAttachmentsSource { + file_name: string; + file_type: string; + title: string; + description: string; + key: string; + file_size: string; + is_secure: string; +} + +/** + * Pre-processes GET /surveys/{id} attachments data + * + * @export + * @class GetAttachmentsData + */ +export class GetAttachmentsData { + attachmentDetails: IGetAttachmentsSource[]; + + constructor(attachments?: any[]) { + this.attachmentDetails = + (attachments?.length && + attachments.map((item: any) => { + return { + file_name: item.file_name, + file_type: item.file_type, + title: item.title, + description: item.description, + key: item.security_token ? '' : item.key, + file_size: item.file_size, + is_secure: item.security_token ? 'true' : 'false' + }; + })) || + []; + } +} + +interface IGetReportAttachmentsSource { + file_name: string; + title: string; + year: string; + description: string; + key: string; + file_size: string; + is_secure: string; + authors?: { author: string }[]; +} + +/** + * Pre-processes GET /surveys/{id} report attachments data + * + * @export + * @class GetReportAttachmentsData + */ +export class GetReportAttachmentsData { + attachmentDetails: IGetReportAttachmentsSource[]; + + constructor(attachments?: any[]) { + this.attachmentDetails = + (attachments?.length && + attachments.map((item: any) => { + const attachmentItem = { + file_name: item.file_name, + title: item.title, + year: item.year, + description: item.description, + key: item.security_token ? '' : item.key, + file_size: item.file_size, + is_secure: item.security_token ? 'true' : 'false' + }; + + if (item.authors?.length) { + attachmentItem['authors'] = item.authors; + } + + return attachmentItem; + })) || + []; + } +} diff --git a/api/src/paths/dwc/eml.test.ts b/api/src/paths/dwc/eml.test.ts index faf27db3e7..d5a035e0d5 100644 --- a/api/src/paths/dwc/eml.test.ts +++ b/api/src/paths/dwc/eml.test.ts @@ -29,7 +29,7 @@ describe('getProjectEml', () => { expect.fail(); } catch (actualError) { expect((actualError as HTTPError).status).to.equal(400); - expect((actualError as HTTPError).message).to.equal('Failed to build SQL get statement'); + expect((actualError as HTTPError).message).to.equal('Failed to get project objectives data'); } }); diff --git a/api/src/paths/project/{projectId}/delete.test.ts b/api/src/paths/project/{projectId}/delete.test.ts index 15bbaecacd..4e56a1d4ee 100644 --- a/api/src/paths/project/{projectId}/delete.test.ts +++ b/api/src/paths/project/{projectId}/delete.test.ts @@ -63,27 +63,6 @@ describe('deleteProject', () => { } }); - it('should throw a 400 error when no sql statement returned for getProjectSQL', async () => { - sinon.stub(db, 'getDBConnection').returns({ - ...dbConnectionObj, - systemUserId: () => { - return 20; - } - }); - - sinon.stub(project_queries, 'getProjectSQL').returns(null); - - try { - const result = delete_project.deleteProject(); - - await result(sampleReq, (null as unknown) as any, (null as unknown) as any); - expect.fail(); - } catch (actualError) { - expect((actualError as HTTPError).status).to.equal(400); - expect((actualError as HTTPError).message).to.equal('Failed to build SQL get statement'); - } - }); - it('should throw a 400 error when fails to get the project cause no rows', async () => { sinon.stub(db, 'getDBConnection').returns({ ...dbConnectionObj, diff --git a/api/src/paths/project/{projectId}/survey/permits/list.test.ts b/api/src/paths/project/{projectId}/survey/permits/list.test.ts index 702552b27a..ba4206f209 100644 --- a/api/src/paths/project/{projectId}/survey/permits/list.test.ts +++ b/api/src/paths/project/{projectId}/survey/permits/list.test.ts @@ -60,27 +60,6 @@ describe('getSurveyPermits', () => { } }); - it('should throw a 400 error when no sql statement returned for assignable survey permits', async () => { - sinon.stub(db, 'getDBConnection').returns({ - ...dbConnectionObj, - systemUserId: () => { - return 20; - } - }); - - sinon.stub(survey_queries, 'getAllAssignablePermitsForASurveySQL').returns(null); - - try { - const result = list.getSurveyPermits(); - - await result(sampleReq, (null as unknown) as any, (null as unknown) as any); - expect.fail(); - } catch (actualError) { - expect((actualError as HTTPError).status).to.equal(400); - expect((actualError as HTTPError).message).to.equal('Failed to build SQL get statement'); - } - }); - it('should return the survey permits on success', async () => { const surveyPermits = [ { diff --git a/api/src/paths/project/{projectId}/survey/{surveyId}/observation/submission/get.test.ts b/api/src/paths/project/{projectId}/survey/{surveyId}/observation/submission/get.test.ts index 8e967cdf57..edb960348d 100644 --- a/api/src/paths/project/{projectId}/survey/{surveyId}/observation/submission/get.test.ts +++ b/api/src/paths/project/{projectId}/survey/{surveyId}/observation/submission/get.test.ts @@ -56,29 +56,6 @@ describe('getObservationSubmission', () => { } }); - it('should throw a 400 error when no sql statement returned for getLatestSurveyOccurrenceSubmission', async () => { - sinon.stub(db, 'getDBConnection').returns({ - ...dbConnectionObj, - systemUserId: () => { - return 20; - } - }); - - sinon.stub(survey_queries, 'getLatestSurveyOccurrenceSubmissionSQL').returns(null); - - try { - const result = observationSubmission.getOccurrenceSubmission(); - - await result(sampleReq, (null as unknown) as any, (null as unknown) as any); - expect.fail(); - } catch (actualError) { - expect((actualError as HTTPError).status).to.equal(400); - expect((actualError as HTTPError).message).to.equal( - 'Failed to build SQL getLatestSurveyOccurrenceSubmissionSQL statement' - ); - } - }); - it('should return an observation submission, on success with no rejected files', async () => { const mockQuery = sinon.stub(); diff --git a/api/src/queries/project/project-update-queries.test.ts b/api/src/queries/project/project-update-queries.test.ts index 679fad89e5..5e19ff1f62 100644 --- a/api/src/queries/project/project-update-queries.test.ts +++ b/api/src/queries/project/project-update-queries.test.ts @@ -61,12 +61,6 @@ describe('getIUCNActionClassificationByProjectSQL', () => { }); describe('getCoordinatorByProjectSQL', () => { - it('Null projectId', () => { - const response = getCoordinatorByProjectSQL((null as unknown) as number); - - expect(response).to.be.null; - }); - it('valid projectId', () => { const response = getCoordinatorByProjectSQL(1); @@ -216,12 +210,6 @@ describe('putProjectSQL', () => { }); describe('getObjectivesByProjectSQL', () => { - it('Null projectId', () => { - const response = getObjectivesByProjectSQL((null as unknown) as number); - - expect(response).to.be.null; - }); - it('valid projectId', () => { const response = getObjectivesByProjectSQL(1); diff --git a/api/src/queries/project/project-update-queries.ts b/api/src/queries/project/project-update-queries.ts index 070a2eeb8b..04dca1154f 100644 --- a/api/src/queries/project/project-update-queries.ts +++ b/api/src/queries/project/project-update-queries.ts @@ -96,11 +96,7 @@ export const getPermitsByProjectSQL = (projectId: number): SQLStatement | null = * @param {number} projectId * @return {*} {(SQLStatement | null)} */ -export const getCoordinatorByProjectSQL = (projectId: number): SQLStatement | null => { - if (!projectId) { - return null; - } - +export const getCoordinatorByProjectSQL = (projectId: number): SQLStatement => { return SQL` SELECT coordinator_first_name, @@ -238,11 +234,7 @@ export const putProjectSQL = ( * @param {number} projectId * @return {*} {(SQLStatement | null)} */ -export const getObjectivesByProjectSQL = (projectId: number): SQLStatement | null => { - if (!projectId) { - return null; - } - +export const getObjectivesByProjectSQL = (projectId: number): SQLStatement => { return SQL` SELECT objectives, diff --git a/api/src/queries/project/project-view-queries.test.ts b/api/src/queries/project/project-view-queries.test.ts index f81896f1f9..cd15e3f016 100644 --- a/api/src/queries/project/project-view-queries.test.ts +++ b/api/src/queries/project/project-view-queries.test.ts @@ -2,6 +2,7 @@ import { expect } from 'chai'; import { describe } from 'mocha'; import { getActivitiesByProjectSQL, + getAttachmentsByProjectSQL, getFundingSourceByProjectSQL, getIndigenousPartnershipsByProjectSQL, getIUCNActionClassificationByProjectSQL, @@ -9,19 +10,11 @@ import { getProjectListSQL, getProjectPermitsSQL, getProjectSQL, + getReportAttachmentsByProjectSQL, getStakeholderPartnershipsByProjectSQL } from './project-view-queries'; describe('getProjectSQL', () => { - describe('Null project id param provided', () => { - it('returns null', () => { - // force the function to accept a null value - const response = getProjectSQL((null as unknown) as number); - - expect(response).to.be.null; - }); - }); - describe('Valid project id param provided', () => { it('returns a SQLStatement', () => { const response = getProjectSQL(1); @@ -118,12 +111,6 @@ describe('getProjectListSQL', () => { }); describe('getIUCNActionClassificationByProjectSQL', () => { - it('returns null response when null projectId provided', () => { - const response = getIUCNActionClassificationByProjectSQL((null as unknown) as number); - - expect(response).to.be.null; - }); - it('returns non null response when valid projectId provided', () => { const response = getIUCNActionClassificationByProjectSQL(1); @@ -160,56 +147,60 @@ describe('getStakeholderPartnershipsByProjectSQL', () => { }); describe('getProjectPermitsSQL', () => { - it('Null projectId', () => { - const response = getProjectPermitsSQL((null as unknown) as number); + it('valid projectId', () => { + const response = getProjectPermitsSQL(1); - expect(response).to.be.null; + expect(response).to.not.be.null; }); +}); +describe('getLocationByProjectSQL', () => { it('valid projectId', () => { - const response = getProjectPermitsSQL(1); + const response = getLocationByProjectSQL(1); expect(response).to.not.be.null; }); }); -describe('getLocationByProjectSQL', () => { - it('Null projectId', () => { - const response = getLocationByProjectSQL((null as unknown) as number); +describe('getActivitiesByProjectSQL', () => { + it('valid projectId', () => { + const response = getActivitiesByProjectSQL(1); - expect(response).to.be.null; + expect(response).to.not.be.null; }); +}); +describe('getFundingSourceByProjectSQL', () => { it('valid projectId', () => { - const response = getLocationByProjectSQL(1); + const response = getFundingSourceByProjectSQL(1); expect(response).to.not.be.null; }); }); -describe('getActivitiesByProjectSQL', () => { +describe('getAttachmentsByProjectSQL', () => { it('Null projectId', () => { - const response = getActivitiesByProjectSQL((null as unknown) as number); + const response = getAttachmentsByProjectSQL((null as unknown) as number); expect(response).to.be.null; }); it('valid projectId', () => { - const response = getActivitiesByProjectSQL(1); + const response = getAttachmentsByProjectSQL(1); expect(response).to.not.be.null; }); }); -describe('getFundingSourceByProjectSQL', () => { +describe('getReportAttachmentsByProjectSQL', () => { it('Null projectId', () => { - const response = getFundingSourceByProjectSQL((null as unknown) as number); + const response = getReportAttachmentsByProjectSQL((null as unknown) as number); expect(response).to.be.null; }); it('valid projectId', () => { - const response = getFundingSourceByProjectSQL(1); + const response = getReportAttachmentsByProjectSQL(1); expect(response).to.not.be.null; }); diff --git a/api/src/queries/project/project-view-queries.ts b/api/src/queries/project/project-view-queries.ts index 761921ff34..0b8249b254 100644 --- a/api/src/queries/project/project-view-queries.ts +++ b/api/src/queries/project/project-view-queries.ts @@ -6,11 +6,7 @@ import { SQL, SQLStatement } from 'sql-template-strings'; * @param {number} projectId * @returns {SQLStatement} sql query object */ -export const getProjectSQL = (projectId: number): SQLStatement | null => { - if (!projectId) { - return null; - } - +export const getProjectSQL = (projectId: number): SQLStatement => { return SQL` SELECT project.project_id as id, @@ -174,11 +170,7 @@ export const getProjectListSQL = ( * @param {number} projectId * @returns {SQLStatement} sql query object */ -export const getIUCNActionClassificationByProjectSQL = (projectId: number): SQLStatement | null => { - if (!projectId) { - return null; - } - +export const getIUCNActionClassificationByProjectSQL = (projectId: number): SQLStatement => { return SQL` SELECT ical1c.iucn_conservation_action_level_1_classification_id as classification, @@ -258,16 +250,73 @@ export const getStakeholderPartnershipsByProjectSQL = (projectId: number): SQLSt }; /** - * SQL query to get permits associated to a project. + * SQL query to get project attachments. + * + * @param {number} projectId + * @returns {SQLStatement} sql query object + */ +export const getAttachmentsByProjectSQL = (projectId: number): SQLStatement | null => { + if (!projectId) { + return null; + } + + return SQL` + SELECT + * + FROM + project_attachment + WHERE + project_id = ${projectId}; + `; +}; + +/** + * SQL query to get project reports. * * @param {number} projectId * @returns {SQLStatement} sql query object */ -export const getProjectPermitsSQL = (projectId: number): SQLStatement | null => { +export const getReportAttachmentsByProjectSQL = (projectId: number): SQLStatement | null => { if (!projectId) { return null; } + return SQL` + SELECT + pra.project_report_attachment_id + , pra.project_id + , pra.file_name + , pra.title + , pra.description + , pra.year + , pra."key" + , pra.file_size + , pra.security_token + , array_remove(array_agg(pra2.first_name ||' '||pra2.last_name), null) authors + FROM + project_report_attachment pra + LEFT JOIN project_report_author pra2 ON pra2.project_report_attachment_id = pra.project_report_attachment_id + WHERE pra.project_id = ${projectId} + GROUP BY + pra.project_report_attachment_id + , pra.project_id + , pra.file_name + , pra.title + , pra.description + , pra.year + , pra."key" + , pra.file_size + , pra.security_token; + `; +}; + +/** + * SQL query to get permits associated to a project. + * + * @param {number} projectId + * @returns {SQLStatement} sql query object + */ +export const getProjectPermitsSQL = (projectId: number): SQLStatement => { return SQL` SELECT number, @@ -285,11 +334,7 @@ export const getProjectPermitsSQL = (projectId: number): SQLStatement | null => * @param {number} projectId * @returns {SQLStatement} sql query object */ -export const getLocationByProjectSQL = (projectId: number): SQLStatement | null => { - if (!projectId) { - return null; - } - +export const getLocationByProjectSQL = (projectId: number): SQLStatement => { return SQL` SELECT p.location_description, @@ -313,11 +358,7 @@ export const getLocationByProjectSQL = (projectId: number): SQLStatement | null * @returns {SQLStatement} sql query object */ -export const getActivitiesByProjectSQL = (projectId: number): SQLStatement | null => { - if (!projectId) { - return null; - } - +export const getActivitiesByProjectSQL = (projectId: number): SQLStatement => { return SQL` SELECT activity_id @@ -333,11 +374,7 @@ export const getActivitiesByProjectSQL = (projectId: number): SQLStatement | nul * @param {number} projectId * @returns {SQLStatement} sql query object */ -export const getFundingSourceByProjectSQL = (projectId: number): SQLStatement | null => { - if (!projectId) { - return null; - } - +export const getFundingSourceByProjectSQL = (projectId: number): SQLStatement => { return SQL` SELECT pfs.project_funding_source_id as id, diff --git a/api/src/queries/survey/survey-create-queries.test.ts b/api/src/queries/survey/survey-create-queries.test.ts index d9290f9200..22a1f76a67 100644 --- a/api/src/queries/survey/survey-create-queries.test.ts +++ b/api/src/queries/survey/survey-create-queries.test.ts @@ -11,19 +11,6 @@ import { } from './survey-create-queries'; describe('postSurveySQL', () => { - it('returns null when null projectId param provided', () => { - const survey = new PostSurveyObject(); - const response = postSurveySQL((null as unknown) as number, survey); - - expect(response).to.be.null; - }); - - it('returns null when null survey data param provided', () => { - const response = postSurveySQL(1, (null as unknown) as PostSurveyObject); - - expect(response).to.be.null; - }); - it('returns a sql statement when geometry array is empty', () => { const surveyData = { survey_details: { @@ -113,18 +100,6 @@ describe('postSurveyProprietorSQL', () => { }); describe('postFocalSpeciesSQL', () => { - it('returns null when null speciesId provided', () => { - const response = postFocalSpeciesSQL((null as unknown) as number, 1); - - expect(response).to.be.null; - }); - - it('returns null when null surveyId provided', () => { - const response = postFocalSpeciesSQL(1, (null as unknown) as number); - - expect(response).to.be.null; - }); - it('returns sql statement when valid params provided', () => { const response = postFocalSpeciesSQL(1, 2); @@ -133,18 +108,6 @@ describe('postFocalSpeciesSQL', () => { }); describe('postAncillarySpeciesSQL', () => { - it('returns null when null speciesId provided', () => { - const response = postAncillarySpeciesSQL((null as unknown) as number, 1); - - expect(response).to.be.null; - }); - - it('returns null when null surveyId provided', () => { - const response = postAncillarySpeciesSQL(1, (null as unknown) as number); - - expect(response).to.be.null; - }); - it('returns sql statement when valid params provided', () => { const response = postAncillarySpeciesSQL(1, 2); @@ -153,36 +116,6 @@ describe('postAncillarySpeciesSQL', () => { }); describe('postNewSurveyPermitSQL', () => { - it('returns null when null projectId provided', () => { - const response = postNewSurveyPermitSQL(1, (null as unknown) as number, 1, '123', 'scientific'); - - expect(response).to.be.null; - }); - - it('returns null when null surveyId provided', () => { - const response = postNewSurveyPermitSQL(1, 1, (null as unknown) as number, '123', 'scientific'); - - expect(response).to.be.null; - }); - - it('returns null when null permitNumber provided', () => { - const response = postNewSurveyPermitSQL(1, 1, 2, (null as unknown) as string, 'scientific'); - - expect(response).to.be.null; - }); - - it('returns null when null permitType provided', () => { - const response = postNewSurveyPermitSQL(1, 1, 2, '123', (null as unknown) as string); - - expect(response).to.be.null; - }); - - it('returns null when null systemUserId provided', () => { - const response = postNewSurveyPermitSQL(null, 1, 2, '123', 'scientific'); - - expect(response).to.be.null; - }); - it('returns sql statement when valid params provided', () => { const response = postNewSurveyPermitSQL(1, 1, 2, '123', 'scientific'); @@ -191,18 +124,6 @@ describe('postNewSurveyPermitSQL', () => { }); describe('insertSurveyFundingSourceSQL', () => { - it('returns null when null surveyId provided', () => { - const response = insertSurveyFundingSourceSQL((null as unknown) as number, 1); - - expect(response).to.be.null; - }); - - it('returns null when null fundingSourceId provided', () => { - const response = insertSurveyFundingSourceSQL(1, (null as unknown) as number); - - expect(response).to.be.null; - }); - it('returns sql statement when valid params provided', () => { const response = insertSurveyFundingSourceSQL(1, 2); diff --git a/api/src/queries/survey/survey-create-queries.ts b/api/src/queries/survey/survey-create-queries.ts index 833bed1103..bd90855cf8 100644 --- a/api/src/queries/survey/survey-create-queries.ts +++ b/api/src/queries/survey/survey-create-queries.ts @@ -9,11 +9,7 @@ import { queries } from '../queries'; * @param {PostSurveyObject} survey * @returns {SQLStatement} sql query object */ -export const postSurveySQL = (projectId: number, survey: PostSurveyObject): SQLStatement | null => { - if (!projectId || !survey) { - return null; - } - +export const postSurveySQL = (projectId: number, survey: PostSurveyObject): SQLStatement => { const sqlStatement: SQLStatement = SQL` INSERT INTO survey ( project_id, @@ -111,11 +107,7 @@ export const postSurveyProprietorSQL = (surveyId: number, survey_proprietor: Pos * @param {number} fundingSourceId * @returns {SQLStatement} sql query object */ -export const insertSurveyFundingSourceSQL = (surveyId: number, fundingSourceId: number): SQLStatement | null => { - if (!surveyId || !fundingSourceId) { - return null; - } - +export const insertSurveyFundingSourceSQL = (surveyId: number, fundingSourceId: number): SQLStatement => { const sqlStatement: SQLStatement = SQL` INSERT INTO survey_funding_source ( survey_id, @@ -132,7 +124,7 @@ export const insertSurveyFundingSourceSQL = (surveyId: number, fundingSourceId: /** * SQL query to insert a survey permit row into the permit table. * - * @param {number | null} systemUserId + * @param {number } systemUserId * @param {number} projectId * @param {number} surveyId * @param {string} permitNumber @@ -140,16 +132,12 @@ export const insertSurveyFundingSourceSQL = (surveyId: number, fundingSourceId: * @returns {SQLStatement} sql query object */ export const postNewSurveyPermitSQL = ( - systemUserId: number | null, + systemUserId: number, projectId: number, surveyId: number, permitNumber: string, permitType: string -): SQLStatement | null => { - if (!systemUserId || !projectId || !surveyId || !permitNumber || !permitType) { - return null; - } - +): SQLStatement => { const sqlStatement: SQLStatement = SQL` INSERT INTO permit ( system_user_id, @@ -176,11 +164,7 @@ export const postNewSurveyPermitSQL = ( * @param {number} surveyId * @returns {SQLStatement} sql query object */ -export const postFocalSpeciesSQL = (speciesId: number, surveyId: number): SQLStatement | null => { - if (!speciesId || !surveyId) { - return null; - } - +export const postFocalSpeciesSQL = (speciesId: number, surveyId: number): SQLStatement => { const sqlStatement: SQLStatement = SQL` INSERT INTO study_species ( wldtaxonomic_units_id, @@ -203,11 +187,7 @@ export const postFocalSpeciesSQL = (speciesId: number, surveyId: number): SQLSta * @param {number} surveyId * @returns {SQLStatement} sql query object */ -export const postAncillarySpeciesSQL = (speciesId: number, surveyId: number): SQLStatement | null => { - if (!speciesId || !surveyId) { - return null; - } - +export const postAncillarySpeciesSQL = (speciesId: number, surveyId: number): SQLStatement => { const sqlStatement: SQLStatement = SQL` INSERT INTO study_species ( wldtaxonomic_units_id, @@ -230,11 +210,7 @@ export const postAncillarySpeciesSQL = (speciesId: number, surveyId: number): SQ * @param {number} surveyId * @returns {SQLStatement} sql query object */ -export const postVantageCodesSQL = (vantageCodeId: number, surveyId: number): SQLStatement | null => { - if (!vantageCodeId || !surveyId) { - return null; - } - +export const postVantageCodesSQL = (vantageCodeId: number, surveyId: number): SQLStatement => { const sqlStatement: SQLStatement = SQL` INSERT INTO survey_vantage ( vantage_id, diff --git a/api/src/queries/survey/survey-occurrence-queries.test.ts b/api/src/queries/survey/survey-occurrence-queries.test.ts index dd3efd5a0d..52531f8615 100644 --- a/api/src/queries/survey/survey-occurrence-queries.test.ts +++ b/api/src/queries/survey/survey-occurrence-queries.test.ts @@ -75,12 +75,6 @@ describe('deleteOccurrenceSubmissionSQL', () => { }); describe('getLatestSurveyOccurrenceSubmission', () => { - it('returns null response when null surveyId provided', () => { - const response = getLatestSurveyOccurrenceSubmissionSQL((null as unknown) as number); - - expect(response).to.be.null; - }); - it('returns non null response when valid params provided', () => { const response = getLatestSurveyOccurrenceSubmissionSQL(1); diff --git a/api/src/queries/survey/survey-occurrence-queries.ts b/api/src/queries/survey/survey-occurrence-queries.ts index daeb94a7ca..20ce666f0e 100644 --- a/api/src/queries/survey/survey-occurrence-queries.ts +++ b/api/src/queries/survey/survey-occurrence-queries.ts @@ -145,11 +145,7 @@ export const updateSurveyOccurrenceSubmissionSQL = (data: { * @param {number} surveyId * @returns {SQLStatement} sql query object */ -export const getLatestSurveyOccurrenceSubmissionSQL = (surveyId: number): SQLStatement | null => { - if (!surveyId) { - return null; - } - +export const getLatestSurveyOccurrenceSubmissionSQL = (surveyId: number): SQLStatement => { return SQL` SELECT os.occurrence_submission_id as id, diff --git a/api/src/queries/survey/survey-view-queries.test.ts b/api/src/queries/survey/survey-view-queries.test.ts index fdc5954388..021558d099 100644 --- a/api/src/queries/survey/survey-view-queries.test.ts +++ b/api/src/queries/survey/survey-view-queries.test.ts @@ -2,6 +2,10 @@ import { expect } from 'chai'; import { describe } from 'mocha'; import { getAllAssignablePermitsForASurveySQL, + getAttachmentsBySurveySQL, + getLatestOccurrenceSubmissionIdSQL, + getLatestSummaryResultIdSQL, + getReportAttachmentsBySurveySQL, getSurveyBasicDataForViewSQL, getSurveyFocalSpeciesDataForViewSQL, getSurveyFundingSourcesDataForViewSQL, @@ -9,12 +13,6 @@ import { } from './survey-view-queries'; describe('getAllAssignablePermitsForASurveySQL', () => { - it('returns null when null project id param provided', () => { - const response = getAllAssignablePermitsForASurveySQL((null as unknown) as number); - - expect(response).to.be.null; - }); - it('returns a non null response when valid params passed in', () => { const response = getAllAssignablePermitsForASurveySQL(1); @@ -31,42 +29,56 @@ describe('getSurveyIdsSQL', () => { }); describe('getSurveyBasicDataForViewSQL', () => { - it('returns a null response when null survey id param provided', () => { - const response = getSurveyBasicDataForViewSQL((null as unknown) as number); + it('returns a non null response when valid params passed in', () => { + const response = getSurveyBasicDataForViewSQL(1); - expect(response).to.be.null; + expect(response).to.not.be.null; }); +}); +describe('getSurveyFundingSourcesDataForViewSQL', () => { it('returns a non null response when valid params passed in', () => { - const response = getSurveyBasicDataForViewSQL(1); + const response = getSurveyFundingSourcesDataForViewSQL(1); expect(response).to.not.be.null; }); }); -describe('getSurveyFundingSourcesDataForViewSQL', () => { - it('returns a null response when null survey id param provided', () => { - const response = getSurveyFundingSourcesDataForViewSQL((null as unknown) as number); +describe('getSurveyFocalSpeciesDataForViewSQL', () => { + it('returns a non null response when valid params passed in', () => { + const response = getSurveyFocalSpeciesDataForViewSQL(1); - expect(response).to.be.null; + expect(response).to.not.be.null; }); +}); +describe('getLatestOccurrenceSubmissionIdSQL', () => { it('returns a non null response when valid params passed in', () => { - const response = getSurveyFundingSourcesDataForViewSQL(1); + const response = getLatestOccurrenceSubmissionIdSQL(1); expect(response).to.not.be.null; }); }); -describe('getSurveyFocalSpeciesDataForViewSQL', () => { - it('returns a null response when null survey id param provided', () => { - const response = getSurveyFocalSpeciesDataForViewSQL((null as unknown) as number); +describe('getLatestSummaryResultIdSQL', () => { + it('returns a non null response when valid params passed in', () => { + const response = getLatestSummaryResultIdSQL(1); + + expect(response).to.not.be.null; + }); +}); + +describe('getAttachmentsBySurveySQL', () => { + it('returns a non null response when valid params passed in', () => { + const response = getAttachmentsBySurveySQL(1); - expect(response).to.be.null; + expect(response).to.not.be.null; }); +}); +describe('getReportAttachmentsBySurveySQL', () => { it('returns a non null response when valid params passed in', () => { - const response = getSurveyFocalSpeciesDataForViewSQL(1); + const response = getReportAttachmentsBySurveySQL(1); expect(response).to.not.be.null; }); diff --git a/api/src/queries/survey/survey-view-queries.ts b/api/src/queries/survey/survey-view-queries.ts index feea64310a..d62f510210 100644 --- a/api/src/queries/survey/survey-view-queries.ts +++ b/api/src/queries/survey/survey-view-queries.ts @@ -9,11 +9,7 @@ import { SQL, SQLStatement } from 'sql-template-strings'; * @param {number} projectId * @returns {SQLStatement} sql query object */ -export const getAllAssignablePermitsForASurveySQL = (projectId: number): SQLStatement | null => { - if (!projectId) { - return null; - } - +export const getAllAssignablePermitsForASurveySQL = (projectId: number): SQLStatement => { return SQL` SELECT number, @@ -44,11 +40,7 @@ export const getSurveyIdsSQL = (projectId: number): SQLStatement => { `; }; -export const getSurveyBasicDataForViewSQL = (surveyId: number): SQLStatement | null => { - if (!surveyId) { - return null; - } - +export const getSurveyBasicDataForViewSQL = (surveyId: number): SQLStatement => { return SQL` SELECT s.survey_id as id, @@ -109,11 +101,7 @@ export const getSurveyBasicDataForViewSQL = (surveyId: number): SQLStatement | n `; }; -export const getSurveyFundingSourcesDataForViewSQL = (surveyId: number): SQLStatement | null => { - if (!surveyId) { - return null; - } - +export const getSurveyFundingSourcesDataForViewSQL = (surveyId: number): SQLStatement => { return SQL` SELECT sfs.project_funding_source_id, @@ -160,11 +148,7 @@ export const getSurveyFundingSourcesDataForViewSQL = (surveyId: number): SQLStat `; }; -export const getSurveyFocalSpeciesDataForViewSQL = (surveyId: number): SQLStatement | null => { - if (!surveyId) { - return null; - } - +export const getSurveyFocalSpeciesDataForViewSQL = (surveyId: number): SQLStatement => { return SQL` SELECT wldtaxonomic_units_id, is_focal @@ -177,11 +161,7 @@ export const getSurveyFocalSpeciesDataForViewSQL = (surveyId: number): SQLStatem `; }; -export const getLatestOccurrenceSubmissionIdSQL = (surveyId: number): SQLStatement | null => { - if (!surveyId) { - return null; - } - +export const getLatestOccurrenceSubmissionIdSQL = (surveyId: number): SQLStatement => { return SQL` SELECT max(occurrence_submission_id) as id @@ -192,11 +172,7 @@ export const getLatestOccurrenceSubmissionIdSQL = (surveyId: number): SQLStateme `; }; -export const getLatestSummaryResultIdSQL = (surveyId: number): SQLStatement | null => { - if (!surveyId) { - return null; - } - +export const getLatestSummaryResultIdSQL = (surveyId: number): SQLStatement => { return SQL` SELECT max(survey_summary_submission_id) as id @@ -206,3 +182,56 @@ export const getLatestSummaryResultIdSQL = (surveyId: number): SQLStatement | nu survey_id = ${surveyId}; `; }; + +/** + * SQL query to get survey attachments. + * + * @param {number} surveyId + * @returns {SQLStatement} sql query object + */ +export const getAttachmentsBySurveySQL = (surveyId: number): SQLStatement => { + return SQL` + SELECT + * + FROM + survey_attachment + WHERE + survey_id = ${surveyId}; + `; +}; + +/** + * SQL query to get survey reports. + * + * @param {number} surveyId + * @returns {SQLStatement} sql query object + */ +export const getReportAttachmentsBySurveySQL = (surveyId: number): SQLStatement => { + return SQL` + SELECT + pra.survey_report_attachment_id + , pra.survey_id + , pra.file_name + , pra.title + , pra.description + , pra.year + , pra."key" + , pra.file_size + , pra.security_token + , array_remove(array_agg(pra2.first_name ||' '||pra2.last_name), null) authors + FROM + survey_report_attachment pra + LEFT JOIN survey_report_author pra2 ON pra2.survey_report_attachment_id = pra.survey_report_attachment_id + WHERE pra.survey_id = ${surveyId} + GROUP BY + pra.survey_report_attachment_id + , pra.survey_id + , pra.file_name + , pra.title + , pra.description + , pra.year + , pra."key" + , pra.file_size + , pra.security_token; + `; +}; diff --git a/api/src/services/eml-service.ts b/api/src/services/eml-service.ts index 4d70306b68..75891b5319 100644 --- a/api/src/services/eml-service.ts +++ b/api/src/services/eml-service.ts @@ -5,8 +5,16 @@ import { coordEach } from '@turf/meta'; import jsonpatch from 'fast-json-patch'; import xml2js from 'xml2js'; import { IDBConnection } from '../database/db'; -import { IGetProject } from '../models/project-view'; -import { SurveyObject } from '../models/survey-view'; +import { + GetAttachmentsData as GetProjectAttachmentsData, + GetReportAttachmentsData as GetProjectReportAttachmentsData, + IGetProject +} from '../models/project-view'; +import { + GetAttachmentsData as GetSurveyAttachmentsData, + GetReportAttachmentsData as GetSurveyReportAttachmentsData, + SurveyObject +} from '../models/survey-view'; import { getDbCharacterSystemMetaDataConstantSQL } from '../queries/codes/db-constant-queries'; import { CodeService, IAllCodeSets } from './code-service'; import { ProjectService } from './project-service'; @@ -36,9 +44,16 @@ type EMLDBConstants = { EML_INTELLECTUAL_RIGHTS: string; }; +type SurveyObjectWithAttachments = SurveyObject & { + attachments?: GetSurveyAttachmentsData; + report_attachments?: GetSurveyReportAttachmentsData; +}; + type Cache = { projectData?: IGetProject; - surveyData?: SurveyObject[]; + surveyData?: SurveyObjectWithAttachments[]; + projectAttachmentData?: GetProjectAttachmentsData; + projectReportAttachmentData?: GetProjectReportAttachmentsData; codes?: IAllCodeSets; }; @@ -188,13 +203,25 @@ export class EmlService extends DBService { return this.cache.projectData; } + get projectAttachmentData(): GetProjectAttachmentsData | undefined { + return this.cache.projectAttachmentData; + } + + get projectReportAttachmentData(): GetProjectReportAttachmentsData | undefined { + return this.cache.projectReportAttachmentData; + } + async loadProjectData() { const projectData = await this.projectService.getProjectById(this.projectId); + const attachmentData = await this.projectService.getAttachmentsData(this.projectId); + const attachmentReportData = await this.projectService.getReportAttachmentsData(this.projectId); this.cache.projectData = projectData; + this.cache.projectAttachmentData = attachmentData; + this.cache.projectReportAttachmentData = attachmentReportData; } - get surveyData(): SurveyObject[] { + get surveyData(): SurveyObjectWithAttachments[] { if (!this.cache.surveyData) { throw Error('Survey data was not loaded'); } @@ -213,6 +240,14 @@ export class EmlService extends DBService { const surveyData = await this.surveyService.getSurveysByIds(includedSurveyIds); this.cache.surveyData = surveyData; + + this.cache.surveyData.forEach( + async (item) => (item.attachments = await this.surveyService.getAttachmentsData(item.survey_details.id)) + ); + this.cache.surveyData.forEach( + async (item) => + (item.report_attachments = await this.surveyService.getReportAttachmentsData(item.survey_details.id)) + ); } buildEMLSection() { @@ -251,11 +286,12 @@ export class EmlService extends DBService { $: { system: this.constants.EML_PROVIDER_URL, id: this.packageId }, title: options?.datasetTitle || this.projectData.project.project_name, creator: this.getDatasetCreator(), - pubDate: new Date().toISOString(), metadataProvider: { organizationName: this.constants.EML_ORGANIZATION_NAME, onlineUrl: this.constants.EML_ORGANIZATION_URL }, + //EML specification expects short ISO format + pubDate: new Date().toISOString().substring(0, 10), language: 'English', contact: this.getProjectContact(), project: { @@ -446,6 +482,62 @@ export class EmlService extends DBService { }); }); + if (this.projectAttachmentData?.attachmentDetails.length) { + data.push({ + describes: this.projectData.project.uuid, + metadata: { + projectAttachments: { + projectAttachment: this.projectAttachmentData.attachmentDetails.map((item) => { + return item; + }) + } + } + }); + } + + if (this.projectReportAttachmentData?.attachmentDetails.length) { + data.push({ + describes: this.projectData.project.uuid, + metadata: { + projectReportAttachments: { + projectReportAttachment: this.projectReportAttachmentData.attachmentDetails.map((item) => { + return item; + }) + } + } + }); + } + + this.surveyData.forEach((item) => { + if (item.attachments?.attachmentDetails.length) { + data.push({ + describes: item.survey_details.uuid, + metadata: { + surveyAttachments: { + surveyAttachment: item.attachments?.attachmentDetails.map((item) => { + return item; + }) + } + } + }); + } + }); + + this.surveyData.forEach((item) => { + if (item.report_attachments?.attachmentDetails.length) { + data.push({ + describes: item.survey_details.uuid, + metadata: { + surveyReportAttachments: { + surveyReportAttachment: item.report_attachments?.attachmentDetails.map((item) => { + return item; + }) + } + } + }); + } + }); + jsonpatch.applyOperation(this.data, { op: 'add', path: '/eml:eml/additionalMetadata', @@ -521,11 +613,11 @@ export class EmlService extends DBService { * Get all contacts for the survey. * * @ - * @param {SurveyObject} surveyData + * @param {SurveyObjectWithAttachments} surveyData * @return {*} {Record[]} * @memberof EmlService */ - getSurveyPersonnel(surveyData: SurveyObject): Record[] { + getSurveyPersonnel(surveyData: SurveyObjectWithAttachments): Record[] { return [ { individualName: { @@ -561,7 +653,7 @@ export class EmlService extends DBService { }; } - getSurveyFundingSources(surveyData: SurveyObject): Record { + getSurveyFundingSources(surveyData: SurveyObjectWithAttachments): Record { if (!surveyData.funding.funding_sources.length) { return {}; } @@ -603,7 +695,7 @@ export class EmlService extends DBService { }; } - getSurveyTemporalCoverageEML(surveyData: SurveyObject): Record { + getSurveyTemporalCoverageEML(surveyData: SurveyObjectWithAttachments): Record { if (!surveyData.survey_details.end_date) { // no end date return { @@ -670,7 +762,7 @@ export class EmlService extends DBService { }; } - getSurveyGeographicCoverageEML(surveyData: SurveyObject): Record { + getSurveyGeographicCoverageEML(surveyData: SurveyObjectWithAttachments): Record { if (!surveyData.location.geometry?.length) { return {}; } @@ -719,7 +811,7 @@ export class EmlService extends DBService { }; } - async getSurveyFocalTaxonomicCoverage(surveyData: SurveyObject): Promise> { + async getSurveyFocalTaxonomicCoverage(surveyData: SurveyObjectWithAttachments): Promise> { const taxonomySearchService = new TaxonomyService(); // TODO include ancillary_species alongside focal_species? @@ -741,7 +833,7 @@ export class EmlService extends DBService { return { taxonomicClassification: taxonomicClassifications }; } - async getSurveyDesignDescription(surveyData: SurveyObject): Promise> { + async getSurveyDesignDescription(surveyData: SurveyObjectWithAttachments): Promise> { return { description: { section: [ @@ -784,7 +876,7 @@ export class EmlService extends DBService { return Promise.all(promises); } - async getSurveyEML(surveyData: SurveyObject): Promise> { + async getSurveyEML(surveyData: SurveyObjectWithAttachments): Promise> { return { $: { id: surveyData.survey_details.uuid, system: this.constants.EML_PROVIDER_URL }, title: surveyData.survey_details.survey_name, diff --git a/api/src/services/project-service.test.ts b/api/src/services/project-service.test.ts index fa4a3000d3..e582178eee 100644 --- a/api/src/services/project-service.test.ts +++ b/api/src/services/project-service.test.ts @@ -392,7 +392,7 @@ describe('ProjectService', () => { }); it('returns empty array if there are no rows', async () => { - const mockQueryResponse = ({ rows: [] } as unknown) as QueryResult; + const mockQueryResponse = ({} as unknown) as QueryResult; const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); sinon.stub(queries.project, 'getProjectListSQL').returns(SQL`valid sql`); @@ -503,3 +503,282 @@ describe('ProjectService', () => { expect(result.id).to.equal(1); }); }); + +describe('getProjectData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if valid return', async () => { + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const projectService = new ProjectService(mockDBConnection); + + const response = await projectService.getProjectData(1); + + expect(response).to.eql(new GetProjectData({ id: 1 }, [{ id: 1 }])); + }); + + it('returns null if response is empty', async () => { + const mockQueryResponse = ({ rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const projectService = new ProjectService(mockDBConnection); + + try { + await projectService.getProjectData(1); + expect.fail(); + } catch (actualError) { + expect((actualError as HTTPError).message).to.equal('Failed to get project data'); + expect((actualError as HTTPError).status).to.equal(400); + } + }); +}); + +describe('getObjectivesData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if valid return', async () => { + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const projectService = new ProjectService(mockDBConnection); + + const response = await projectService.getObjectivesData(1); + + expect(response).to.eql(new GetObjectivesData({ id: 1 })); + }); + + it('returns null if response is empty', async () => { + const mockQueryResponse = ({ rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const projectService = new ProjectService(mockDBConnection); + + try { + await projectService.getObjectivesData(1); + expect.fail(); + } catch (actualError) { + expect((actualError as HTTPError).message).to.equal('Failed to get project objectives data'); + expect((actualError as HTTPError).status).to.equal(400); + } + }); +}); + +describe('getCoordinatorData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if valid return', async () => { + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const projectService = new ProjectService(mockDBConnection); + + const response = await projectService.getCoordinatorData(1); + + expect(response).to.eql(new GetCoordinatorData({ id: 1 })); + }); + + it('returns null if response is empty', async () => { + const mockQueryResponse = ({ rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const projectService = new ProjectService(mockDBConnection); + + try { + await projectService.getCoordinatorData(1); + expect.fail(); + } catch (actualError) { + expect((actualError as HTTPError).message).to.equal('Failed to get project contact data'); + expect((actualError as HTTPError).status).to.equal(400); + } + }); +}); + +describe('getPermitData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if valid return', async () => { + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const projectService = new ProjectService(mockDBConnection); + + const response = await projectService.getPermitData(1); + + expect(response).to.eql(new GetPermitData([{ id: 1 }])); + }); + + it('returns null if response is empty', async () => { + const mockQueryResponse = ({ rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const projectService = new ProjectService(mockDBConnection); + + try { + await projectService.getPermitData(1); + expect.fail(); + } catch (actualError) { + expect((actualError as HTTPError).message).to.equal('Failed to get project permit data'); + expect((actualError as HTTPError).status).to.equal(400); + } + }); +}); + +describe('getLocationData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if valid return', async () => { + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const projectService = new ProjectService(mockDBConnection); + + const response = await projectService.getLocationData(1); + + expect(response).to.eql(new GetLocationData([{ id: 1 }])); + }); + + it('returns null if response is empty', async () => { + const mockQueryResponse = ({ rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const projectService = new ProjectService(mockDBConnection); + + try { + await projectService.getLocationData(1); + expect.fail(); + } catch (actualError) { + expect((actualError as HTTPError).message).to.equal('Failed to get project data'); + expect((actualError as HTTPError).status).to.equal(400); + } + }); +}); + +describe('getIUCNClassificationData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if valid return', async () => { + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const projectService = new ProjectService(mockDBConnection); + + const response = await projectService.getIUCNClassificationData(1); + + expect(response).to.eql(new GetIUCNClassificationData([{ id: 1 }])); + }); + + it('returns null if response is empty', async () => { + const mockQueryResponse = ({ rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const projectService = new ProjectService(mockDBConnection); + + try { + await projectService.getIUCNClassificationData(1); + expect.fail(); + } catch (actualError) { + expect((actualError as HTTPError).message).to.equal('Failed to get project data'); + expect((actualError as HTTPError).status).to.equal(400); + } + }); +}); + +describe('getFundingData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if valid return', async () => { + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const projectService = new ProjectService(mockDBConnection); + + const response = await projectService.getFundingData(1); + + expect(response).to.eql(new GetFundingData([{ id: 1 }])); + }); + + it('returns null if response is empty', async () => { + const mockQueryResponse = ({} as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const projectService = new ProjectService(mockDBConnection); + + try { + await projectService.getFundingData(1); + expect.fail(); + } catch (actualError) { + expect((actualError as HTTPError).message).to.equal('Failed to get project data'); + expect((actualError as HTTPError).status).to.equal(400); + } + }); +}); + +describe('getPartnershipsData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if valid return', async () => { + sinon.stub(ProjectService.prototype, 'getIndigenousPartnershipsRows').resolves([]); + sinon.stub(ProjectService.prototype, 'getStakeholderPartnershipsRows').resolves([]); + + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const projectService = new ProjectService(mockDBConnection); + + const response = await projectService.getPartnershipsData(1); + + expect(response).to.eql(new GetPartnershipsData([], [])); + }); + + it('throws error if indigenous partnership is empty', async () => { + sinon.stub(ProjectService.prototype, 'getIndigenousPartnershipsRows').resolves(undefined); + sinon.stub(ProjectService.prototype, 'getStakeholderPartnershipsRows').resolves([]); + const mockQueryResponse = ({} as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const projectService = new ProjectService(mockDBConnection); + + try { + await projectService.getPartnershipsData(1); + expect.fail(); + } catch (actualError) { + expect((actualError as HTTPError).message).to.equal('Failed to get indigenous partnership data'); + expect((actualError as HTTPError).status).to.equal(400); + } + }); + + it('throws error if stakeholder partnership is empty', async () => { + sinon.stub(ProjectService.prototype, 'getIndigenousPartnershipsRows').resolves([]); + sinon.stub(ProjectService.prototype, 'getStakeholderPartnershipsRows').resolves(undefined); + + const mockQueryResponse = ({} as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const projectService = new ProjectService(mockDBConnection); + + try { + await projectService.getPartnershipsData(1); + expect.fail(); + } catch (actualError) { + expect((actualError as HTTPError).message).to.equal('Failed to get stakeholder partnership data'); + expect((actualError as HTTPError).status).to.equal(400); + } + }); +}); diff --git a/api/src/services/project-service.ts b/api/src/services/project-service.ts index 40ecb996e2..0412763347 100644 --- a/api/src/services/project-service.ts +++ b/api/src/services/project-service.ts @@ -21,6 +21,7 @@ import { PutProjectData } from '../models/project-update'; import { + GetAttachmentsData, GetCoordinatorData, GetFundingData, GetIUCNClassificationData, @@ -29,6 +30,7 @@ import { GetPartnershipsData, GetPermitData, GetProjectData, + GetReportAttachmentsData, IGetProject } from '../models/project-view'; import { getSurveyAttachmentS3Keys } from '../paths/project/{projectId}/survey/{surveyId}/delete'; @@ -354,10 +356,6 @@ export class ProjectService extends DBService { const getProjectSqlStatement = queries.project.getProjectSQL(projectId); const getProjectActivitiesSQLStatement = queries.project.getActivitiesByProjectSQL(projectId); - if (!getProjectSqlStatement || !getProjectActivitiesSQLStatement) { - throw new HTTP400('Failed to build SQL get statement'); - } - const [project, activity] = await Promise.all([ this.connection.query(getProjectSqlStatement.text, getProjectSqlStatement.values), this.connection.query(getProjectActivitiesSQLStatement.text, getProjectActivitiesSQLStatement.values) @@ -376,12 +374,7 @@ export class ProjectService extends DBService { async getObjectivesData(projectId: number): Promise { const sqlStatement = queries.project.getObjectivesByProjectSQL(projectId); - if (!sqlStatement) { - throw new HTTP400('Failed to build SQL get statement'); - } - const response = await this.connection.query(sqlStatement.text, sqlStatement.values); - const result = (response && response.rows && response.rows[0]) || null; if (!result) { @@ -394,12 +387,7 @@ export class ProjectService extends DBService { async getCoordinatorData(projectId: number): Promise { const sqlStatement = queries.project.getCoordinatorByProjectSQL(projectId); - if (!sqlStatement) { - throw new HTTP400('Failed to build SQL get statement'); - } - const response = await this.connection.query(sqlStatement.text, sqlStatement.values); - const result = (response && response.rows && response.rows[0]) || null; if (!result) { @@ -412,12 +400,7 @@ export class ProjectService extends DBService { async getPermitData(projectId: number): Promise { const sqlStatement = queries.project.getProjectPermitsSQL(projectId); - if (!sqlStatement) { - throw new HTTP400('Failed to build SQL select statement'); - } - const response = await this.connection.query(sqlStatement.text, sqlStatement.values); - const result = (response && response.rows) || null; if (!result) { @@ -430,10 +413,6 @@ export class ProjectService extends DBService { async getLocationData(projectId: number): Promise { const sqlStatement = queries.project.getLocationByProjectSQL(projectId); - if (!sqlStatement) { - throw new HTTP400('Failed to build SQL get statement'); - } - const response = await this.connection.query(sqlStatement.text, sqlStatement.values); const result = (response && response.rows) || null; @@ -448,10 +427,6 @@ export class ProjectService extends DBService { async getIUCNClassificationData(projectId: number): Promise { const sqlStatement = queries.project.getIUCNActionClassificationByProjectSQL(projectId); - if (!sqlStatement) { - throw new HTTP400('Failed to build SQL get statement'); - } - const response = await this.connection.query(sqlStatement.text, sqlStatement.values); const result = (response && response.rows) || null; @@ -466,10 +441,6 @@ export class ProjectService extends DBService { async getFundingData(projectId: number): Promise { const sqlStatement = queries.project.getFundingSourceByProjectSQL(projectId); - if (!sqlStatement) { - throw new HTTP400('Failed to build SQL get statement'); - } - const response = await this.connection.query(sqlStatement.text, sqlStatement.values); const result = (response && response.rows) || null; @@ -522,6 +493,34 @@ export class ProjectService extends DBService { return (response && response.rows) || null; } + async getAttachmentsData(projectId: number): Promise { + const sqlStatement = queries.project.getAttachmentsByProjectSQL(projectId); + + if (!sqlStatement) { + throw new HTTP400('Failed to build SQL get statement'); + } + + const response = await this.connection.query(sqlStatement.text, sqlStatement.values); + + const result = (response && response.rows) || null; + + return new GetAttachmentsData(result); + } + + async getReportAttachmentsData(projectId: number): Promise { + const sqlStatement = queries.project.getReportAttachmentsByProjectSQL(projectId); + + if (!sqlStatement) { + throw new HTTP400('Failed to build SQL get statement'); + } + + const response = await this.connection.query(sqlStatement.text, sqlStatement.values); + + const result = (response && response.rows) || null; + + return new GetReportAttachmentsData(result); + } + async createProject(postProjectData: PostProjectObject): Promise { const projectId = await this.insertProject(postProjectData); diff --git a/api/src/services/survey-service.test.ts b/api/src/services/survey-service.test.ts index 15645a832c..aca9551863 100644 --- a/api/src/services/survey-service.test.ts +++ b/api/src/services/survey-service.test.ts @@ -3,9 +3,24 @@ import { describe } from 'mocha'; import { QueryResult } from 'pg'; import sinon from 'sinon'; import sinonChai from 'sinon-chai'; +import { ApiGeneralError } from '../errors/custom-error'; +import { GetReportAttachmentsData } from '../models/project-view'; +import { PostProprietorData, PostSurveyObject } from '../models/survey-create'; import { PutSurveyObject } from '../models/survey-update'; +import { + GetAncillarySpeciesData, + GetAttachmentsData, + GetFocalSpeciesData, + GetPermitData, + GetSurveyData, + GetSurveyFundingSources, + GetSurveyLocationData, + GetSurveyProprietorData, + GetSurveyPurposeAndMethodologyData +} from '../models/survey-view'; import { getMockDBConnection } from '../__mocks__/db'; import { SurveyService } from './survey-service'; +import { TaxonomyService } from './taxonomy-service'; chai.use(sinonChai); @@ -104,4 +119,987 @@ describe('SurveyService', () => { expect(response).to.eql({ id: 123 }); }); }); + + describe('getSurveyIdsByProjectId', () => { + afterEach(() => { + sinon.restore(); + }); + + it('Gets survey ids by project id', async () => { + const mockRowObj = { id: 123 }; + const mockQueryResponse = ({ rows: [mockRowObj] } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ sql: async () => mockQueryResponse }); + + const projectId = 1; + + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.getSurveyIdsByProjectId(projectId); + + expect(response).to.eql([{ id: 123 }]); + }); + }); + + describe('getSurveyById', () => { + afterEach(() => { + sinon.restore(); + }); + + it('Gets survey data by id', async () => { + const getSurveyDataStub = sinon + .stub(SurveyService.prototype, 'getSurveyData') + .resolves(({ id: 1 } as unknown) as GetSurveyData); + + const getSpeciesDataStub = sinon + .stub(SurveyService.prototype, 'getSpeciesData') + .resolves(({ focal_species: [1] } as unknown) as GetFocalSpeciesData & GetAncillarySpeciesData); + + const getPermitDataStub = sinon + .stub(SurveyService.prototype, 'getPermitData') + .resolves(({ permit_number: 1 } as unknown) as GetPermitData); + + const getSurveyFundingSourcesDataStub = sinon + .stub(SurveyService.prototype, 'getSurveyFundingSourcesData') + .resolves(({ funding_sources: [1] } as unknown) as GetSurveyFundingSources); + + const getSurveyPurposeAndMethodologyStub = sinon + .stub(SurveyService.prototype, 'getSurveyPurposeAndMethodology') + .resolves(({ GetSurveyPurposeAndMethodologyData: 1 } as unknown) as GetSurveyPurposeAndMethodologyData); + + const getSurveyProprietorDataForViewStub = sinon + .stub(SurveyService.prototype, 'getSurveyProprietorDataForView') + .resolves(({ proprietor_type_id: 1 } as unknown) as GetSurveyProprietorData); + + const getSurveyLocationDataStub = sinon + .stub(SurveyService.prototype, 'getSurveyLocationData') + .resolves(({ survey_area_name: 'name' } as unknown) as GetSurveyLocationData); + + const surveyService = new SurveyService(getMockDBConnection()); + const response = await surveyService.getSurveyById(1); + + expect(response).to.eql({ + survey_details: { id: 1 }, + species: { focal_species: [1] }, + permit: { permit_number: 1 }, + purpose_and_methodology: { GetSurveyPurposeAndMethodologyData: 1 }, + funding: { funding_sources: [1] }, + proprietor: { proprietor_type_id: 1 }, + location: { survey_area_name: 'name' } + }); + + expect(getSurveyDataStub).to.be.calledOnce; + expect(getSpeciesDataStub).to.be.calledOnce; + expect(getPermitDataStub).to.be.calledOnce; + expect(getSurveyFundingSourcesDataStub).to.be.calledOnce; + expect(getSurveyPurposeAndMethodologyStub).to.be.calledOnce; + expect(getSurveyProprietorDataForViewStub).to.be.calledOnce; + expect(getSurveyLocationDataStub).to.be.calledOnce; + }); + }); + + describe('getSurveySupplementaryDataById', () => { + afterEach(() => { + sinon.restore(); + }); + + it('Gets data if no errors', async () => { + const getOccurrenceSubmissionIdStub = sinon + .stub(SurveyService.prototype, 'getOccurrenceSubmissionId') + .resolves(({ occurrence_submission: 1 } as unknown) as any); + + const getSummaryResultIdStub = sinon + .stub(SurveyService.prototype, 'getSummaryResultId') + .resolves(({ survey_summary_submission: 1 } as unknown) as any); + + const surveyService = new SurveyService(getMockDBConnection()); + + const response = await surveyService.getSurveySupplementaryDataById(1); + + expect(response).to.eql({ + occurrence_submission: { occurrence_submission: 1 }, + summary_result: { survey_summary_submission: 1 } + }); + expect(getOccurrenceSubmissionIdStub).to.be.calledOnce; + expect(getSummaryResultIdStub).to.be.calledOnce; + }); + }); + + describe('getSurveyData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('throws api error if response is null', async () => { + const mockQueryResponse = ({} as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ sql: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + try { + await surveyService.getSurveyData(1); + expect.fail(); + } catch (actualError) { + expect((actualError as ApiGeneralError).message).to.equal('Failed to get project survey details data'); + } + }); + + it('Gets all survey data if response is not null', async () => { + const mockRowObj = { id: 123 }; + const mockQueryResponse = ({ rows: [mockRowObj] } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ sql: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.getSurveyData(1); + + expect(response).to.eql(new GetSurveyData(mockRowObj)); + }); + }); + + describe('getSpeciesData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('throws api error if response is null', async () => { + const mockQueryResponse = ({} as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + try { + await surveyService.getSpeciesData(1); + expect.fail(); + } catch (actualError) { + expect((actualError as ApiGeneralError).message).to.equal('Failed to get survey species data'); + } + }); + + it('returns data if response is not null', async () => { + const getSpeciesFromIds = sinon + .stub(TaxonomyService.prototype, 'getSpeciesFromIds') + .resolves(([{ id: 123 }] as unknown) as any); + + const mockRowObj = [ + { is_focal: true, wldtaxonomic_units_id: 123 }, + { is_focal: false, wldtaxonomic_units_id: 321 } + ]; + const mockQueryResponse = ({ rows: [mockRowObj] } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.getSpeciesData(1); + + expect(response).to.eql({ + ...new GetFocalSpeciesData([{ id: 123 }]), + ...new GetAncillarySpeciesData([{ id: 123 }]) + }); + expect(getSpeciesFromIds).to.be.calledTwice; + }); + }); + + describe('getPermitData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if valid return', async () => { + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.getPermitData(1); + + expect(response).to.eql(new GetPermitData({ id: 1 })); + }); + }); + + describe('getSurveyPurposeAndMethodology', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if valid return', async () => { + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.getSurveyPurposeAndMethodology(1); + + expect(response).to.eql(new GetSurveyPurposeAndMethodologyData({ id: 1 })); + }); + + it('throws error if response is invalid', async () => { + const mockQueryResponse = ({ rows: [] } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + try { + await surveyService.getSurveyPurposeAndMethodology(1); + expect.fail(); + } catch (actualError) { + expect((actualError as ApiGeneralError).message).to.equal('Failed to get survey purpose and methodology data'); + } + }); + }); + + describe('getSurveyFundingSourcesData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if valid return', async () => { + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.getSurveyFundingSourcesData(1); + + expect(response).to.eql(new GetSurveyFundingSources([{ id: 1 }])); + }); + + it('throws error if response is invalid', async () => { + const mockQueryResponse = ({} as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + try { + await surveyService.getSurveyFundingSourcesData(1); + expect.fail(); + } catch (actualError) { + expect((actualError as ApiGeneralError).message).to.equal('Failed to get survey funding sources data'); + } + }); + }); + + describe('getSurveyProprietorDataForView', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if valid return', async () => { + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.getSurveyProprietorDataForView(1); + + expect(response).to.eql(new GetSurveyProprietorData([{ id: 1 }])); + }); + }); + + describe('getSurveyLocationData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if valid return', async () => { + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ sql: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.getSurveyLocationData(1); + + expect(response).to.eql(new GetSurveyLocationData({ id: 1 })); + }); + + it('throws error if response is invalid', async () => { + const mockQueryResponse = ({ rows: [] } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ sql: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + try { + await surveyService.getSurveyLocationData(1); + expect.fail(); + } catch (actualError) { + expect((actualError as ApiGeneralError).message).to.equal('Failed to get project survey details data'); + } + }); + }); + + describe('getOccurrenceSubmissionId', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if valid return', async () => { + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.getOccurrenceSubmissionId(1); + + expect(response).to.eql({ id: 1 }); + }); + + it('returns null if response is empty', async () => { + const mockQueryResponse = ({ rows: [], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.getOccurrenceSubmissionId(1); + + expect(response).to.eql(null); + }); + }); + + describe('getLatestSurveyOccurrenceSubmission', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if valid return', async () => { + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.getLatestSurveyOccurrenceSubmission(1); + + expect(response).to.eql({ id: 1 }); + }); + + it('returns null if response is empty', async () => { + const mockQueryResponse = ({ rows: [], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.getLatestSurveyOccurrenceSubmission(1); + + expect(response).to.eql(null); + }); + }); + + describe('getSummaryResultId', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if valid return', async () => { + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.getSummaryResultId(1); + + expect(response).to.eql({ id: 1 }); + }); + + it('returns null if response is empty', async () => { + const mockQueryResponse = ({ rows: [], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.getSummaryResultId(1); + + expect(response).to.eql(null); + }); + }); + + describe('getAttachmentsData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if valid return', async () => { + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.getAttachmentsData(1); + + expect(response).to.eql(new GetAttachmentsData([{ id: 1 }])); + }); + }); + + describe('getReportAttachmentsData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if valid return', async () => { + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.getReportAttachmentsData(1); + + expect(response).to.eql(new GetReportAttachmentsData([{ id: 1 }])); + }); + }); + + describe('insertSurveyData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if valid return', async () => { + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ sql: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.insertSurveyData(1, ({ + survey_details: { + survey_name: 'name', + start_date: 'date', + end_date: 'date', + biologist_first_name: 'name', + biologist_last_name: 'name' + }, + purpose_and_methodology: { + field_method_id: 'name', + additional_details: 'date', + ecological_season_id: 'date', + intended_outcome_id: 'name', + surveyed_all_areas: 'name' + }, + location: { survey_area_name: 'name', geometry: [{ stuff: 'geometry' }] } + } as unknown) as PostSurveyObject); + + expect(response).to.eql(1); + }); + + it('throws error if response is invalid', async () => { + const mockQueryResponse = ({ rows: [] } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ sql: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + try { + await surveyService.insertSurveyData(1, ({ + survey_details: { + survey_name: 'name', + start_date: 'date', + end_date: 'date', + biologist_first_name: 'name', + biologist_last_name: 'name' + }, + purpose_and_methodology: { + field_method_id: 'name', + additional_details: 'date', + ecological_season_id: 'date', + intended_outcome_id: 'name', + surveyed_all_areas: 'name' + }, + location: { survey_area_name: 'name', geometry: [{ stuff: 'geometry' }] } + } as unknown) as PostSurveyObject); + expect.fail(); + } catch (actualError) { + expect((actualError as ApiGeneralError).message).to.equal('Failed to insert survey data'); + } + }); + }); + + describe('insertFocalSpecies', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if valid return', async () => { + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.insertFocalSpecies(1, 1); + + expect(response).to.eql(1); + }); + + it('throws error if response is invalid', async () => { + const mockQueryResponse = ({ rows: [] } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + try { + await surveyService.insertFocalSpecies(1, 1); + expect.fail(); + } catch (actualError) { + expect((actualError as ApiGeneralError).message).to.equal('Failed to insert focal species data'); + } + }); + }); + + describe('insertAncillarySpecies', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if valid return', async () => { + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.insertAncillarySpecies(1, 1); + + expect(response).to.eql(1); + }); + + it('throws error if response is invalid', async () => { + const mockQueryResponse = ({ rows: [] } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + try { + await surveyService.insertAncillarySpecies(1, 1); + expect.fail(); + } catch (actualError) { + expect((actualError as ApiGeneralError).message).to.equal('Failed to insert ancillary species data'); + } + }); + }); + + describe('insertVantageCodes', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if valid return', async () => { + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.insertVantageCodes(1, 1); + + expect(response).to.eql(1); + }); + + it('throws error if response is invalid', async () => { + const mockQueryResponse = ({ rows: [] } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + try { + await surveyService.insertVantageCodes(1, 1); + expect.fail(); + } catch (actualError) { + expect((actualError as ApiGeneralError).message).to.equal('Failed to insert ancillary species data'); + } + }); + }); + + describe('insertSurveyProprietor', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns in survey_data_proprietary is undefinded', async () => { + const mockQueryResponse = ({ rows: [], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.insertSurveyProprietor(({ prt_id: 1 } as unknown) as PostProprietorData, 1); + + expect(response).to.eql(undefined); + }); + + it('throws error if response is invalid', async () => { + const mockQueryResponse = ({ rows: [] } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + try { + await surveyService.insertSurveyProprietor( + ({ survey_data_proprietary: 'data', prt_id: 1 } as unknown) as PostProprietorData, + 1 + ); + expect.fail(); + } catch (actualError) { + expect((actualError as ApiGeneralError).message).to.equal('Failed to insert survey proprietor data'); + } + }); + + it('returns data if response is not null', async () => { + const mockQueryResponse = ({ rows: [{ id: 1 }], rowCount: 1 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.insertSurveyProprietor( + ({ survey_data_proprietary: 'data', prt_id: 1 } as unknown) as PostProprietorData, + 1 + ); + + expect(response).to.eql(1); + }); + }); + + describe('insertOrAssociatePermitToSurvey', () => { + afterEach(() => { + sinon.restore(); + }); + + it('throws api error if response is null', async () => { + const mockQueryResponse = ({ rows: [], rowCount: 0 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ sql: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + try { + await surveyService.insertOrAssociatePermitToSurvey(1, 1, 1, 'string', 'type'); + expect.fail(); + } catch (actualError) { + expect((actualError as ApiGeneralError).message).to.equal('Failed to upsert survey permit record'); + } + }); + + it('returns data if response is not null', async () => { + const mockQueryResponse = ({ rows: [{ data: 1 }], rowCount: 1 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ sql: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.insertOrAssociatePermitToSurvey(1, 1, 1, 'string', ''); + + expect(response).to.eql(undefined); + }); + }); + + describe('insertSurveyFundingSource', () => { + afterEach(() => { + sinon.restore(); + }); + + it('throws api error if response is null', async () => { + const mockDBConnection = getMockDBConnection({ query: async () => (undefined as unknown) as any }); + const surveyService = new SurveyService(mockDBConnection); + + try { + await surveyService.insertSurveyFundingSource(1, 1); + expect.fail(); + } catch (actualError) { + expect((actualError as ApiGeneralError).message).to.equal('Failed to insert survey funding source data'); + } + }); + + it('returns data if response is not null', async () => { + const mockQueryResponse = ({ response: 'something' } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.insertSurveyFundingSource(1, 1); + + expect(response).to.eql(undefined); + }); + }); + + describe('updateSurveyDetailsData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('throws api error if response is null', async () => { + const mockDBConnection = getMockDBConnection({ knex: async () => (undefined as unknown) as any }); + const surveyService = new SurveyService(mockDBConnection); + + try { + await surveyService.updateSurveyDetailsData(1, ({ survey_details: 'details' } as unknown) as PutSurveyObject); + expect.fail(); + } catch (actualError) { + expect((actualError as ApiGeneralError).message).to.equal('Failed to update survey data'); + } + }); + + it('returns data if response is not null', async () => { + const mockQueryResponse = ({ response: 'something', rowCount: 1 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ knex: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.updateSurveyDetailsData(1, ({ + survey_details: 'details' + } as unknown) as PutSurveyObject); + + expect(response).to.eql(undefined); + }); + }); + + describe('updateSurveySpeciesData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if response is not null', async () => { + sinon.stub(SurveyService.prototype, 'deleteSurveySpeciesData').resolves(); + sinon.stub(SurveyService.prototype, 'insertFocalSpecies').resolves(1); + sinon.stub(SurveyService.prototype, 'insertAncillarySpecies').resolves(1); + + const mockQueryResponse = ({ response: 'something', rowCount: 1 } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ knex: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.updateSurveySpeciesData(1, ({ + survey_details: 'details', + species: { focal_species: [1], ancillary_species: [1] } + } as unknown) as PutSurveyObject); + + expect(response).to.eql([1, 1]); + }); + }); + + describe('deleteSurveySpeciesData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if response is not null', async () => { + const mockQueryResponse = (undefined as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ sql: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.deleteSurveySpeciesData(1); + + expect(response).to.eql(undefined); + }); + }); + + describe('updateSurveyPermitData', () => { + afterEach(() => { + sinon.restore(); + }); + it('returns undefined if not permit number is given', async () => { + sinon.stub(SurveyService.prototype, 'unassociatePermitFromSurvey').resolves(); + sinon.stub(SurveyService.prototype, 'insertOrAssociatePermitToSurvey').resolves(undefined); + + const mockQueryResponse = (undefined as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ sql: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.updateSurveyPermitData(1, 1, ({ + permit: {} + } as unknown) as PutSurveyObject); + + expect(response).to.eql(undefined); + }); + + it('returns data if response is not null', async () => { + sinon.stub(SurveyService.prototype, 'unassociatePermitFromSurvey').resolves(); + sinon.stub(SurveyService.prototype, 'insertOrAssociatePermitToSurvey').resolves(undefined); + + const mockQueryResponse = (undefined as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ sql: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.updateSurveyPermitData(1, 1, ({ + permit: { permit_number: '1', permit_type: 'type' } + } as unknown) as PutSurveyObject); + + expect(response).to.eql(undefined); + }); + }); + + describe('unassociatePermitFromSurvey', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if response is not null', async () => { + const mockQueryResponse = (undefined as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ sql: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.unassociatePermitFromSurvey(1); + + expect(response).to.eql(undefined); + }); + }); + + describe('updateSurveyFundingData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if response is not null', async () => { + sinon.stub(SurveyService.prototype, 'deleteSurveyFundingSourcesData').resolves(undefined); + sinon.stub(SurveyService.prototype, 'insertSurveyFundingSource').resolves(undefined); + + const mockQueryResponse = (undefined as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ sql: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.updateSurveyFundingData(1, ({ + permit: { permit_number: '1', permit_type: 'type' }, + funding: { funding_sources: [1] } + } as unknown) as PutSurveyObject); + + expect(response).to.eql([undefined]); + }); + }); + + describe('deleteSurveyFundingSourcesData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if response is not null', async () => { + const mockQueryResponse = (undefined as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ sql: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.deleteSurveyFundingSourcesData(1); + + expect(response).to.eql(undefined); + }); + }); + + describe('updateSurveyProprietorData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns undefined if not survey_data_proprietary is given', async () => { + const mockQueryResponse = (undefined as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ sql: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.updateSurveyProprietorData(1, ({ + permit: { permit_number: '1', permit_type: 'type' }, + funding: { funding_sources: [1] }, + proprietor: { survey_data_proprietary: undefined } + } as unknown) as PutSurveyObject); + + expect(response).to.eql(undefined); + }); + + it('returns data if response is not null', async () => { + sinon.stub(SurveyService.prototype, 'insertSurveyProprietor').resolves(1); + + const mockQueryResponse = (undefined as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ sql: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.updateSurveyProprietorData(1, ({ + permit: { permit_number: '1', permit_type: 'type' }, + funding: { funding_sources: [1] }, + proprietor: { survey_data_proprietary: 'asd' } + } as unknown) as PutSurveyObject); + + expect(response).to.eql(1); + }); + }); + + describe('deleteSurveyProprietorData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns data if response is not null', async () => { + const mockQueryResponse = (undefined as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ sql: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.deleteSurveyProprietorData(1); + + expect(response).to.eql(undefined); + }); + }); + + describe('updateSurveyVantageCodesData', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns [] if not vantage_code_ids is given', async () => { + sinon.stub(SurveyService.prototype, 'deleteSurveyVantageCodes').resolves(); + + const mockQueryResponse = (undefined as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ sql: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.updateSurveyVantageCodesData(1, ({ + permit: { permit_number: '1', permit_type: 'type' }, + funding: { funding_sources: [1] }, + purpose_and_methodology: { vantage_code_ids: undefined } + } as unknown) as PutSurveyObject); + + expect(response).to.eql([]); + }); + + it('returns data if response is not null', async () => { + sinon.stub(SurveyService.prototype, 'deleteSurveyVantageCodes').resolves(); + sinon.stub(SurveyService.prototype, 'insertVantageCodes').resolves(1); + + const mockQueryResponse = (undefined as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ sql: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.updateSurveyVantageCodesData(1, ({ + permit: { permit_number: '1', permit_type: 'type' }, + funding: { funding_sources: [1] }, + proprietor: { survey_data_proprietary: 'asd' }, + purpose_and_methodology: { vantage_code_ids: [1] } + } as unknown) as PutSurveyObject); + + expect(response).to.eql([1]); + }); + }); + + describe('deleteSurveyVantageCodes', () => { + afterEach(() => { + sinon.restore(); + }); + + it('throws errors if response is empty', async () => { + const mockQueryResponse = (undefined as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + try { + await surveyService.deleteSurveyVantageCodes(1); + expect.fail(); + } catch (actualError) { + expect((actualError as ApiGeneralError).message).to.equal('Failed to delete survey vantage codes'); + } + }); + + it('returns data if response is not null', async () => { + const mockQueryResponse = ({ rows: [] } as unknown) as QueryResult; + + const mockDBConnection = getMockDBConnection({ query: async () => mockQueryResponse }); + const surveyService = new SurveyService(mockDBConnection); + + const response = await surveyService.deleteSurveyVantageCodes(1); + + expect(response).to.eql(undefined); + }); + }); }); diff --git a/api/src/services/survey-service.ts b/api/src/services/survey-service.ts index f42d4aea0c..f2cfa2ceb5 100644 --- a/api/src/services/survey-service.ts +++ b/api/src/services/survey-service.ts @@ -4,8 +4,10 @@ import { PostProprietorData, PostSurveyObject } from '../models/survey-create'; import { PutSurveyObject } from '../models/survey-update'; import { GetAncillarySpeciesData, + GetAttachmentsData, GetFocalSpeciesData, GetPermitData, + GetReportAttachmentsData, GetSurveyData, GetSurveyFundingSources, GetSurveyLocationData, @@ -163,10 +165,6 @@ export class SurveyService extends DBService { async getSurveyFundingSourcesData(surveyId: number): Promise { const sqlStatement = queries.survey.getSurveyFundingSourcesDataForViewSQL(surveyId); - if (!sqlStatement) { - throw new ApiGeneralError('Failed to build SQL get statement'); - } - const response = await this.connection.query(sqlStatement.text, sqlStatement.values); const result = (response && response.rows) || null; @@ -214,10 +212,6 @@ export class SurveyService extends DBService { async getOccurrenceSubmissionId(surveyId: number) { const sqlStatement = queries.survey.getLatestOccurrenceSubmissionIdSQL(surveyId); - if (!sqlStatement) { - throw new ApiGeneralError('Failed to build SQL get statement'); - } - const response = await this.connection.query(sqlStatement.text, sqlStatement.values); return (response && response.rows?.[0]) || null; @@ -233,10 +227,6 @@ export class SurveyService extends DBService { async getLatestSurveyOccurrenceSubmission(surveyId: number) { const sqlStatement = queries.survey.getLatestSurveyOccurrenceSubmissionSQL(surveyId); - if (!sqlStatement) { - throw new ApiGeneralError('Failed to build SQL get statement'); - } - const response = await this.connection.query(sqlStatement.text, sqlStatement.values); return (response && response.rows?.[0]) || null; @@ -245,10 +235,6 @@ export class SurveyService extends DBService { async getSummaryResultId(surveyId: number) { const sqlStatement = queries.survey.getLatestSummaryResultIdSQL(surveyId); - if (!sqlStatement) { - throw new ApiGeneralError('Failed to build SQL get statement'); - } - const response = await this.connection.query(sqlStatement.text, sqlStatement.values); return (response && response.rows?.[0]) || null; @@ -323,16 +309,29 @@ export class SurveyService extends DBService { return surveyId; } + async getAttachmentsData(surveyId: number): Promise { + const sqlStatement = queries.survey.getAttachmentsBySurveySQL(surveyId); + + const response = await this.connection.query(sqlStatement.text, sqlStatement.values); + const result = (response && response.rows) || null; + + return new GetAttachmentsData(result); + } + + async getReportAttachmentsData(surveyId: number): Promise { + const sqlStatement = queries.survey.getReportAttachmentsBySurveySQL(surveyId); + + const response = await this.connection.query(sqlStatement.text, sqlStatement.values); + const result = (response && response.rows) || null; + + return new GetReportAttachmentsData(result); + } + async insertSurveyData(projectId: number, surveyData: PostSurveyObject): Promise { const sqlStatement = queries.survey.postSurveySQL(projectId, surveyData); - if (!sqlStatement) { - throw new ApiGeneralError('Failed to build survey SQL insert statement'); - } - const response = await this.connection.sql(sqlStatement); - - const result = response.rows[0] || null; + const result = (response && response.rows && response.rows[0]) || null; if (!result) { throw new ApiGeneralError('Failed to insert survey data'); @@ -344,10 +343,6 @@ export class SurveyService extends DBService { async insertFocalSpecies(focal_species_id: number, surveyId: number): Promise { const sqlStatement = queries.survey.postFocalSpeciesSQL(focal_species_id, surveyId); - if (!sqlStatement) { - throw new ApiGeneralError('Failed to build SQL insert statement'); - } - const response = await this.connection.query(sqlStatement.text, sqlStatement.values); const result = (response && response.rows && response.rows[0]) || null; @@ -361,10 +356,6 @@ export class SurveyService extends DBService { async insertAncillarySpecies(ancillary_species_id: number, surveyId: number): Promise { const sqlStatement = queries.survey.postAncillarySpeciesSQL(ancillary_species_id, surveyId); - if (!sqlStatement) { - throw new ApiGeneralError('Failed to build SQL insert statement'); - } - const response = await this.connection.query(sqlStatement.text, sqlStatement.values); const result = (response && response.rows && response.rows[0]) || null; @@ -378,10 +369,6 @@ export class SurveyService extends DBService { async insertVantageCodes(vantage_code_id: number, surveyId: number): Promise { const sqlStatement = queries.survey.postVantageCodesSQL(vantage_code_id, surveyId); - if (!sqlStatement) { - throw new ApiGeneralError('Failed to build SQL insert statement'); - } - const response = await this.connection.query(sqlStatement.text, sqlStatement.values); const result = (response && response.rows && response.rows[0]) || null; @@ -399,10 +386,6 @@ export class SurveyService extends DBService { const sqlStatement = queries.survey.postSurveyProprietorSQL(surveyId, survey_proprietor); - if (!sqlStatement) { - throw new ApiGeneralError('Failed to build SQL insert statement'); - } - const response = await this.connection.query(sqlStatement.text, sqlStatement.values); const result = (response && response.rows && response.rows[0]) || null; @@ -438,10 +421,6 @@ export class SurveyService extends DBService { async insertSurveyFundingSource(funding_source_id: number, surveyId: number) { const sqlStatement = queries.survey.insertSurveyFundingSourceSQL(surveyId, funding_source_id); - if (!sqlStatement) { - throw new ApiGeneralError('Failed to build SQL statement for insertSurveyFundingSource'); - } - const response = await this.connection.query(sqlStatement.text, sqlStatement.values); if (!response) { @@ -482,10 +461,6 @@ export class SurveyService extends DBService { async updateSurveyDetailsData(surveyId: number, surveyData: PutSurveyObject) { const updateSurveyQueryBuilder = queries.survey.putSurveyDetailsSQL(surveyId, surveyData); - if (!updateSurveyQueryBuilder) { - throw new ApiGeneralError('Failed to build SQL update statement'); - } - const result = await this.connection.knex(updateSurveyQueryBuilder); if (!result || !result.rowCount) { diff --git a/database/src/migrations/smoke_tests/smoketest_release.1.1.0.sql b/database/src/migrations/smoke_tests/smoketest_release.1.1.0.sql index f671ce52fe..f862ee4681 100644 --- a/database/src/migrations/smoke_tests/smoketest_release.1.1.0.sql +++ b/database/src/migrations/smoke_tests/smoketest_release.1.1.0.sql @@ -50,6 +50,7 @@ declare _project_funding_source_id project_funding_source.project_funding_source_id%type; _project_report_attachment_id project_report_attachment.project_report_attachment_id%type; _survey_report_attachment_id survey_report_attachment.survey_report_attachment_id%type; + _survey_attachment_id survey_attachment.survey_attachment_id%type; begin -- set security context select api_set_context('myIDIR', 'IDIR') into _system_user_id; @@ -93,6 +94,7 @@ begin insert into project_report_author (project_report_attachment_id, first_name, last_name) values (_project_report_attachment_id, 'john', 'doe'); insert into project_report_author (project_report_attachment_id, first_name, last_name) values (_project_report_attachment_id, 'bob', 'dole'); insert into project_first_nation (project_id, first_nations_id) values (_project_id, (select first_nations_id from first_nations where name = 'Kitselas Nation')); + update project_report_attachment set security_token = null where project_report_attachment_id = _project_report_attachment_id; insert into permit (system_user_id, project_id, number, type, issue_date, end_date) values (_system_user_id, _project_id, '8377262', 'permit type', now(), now()+interval '1 day'); select count(1) into _count from stakeholder_partnership; @@ -131,7 +133,8 @@ begin , lead_last_name , geography , ecological_season_id - , intended_outcome_id) + , intended_outcome_id + , field_method_id) values (_project_id , 'survey name' , 'survey objectives' @@ -143,11 +146,13 @@ begin , _geography , (select ecological_season_id from ecological_season where name = 'Growing') , (select intended_outcome_id from intended_outcome where name = 'Survival') + , (select field_method_id from field_method where name = 'Stratified Random Block') ) returning survey_id into _survey_id; insert into survey_proprietor (survey_id, first_nations_id, proprietor_type_id, rationale,disa_required) values (_survey_id, (select first_nations_id from first_nations where name = 'Squamish Nation'), (select proprietor_type_id from proprietor_type where name = 'First Nations Land'), 'proprietor rationale', true); - insert into survey_attachment (survey_id, file_name, title, key, file_size, file_type) values (_survey_id, 'test_filename.txt', 'test filename', 'projects/'||_project_id::text||'/surveys/'||_survey_id::text, 10000, 'video'); + insert into survey_attachment (survey_id, file_name, title, key, file_size, file_type) values (_survey_id, 'test_filename.txt', 'test filename', 'projects/'||_project_id::text||'/surveys/'||_survey_id::text, 10000, 'video') returning survey_attachment_id into _survey_attachment_id; + update survey_attachment set security_token = null where survey_attachment_id = _survey_attachment_id; insert into survey_report_attachment (survey_id, file_name, title, key, file_size, year, description) values (_survey_id, 'test_filename.txt', 'test filename', 'projects/'||_survey_id::text, 10000, '2021', 'example abstract') returning survey_report_attachment_id into _survey_report_attachment_id; insert into survey_report_author (survey_report_attachment_id, first_name, last_name) values (_survey_report_attachment_id, 'john', 'doe'); insert into survey_report_author (survey_report_attachment_id, first_name, last_name) values (_survey_report_attachment_id, 'bob', 'dole'); @@ -174,7 +179,7 @@ begin -- occurrence -- occurrence submission 1 - insert into occurrence_submission (survey_id, source, event_timestamp) values (_survey_id, 'BIOHUB BATCH', now()-interval '1 day') returning occurrence_submission_id into _occurrence_submission_id; + insert into occurrence_submission (survey_id, source, event_timestamp, input_file_name) values (_survey_id, 'BIOHUB BATCH', now()-interval '1 day', 'filename1.xsl') returning occurrence_submission_id into _occurrence_submission_id; select count(1) into _count from occurrence_submission; assert _count = 1, 'FAIL occurrence_submission'; insert into occurrence (occurrence_submission_id, taxonid, lifestage, eventdate, sex) values (_occurrence_submission_id, 'M-ALAL', 'Adult', now()-interval '10 day', 'male'); @@ -187,7 +192,7 @@ begin --insert into system_user_role (system_user_id, system_role_id) values (_system_user_id, (select system_role_id from system_role where name = 'System Administrator')); -- occurrence submission 2 - insert into occurrence_submission (survey_id, source, event_timestamp) values (_survey_id, 'BIOHUB BATCH', now()) returning occurrence_submission_id into _occurrence_submission_id; + insert into occurrence_submission (survey_id, source, event_timestamp, input_file_name) values (_survey_id, 'BIOHUB BATCH', now(), 'filename2.xsl') returning occurrence_submission_id into _occurrence_submission_id; select count(1) into _count from occurrence_submission; assert _count = 2, 'FAIL occurrence_submission'; insert into occurrence (occurrence_submission_id, taxonid, lifestage, eventdate, sex) values (_occurrence_submission_id, 'M-ALAL', 'Adult', now()-interval '5 day', 'female'); @@ -232,10 +237,10 @@ begin -- delete project raise notice 'deleting data.'; - call api_delete_project(_project_id); + --call api_delete_project(_project_id); raise notice 'smoketest_release(2): PASS'; end $$; -delete from permit; +--delete from permit; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000..ee52161427 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "sims", + "lockfileVersion": 2, + "requires": true, + "packages": {} +}