diff --git a/api/src/database-models/deployment.ts b/api/src/database-models/deployment.ts index dee2f428ee..2197f974bb 100644 --- a/api/src/database-models/deployment.ts +++ b/api/src/database-models/deployment.ts @@ -11,8 +11,14 @@ export const DeploymentModel = z.object({ critter_id: z.number(), device_id: z.number(), device_key: z.string(), - attachment_start: z.string(), - attachment_end: z.string().nullable(), + frequency: z.number().nullable(), + frequency_unit_id: z.number().nullable(), + attachment_start_date: z.string(), + attachment_start_time: z.string().nullable(), + attachment_start_timestamp: z.string(), + attachment_end_date: z.string().nullable(), + attachment_end_time: z.string().nullable(), + attachment_end_timestamp: z.string(), critterbase_start_capture_id: z.string().uuid().nullable(), critterbase_end_capture_id: z.string().uuid().nullable(), critterbase_end_mortality_id: z.string().uuid().nullable(), diff --git a/api/src/errors/api-error.ts b/api/src/errors/api-error.ts index 1ac85601de..24b4912b1f 100644 --- a/api/src/errors/api-error.ts +++ b/api/src/errors/api-error.ts @@ -69,16 +69,3 @@ export class ApiBuildSQLError extends ApiError { super(ApiErrorType.BUILD_SQL, message, errors); } } - -/** - * The API was unable to perform an action due to a lack of project permissions. - * - * @export - * @class ProjectPermissionError - * @extends {ApiError} - */ -export class ProjectPermissionError extends ApiError { - constructor(message: string, errors?: (string | object)[]) { - super(ApiErrorType.PROJECT_PERMISSION, message, errors); - } -} diff --git a/api/src/repositories/deployment-repository/deployment-repository.ts b/api/src/repositories/deployment-repository/deployment-repository.ts index 823ab1e805..04c9a696be 100644 --- a/api/src/repositories/deployment-repository/deployment-repository.ts +++ b/api/src/repositories/deployment-repository/deployment-repository.ts @@ -1,6 +1,6 @@ import SQL from 'sql-template-strings'; import { DeploymentRecord } from '../../database-models/deployment'; -import { ApiExecuteSQLError, ProjectPermissionError } from '../../errors/api-error'; +import { ApiExecuteSQLError } from '../../errors/api-error'; import { BaseRepository } from '../base-repository'; import { CreateDeployment, UpdateDeployment } from './deployment-repository.interface'; @@ -12,13 +12,7 @@ import { CreateDeployment, UpdateDeployment } from './deployment-repository.inte * @extends {BaseRepository} */ export class DeploymentRepository extends BaseRepository { - async createDeployment(surveyId: number, deployment: CreateDeployment): Promise { - if (deployment.survey_id !== surveyId) { - throw new ProjectPermissionError('Failed to create deployment', [ - `User is not authorized to create a deployment for survey ${deployment.survey_id}` - ]); - } - + async createDeployment(deployment: CreateDeployment): Promise { const sqlStatement = SQL` INSERT INTO deployment2 ( survey_id, diff --git a/api/src/services/deployment-services/deployment-service.ts b/api/src/services/deployment-services/deployment-service.ts index b5cdcaf928..726ad8f354 100644 --- a/api/src/services/deployment-services/deployment-service.ts +++ b/api/src/services/deployment-services/deployment-service.ts @@ -26,13 +26,12 @@ export class DeploymentService extends DBService { /** * Create a new deployment. * - * @param {number} surveyId * @param {CreateDeployment} deployment * @return {*} {Promise} * @memberof DeploymentService */ - async createDeployment(surveyId: number, deployment: CreateDeployment): Promise { - return this.deploymentRepository.createDeployment(surveyId, deployment); + async createDeployment(deployment: CreateDeployment): Promise { + return this.deploymentRepository.createDeployment(deployment); } /** diff --git a/database/src/migrations/20241008000000_bctw_migration.ts b/database/src/migrations/20241008000000_bctw_migration.ts index 9ac7b06029..baa43a6672 100644 --- a/database/src/migrations/20241008000000_bctw_migration.ts +++ b/database/src/migrations/20241008000000_bctw_migration.ts @@ -82,8 +82,12 @@ export async function up(knex: Knex): Promise { device_key varchar NOT NULL, frequency integer, frequency_unit_id integer, - attachment_start timestamptz(6) NOT NULL, - attachment_end timestamptz(6), + attachment_start_date date NOT NULL, + attachment_start_time time, + attachment_start_timestamp timestamptz(6) GENERATED ALWAYS AS (COALESCE(attachment_start_date + attachment_start_time, attachment_start_date::timestamp)) stored, + attachment_end_date date, + attachment_end_time time, + attachment_end_timestamp timestamptz(6) GENERATED ALWAYS AS (COALESCE(attachment_end_date + attachment_end_time, attachment_end_date::timestamp)) stored, critterbase_start_capture_id uuid, critterbase_end_capture_id uuid, critterbase_end_mortality_id uuid, @@ -93,7 +97,9 @@ export async function up(knex: Knex): Promise { update_user integer, revision_count integer DEFAULT 0 NOT NULL, -- Check that the attachment_start is before attachment_end - CONSTRAINT check_attachment_start_before_end CHECK (attachment_start <= attachment_end), + CONSTRAINT check_attachment_start_before_end CHECK (attachment_start_timestamp <= attachment_end_timestamp), + -- Check that if frequency is set, frequency_unit_id is also set and vice versa + CONSTRAINT check_frequency_and_unit CHECK ((frequency IS NOT NULL AND frequency_unit_id IS NOT NULL) OR (frequency IS NULL AND frequency_unit_id IS NULL)), -- Check that for deployments of the same device_key, that the attachment dates do not overlap CONSTRAINT check_no_device_attachment_date_overlap EXCLUDE USING gist ( device_key WITH =, @@ -110,8 +116,12 @@ export async function up(knex: Knex): Promise { COMMENT ON COLUMN deployment2.device_key IS '(Generated) The SIMS unique key for the device.'; COMMENT ON COLUMN deployment2.frequency IS 'The frequency of the device.'; COMMENT ON COLUMN deployment2.frequency_unit_id IS 'Foreign key to the frequency_unit table.'; - COMMENT ON COLUMN deployment2.attachment_start IS 'The date the telemetry device was attached.'; - COMMENT ON COLUMN deployment2.attachment_end IS 'The date the telemetry device was removed.'; + COMMENT ON COLUMN deployment2.attachment_start_date IS 'The date the device was attached to the animal.'; + COMMENT ON COLUMN deployment2.attachment_start_time IS 'The time the device was attached to the animal.'; + COMMENT ON COLUMN deployment2.attachment_start_timestamp IS '(Generated) The timestamp the device was attached to the animal.'; + COMMENT ON COLUMN deployment2.attachment_end_date IS 'The date the device was removed from the animal.'; + COMMENT ON COLUMN deployment2.attachment_end_time IS 'The time the device was removed from the animal.'; + COMMENT ON COLUMN deployment2.attachment_end_timestamp IS '(Generated) The timestamp the device was removed from the animal.'; COMMENT ON COLUMN deployment2.critterbase_start_capture_id IS 'UUID of an external Critterbase capture record. The capture event during which the device was attached to the animal.'; COMMENT ON COLUMN deployment2.critterbase_end_capture_id IS 'UUID of an external Critterbase capture record. The capture event during which the device was removed from the animal.'; COMMENT ON COLUMN deployment2.critterbase_end_mortality_id IS 'UUID of an external Critterbase mortality record. The mortality event during which the device was removed from the animal.'; @@ -175,8 +185,8 @@ export async function up(knex: Knex): Promise { COMMENT ON COLUMN telemetry_manual.deployment2_id IS 'Foreign key to the deployment table.'; COMMENT ON COLUMN telemetry_manual.latitude IS 'The latitude of the telemetry record, having ten points of total precision and 7 points of precision after the decimal.'; COMMENT ON COLUMN telemetry_manual.longitude IS 'The longitude of the telemetry record, having ten points of total precision and 7 points of precision after the decimal.'; - COMMENT ON COLUMN telemetry_manual.acquisition_date IS 'The date the telemetry record was recorded.'; - COMMENT ON COLUMN telemetry_manual.transmission_date IS 'The date the telemetry record was transmitted.'; + COMMENT ON COLUMN telemetry_manual.acquisition_date IS 'The date the device recorded the telemetry record. (Ex: the device captures a gps point every hour).' + COMMENT ON COLUMN telemetry_manual.transmission_date IS 'The date the device transmitted the telemetry record to the vendor. (Ex: the device transmits all recorded gps points to the vendor every 24 hours).'; COMMENT ON COLUMN telemetry_manual.create_date IS 'The datetime the record was created.'; COMMENT ON COLUMN telemetry_manual.create_user IS 'The id of the user who created the record as identified in the system user table.'; COMMENT ON COLUMN telemetry_manual.update_date IS 'The datetime the record was updated.';