chore: import DH V2 D5.6.4 production baseline
This commit is contained in:
@@ -0,0 +1,554 @@
|
||||
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
|
||||
`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user