Skip to content

Commit

Permalink
SIMSBIOHUB-627: Fix Manage Telemetry Page (#1452)
Browse files Browse the repository at this point in the history
* Minor UI cleanup/tweaks.
* Update delete survey procedure
* Delete old bctw-related api code
* Fix telemetry credential upload endpoint
* Fix Manual telemetry create, edit, delete.
* Update backend service/repo functions. Remove some duplicate code.
* Add telemetry pagination/sorting.
* Add placeholder when critterbase record cant be found.
* Disable telemetry import button (temporarily)
* chore: deprecating bctw related code
* fix: dropped telemetry context provider and custom hook

---------

Co-authored-by: Mac Deluca <[email protected]>
  • Loading branch information
NickPhura and MacQSL authored Dec 16, 2024
1 parent 227667d commit 19c4239
Show file tree
Hide file tree
Showing 63 changed files with 683 additions and 1,800 deletions.
4 changes: 0 additions & 4 deletions api/.pipeline/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ const phases = {
backboneArtifactIntakePath: '/api/artifact/intake',
biohubTaxonPath: '/api/taxonomy/taxon',
biohubTaxonTsnPath: '/api/taxonomy/taxon/tsn',
bctwApiHost: 'https://moe-bctw-api-dev.apps.silver.devops.gov.bc.ca',
critterbaseApiHost: 'https://moe-critterbase-api-dev.apps.silver.devops.gov.bc.ca/api',
nodeEnv: 'development',
s3KeyPrefix: (isStaticDeployment && 'sims') || `local/${deployChangeId}/sims`,
Expand Down Expand Up @@ -130,7 +129,6 @@ const phases = {
backboneArtifactIntakePath: '/api/artifact/intake',
biohubTaxonPath: '/api/taxonomy/taxon',
biohubTaxonTsnPath: '/api/taxonomy/taxon/tsn',
bctwApiHost: 'https://moe-bctw-api-test.apps.silver.devops.gov.bc.ca',
critterbaseApiHost: 'https://moe-critterbase-api-test.apps.silver.devops.gov.bc.ca/api',
nodeEnv: 'production',
s3KeyPrefix: 'sims',
Expand Down Expand Up @@ -175,7 +173,6 @@ const phases = {
backboneArtifactIntakePath: '/api/artifact/intake',
biohubTaxonPath: '/api/taxonomy/taxon',
biohubTaxonTsnPath: '/api/taxonomy/taxon/tsn',
bctwApiHost: 'https://moe-bctw-api-test.apps.silver.devops.gov.bc.ca',
critterbaseApiHost: 'https://moe-critterbase-api-test.apps.silver.devops.gov.bc.ca/api',
nodeEnv: 'production',
s3KeyPrefix: 'sims',
Expand Down Expand Up @@ -220,7 +217,6 @@ const phases = {
backboneArtifactIntakePath: '/api/artifact/intake',
biohubTaxonPath: '/api/taxonomy/taxon',
biohubTaxonTsnPath: '/api/taxonomy/taxon/tsn',
bctwApiHost: 'https://moe-bctw-api-prod.apps.silver.devops.gov.bc.ca',
critterbaseApiHost: 'https://moe-critterbase-api-prod.apps.silver.devops.gov.bc.ca/api',
nodeEnv: 'production',
s3KeyPrefix: 'sims',
Expand Down
3 changes: 1 addition & 2 deletions api/.pipeline/lib/api.deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ const apiDeploy = async (settings) => {
BACKBONE_ARTIFACT_INTAKE_PATH: phases[phase].backboneArtifactIntakePath,
BIOHUB_TAXON_PATH: phases[phase].biohubTaxonPath,
BIOHUB_TAXON_TSN_PATH: phases[phase].biohubTaxonTsnPath,
// BCTW / Critterbase
BCTW_API_HOST: phases[phase].bctwApiHost,
// Critterbase
CB_API_HOST: phases[phase].critterbaseApiHost,
// S3
S3_KEY_PREFIX: phases[phase].s3KeyPrefix,
Expand Down
9 changes: 2 additions & 7 deletions api/.pipeline/templates/api.dc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,10 @@ parameters:
- name: BIOHUB_TAXON_PATH
required: true
description: API path for BioHub Platform Backbone taxon endpoint. Example "/api/path/to/taxon".
# BCTW / Critterbase
# Critterbase
- name: CB_API_HOST
description: API host for the Critterbase service, SIMS API will hit this to retrieve critter metadata. Example "https://critterbase.com".
required: true
- name: BCTW_API_HOST
description: API host for the BC Telemetry Warehouse service. SIMS API will hit this for device deployments and other telemetry operations. Example "https://bctw.com".
required: true
# Database
- name: TZ
description: Application timezone
Expand Down Expand Up @@ -309,11 +306,9 @@ objects:
value: ${BIOHUB_TAXON_TSN_PATH}
- name: BIOHUB_TAXON_PATH
value: ${BIOHUB_TAXON_PATH}
# BCTW / Critterbase
# Critterbase
- name: CB_API_HOST
value: ${CB_API_HOST}
- name: BCTW_API_HOST
value: ${BCTW_API_HOST}
# Clamav
- name: ENABLE_FILE_VIRUS_SCAN
value: ${ENABLE_FILE_VIRUS_SCAN}
Expand Down
99 changes: 0 additions & 99 deletions api/src/models/bctw.ts

This file was deleted.

25 changes: 25 additions & 0 deletions api/src/models/deployment-view.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export interface IDeploymentAdvancedFilters {
/**
* Filter results by system user id.
*
* Note: This is not the id of the user making the request.
*
* @type {number}
* @memberof IAnimalAdvancedFilters
*/
system_user_id?: number;
/**
* Filter results by deployment ids.
*
* @type {number[]}
* @memberof IDeploymentAdvancedFilters
*/
deployment_ids?: number[];
/**
* Filter results by survey ids.
*
* @type {number[]}
* @memberof IAnimalAdvancedFilters
*/
survey_ids?: number[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import * as db from '../../../../../../../database/db';
import { HTTPError } from '../../../../../../../errors/http-error';
import { SurveyTelemetryCredentialAttachment } from '../../../../../../../repositories/attachment-repository';
import { AttachmentService } from '../../../../../../../services/attachment-service';
import { BctwKeyxService } from '../../../../../../../services/bctw-service/bctw-keyx-service';
import * as file_utils from '../../../../../../../utils/file-utils';
import { KeycloakUserInformation } from '../../../../../../../utils/keycloak-utils';
import { getMockDBConnection, getRequestHandlerMocks } from '../../../../../../../__mocks__/db';
Expand Down Expand Up @@ -53,7 +52,7 @@ describe('postSurveyTelemetryCredentialAttachment', () => {
}
});

it('succeeds and uploads a KeyX file to BCTW', async () => {
it('successfully imports a credential file', async () => {
const dbConnectionObj = getMockDBConnection();
sinon.stub(db, 'getDBConnection').returns(dbConnectionObj);

Expand All @@ -63,47 +62,6 @@ describe('postSurveyTelemetryCredentialAttachment', () => {

const uploadFileToS3Stub = sinon.stub(file_utils, 'uploadFileToS3').resolves();

const uploadKeyXStub = sinon.stub(BctwKeyxService.prototype, 'uploadKeyX').resolves();

const { mockReq, mockRes, mockNext } = getRequestHandlerMocks();

mockReq.keycloak_token = {} as KeycloakUserInformation;
mockReq.params = {
projectId: '1',
surveyId: '2'
};
mockReq.files = [
{
fieldname: 'media',
originalname: 'test.keyx',
encoding: '7bit',
mimetype: 'text/plain',
size: 340
}
] as Express.Multer.File[];

const requestHandler = postSurveyTelemetryCredentialAttachment();

await requestHandler(mockReq, mockRes, mockNext);

expect(mockRes.jsonValue).to.eql({ survey_telemetry_credential_attachment_id: 44 });
expect(upsertSurveyTelemetryCredentialAttachmentStub).to.be.calledOnce;
expect(uploadKeyXStub).to.be.calledOnce;
expect(uploadFileToS3Stub).to.be.calledOnce;
});

it('succeeds and does not upload a Cfg file to BCTW', async () => {
const dbConnectionObj = getMockDBConnection();
sinon.stub(db, 'getDBConnection').returns(dbConnectionObj);

const upsertSurveyTelemetryCredentialAttachmentStub = sinon
.stub(AttachmentService.prototype, 'upsertSurveyTelemetryCredentialAttachment')
.resolves({ survey_telemetry_credential_attachment_id: 44, key: 'path/to/file/test.keyx' });

const uploadFileToS3Stub = sinon.stub(file_utils, 'uploadFileToS3').resolves();

const uploadKeyXStub = sinon.stub(BctwKeyxService.prototype, 'uploadKeyX').resolves();

const { mockReq, mockRes, mockNext } = getRequestHandlerMocks();

mockReq.keycloak_token = {} as KeycloakUserInformation;
Expand All @@ -127,20 +85,18 @@ describe('postSurveyTelemetryCredentialAttachment', () => {

expect(mockRes.jsonValue).to.eql({ survey_telemetry_credential_attachment_id: 44 });
expect(upsertSurveyTelemetryCredentialAttachmentStub).to.be.calledOnce;
expect(uploadKeyXStub).not.to.be.called; // not called
expect(uploadFileToS3Stub).to.be.calledOnce;
});

it('should catch and re-throw an error', async () => {
const dbConnectionObj = getMockDBConnection();
sinon.stub(db, 'getDBConnection').returns(dbConnectionObj);

const mockError = new Error('A test error');

const upsertSurveyTelemetryCredentialAttachmentStub = sinon
.stub(AttachmentService.prototype, 'upsertSurveyTelemetryCredentialAttachment')
.resolves({ survey_telemetry_credential_attachment_id: 44, key: 'path/to/file/test.keyx' });

const mockError = new Error('A test error');
const uploadKeyXStub = sinon.stub(BctwKeyxService.prototype, 'uploadKeyX').rejects(mockError);
.rejects(mockError);

const { mockReq, mockRes, mockNext } = getRequestHandlerMocks();

Expand Down Expand Up @@ -168,7 +124,6 @@ describe('postSurveyTelemetryCredentialAttachment', () => {
expect((actualError as HTTPError).message).to.equal(mockError.message);

expect(upsertSurveyTelemetryCredentialAttachmentStub).to.have.been.calledOnce;
expect(uploadKeyXStub).to.have.been.calledOnce;
}
});
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import { RequestHandler } from 'express';
import { Operation } from 'express-openapi';
import { TELEMETRY_CREDENTIAL_ATTACHMENT_TYPE } from '../../../../../../../constants/attachments';
import { PROJECT_PERMISSION, SYSTEM_ROLE } from '../../../../../../../constants/roles';
import { getDBConnection } from '../../../../../../../database/db';
import { HTTP400 } from '../../../../../../../errors/http-error';
import { fileSchema } from '../../../../../../../openapi/schemas/file';
import { authorizeRequestHandler } from '../../../../../../../request-handlers/security/authorization';
import { AttachmentService } from '../../../../../../../services/attachment-service';
import { BctwKeyxService } from '../../../../../../../services/bctw-service/bctw-keyx-service';
import { getBctwUser } from '../../../../../../../services/bctw-service/bctw-service';
import { uploadFileToS3 } from '../../../../../../../utils/file-utils';
import { getLogger } from '../../../../../../../utils/logger';
import { isValidTelementryCredentialFile } from '../../../../../../../utils/media/media-utils';
Expand Down Expand Up @@ -157,12 +154,6 @@ export function postSurveyTelemetryCredentialAttachment(): RequestHandler {
isTelemetryCredentialFile.type
);

// Upload telemetry credential file content to BCTW (for supported file types)
if (isTelemetryCredentialFile.type === TELEMETRY_CREDENTIAL_ATTACHMENT_TYPE.KEYX) {
const bctwKeyxService = new BctwKeyxService(getBctwUser(req));
await bctwKeyxService.uploadKeyX(rawMediaFile);
}

// Upload telemetry credential file to SIMS S3 Storage
const metadata = {
filename: rawMediaFile.originalname,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { TelemetryDeploymentService } from '../../../../../../../../services/tel
import { getLogger } from '../../../../../../../../utils/logger';
import { numberOrNull } from '../../../../../../../../utils/string-utils';

const defaultLog = getLogger('paths/project/{projectId}/survey/{surveyId}/critters/{critterId}/deployments');
const defaultLog = getLogger('paths/project/{projectId}/survey/{surveyId}/critters/{critterId}/deployments2');

export const POST: Operation = [
authorizeRequestHandler((req) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ import { getDBConnection } from '../../../../../../../database/db';
import { HTTP400, HTTPError, HTTPErrorType } from '../../../../../../../errors/http-error';
import { bulkUpdateResponse, critterBulkRequestObject } from '../../../../../../../openapi/schemas/critter';
import { authorizeRequestHandler } from '../../../../../../../request-handlers/security/authorization';
import { getBctwUser } from '../../../../../../../services/bctw-service/bctw-service';
import { CritterAttachmentService } from '../../../../../../../services/critter-attachment-service';
import { CritterbaseService, ICritterbaseUser } from '../../../../../../../services/critterbase-service';
import {
CritterbaseService,
getCritterbaseUser,
ICritterbaseUser
} from '../../../../../../../services/critterbase-service';
import { SurveyCritterService } from '../../../../../../../services/survey-critter-service';
import { getLogger } from '../../../../../../../utils/logger';

Expand Down Expand Up @@ -95,7 +98,7 @@ export function updateSurveyCritter(): RequestHandler {
const connection = getDBConnection(req.keycloak_token);
try {
await connection.open();
const user = getBctwUser(req);
const user = getCritterbaseUser(req);

if (!critterbaseCritterId) {
throw new HTTPError(HTTPErrorType.BAD_REQUEST, 400, 'No external critter ID was found.');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const GET: Operation = [

GET.apiDoc = {
description: 'Get telemetry points for a specific critter.',
tags: ['bctw'],
tags: ['telemetry'],
security: [
{
Bearer: []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,15 @@ describe('getDeploymentsInSurvey', () => {
critterbase_end_capture_id: null,
critterbase_end_mortality_id: null,
// device data
serial: '1234',
device_make_id: 1,
model: 'ModelX',
// critter data
critterbase_critter_id: 'critter123'
}
];

sinon.stub(TelemetryDeploymentService.prototype, 'getDeploymentsForSurveyId').resolves(mockDeployments);
sinon.stub(TelemetryDeploymentService.prototype, 'getDeploymentsForSurvey').resolves(mockDeployments);
sinon.stub(TelemetryDeploymentService.prototype, 'getDeploymentsCount').resolves(1);

const { mockReq, mockRes, mockNext } = getRequestHandlerMocks();
Expand Down Expand Up @@ -78,7 +79,7 @@ describe('getDeploymentsInSurvey', () => {
const mockError = new Error('Test error');

const getDeploymentsForSurveyIdStub = sinon
.stub(TelemetryDeploymentService.prototype, 'getDeploymentsForSurveyId')
.stub(TelemetryDeploymentService.prototype, 'getDeploymentsForSurvey')
.rejects(mockError);

const { mockReq, mockRes, mockNext } = getRequestHandlerMocks();
Expand Down
Loading

0 comments on commit 19c4239

Please sign in to comment.