555 lines
22 KiB
TypeScript
555 lines
22 KiB
TypeScript
import { MigrationInterface, QueryRunner } from 'typeorm';
|
|
|
|
const newPermissions = [
|
|
'inspection_closure.read',
|
|
'inspection_closure.prepare',
|
|
'inspection_closure.sign',
|
|
'inspection_closure.close',
|
|
] as const;
|
|
|
|
const rolePermissionValues = `
|
|
('admin', 'inspection_closure.read'),
|
|
('admin', 'inspection_closure.prepare'),
|
|
('admin', 'inspection_closure.sign'),
|
|
('admin', 'inspection_closure.close'),
|
|
('director', 'inspection_closure.read'),
|
|
('director', 'inspection_closure.close'),
|
|
('supervisor', 'inspection_closure.read'),
|
|
('supervisor', 'inspection_closure.prepare'),
|
|
('supervisor', 'inspection_closure.sign'),
|
|
('supervisor', 'inspection_closure.close'),
|
|
('inspector', 'inspection_closure.read'),
|
|
('inspector', 'inspection_closure.prepare'),
|
|
('inspector', 'inspection_closure.sign'),
|
|
('inspector', 'inspection_closure.close'),
|
|
('auditor', 'inspection_closure.read')
|
|
`;
|
|
|
|
function quoteIdentifier(identifier: string): string {
|
|
return `"${identifier.replaceAll('"', '""')}"`;
|
|
}
|
|
|
|
export class PhaseD5ActClosingSignatures1787328000000 implements MigrationInterface {
|
|
name = 'PhaseD5ActClosingSignatures1787328000000';
|
|
|
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
await queryRunner.query(`
|
|
ALTER TABLE inspection_acts
|
|
ADD COLUMN closed_at timestamptz,
|
|
ADD COLUMN closed_by uuid,
|
|
ADD COLUMN closure_sha256 char(64),
|
|
ADD CONSTRAINT fk_inspection_acts_closed_by FOREIGN KEY (closed_by)
|
|
REFERENCES users(id) ON DELETE SET NULL,
|
|
ADD CONSTRAINT chk_inspection_acts_closure CHECK (
|
|
status <> 'CLOSED'
|
|
OR (
|
|
closed_at IS NOT NULL
|
|
AND closed_by IS NOT NULL
|
|
AND closure_sha256 ~ '^[0-9a-f]{64}$'
|
|
)
|
|
)
|
|
`);
|
|
await queryRunner.query(`
|
|
CREATE INDEX idx_inspection_acts_closure_sha256
|
|
ON inspection_acts (closure_sha256)
|
|
WHERE closure_sha256 IS NOT NULL
|
|
`);
|
|
await queryRunner.query(`
|
|
ALTER TABLE inspection_act_versions
|
|
DROP CONSTRAINT chk_inspection_act_versions_event
|
|
`);
|
|
await queryRunner.query(`
|
|
ALTER TABLE inspection_act_versions
|
|
ADD CONSTRAINT chk_inspection_act_versions_event CHECK (
|
|
event IN ('CREATED', 'UPDATED', 'READY', 'REOPENED', 'CLOSED', 'CANCELLED')
|
|
)
|
|
`);
|
|
|
|
await queryRunner.query(`
|
|
CREATE TABLE inspection_act_responsibles (
|
|
act_id uuid PRIMARY KEY,
|
|
attendance_status varchar(20) NOT NULL,
|
|
full_name varchar(200),
|
|
document_type varchar(20),
|
|
document_number varchar(40),
|
|
position varchar(200),
|
|
email varchar(320),
|
|
phone varchar(50),
|
|
absence_reason text,
|
|
updated_by uuid,
|
|
created_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
CONSTRAINT chk_inspection_act_responsibles_attendance CHECK (
|
|
attendance_status IN ('PRESENT', 'ABSENT')
|
|
),
|
|
CONSTRAINT chk_inspection_act_responsibles_document_type CHECK (
|
|
document_type IS NULL OR document_type IN ('DNI', 'CUIL', 'PASSPORT', 'OTHER')
|
|
),
|
|
CONSTRAINT chk_inspection_act_responsibles_details CHECK (
|
|
(
|
|
attendance_status = 'PRESENT'
|
|
AND LENGTH(TRIM(COALESCE(full_name, ''))) > 0
|
|
AND document_type IS NOT NULL
|
|
AND LENGTH(TRIM(COALESCE(document_number, ''))) > 0
|
|
AND LENGTH(TRIM(COALESCE(position, ''))) > 0
|
|
AND absence_reason IS NULL
|
|
) OR (
|
|
attendance_status = 'ABSENT'
|
|
AND LENGTH(TRIM(COALESCE(absence_reason, ''))) >= 10
|
|
)
|
|
),
|
|
CONSTRAINT fk_inspection_act_responsibles_act FOREIGN KEY (act_id)
|
|
REFERENCES inspection_acts(id) ON DELETE RESTRICT,
|
|
CONSTRAINT fk_inspection_act_responsibles_updated_by FOREIGN KEY (updated_by)
|
|
REFERENCES users(id) ON DELETE SET NULL
|
|
)
|
|
`);
|
|
|
|
await queryRunner.query(`
|
|
CREATE TABLE inspection_act_closures (
|
|
act_id uuid PRIMARY KEY,
|
|
schema_version varchar(40) NOT NULL,
|
|
prepared_snapshot jsonb NOT NULL,
|
|
prepared_sha256 char(64) NOT NULL,
|
|
prepared_at timestamptz NOT NULL,
|
|
prepared_by uuid NOT NULL,
|
|
final_snapshot jsonb,
|
|
final_sha256 char(64),
|
|
device_closed_at timestamptz,
|
|
server_closed_at timestamptz,
|
|
upload_mode varchar(20),
|
|
closed_by uuid,
|
|
created_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
CONSTRAINT chk_inspection_act_closures_schema CHECK (
|
|
LENGTH(TRIM(schema_version)) > 0
|
|
),
|
|
CONSTRAINT chk_inspection_act_closures_prepared_sha CHECK (
|
|
prepared_sha256 ~ '^[0-9a-f]{64}$'
|
|
),
|
|
CONSTRAINT chk_inspection_act_closures_final_sha CHECK (
|
|
final_sha256 IS NULL OR final_sha256 ~ '^[0-9a-f]{64}$'
|
|
),
|
|
CONSTRAINT chk_inspection_act_closures_upload_mode CHECK (
|
|
upload_mode IS NULL OR upload_mode IN ('IMMEDIATE', 'DEFERRED')
|
|
),
|
|
CONSTRAINT chk_inspection_act_closures_final CHECK (
|
|
(
|
|
final_snapshot IS NULL
|
|
AND final_sha256 IS NULL
|
|
AND device_closed_at IS NULL
|
|
AND server_closed_at IS NULL
|
|
AND upload_mode IS NULL
|
|
AND closed_by IS NULL
|
|
) OR (
|
|
final_snapshot IS NOT NULL
|
|
AND final_sha256 IS NOT NULL
|
|
AND device_closed_at IS NOT NULL
|
|
AND server_closed_at IS NOT NULL
|
|
AND upload_mode IS NOT NULL
|
|
AND closed_by IS NOT NULL
|
|
)
|
|
),
|
|
CONSTRAINT fk_inspection_act_closures_act FOREIGN KEY (act_id)
|
|
REFERENCES inspection_acts(id) ON DELETE RESTRICT,
|
|
CONSTRAINT fk_inspection_act_closures_prepared_by FOREIGN KEY (prepared_by)
|
|
REFERENCES users(id) ON DELETE RESTRICT,
|
|
CONSTRAINT fk_inspection_act_closures_closed_by FOREIGN KEY (closed_by)
|
|
REFERENCES users(id) ON DELETE RESTRICT
|
|
)
|
|
`);
|
|
await queryRunner.query(`
|
|
CREATE INDEX idx_inspection_act_closures_prepared_sha
|
|
ON inspection_act_closures (prepared_sha256)
|
|
`);
|
|
await queryRunner.query(`
|
|
CREATE UNIQUE INDEX uq_inspection_act_closures_final_sha
|
|
ON inspection_act_closures (final_sha256)
|
|
WHERE final_sha256 IS NOT NULL
|
|
`);
|
|
|
|
await queryRunner.query(`
|
|
CREATE TABLE inspection_act_signatures (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
act_id uuid NOT NULL,
|
|
signer_type varchar(32) NOT NULL,
|
|
signer_user_id uuid,
|
|
signer_name varchar(200) NOT NULL,
|
|
document_type varchar(20),
|
|
document_number varchar(40),
|
|
position varchar(200),
|
|
status varchar(20) NOT NULL,
|
|
reason text,
|
|
original_name varchar(255),
|
|
stored_name varchar(80),
|
|
mime_type varchar(100),
|
|
size_bytes bigint,
|
|
image_sha256 char(64),
|
|
consent_text text,
|
|
consent_version varchar(20),
|
|
consent_accepted_at timestamptz,
|
|
client_signed_at timestamptz,
|
|
signed_at timestamptz,
|
|
latitude numeric(9, 6),
|
|
longitude numeric(9, 6),
|
|
accuracy_m numeric(12, 3),
|
|
device_label varchar(200),
|
|
source varchar(20) NOT NULL,
|
|
prepared_sha256 char(64) NOT NULL,
|
|
signature_payload_sha256 char(64) NOT NULL,
|
|
uploaded_by uuid NOT NULL,
|
|
created_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
CONSTRAINT uq_inspection_act_signatures_stored_name UNIQUE (stored_name),
|
|
CONSTRAINT chk_inspection_act_signatures_signer_type CHECK (
|
|
signer_type IN ('INSPECTOR', 'COMPANY_RESPONSIBLE')
|
|
),
|
|
CONSTRAINT chk_inspection_act_signatures_status CHECK (
|
|
status IN ('SIGNED', 'REFUSED', 'ABSENT')
|
|
),
|
|
CONSTRAINT chk_inspection_act_signatures_document_type CHECK (
|
|
document_type IS NULL OR document_type IN ('DNI', 'CUIL', 'PASSPORT', 'OTHER')
|
|
),
|
|
CONSTRAINT chk_inspection_act_signatures_source CHECK (
|
|
source IN ('WEB', 'ANDROID')
|
|
),
|
|
CONSTRAINT chk_inspection_act_signatures_sha CHECK (
|
|
prepared_sha256 ~ '^[0-9a-f]{64}$'
|
|
AND signature_payload_sha256 ~ '^[0-9a-f]{64}$'
|
|
AND (image_sha256 IS NULL OR image_sha256 ~ '^[0-9a-f]{64}$')
|
|
),
|
|
CONSTRAINT chk_inspection_act_signatures_coordinates CHECK (
|
|
(latitude IS NULL AND longitude IS NULL)
|
|
OR (
|
|
latitude IS NOT NULL AND longitude IS NOT NULL
|
|
AND latitude BETWEEN -90 AND 90
|
|
AND longitude BETWEEN -180 AND 180
|
|
)
|
|
),
|
|
CONSTRAINT chk_inspection_act_signatures_accuracy CHECK (
|
|
accuracy_m IS NULL OR (accuracy_m >= 0 AND latitude IS NOT NULL)
|
|
),
|
|
CONSTRAINT chk_inspection_act_signatures_inspector CHECK (
|
|
signer_type <> 'INSPECTOR'
|
|
OR (signer_user_id IS NOT NULL AND status = 'SIGNED')
|
|
),
|
|
CONSTRAINT chk_inspection_act_signatures_company CHECK (
|
|
signer_type <> 'COMPANY_RESPONSIBLE' OR signer_user_id IS NULL
|
|
),
|
|
CONSTRAINT chk_inspection_act_signatures_signed CHECK (
|
|
(
|
|
status = 'SIGNED'
|
|
AND reason IS NULL
|
|
AND stored_name IS NOT NULL
|
|
AND mime_type = 'image/png'
|
|
AND size_bytes BETWEEN 1 AND 1048576
|
|
AND image_sha256 IS NOT NULL
|
|
AND LENGTH(TRIM(COALESCE(consent_text, ''))) > 0
|
|
AND consent_version IS NOT NULL
|
|
AND consent_accepted_at IS NOT NULL
|
|
AND signed_at IS NOT NULL
|
|
) OR (
|
|
status IN ('REFUSED', 'ABSENT')
|
|
AND signer_type = 'COMPANY_RESPONSIBLE'
|
|
AND LENGTH(TRIM(COALESCE(reason, ''))) >= 10
|
|
AND stored_name IS NULL
|
|
AND mime_type IS NULL
|
|
AND size_bytes IS NULL
|
|
AND image_sha256 IS NULL
|
|
AND consent_text IS NULL
|
|
AND consent_version IS NULL
|
|
AND consent_accepted_at IS NULL
|
|
AND signed_at IS NULL
|
|
)
|
|
),
|
|
CONSTRAINT fk_inspection_act_signatures_act FOREIGN KEY (act_id)
|
|
REFERENCES inspection_acts(id) ON DELETE RESTRICT,
|
|
CONSTRAINT fk_inspection_act_signatures_signer_user FOREIGN KEY (signer_user_id)
|
|
REFERENCES users(id) ON DELETE RESTRICT,
|
|
CONSTRAINT fk_inspection_act_signatures_uploaded_by FOREIGN KEY (uploaded_by)
|
|
REFERENCES users(id) ON DELETE RESTRICT
|
|
)
|
|
`);
|
|
await queryRunner.query(`
|
|
CREATE INDEX idx_inspection_act_signatures_act_created
|
|
ON inspection_act_signatures (act_id, created_at)
|
|
`);
|
|
await queryRunner.query(`
|
|
CREATE INDEX idx_inspection_act_signatures_sha256
|
|
ON inspection_act_signatures (signature_payload_sha256)
|
|
`);
|
|
await queryRunner.query(`
|
|
CREATE UNIQUE INDEX uq_inspection_act_inspector_signature
|
|
ON inspection_act_signatures (act_id, signer_user_id)
|
|
WHERE signer_type = 'INSPECTOR'
|
|
`);
|
|
await queryRunner.query(`
|
|
CREATE UNIQUE INDEX uq_inspection_act_company_outcome
|
|
ON inspection_act_signatures (act_id)
|
|
WHERE signer_type = 'COMPANY_RESPONSIBLE'
|
|
`);
|
|
|
|
await queryRunner.query(`
|
|
CREATE OR REPLACE FUNCTION dhv2_guard_act_responsible_draft()
|
|
RETURNS trigger LANGUAGE plpgsql AS $$
|
|
DECLARE act_status varchar(24);
|
|
BEGIN
|
|
SELECT status INTO act_status FROM inspection_acts WHERE id = NEW.act_id;
|
|
IF act_status <> 'DRAFT' THEN
|
|
RAISE EXCEPTION 'El responsable sólo puede modificarse con el acta en borrador';
|
|
END IF;
|
|
NEW.updated_at := CURRENT_TIMESTAMP;
|
|
RETURN NEW;
|
|
END
|
|
$$
|
|
`);
|
|
await queryRunner.query(`
|
|
CREATE TRIGGER trg_inspection_act_responsibles_draft
|
|
BEFORE INSERT OR UPDATE ON inspection_act_responsibles
|
|
FOR EACH ROW EXECUTE FUNCTION dhv2_guard_act_responsible_draft()
|
|
`);
|
|
|
|
await queryRunner.query(`
|
|
CREATE OR REPLACE FUNCTION dhv2_guard_act_signature_ready()
|
|
RETURNS trigger LANGUAGE plpgsql AS $$
|
|
DECLARE current_status varchar(24);
|
|
DECLARE current_sha char(64);
|
|
BEGIN
|
|
SELECT act.status, closure.prepared_sha256
|
|
INTO current_status, current_sha
|
|
FROM inspection_acts act
|
|
INNER JOIN inspection_act_closures closure ON closure.act_id = act.id
|
|
WHERE act.id = NEW.act_id;
|
|
IF current_status <> 'READY' OR current_sha IS DISTINCT FROM NEW.prepared_sha256 THEN
|
|
RAISE EXCEPTION 'La firma no corresponde a un acta preparada vigente';
|
|
END IF;
|
|
RETURN NEW;
|
|
END
|
|
$$
|
|
`);
|
|
await queryRunner.query(`
|
|
CREATE TRIGGER trg_inspection_act_signatures_ready
|
|
BEFORE INSERT ON inspection_act_signatures
|
|
FOR EACH ROW EXECUTE FUNCTION dhv2_guard_act_signature_ready()
|
|
`);
|
|
|
|
await queryRunner.query(`
|
|
CREATE OR REPLACE FUNCTION dhv2_guard_closed_act_immutable()
|
|
RETURNS trigger LANGUAGE plpgsql AS $$
|
|
BEGIN
|
|
IF OLD.status IN ('CLOSED', 'RECTIFIED') THEN
|
|
RAISE EXCEPTION 'El acta cerrada es inmutable';
|
|
END IF;
|
|
RETURN NEW;
|
|
END
|
|
$$
|
|
`);
|
|
await queryRunner.query(`
|
|
CREATE TRIGGER trg_inspection_acts_closed_immutable
|
|
BEFORE UPDATE ON inspection_acts
|
|
FOR EACH ROW EXECUTE FUNCTION dhv2_guard_closed_act_immutable()
|
|
`);
|
|
|
|
await queryRunner.query(`
|
|
CREATE OR REPLACE FUNCTION dhv2_guard_closed_closure_immutable()
|
|
RETURNS trigger LANGUAGE plpgsql AS $$
|
|
BEGIN
|
|
IF OLD.server_closed_at IS NOT NULL THEN
|
|
RAISE EXCEPTION 'El cierre sellado es inmutable';
|
|
END IF;
|
|
NEW.updated_at := CURRENT_TIMESTAMP;
|
|
RETURN NEW;
|
|
END
|
|
$$
|
|
`);
|
|
await queryRunner.query(`
|
|
CREATE TRIGGER trg_inspection_act_closures_immutable
|
|
BEFORE UPDATE ON inspection_act_closures
|
|
FOR EACH ROW EXECUTE FUNCTION dhv2_guard_closed_closure_immutable()
|
|
`);
|
|
|
|
await queryRunner.query(`
|
|
CREATE OR REPLACE FUNCTION dhv2_guard_act_asset_draft()
|
|
RETURNS trigger LANGUAGE plpgsql AS $$
|
|
DECLARE act_status varchar(24);
|
|
BEGIN
|
|
SELECT status INTO act_status FROM inspection_acts
|
|
WHERE id = COALESCE(NEW.act_id, OLD.act_id);
|
|
IF act_status <> 'DRAFT' THEN
|
|
RAISE EXCEPTION 'Los activos del acta están congelados';
|
|
END IF;
|
|
IF TG_OP = 'DELETE' THEN
|
|
RETURN OLD;
|
|
END IF;
|
|
RETURN NEW;
|
|
END
|
|
$$
|
|
`);
|
|
await queryRunner.query(`
|
|
CREATE TRIGGER trg_inspection_act_assets_draft
|
|
BEFORE INSERT OR UPDATE OR DELETE ON inspection_act_assets
|
|
FOR EACH ROW EXECUTE FUNCTION dhv2_guard_act_asset_draft()
|
|
`);
|
|
|
|
await queryRunner.query(`
|
|
CREATE OR REPLACE FUNCTION dhv2_guard_finding_inspection_fields()
|
|
RETURNS trigger LANGUAGE plpgsql AS $$
|
|
DECLARE act_status varchar(24);
|
|
BEGIN
|
|
IF TG_OP = 'INSERT' THEN
|
|
SELECT status INTO act_status FROM inspection_acts WHERE id = NEW.act_id;
|
|
IF act_status <> 'DRAFT' THEN
|
|
RAISE EXCEPTION 'No pueden agregarse hallazgos al acta congelada';
|
|
END IF;
|
|
RETURN NEW;
|
|
END IF;
|
|
SELECT status INTO act_status FROM inspection_acts WHERE id = OLD.act_id;
|
|
IF act_status <> 'DRAFT' AND (
|
|
NEW.act_id IS DISTINCT FROM OLD.act_id
|
|
OR NEW.asset_id IS DISTINCT FROM OLD.asset_id
|
|
OR NEW.catalog_item_id IS DISTINCT FROM OLD.catalog_item_id
|
|
OR NEW.finding_number IS DISTINCT FROM OLD.finding_number
|
|
OR NEW.code IS DISTINCT FROM OLD.code
|
|
OR NEW.title IS DISTINCT FROM OLD.title
|
|
OR NEW.description IS DISTINCT FROM OLD.description
|
|
OR NEW.legal_basis IS DISTINCT FROM OLD.legal_basis
|
|
OR NEW.glossary IS DISTINCT FROM OLD.glossary
|
|
OR NEW.catalog_revision IS DISTINCT FROM OLD.catalog_revision
|
|
) THEN
|
|
RAISE EXCEPTION 'El contenido constatado del hallazgo está congelado';
|
|
END IF;
|
|
RETURN NEW;
|
|
END
|
|
$$
|
|
`);
|
|
await queryRunner.query(`
|
|
CREATE TRIGGER trg_inspection_findings_frozen_fields
|
|
BEFORE INSERT OR UPDATE ON inspection_findings
|
|
FOR EACH ROW EXECUTE FUNCTION dhv2_guard_finding_inspection_fields()
|
|
`);
|
|
|
|
await queryRunner.query(`
|
|
CREATE OR REPLACE FUNCTION dhv2_guard_observation_evidence_draft()
|
|
RETURNS trigger LANGUAGE plpgsql AS $$
|
|
DECLARE act_status varchar(24);
|
|
BEGIN
|
|
IF NEW.purpose = 'OBSERVATION' THEN
|
|
SELECT act.status INTO act_status
|
|
FROM inspection_findings finding
|
|
INNER JOIN inspection_acts act ON act.id = finding.act_id
|
|
WHERE finding.id = NEW.finding_id;
|
|
IF act_status <> 'DRAFT' THEN
|
|
RAISE EXCEPTION 'La evidencia de constatación pertenece a un acta congelada';
|
|
END IF;
|
|
END IF;
|
|
RETURN NEW;
|
|
END
|
|
$$
|
|
`);
|
|
await queryRunner.query(`
|
|
CREATE TRIGGER trg_inspection_evidence_observation_draft
|
|
BEFORE INSERT ON inspection_finding_evidence
|
|
FOR EACH ROW EXECUTE FUNCTION dhv2_guard_observation_evidence_draft()
|
|
`);
|
|
|
|
await queryRunner.query(`
|
|
INSERT INTO permissions (code, description)
|
|
VALUES
|
|
('inspection_closure.read', 'Consultar responsable, firmas y cierre del acta'),
|
|
('inspection_closure.prepare', 'Identificar responsable y preparar el acta para firmas'),
|
|
('inspection_closure.sign', 'Registrar firmas o resultado de recepción del acta'),
|
|
('inspection_closure.close', 'Cerrar y sellar el acta y la visita')
|
|
ON CONFLICT (code) DO UPDATE SET description = EXCLUDED.description
|
|
`);
|
|
await queryRunner.query(`
|
|
WITH mapping(role_code, permission_code) AS (VALUES ${rolePermissionValues})
|
|
INSERT INTO role_permissions (role_id, permission_id)
|
|
SELECT role.id, permission.id
|
|
FROM mapping
|
|
INNER JOIN roles role ON role.code = mapping.role_code
|
|
INNER JOIN permissions permission ON permission.code = mapping.permission_code
|
|
ON CONFLICT (role_id, permission_id) DO NOTHING
|
|
`);
|
|
|
|
const appRole = process.env.DB_APP_USER;
|
|
if (!appRole) throw new Error('Missing required environment variable: DB_APP_USER');
|
|
const applicationRole = quoteIdentifier(appRole);
|
|
await queryRunner.query(`
|
|
GRANT SELECT, INSERT, UPDATE ON TABLE
|
|
inspection_act_responsibles,
|
|
inspection_act_closures
|
|
TO ${applicationRole}
|
|
`);
|
|
await queryRunner.query(`
|
|
GRANT SELECT, INSERT ON TABLE inspection_act_signatures
|
|
TO ${applicationRole}
|
|
`);
|
|
await queryRunner.query(`
|
|
REVOKE DELETE ON TABLE
|
|
inspection_act_responsibles,
|
|
inspection_act_closures,
|
|
inspection_act_signatures
|
|
FROM ${applicationRole}
|
|
`);
|
|
await queryRunner.query(`
|
|
REVOKE UPDATE ON TABLE inspection_act_signatures
|
|
FROM ${applicationRole}
|
|
`);
|
|
}
|
|
|
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
await queryRunner.query('DROP TRIGGER trg_inspection_evidence_observation_draft ON inspection_finding_evidence');
|
|
await queryRunner.query('DROP FUNCTION dhv2_guard_observation_evidence_draft()');
|
|
await queryRunner.query('DROP TRIGGER trg_inspection_findings_frozen_fields ON inspection_findings');
|
|
await queryRunner.query('DROP FUNCTION dhv2_guard_finding_inspection_fields()');
|
|
await queryRunner.query('DROP TRIGGER trg_inspection_act_assets_draft ON inspection_act_assets');
|
|
await queryRunner.query('DROP FUNCTION dhv2_guard_act_asset_draft()');
|
|
await queryRunner.query('DROP TRIGGER trg_inspection_act_closures_immutable ON inspection_act_closures');
|
|
await queryRunner.query('DROP FUNCTION dhv2_guard_closed_closure_immutable()');
|
|
await queryRunner.query('DROP TRIGGER trg_inspection_acts_closed_immutable ON inspection_acts');
|
|
await queryRunner.query('DROP FUNCTION dhv2_guard_closed_act_immutable()');
|
|
await queryRunner.query('DROP TRIGGER trg_inspection_act_signatures_ready ON inspection_act_signatures');
|
|
await queryRunner.query('DROP FUNCTION dhv2_guard_act_signature_ready()');
|
|
await queryRunner.query('DROP TRIGGER trg_inspection_act_responsibles_draft ON inspection_act_responsibles');
|
|
await queryRunner.query('DROP FUNCTION dhv2_guard_act_responsible_draft()');
|
|
|
|
await queryRunner.query(`
|
|
WITH mapping(role_code, permission_code) AS (VALUES ${rolePermissionValues})
|
|
DELETE FROM role_permissions role_permission
|
|
USING roles role, permissions permission, mapping
|
|
WHERE role_permission.role_id = role.id
|
|
AND role_permission.permission_id = permission.id
|
|
AND role.code = mapping.role_code
|
|
AND permission.code = mapping.permission_code
|
|
`);
|
|
await queryRunner.query(
|
|
`DELETE FROM permissions WHERE code = ANY($1::varchar[])
|
|
AND NOT EXISTS (
|
|
SELECT 1 FROM role_permissions WHERE permission_id = permissions.id
|
|
)`,
|
|
[newPermissions],
|
|
);
|
|
|
|
await queryRunner.query('DROP TABLE inspection_act_signatures');
|
|
await queryRunner.query('DROP TABLE inspection_act_closures');
|
|
await queryRunner.query('DROP TABLE inspection_act_responsibles');
|
|
await queryRunner.query(`
|
|
ALTER TABLE inspection_act_versions
|
|
DROP CONSTRAINT chk_inspection_act_versions_event
|
|
`);
|
|
await queryRunner.query(`
|
|
ALTER TABLE inspection_act_versions
|
|
ADD CONSTRAINT chk_inspection_act_versions_event CHECK (
|
|
event IN ('CREATED', 'UPDATED', 'CANCELLED')
|
|
)
|
|
`);
|
|
await queryRunner.query(`
|
|
ALTER TABLE inspection_acts
|
|
DROP CONSTRAINT chk_inspection_acts_closure,
|
|
DROP CONSTRAINT fk_inspection_acts_closed_by,
|
|
DROP COLUMN closure_sha256,
|
|
DROP COLUMN closed_by,
|
|
DROP COLUMN closed_at
|
|
`);
|
|
}
|
|
}
|