Skip to content

Commit

Permalink
Merge branch 'dev' into bugFix-obs-environments
Browse files Browse the repository at this point in the history
  • Loading branch information
mauberti-bc authored Dec 7, 2024
2 parents 7367e5e + 662ae2f commit 11ebdd9
Show file tree
Hide file tree
Showing 55 changed files with 3,157 additions and 1,889 deletions.
41 changes: 41 additions & 0 deletions api/src/openapi/schemas/csv.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { OpenAPIV3 } from 'openapi-types';

/**
* CSV validation error object schema
*
*/
export const CSVErrorSchema: OpenAPIV3.SchemaObject = {
title: 'CSV validation error object',
type: 'object',
additionalProperties: false,
required: ['error', 'solution', 'row'],
properties: {
error: {
description: 'The error message',
type: 'string'
},
solution: {
description: 'The error solution or instructions to resolve',
type: 'string'
},
values: {
description: 'The list of allowed values if applicable',
type: 'array',
items: {
oneOf: [{ type: 'string' }, { type: 'number' }]
}
},
cell: {
description: 'The CSV cell value',
oneOf: [{ type: 'string' }, { type: 'number' }]
},
header: {
description: 'The header name used in the CSV file',
type: 'string'
},
row: {
description: 'The row index the error occurred. Header row index 0. First data row index 1.',
type: 'number'
}
}
};
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { expect } from 'chai';
import sinon from 'sinon';
import * as db from '../../../../../../database/db';
import * as strategy from '../../../../../../services/import-services/import-csv';
import { ImportCrittersService } from '../../../../../../services/import-services/critter/import-critters-service';
import { getMockDBConnection, getRequestHandlerMocks } from '../../../../../../__mocks__/db';
import { importCsv } from './import';
import { importCritterCSV } from './import';

describe('importCsv', () => {
afterEach(() => {
sinon.restore();
});

it('returns imported critters', async () => {
it('status 200 when successful', async () => {
const mockDBConnection = getMockDBConnection({ open: sinon.stub(), commit: sinon.stub(), release: sinon.stub() });
const getDBConnectionStub = sinon.stub(db, 'getDBConnection').returns(mockDBConnection);
const mockImportCSV = sinon.stub(strategy, 'importCSV').resolves([1, 2]);

const importCSVWorksheetStub = sinon.stub(ImportCrittersService.prototype, 'importCSVWorksheet');

const mockFile = { originalname: 'test.csv', mimetype: 'test.csv', buffer: Buffer.alloc(1) } as Express.Multer.File;

Expand All @@ -22,17 +23,18 @@ describe('importCsv', () => {
mockReq.files = [mockFile];
mockReq.params.surveyId = '1';

const requestHandler = importCsv();
const requestHandler = importCritterCSV();

await requestHandler(mockReq, mockRes, mockNext);

expect(mockDBConnection.open).to.have.been.calledOnce;

expect(getDBConnectionStub).to.have.been.calledOnce;

expect(mockImportCSV).to.have.been.calledOnce;
expect(importCSVWorksheetStub).to.have.been.calledOnce;

expect(mockRes.json).to.have.been.calledOnceWithExactly({ survey_critter_ids: [1, 2] });
expect(mockRes.status).to.have.been.calledOnceWithExactly(200);
expect(mockRes.send).to.have.been.calledOnceWithExactly();

expect(mockDBConnection.commit).to.have.been.calledOnce;
expect(mockDBConnection.release).to.have.been.calledOnce;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { PROJECT_PERMISSION, SYSTEM_ROLE } from '../../../../../../constants/rol
import { getDBConnection } from '../../../../../../database/db';
import { csvFileSchema } from '../../../../../../openapi/schemas/file';
import { authorizeRequestHandler } from '../../../../../../request-handlers/security/authorization';
import { ImportCrittersStrategy } from '../../../../../../services/import-services/critter/import-critters-strategy';
import { importCSV } from '../../../../../../services/import-services/import-csv';
import { ImportCrittersService } from '../../../../../../services/import-services/critter/import-critters-service';
import { getLogger } from '../../../../../../utils/logger';
import { parseMulterFile } from '../../../../../../utils/media/media-utils';
import { getFileFromRequest } from '../../../../../../utils/request';
import { constructXLSXWorkbook, getDefaultWorksheet } from '../../../../../../utils/xlsx-utils/worksheet-utils';

const defaultLog = getLogger('/api/project/{projectId}/survey/{surveyId}/critters/import');

Expand All @@ -28,7 +28,7 @@ export const POST: Operation = [
]
};
}),
importCsv()
importCritterCSV()
];

POST.apiDoc = {
Expand Down Expand Up @@ -83,25 +83,7 @@ POST.apiDoc = {
},
responses: {
200: {
description: 'Import OK',
content: {
'application/json': {
schema: {
type: 'object',
additionalProperties: false,
required: ['survey_critter_ids'],
properties: {
survey_critter_ids: {
type: 'array',
items: {
type: 'integer',
minimum: 1
}
}
}
}
}
}
description: 'Import OK'
},
400: {
$ref: '#/components/responses/400'
Expand All @@ -126,26 +108,26 @@ POST.apiDoc = {
*
* @return {*} {RequestHandler}
*/
export function importCsv(): RequestHandler {
export function importCritterCSV(): RequestHandler {
return async (req, res) => {
const surveyId = Number(req.params.surveyId);
const rawFile = getFileFromRequest(req);

const connection = getDBConnection(req.keycloak_token);

const mediaFile = parseMulterFile(rawFile);
const worksheet = getDefaultWorksheet(constructXLSXWorkbook(mediaFile));

try {
await connection.open();

// Critter CSV import strategy - child of CSVImportStrategy
const importCsvCritters = new ImportCrittersStrategy(connection, surveyId);

const surveyCritterIds = await importCSV(parseMulterFile(rawFile), importCsvCritters);
const importService = new ImportCrittersService(connection, worksheet, surveyId);

defaultLog.info({ label: 'importCritterCsv', message: 'result', survey_critter_ids: surveyCritterIds });
await importService.importCSVWorksheet();

await connection.commit();

return res.status(200).json({ survey_critter_ids: surveyCritterIds });
return res.status(200).send();
} catch (error) {
defaultLog.error({ label: 'importCritterCsv', message: 'error', error });
await connection.rollback();
Expand Down
Loading

0 comments on commit 11ebdd9

Please sign in to comment.