Skip to content

Commit

Permalink
Merge branch 'dev' into prettier-plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
NickPhura authored Apr 27, 2022
2 parents efedd5b + 5e25347 commit 8a3a273
Show file tree
Hide file tree
Showing 41 changed files with 347 additions and 139 deletions.
65 changes: 63 additions & 2 deletions api/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import multer from 'multer';
import { OpenAPIV3 } from 'openapi-types';
import swaggerUIExperss from 'swagger-ui-express';
import { defaultPoolConfig, initDBPool } from './database/db';
import { ensureHTTPError } from './errors/custom-error';
import { ensureHTTPError, HTTPErrorType } from './errors/custom-error';
import { rootAPIDoc } from './openapi/root-api-doc';
import { authenticateRequest } from './request-handlers/security/authentication';
import { getLogger } from './utils/logger';
Expand Down Expand Up @@ -38,7 +38,11 @@ app.use(function (req: Request, res: Response, next: NextFunction) {

// Initialize express-openapi framework
const openAPIFramework = initialize({
apiDoc: rootAPIDoc as OpenAPIV3.Document, // base open api spec
apiDoc: {
...(rootAPIDoc as OpenAPIV3.Document), // base open api spec
'x-express-openapi-additional-middleware': [validateAllResponses],
'x-express-openapi-validation-strict': true
},
app: app, // express app to initialize
paths: './src/paths', // base folder for endpoint routes
pathsIgnore: new RegExp('.(spec|test)$'), // ignore test files in paths
Expand Down Expand Up @@ -107,3 +111,60 @@ try {
defaultLog.error({ label: 'start api', message: 'error', error });
process.exit(1);
}

/**
* Middleware to apply openapi response validation to all routes.
*
* Note: validates `<data>` sent via `res.status(<status>).json(<data>)` against the matching openapi response schema
* for `<status>`.
*
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
function validateAllResponses(req: Request, res: Response, next: NextFunction) {
const isStrictValidation = !!req['apiDoc']['x-express-openapi-validation-strict'] || false;

if (typeof res['validateResponse'] === 'function') {
const json = res.json;

res.json = (...args) => {
if (res.get('x-express-openapi-validation-error-for')) {
// Already validated, return
return json.apply(res, args);
}

const body = args[0];

const validationResult: { message: any; errors: any[] } | undefined = res['validateResponse'](
res.statusCode,
body
);

let validationMessage = '';
let errorList = [];

if (validationResult?.errors) {
validationMessage = `Invalid response for status code ${res.statusCode}`;

errorList = Array.from(validationResult.errors);

// Set to avoid a loop, and to provide the original status code
res.set('x-express-openapi-validation-error-for', res.statusCode.toString());
}

if (!isStrictValidation || !validationResult?.errors) {
return json.apply(res, args);
} else {
return res.status(500).json({
name: HTTPErrorType.INTERNAL_SERVER_ERROR,
status: 500,
message: validationMessage,
errors: errorList
});
}
};
}

next();
}
16 changes: 8 additions & 8 deletions api/src/models/project-survey-attachments.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ describe('PostReportAttachmentsMetaData', () => {
});

it('sets attachmentsData', function () {
expect(postReportAttachmentsData).to.eql({ title: null, year_published: null, authors: [], description: null });
expect(postReportAttachmentsData).to.eql({ title: null, year_published: 0, authors: [], description: null });
});
});

Expand All @@ -72,7 +72,7 @@ describe('PostReportAttachmentsMetaData', () => {

const input = {
title: 'Report 1',
year_published: '2000',
year_published: 2000,
authors: [{ first_name: 'John', last_name: 'Smith' }],
description: 'abstract of the report'
};
Expand All @@ -84,7 +84,7 @@ describe('PostReportAttachmentsMetaData', () => {
it('sets the report metadata', function () {
expect(postReportAttachmentsData).to.eql({
title: 'Report 1',
year_published: '2000',
year_published: 2000,
authors: [{ first_name: 'John', last_name: 'Smith' }],
description: 'abstract of the report'
});
Expand All @@ -98,7 +98,7 @@ describe('PutReportAttachmentMetaData', () => {
const putReportAttachmentData = new PutReportAttachmentMetadata(null);

expect(putReportAttachmentData.title).to.equal(null);
expect(putReportAttachmentData.year_published).to.equal(null);
expect(putReportAttachmentData.year_published).to.equal(0);
expect(putReportAttachmentData.authors).to.eql([]);
expect(putReportAttachmentData.description).to.equal(null);
expect(putReportAttachmentData.revision_count).to.equal(null);
Expand All @@ -108,7 +108,7 @@ describe('PutReportAttachmentMetaData', () => {
describe('All values provided', () => {
const input = {
title: 'Report 1',
year_published: '2000',
year_published: 2000,
authors: [{ first_name: 'John', last_name: 'Smith' }],
description: 'abstract of the report',
revision_count: 1
Expand All @@ -133,7 +133,7 @@ describe('GetReportAttachmentMetaData', () => {
expect(getReportAttachmentData).to.eql({
attachment_id: null,
title: null,
year_published: null,
year_published: 0,
authors: [],
description: null,
last_modified: null,
Expand All @@ -148,7 +148,7 @@ describe('GetReportAttachmentMetaData', () => {
title: 'My Report',
update_date: '2020-10-10',
description: 'abstract of the report',
year: '2020',
year_published: 2020,
revision_count: 2,
authors: [{ first_name: 'John', last_name: 'Smith' }]
};
Expand All @@ -157,7 +157,7 @@ describe('GetReportAttachmentMetaData', () => {
const getReportAttachmentData = new GetReportAttachmentMetadata(input);

expect(getReportAttachmentData.title).to.equal(input.title);
expect(getReportAttachmentData.year_published).to.equal(input.year);
expect(getReportAttachmentData.year_published).to.equal(input.year_published);
expect(getReportAttachmentData.description).to.equal(input.description);
expect(getReportAttachmentData.last_modified).to.equal(input.update_date);
expect(getReportAttachmentData.revision_count).to.equal(input.revision_count);
Expand Down
10 changes: 5 additions & 5 deletions api/src/models/project-survey-attachments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class GetAttachmentsData {
id: item.id,
fileName: item.file_name,
fileType: item.file_type || 'Report',
lastModified: item.update_date || item.create_date,
lastModified: (item.update_date || item.create_date).toString(),
size: item.file_size,
securityToken: item.security_token
};
Expand All @@ -37,13 +37,13 @@ export interface IReportAttachmentAuthor {

export class PostReportAttachmentMetadata {
title: string;
year_published: string;
year_published: number;
authors: IReportAttachmentAuthor[];
description: string;

constructor(obj?: any) {
this.title = (obj && obj?.title) || null;
this.year_published = (obj && obj?.year_published) || null;
this.year_published = Number((obj && obj?.year_published) || null);
this.authors = (obj?.authors?.length && obj.authors) || [];
this.description = (obj && obj?.description) || null;
}
Expand Down Expand Up @@ -71,9 +71,9 @@ export class GetReportAttachmentMetadata {
constructor(metaObj?: any, authorObj?: any) {
this.attachment_id = (metaObj && metaObj?.attachment_id) || null;
this.title = (metaObj && metaObj?.title) || null;
this.last_modified = (metaObj && metaObj?.update_date) || null;
this.last_modified = (metaObj && metaObj?.update_date.toString()) || null;
this.description = (metaObj && metaObj?.description) || null;
this.year_published = (metaObj && metaObj?.year) || null;
this.year_published = Number((metaObj && metaObj?.year_published) || null);
this.revision_count = (metaObj && metaObj?.revision_count) || null;
this.authors =
(authorObj &&
Expand Down
2 changes: 1 addition & 1 deletion api/src/models/project-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export class GetProjectData {
moment(projectData.end_date).endOf('day').isBefore(moment()) &&
COMPLETION_STATUS.COMPLETED) ||
COMPLETION_STATUS.ACTIVE;
this.publish_date = projectData?.publish_date || '';
this.publish_date = String(projectData?.publish_date || '');
this.revision_count = projectData?.revision_count ?? null;
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/src/models/public/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export class GetPublicAttachmentsData {
id: item.id,
fileName: item.file_name,
fileType: item.file_type || 'Report',
lastModified: item.update_date || item.create_date,
lastModified: (item.update_date || item.create_date).toString(),
size: item.file_size,
securityToken: item.is_secured
};
Expand Down
2 changes: 1 addition & 1 deletion api/src/models/survey-update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export class GetUpdateSurveyDetailsData {
moment(surveyDetailsData.end_date).endOf('day').isBefore(moment()) &&
COMPLETION_STATUS.COMPLETED) ||
COMPLETION_STATUS.ACTIVE;
this.publish_date = surveyDetailsData?.publish_date || '';
this.publish_date = String(surveyDetailsData?.publish_date || '');
}
}

Expand Down
2 changes: 1 addition & 1 deletion api/src/models/survey-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export class GetViewSurveyDetailsData {
moment(surveyDetailsData.end_date).endOf('day').isBefore(moment()) &&
COMPLETION_STATUS.COMPLETED) ||
COMPLETION_STATUS.ACTIVE;
this.publish_date = surveyDetailsData?.publish_date || '';
this.publish_date = String(surveyDetailsData?.publish_date || '');
}
}

Expand Down
4 changes: 2 additions & 2 deletions api/src/openapi/schemas/administrative-activity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ export const administrativeActivityResponseObject = {
type: 'number'
},
date: {
type: 'string',
description: 'The date this administrative activity was made'
description: 'The date this administrative activity was made',
oneOf: [{ type: 'object' }, { type: 'string', format: 'date' }]
}
}
};
Expand Down
2 changes: 1 addition & 1 deletion api/src/openapi/schemas/permit-no-sampling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const permitNoSamplingPostBody = {
export const permitNoSamplingResponseBody = {
title: 'Permit no sampling Response Object',
type: 'object',
required: ['id'],
required: ['ids'],
properties: {
ids: {
type: 'array',
Expand Down
8 changes: 5 additions & 3 deletions api/src/paths/administrative-activities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,12 @@ GET.apiDoc = {
description: 'Administrative activity status type name'
},
description: {
type: 'string'
type: 'string',
nullable: true
},
notes: {
type: 'string'
type: 'string',
nullable: true
},
data: {
type: 'object',
Expand All @@ -105,7 +107,7 @@ GET.apiDoc = {
}
},
create_date: {
type: 'string'
oneOf: [{ type: 'object' }, { type: 'string', format: 'date' }]
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions api/src/paths/dwc/view-occurrences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ POST.apiDoc = {
'application/json': {
schema: {
title: 'Occurrences spatial and metadata response object, for view purposes',
type: 'object',
properties: {}
type: 'array',
items: {}
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion api/src/paths/permit/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ GET.apiDoc = {
type: 'string'
},
project_name: {
type: 'string'
type: 'string',
nullable: true
}
}
},
Expand Down
59 changes: 29 additions & 30 deletions api/src/paths/project/{projectId}/attachments/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,36 +49,35 @@ GET.apiDoc = {
content: {
'application/json': {
schema: {
type: 'array',
items: {
type: 'object',
required: ['projectId', 'fileName', 'fileType', 'lastModified', 'size', 'securityToken', 'revisionCount'],
properties: {
projectId: {
type: 'number'
},
fileName: {
description: 'The file name of the attachment',
type: 'string'
},
fileType: {
description: 'The file type of the attachment',
type: 'string'
},
lastModified: {
description: 'The date the object was last modified',
type: 'string'
},
size: {
description: 'The size of the attachment',
type: 'number'
},
securityToken: {
description: 'The security token of the attachment',
type: 'string'
},
revisionCount: {
type: 'number'
type: 'object',
properties: {
attachmentsList: {
type: 'array',
items: {
type: 'object',
required: ['id', 'fileName', 'fileType', 'lastModified', 'securityToken', 'size'],
properties: {
id: {
type: 'number'
},
fileName: {
type: 'string'
},
fileType: {
type: 'string'
},
lastModified: {
type: 'string'
},
securityToken: {
description: 'The security token of the attachment',
type: 'string',
nullable: true
},
size: {
type: 'number'
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ POST.apiDoc = {
type: 'string'
},
year_published: {
type: 'string'
type: 'string',
description:
'Year the report is published. (Note: Content-Type: multipart/form-data requires all parameters to be strings.)'
},
authors: {
type: 'array',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ POST.apiDoc = {
type: 'string'
},
securityToken: {
type: 'string'
type: 'string',
nullable: true
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ describe('gets metadata for a project report', () => {
title: 'My report',
update_date: '2020-10-10',
description: 'some description',
year: '2020',
year_published: 2020,
revision_count: '1'
}
]
Expand All @@ -153,7 +153,7 @@ describe('gets metadata for a project report', () => {
title: 'My report',
last_modified: '2020-10-10',
description: 'some description',
year_published: '2020',
year_published: 2020,
revision_count: '1',
authors: [{ first_name: 'John', last_name: 'Smith' }]
});
Expand Down
Loading

0 comments on commit 8a3a273

Please sign in to comment.