diff --git a/api/src/paths/telemetry/code.test.ts b/api/src/paths/telemetry/code.test.ts deleted file mode 100644 index e510c3b65f..0000000000 --- a/api/src/paths/telemetry/code.test.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { expect } from 'chai'; -import sinon from 'sinon'; -import { SystemUser } from '../../repositories/user-repository'; -import { BctwService } from '../../services/bctw-service/bctw-service'; -import { getRequestHandlerMocks } from '../../__mocks__/db'; -import { getCodeValues } from './code'; - -describe('getCodeValues', () => { - afterEach(() => { - sinon.restore(); - }); - - it('returns a list of Bctw code objects', async () => { - const mockCodeValues = [ - { - code_header_title: 'title', - code_header_name: 'name', - id: 123, - code: 'code', - description: 'description', - long_description: 'long_description' - } - ]; - const mockGetCode = sinon.stub(BctwService.prototype, 'getCode').resolves(mockCodeValues); - - const { mockReq, mockRes, mockNext } = getRequestHandlerMocks(); - - mockReq.system_user = { user_identifier: 'user', user_guid: 'guid' } as SystemUser; - - const requestHandler = getCodeValues(); - - await requestHandler(mockReq, mockRes, mockNext); - - expect(mockRes.jsonValue).to.eql(mockCodeValues); - expect(mockRes.statusValue).to.equal(200); - expect(mockGetCode).to.have.been.calledOnce; - }); - - it('catches and re-throws errors', async () => { - const mockError = new Error('mock error'); - const mockGetCode = sinon.stub(BctwService.prototype, 'getCode').rejects(mockError); - - const { mockReq, mockRes, mockNext } = getRequestHandlerMocks(); - - mockReq.system_user = { user_identifier: 'user', user_guid: 'guid' } as SystemUser; - - const requestHandler = getCodeValues(); - - try { - await requestHandler(mockReq, mockRes, mockNext); - expect.fail(); - } catch (actualError) { - expect(actualError).to.equal(mockError); - expect(mockGetCode).to.have.been.calledOnce; - } - }); -}); diff --git a/api/src/paths/telemetry/code.ts b/api/src/paths/telemetry/code.ts deleted file mode 100644 index a2537809a7..0000000000 --- a/api/src/paths/telemetry/code.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { RequestHandler } from 'express'; -import { Operation } from 'express-openapi'; -import { authorizeRequestHandler } from '../../request-handlers/security/authorization'; -import { BctwService, getBctwUser } from '../../services/bctw-service/bctw-service'; -import { getLogger } from '../../utils/logger'; - -const defaultLog = getLogger('paths/telemetry/code'); - -export const GET: Operation = [ - authorizeRequestHandler(() => { - return { - and: [ - { - discriminator: 'SystemUser' - } - ] - }; - }), - getCodeValues() -]; - -GET.apiDoc = { - description: 'Get a list of "code" values from the exterior telemetry system.', - tags: ['telemetry'], - security: [ - { - Bearer: [] - } - ], - responses: { - 200: { - description: 'Generic telemetry code response.', - content: { - 'application/json': { - schema: { - type: 'array', - items: { - type: 'object', - additionalProperties: false, - properties: { - id: { type: 'number' }, - code: { type: 'string' }, - code_header_title: { type: 'string' }, - code_header_name: { type: 'string' }, - description: { type: 'string' }, - long_description: { type: 'string' } - } - } - } - } - } - }, - 400: { - $ref: '#/components/responses/400' - }, - 401: { - $ref: '#/components/responses/401' - }, - 403: { - $ref: '#/components/responses/403' - }, - 500: { - $ref: '#/components/responses/500' - }, - default: { - $ref: '#/components/responses/default' - } - } -}; - -export function getCodeValues(): RequestHandler { - return async (req, res) => { - const user = getBctwUser(req); - - const bctwService = new BctwService(user); - - const codeHeader = String(req.query.codeHeader); - - try { - const result = await bctwService.getCode(codeHeader); - - return res.status(200).json(result); - } catch (error) { - defaultLog.error({ label: 'getCodeValues', message: 'error', error }); - throw error; - } - }; -} diff --git a/api/src/paths/telemetry/deployments.test.ts b/api/src/paths/telemetry/deployments.test.ts deleted file mode 100644 index 471f6a2f23..0000000000 --- a/api/src/paths/telemetry/deployments.test.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { expect } from 'chai'; -import sinon from 'sinon'; -import { SystemUser } from '../../repositories/user-repository'; -import { BctwTelemetryService, IAllTelemetry } from '../../services/bctw-service/bctw-telemetry-service'; -import { getRequestHandlerMocks } from '../../__mocks__/db'; -import { getAllTelemetryByDeploymentIds } from './deployments'; - -const mockTelemetry: IAllTelemetry[] = [ - { - id: '123-123-123', - telemetry_id: null, - telemetry_manual_id: '123-123-123', - deployment_id: '345-345-345', - latitude: 49.123, - longitude: -126.123, - acquisition_date: '2021-01-01', - telemetry_type: 'manual' - }, - { - id: '567-567-567', - telemetry_id: '567-567-567', - telemetry_manual_id: null, - deployment_id: '345-345-345', - latitude: 49.123, - longitude: -126.123, - acquisition_date: '2021-01-01', - telemetry_type: 'vendor' - } -]; - -describe('getAllTelemetryByDeploymentIds', () => { - afterEach(() => { - sinon.restore(); - }); - it('should retrieve both manual and vendor telemetry', async () => { - const mockGetTelemetry = sinon - .stub(BctwTelemetryService.prototype, 'getAllTelemetryByDeploymentIds') - .resolves(mockTelemetry); - - const { mockReq, mockRes, mockNext } = getRequestHandlerMocks(); - - mockReq.system_user = { user_identifier: 'user', user_guid: 'guid' } as SystemUser; - - const requestHandler = getAllTelemetryByDeploymentIds(); - - await requestHandler(mockReq, mockRes, mockNext); - - expect(mockRes.jsonValue).to.eql(mockTelemetry); - expect(mockRes.statusValue).to.equal(200); - expect(mockGetTelemetry).to.have.been.calledOnce; - }); - it('should catch error', async () => { - const mockError = new Error('test error'); - const mockGetTelemetry = sinon - .stub(BctwTelemetryService.prototype, 'getAllTelemetryByDeploymentIds') - .rejects(mockError); - - const { mockReq, mockRes, mockNext } = getRequestHandlerMocks(); - - mockReq.system_user = { user_identifier: 'user', user_guid: 'guid' } as SystemUser; - - const requestHandler = getAllTelemetryByDeploymentIds(); - - try { - await requestHandler(mockReq, mockRes, mockNext); - } catch (err) { - expect(err).to.equal(mockError); - expect(mockGetTelemetry).to.have.been.calledOnce; - } - }); -}); diff --git a/api/src/paths/telemetry/deployments.ts b/api/src/paths/telemetry/deployments.ts deleted file mode 100644 index 035276ad86..0000000000 --- a/api/src/paths/telemetry/deployments.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { RequestHandler } from 'express'; -import { Operation } from 'express-openapi'; -import { AllTelemetrySchema } from '../../openapi/schemas/telemetry'; -import { authorizeRequestHandler } from '../../request-handlers/security/authorization'; -import { getBctwUser } from '../../services/bctw-service/bctw-service'; -import { BctwTelemetryService } from '../../services/bctw-service/bctw-telemetry-service'; -import { getLogger } from '../../utils/logger'; - -const defaultLog = getLogger('paths/telemetry/deployments'); - -export const GET: Operation = [ - authorizeRequestHandler(() => { - return { - and: [ - { - discriminator: 'SystemUser' - } - ] - }; - }), - getAllTelemetryByDeploymentIds() -]; - -GET.apiDoc = { - description: 'Get manual and vendor telemetry for a set of deployment Ids', - tags: ['telemetry'], - security: [ - { - Bearer: [] - } - ], - parameters: [ - { - in: 'query', - name: 'bctwDeploymentIds', - schema: { - type: 'array', - items: { type: 'string', format: 'uuid', minimum: 1 } - }, - required: true - } - ], - responses: { - 200: { - description: 'Manual and Vendor telemetry response object', - content: { - 'application/json': { - schema: { - type: 'array', - items: AllTelemetrySchema - } - } - } - }, - 400: { - $ref: '#/components/responses/400' - }, - 401: { - $ref: '#/components/responses/401' - }, - 403: { - $ref: '#/components/responses/403' - }, - 500: { - $ref: '#/components/responses/500' - }, - default: { - $ref: '#/components/responses/default' - } - } -}; - -export function getAllTelemetryByDeploymentIds(): RequestHandler { - return async (req, res) => { - const user = getBctwUser(req); - - const bctwTelemetryService = new BctwTelemetryService(user); - - try { - const bctwDeploymentIds = req.query.bctwDeploymentIds as string[]; - - const result = await bctwTelemetryService.getAllTelemetryByDeploymentIds(bctwDeploymentIds); - - return res.status(200).json(result); - } catch (error) { - defaultLog.error({ label: 'getAllTelemetryByDeploymentIds', message: 'error', error }); - throw error; - } - }; -} diff --git a/api/src/paths/telemetry/vendor/deployments.test.ts b/api/src/paths/telemetry/vendor/deployments.test.ts deleted file mode 100644 index c1a0d360cd..0000000000 --- a/api/src/paths/telemetry/vendor/deployments.test.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { expect } from 'chai'; -import sinon from 'sinon'; -import { SystemUser } from '../../../repositories/user-repository'; -import { BctwTelemetryService, IVendorTelemetry } from '../../../services/bctw-service/bctw-telemetry-service'; -import { getRequestHandlerMocks } from '../../../__mocks__/db'; -import { getVendorTelemetryByDeploymentIds } from './deployments'; - -const mockTelemetry: IVendorTelemetry[] = [ - { - telemetry_id: '123-123-123', - deployment_id: '345-345-345', - latitude: 49.123, - longitude: -126.123, - acquisition_date: '2021-01-01', - collar_transaction_id: '45-45-45', - critter_id: '78-78-78', - deviceid: 123456, - elevation: 200, - vendor: 'vendor1' - }, - { - telemetry_id: '456-456-456', - deployment_id: '789-789-789', - latitude: 49.123, - longitude: -126.123, - acquisition_date: '2021-01-01', - collar_transaction_id: '54-54-54', - critter_id: '87-87-87', - deviceid: 654321, - elevation: 10, - vendor: 'vendor2' - } -]; - -describe('getVendorTelemetryByDeploymentIds', () => { - afterEach(() => { - sinon.restore(); - }); - it('should retrieve all vendor telemetry by deployment ids', async () => { - const mockGetTelemetry = sinon - .stub(BctwTelemetryService.prototype, 'getVendorTelemetryByDeploymentIds') - .resolves(mockTelemetry); - - const { mockReq, mockRes, mockNext } = getRequestHandlerMocks(); - - mockReq.system_user = { user_identifier: 'user', user_guid: 'guid' } as SystemUser; - - const requestHandler = getVendorTelemetryByDeploymentIds(); - - await requestHandler(mockReq, mockRes, mockNext); - - expect(mockRes.jsonValue).to.eql(mockTelemetry); - expect(mockRes.statusValue).to.equal(200); - expect(mockGetTelemetry).to.have.been.calledOnce; - }); - it('should catch error', async () => { - const mockError = new Error('test error'); - const mockGetTelemetry = sinon - .stub(BctwTelemetryService.prototype, 'getVendorTelemetryByDeploymentIds') - .rejects(mockError); - - const { mockReq, mockRes, mockNext } = getRequestHandlerMocks(); - - mockReq.system_user = { user_identifier: 'user', user_guid: 'guid' } as SystemUser; - - const requestHandler = getVendorTelemetryByDeploymentIds(); - - try { - await requestHandler(mockReq, mockRes, mockNext); - } catch (err) { - expect(err).to.equal(mockError); - expect(mockGetTelemetry).to.have.been.calledOnce; - } - }); -}); diff --git a/api/src/paths/telemetry/vendor/deployments.ts b/api/src/paths/telemetry/vendor/deployments.ts deleted file mode 100644 index e2b2997ce7..0000000000 --- a/api/src/paths/telemetry/vendor/deployments.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { RequestHandler } from 'express'; -import { Operation } from 'express-openapi'; -import { authorizeRequestHandler } from '../../../request-handlers/security/authorization'; -import { getBctwUser } from '../../../services/bctw-service/bctw-service'; -import { BctwTelemetryService } from '../../../services/bctw-service/bctw-telemetry-service'; -import { getLogger } from '../../../utils/logger'; - -const defaultLog = getLogger('paths/telemetry/vendor/deployments'); - -const vendor_telemetry_responses = { - 200: { - description: 'Manual telemetry response object', - content: { - 'application/json': { - schema: { - type: 'array', - items: { - type: 'object', - additionalProperties: false, - properties: { - telemetry_id: { type: 'string', format: 'uuid' }, - deployment_id: { type: 'string', format: 'uuid' }, - collar_transaction_id: { type: 'string', format: 'uuid' }, - critter_id: { type: 'string', format: 'uuid' }, - deviceid: { type: 'number' }, - latitude: { type: 'number', nullable: true }, - longitude: { type: 'number', nullable: true }, - elevation: { type: 'number', nullable: true }, - vendor: { type: 'string', nullable: true }, - acquisition_date: { type: 'string', nullable: true } - } - } - } - } - } - }, - 400: { - $ref: '#/components/responses/400' - }, - 401: { - $ref: '#/components/responses/401' - }, - 403: { - $ref: '#/components/responses/403' - }, - 500: { - $ref: '#/components/responses/500' - }, - default: { - $ref: '#/components/responses/default' - } -}; - -export const POST: Operation = [ - authorizeRequestHandler(() => { - return { - and: [ - { - discriminator: 'SystemUser' - } - ] - }; - }), - getVendorTelemetryByDeploymentIds() -]; - -POST.apiDoc = { - description: 'Get a list of vendor retrieved telemetry by deployment ids', - tags: ['telemetry'], - security: [ - { - Bearer: [] - } - ], - responses: vendor_telemetry_responses, - requestBody: { - description: 'Request body', - required: true, - content: { - 'application/json': { - schema: { - title: 'Telemetry for Deployment ids', - type: 'array', - minItems: 1, - items: { - title: 'Vendor telemetry deployment ids', - type: 'string', - format: 'uuid' - } - } - } - } - } -}; - -export function getVendorTelemetryByDeploymentIds(): RequestHandler { - return async (req, res) => { - const user = getBctwUser(req); - - const bctwService = new BctwTelemetryService(user); - try { - const result = await bctwService.getVendorTelemetryByDeploymentIds(req.body); - return res.status(200).json(result); - } catch (error) { - defaultLog.error({ label: 'getManualTelemetryByDeploymentIds', message: 'error', error }); - throw error; - } - }; -} diff --git a/api/src/services/bctw-service/bctw-deployment-service.ts b/api/src/services/bctw-service/bctw-deployment-service.ts deleted file mode 100644 index 1d4a9da582..0000000000 --- a/api/src/services/bctw-service/bctw-deployment-service.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { z } from 'zod'; -import { BctwService } from './bctw-service'; - -export const BctwDeploymentRecordWithDeviceMeta = z.object({ - assignment_id: z.string().uuid(), - collar_id: z.string().uuid(), - critter_id: z.string().uuid(), - created_at: z.string(), - created_by_user_id: z.string().nullable(), - updated_at: z.string().nullable(), - updated_by_user_id: z.string().nullable(), - valid_from: z.string(), - valid_to: z.string().nullable(), - attachment_start: z.string(), - attachment_end: z.string().nullable(), - deployment_id: z.string(), - device_id: z.number().nullable(), - device_make: z.number().nullable(), - device_model: z.string().nullable(), - frequency: z.number().nullable(), - frequency_unit: z.number().nullable() -}); -export type BctwDeploymentRecordWithDeviceMeta = z.infer; - -export const BctwDeploymentRecord = z.object({ - assignment_id: z.string(), - collar_id: z.string(), - critter_id: z.string(), - created_at: z.string(), - created_by_user_id: z.string(), - updated_at: z.string().nullable(), - updated_by_user_id: z.string().nullable(), - valid_from: z.string(), - valid_to: z.string().nullable(), - attachment_start: z.string(), - attachment_end: z.string().nullable(), - deployment_id: z.string(), - device_id: z.number() -}); -export type BctwDeploymentRecord = z.infer; - -export const BctwDeploymentUpdate = z.object({ - deployment_id: z.string(), - attachment_start: z.string(), - attachment_end: z.string().nullable() -}); -export type BctwDeploymentUpdate = z.infer; - -export const BctwDeployDevice = z.object({ - deployment_id: z.string().uuid(), - device_id: z.number(), - frequency: z.number().optional(), - frequency_unit: z.string().optional(), - device_make: z.string().optional(), - device_model: z.string().optional(), - attachment_start: z.string(), - attachment_end: z.string().nullable(), - critter_id: z.string() -}); -export type BctwDeployDevice = z.infer; - -export class BctwDeploymentService extends BctwService { - /** - * Create a new deployment for a telemetry device on a critter. - * - * @param {BctwDeployDevice} device - * @return {*} {Promise} - * @memberof BctwDeploymentService - */ - async createDeployment(device: BctwDeployDevice): Promise { - const { data } = await this.axiosInstance.post('/deploy-device', device); - - return data; - } - - /** - * Get deployment records for a list of deployment IDs. - * - * @param {string[]} deploymentIds - * @return {*} {Promise} - * @memberof BctwDeploymentService - */ - async getDeploymentsByIds(deploymentIds: string[]): Promise { - const { data } = await this.axiosInstance.post('/get-deployments', deploymentIds); - - return data; - } - - /** - * Get all existing deployments for a list of critter IDs. - * - * @param {string[]} critter_ids - * @return {*} {Promise} - * @memberof BctwDeploymentService - */ - async getDeploymentsByCritterId(critter_ids: string[]): Promise { - const { data } = await this.axiosInstance.get('/get-deployments-by-critter-id', { - params: { critter_ids: critter_ids } - }); - - return data; - } - - /** - * Update the start and end dates of an existing deployment. - * - * @param {BctwDeploymentUpdate} deployment - * @return {*} {Promise} - * @memberof BctwDeploymentService - */ - async updateDeployment(deployment: BctwDeploymentUpdate): Promise[]> { - const { data } = await this.axiosInstance.patch('/update-deployment', deployment); - - return data; - } - - /** - * Soft deletes the deployment in BCTW. - * - * @param {string} deployment_id uuid - * @returns {*} {Promise} - * @memberof BctwDeploymentService - */ - async deleteDeployment(deployment_id: string): Promise { - const { data } = await this.axiosInstance.delete(`/delete-deployment/${deployment_id}`); - - return data; - } -} diff --git a/api/src/services/bctw-service/bctw-keyx-service.test.ts b/api/src/services/bctw-service/bctw-keyx-service.test.ts deleted file mode 100644 index 52ad7a64e1..0000000000 --- a/api/src/services/bctw-service/bctw-keyx-service.test.ts +++ /dev/null @@ -1,83 +0,0 @@ -import chai, { expect } from 'chai'; -import FormData from 'form-data'; -import { describe } from 'mocha'; -import sinon from 'sinon'; -import sinonChai from 'sinon-chai'; -import { BctwKeyxService } from '../bctw-service/bctw-keyx-service'; - -chai.use(sinonChai); - -describe('BctwKeyxService', () => { - afterEach(() => { - sinon.restore(); - }); - - describe('uploadKeyX', () => { - it('should send a post request', async () => { - const mockUser = { keycloak_guid: 'abc123', username: 'testuser' }; - - const bctwKeyxService = new BctwKeyxService(mockUser); - - const mockAxios = sinon - .stub(bctwKeyxService.axiosInstance, 'post') - .resolves({ data: { results: [], errors: [] } }); - - const mockMulterFile = { buffer: 'buffer', originalname: 'originalname.keyx' } as unknown as Express.Multer.File; - - sinon.stub(FormData.prototype, 'append'); - - const mockGetFormDataHeaders = sinon - .stub(FormData.prototype, 'getHeaders') - .resolves({ 'content-type': 'multipart/form-data' }); - - const result = await bctwKeyxService.uploadKeyX(mockMulterFile); - - expect(mockGetFormDataHeaders).to.have.been.calledOnce; - expect(result).to.eql({ totalKeyxFiles: 0, newRecords: 0, existingRecords: 0 }); - expect(mockAxios).to.have.been.calledOnce; - }); - - it('should throw an error if the file is not a valid keyx file', async () => { - const mockUser = { keycloak_guid: 'abc123', username: 'testuser' }; - - const bctwKeyxService = new BctwKeyxService(mockUser); - - sinon.stub(bctwKeyxService.axiosInstance, 'post').rejects(); - - const mockMulterFile = { - buffer: 'buffer', - originalname: 'originalname.notValid' // invalid file extension - } as unknown as Express.Multer.File; - - sinon.stub(FormData.prototype, 'append'); - - sinon.stub(FormData.prototype, 'getHeaders').resolves({ 'content-type': 'multipart/form-data' }); - - await bctwKeyxService - .uploadKeyX(mockMulterFile) - .catch((e) => - expect(e.message).to.equal('File is neither a .keyx file, nor an archive containing only .keyx files') - ); - }); - - it('should throw an error if the response body has errors', async () => { - const mockUser = { keycloak_guid: 'abc123', username: 'testuser' }; - - const bctwKeyxService = new BctwKeyxService(mockUser); - - sinon - .stub(bctwKeyxService.axiosInstance, 'post') - .resolves({ data: { results: [], errors: [{ error: 'error' }] } }); - - const mockMulterFile = { buffer: 'buffer', originalname: 'originalname.keyx' } as unknown as Express.Multer.File; - - sinon.stub(FormData.prototype, 'append'); - - sinon.stub(FormData.prototype, 'getHeaders').resolves({ 'content-type': 'multipart/form-data' }); - - await bctwKeyxService - .uploadKeyX(mockMulterFile) - .catch((e) => expect(e.message).to.equal('API request failed with errors')); - }); - }); -}); diff --git a/api/src/services/bctw-service/bctw-keyx-service.ts b/api/src/services/bctw-service/bctw-keyx-service.ts deleted file mode 100644 index 5ced5e4c17..0000000000 --- a/api/src/services/bctw-service/bctw-keyx-service.ts +++ /dev/null @@ -1,102 +0,0 @@ -import FormData from 'form-data'; -import { z } from 'zod'; -import { ApiError, ApiErrorType } from '../../errors/api-error'; -import { checkFileForKeyx } from '../../utils/media/media-utils'; -import { BctwService } from './bctw-service'; - -export const BctwUploadKeyxResponse = z.object({ - errors: z.array( - z.object({ - row: z.string(), - error: z.string(), - rownum: z.number() - }) - ), - results: z.array( - z.object({ - idcollar: z.number(), - comtype: z.string(), - idcom: z.string(), - collarkey: z.string(), - collartype: z.number(), - dtlast_fetch: z.string().nullable() - }) - ) -}); -export type BctwUploadKeyxResponse = z.infer; - -export const BctwKeyXDetails = z.object({ - device_id: z.number(), - keyx: z - .object({ - idcom: z.string(), - comtype: z.string(), - idcollar: z.number(), - collarkey: z.string(), - collartype: z.number() - }) - .nullable() -}); -export type BctwKeyXDetails = z.infer; - -export class BctwKeyxService extends BctwService { - /** - * Upload a single or multiple zipped keyX files to the BCTW API. - * - * @param {Express.Multer.File} keyX - * @return {*} {Promise} - * @memberof BctwKeyxService - */ - async uploadKeyX(keyX: Express.Multer.File) { - const isValidKeyX = checkFileForKeyx(keyX); - - if (isValidKeyX.error) { - throw new ApiError(ApiErrorType.GENERAL, isValidKeyX.error); - } - - const formData = new FormData(); - - formData.append('xml', keyX.buffer, keyX.originalname); - - const config = { - headers: { - ...formData.getHeaders() - } - }; - - const response = await this.axiosInstance.post('/import-xml', formData, config); - - const data: BctwUploadKeyxResponse = response.data; - - if (data.errors.length) { - const actualErrors: string[] = []; - - for (const error of data.errors) { - // Ignore errors that indicate that a keyX already exists - if (!error.error.endsWith('already exists')) { - actualErrors.push(error.error); - } - } - - if (actualErrors.length) { - throw new ApiError(ApiErrorType.UNKNOWN, 'API request failed with errors', actualErrors); - } - } - - return { - totalKeyxFiles: data.results.length + data.errors.length, - newRecords: data.results.length, - existingRecords: data.errors.length - }; - } - - async getKeyXDetails(deviceIds: number[]): Promise { - const { data } = await this.axiosInstance.get('/get-collars-keyx', { - params: { - device_ids: deviceIds.map((id) => String(id)) - } - }); - - return data; - } -} diff --git a/api/src/services/bctw-service/bctw-service.ts b/api/src/services/bctw-service/bctw-service.ts deleted file mode 100644 index eb28484b91..0000000000 --- a/api/src/services/bctw-service/bctw-service.ts +++ /dev/null @@ -1,124 +0,0 @@ -import axios, { AxiosError, AxiosInstance, AxiosResponse } from 'axios'; -import { Request } from 'express'; -import { z } from 'zod'; -import { ApiError, ApiErrorType } from '../../errors/api-error'; -import { HTTP500 } from '../../errors/http-error'; -import { ICodeResponse } from '../../models/bctw'; -import { KeycloakService } from '../keycloak-service'; - -export const BctwUser = z.object({ - keycloak_guid: z.string(), - username: z.string() -}); -export type BctwUser = z.infer; - -export const getBctwUser = (req: Request): BctwUser => ({ - keycloak_guid: req.system_user?.user_guid ?? '', - username: req.system_user?.user_identifier ?? '' -}); - -export class BctwService { - user: BctwUser; - keycloak: KeycloakService; - axiosInstance: AxiosInstance; - - constructor(user: BctwUser) { - this.user = user; - this.keycloak = new KeycloakService(); - this.axiosInstance = axios.create({ - headers: { - user: this.getUserHeader() - }, - baseURL: process.env.BCTW_API_HOST || '', - timeout: 10000 - }); - - this.axiosInstance.interceptors.response.use( - (response: AxiosResponse) => { - return response; - }, - (error: AxiosError) => { - if ( - error?.code === 'ECONNREFUSED' || - error?.code === 'ECONNRESET' || - error?.code === 'ETIMEOUT' || - error?.code === 'ECONNABORTED' - ) { - return Promise.reject( - new HTTP500('Connection to the BCTW API server was refused. Please try again later.', [error?.message]) - ); - } - const data: any = error.response?.data; - const errMsg = data?.error ?? data?.errors ?? data ?? 'Unknown error'; - const issues = data?.issues ?? []; - - return Promise.reject( - new ApiError( - ApiErrorType.UNKNOWN, - `API request failed with status code ${error?.response?.status}: ${errMsg}`, - [].concat(errMsg).concat(issues) - ) - ); - } - ); - - // Async request interceptor - this.axiosInstance.interceptors.request.use( - async (config) => { - const token = await this.getToken(); - config.headers['Authorization'] = `Bearer ${token}`; - - return config; - }, - (error) => { - return Promise.reject(error); - } - ); - } - - /** - * Return user information as a JSON string. - * - * @return {*} {string} - * @memberof BctwService - */ - getUserHeader(): string { - return JSON.stringify(this.user); - } - - /** - * Retrieve an authentication token using Keycloak service. - * - * @return {*} {Promise} - * @memberof BctwService - */ - async getToken(): Promise { - const token = await this.keycloak.getKeycloakServiceToken(); - return token; - } - - /** - * Get the health of the platform. - * - * @return {*} {Promise} - * @memberof BctwService - */ - async getHealth(): Promise { - const { data } = await this.axiosInstance.get('/health'); - - return data; - } - - /** - * Get a list of all BCTW codes with a given header name. - * - * @param {string} codeHeaderName - * @return {*} {Promise} - * @memberof BctwService - */ - async getCode(codeHeaderName: string): Promise { - const { data } = await this.axiosInstance.get('/get-code', { params: { codeHeader: codeHeaderName } }); - - return data; - } -} diff --git a/api/src/services/bctw-service/bctw-telemetry-service.ts b/api/src/services/bctw-service/bctw-telemetry-service.ts deleted file mode 100644 index c8d1d2deba..0000000000 --- a/api/src/services/bctw-service/bctw-telemetry-service.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { z } from 'zod'; -import { BctwService } from './bctw-service'; - -export const IAllTelemetry = z - .object({ - id: z.string().uuid(), - deployment_id: z.string().uuid(), - latitude: z.number(), - longitude: z.number(), - acquisition_date: z.string(), - telemetry_type: z.string() - }) - .and( - // One of telemetry_id or telemetry_manual_id is expected to be non-null - z.union([ - z.object({ - telemetry_id: z.string().uuid(), - telemetry_manual_id: z.null() - }), - z.object({ - telemetry_id: z.null(), - telemetry_manual_id: z.string().uuid() - }) - ]) - ); -export type IAllTelemetry = z.infer; - -export const IVendorTelemetry = z.object({ - telemetry_id: z.string(), - deployment_id: z.string().uuid(), - collar_transaction_id: z.string().uuid(), - critter_id: z.string().uuid(), - deviceid: z.number(), - latitude: z.number(), - longitude: z.number(), - elevation: z.number(), - vendor: z.string(), - acquisition_date: z.string() -}); -export type IVendorTelemetry = z.infer; - -export const IManualTelemetry = z.object({ - telemetry_manual_id: z.string().uuid(), - deployment_id: z.string().uuid(), - latitude: z.number(), - longitude: z.number(), - acquisition_date: z.string() -}); -export type IManualTelemetry = z.infer; - -export interface ICreateManualTelemetry { - deployment_id: string; - latitude: number; - longitude: number; - acquisition_date: string; -} - -export class BctwTelemetryService extends BctwService { - /** - * Get all manual telemetry records - * This set of telemetry is mostly useful for testing purposes. - * - * @returns {*} IManualTelemetry[] - **/ - async getManualTelemetry(): Promise { - const res = await this.axiosInstance.get('/manual-telemetry'); - return res.data; - } - - /** - * retrieves manual telemetry from list of deployment ids - * - * @async - * @param {string[]} deployment_ids - bctw deployments - * @returns {*} IManualTelemetry[] - */ - async getManualTelemetryByDeploymentIds(deployment_ids: string[]): Promise { - const res = await this.axiosInstance.post('/manual-telemetry/deployments', deployment_ids); - return res.data; - } - - /** - * retrieves manual telemetry from list of deployment ids - * - * @async - * @param {string[]} deployment_ids - bctw deployments - * @returns {*} IVendorTelemetry[] - */ - async getVendorTelemetryByDeploymentIds(deployment_ids: string[]): Promise { - const res = await this.axiosInstance.post('/vendor-telemetry/deployments', deployment_ids); - return res.data; - } - - /** - * retrieves manual and vendor telemetry from list of deployment ids - * - * @async - * @param {string[]} deploymentIds - bctw deployments - * @returns {*} IAllTelemetry[] - */ - async getAllTelemetryByDeploymentIds(deploymentIds: string[]): Promise { - const res = await this.axiosInstance.post('/all-telemetry/deployments', deploymentIds); - return res.data; - } - - /** - * Delete manual telemetry records by telemetry_manual_id - * Note: This is a post request that accepts an array of ids - * @param {string[]} telemetry_manual_ids - * - * @returns {*} IManualTelemetry[] - **/ - async deleteManualTelemetry(telemetry_manual_ids: string[]): Promise { - const res = await this.axiosInstance.post('/manual-telemetry/delete', telemetry_manual_ids); - return res.data; - } - - /** - * Bulk create manual telemetry records - * @param {ICreateManualTelemetry[]} payload - * - * @returns {*} IManualTelemetry[] - **/ - async createManualTelemetry(payload: ICreateManualTelemetry[]): Promise { - const res = await this.axiosInstance.post('/manual-telemetry', payload); - return res.data; - } - - /** - * Bulk update manual telemetry records - * @param {IManualTelemetry} payload - * - * @returns {*} IManualTelemetry[] - **/ - async updateManualTelemetry(payload: IManualTelemetry[]): Promise { - const res = await this.axiosInstance.patch('/manual-telemetry', payload); - return res.data; - } -}