192 lines
7.2 KiB
TypeScript
192 lines
7.2 KiB
TypeScript
import { MigrationInterface, QueryRunner } from 'typeorm';
|
|
|
|
const newPermissions = [
|
|
'assets.read_provenance',
|
|
'assets.manage_provenance',
|
|
'assets.verify_provenance',
|
|
'assets.read_temporal',
|
|
] as const;
|
|
|
|
const rolePermissionValues = `
|
|
('admin', 'assets.read_provenance'),
|
|
('admin', 'assets.manage_provenance'),
|
|
('admin', 'assets.verify_provenance'),
|
|
('admin', 'assets.read_temporal'),
|
|
('director', 'assets.read_provenance'),
|
|
('director', 'assets.verify_provenance'),
|
|
('director', 'assets.read_temporal'),
|
|
('supervisor', 'assets.read_provenance'),
|
|
('supervisor', 'assets.manage_provenance'),
|
|
('supervisor', 'assets.verify_provenance'),
|
|
('supervisor', 'assets.read_temporal'),
|
|
('inspector', 'assets.read_provenance'),
|
|
('inspector', 'assets.manage_provenance'),
|
|
('inspector', 'assets.read_temporal'),
|
|
('auditor', 'assets.read_provenance'),
|
|
('auditor', 'assets.read_temporal')
|
|
`;
|
|
|
|
export class PhaseB5ProvenanceTemporal1786723203000 implements MigrationInterface {
|
|
name = 'PhaseB5ProvenanceTemporal1786723203000';
|
|
|
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
await queryRunner.query(`
|
|
ALTER TABLE assets
|
|
ADD COLUMN data_origin varchar(32) NOT NULL DEFAULT 'MANUAL',
|
|
ADD COLUMN source_name varchar(160),
|
|
ADD COLUMN source_reference varchar(255),
|
|
ADD COLUMN source_observed_at timestamptz,
|
|
ADD COLUMN source_notes text,
|
|
ADD COLUMN provenance_verified_at timestamptz,
|
|
ADD COLUMN provenance_verified_by uuid,
|
|
ADD COLUMN provenance_updated_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
ADD COLUMN provenance_updated_by uuid,
|
|
ADD CONSTRAINT chk_assets_data_origin CHECK (data_origin IN (
|
|
'MANUAL', 'FIELD_SURVEY', 'PROVIDED_DOCUMENT', 'IMPORT', 'SYSTEM'
|
|
)),
|
|
ADD CONSTRAINT fk_assets_provenance_verified_by FOREIGN KEY (provenance_verified_by)
|
|
REFERENCES users(id) ON DELETE SET NULL,
|
|
ADD CONSTRAINT fk_assets_provenance_updated_by FOREIGN KEY (provenance_updated_by)
|
|
REFERENCES users(id) ON DELETE SET NULL
|
|
`);
|
|
await queryRunner.query(`
|
|
UPDATE assets
|
|
SET provenance_updated_by = updated_by
|
|
`);
|
|
await queryRunner.query(`CREATE INDEX idx_assets_data_origin ON assets (data_origin)`);
|
|
await queryRunner.query(`
|
|
CREATE INDEX idx_assets_provenance_verified_at
|
|
ON assets (provenance_verified_at)
|
|
`);
|
|
|
|
await queryRunner.query(`
|
|
ALTER TABLE asset_versions
|
|
DROP CONSTRAINT chk_asset_versions_change_type
|
|
`);
|
|
await queryRunner.query(`
|
|
ALTER TABLE asset_versions
|
|
ADD CONSTRAINT chk_asset_versions_change_type CHECK (change_type IN (
|
|
'BASELINE', 'CREATED', 'UPDATED', 'STATUS_CHANGED',
|
|
'GEOMETRY_UPDATED', 'GEOMETRY_REMOVED',
|
|
'MEDIA_UPLOADED', 'MEDIA_UPDATED', 'MEDIA_REMOVED',
|
|
'PROVENANCE_BASELINE', 'PROVENANCE_UPDATED', 'PROVENANCE_VERIFIED'
|
|
))
|
|
`);
|
|
|
|
await queryRunner.query(`
|
|
WITH bumped AS (
|
|
UPDATE assets
|
|
SET current_version = current_version + 1
|
|
RETURNING *
|
|
)
|
|
INSERT INTO asset_versions (
|
|
asset_id, version_number, change_type, changed_fields, snapshot,
|
|
actor_user_id, actor_username, source, request_id
|
|
)
|
|
SELECT
|
|
asset.id,
|
|
asset.current_version,
|
|
'PROVENANCE_BASELINE',
|
|
ARRAY['provenance']::text[],
|
|
COALESCE(previous.snapshot, '{}'::jsonb) || JSONB_BUILD_OBJECT(
|
|
'provenance', JSONB_BUILD_OBJECT(
|
|
'origin', asset.data_origin,
|
|
'sourceName', asset.source_name,
|
|
'sourceReference', asset.source_reference,
|
|
'observedAt', asset.source_observed_at,
|
|
'notes', asset.source_notes,
|
|
'verifiedAt', asset.provenance_verified_at,
|
|
'verifiedBy', asset.provenance_verified_by,
|
|
'updatedAt', asset.provenance_updated_at,
|
|
'updatedBy', asset.provenance_updated_by
|
|
),
|
|
'currentVersion', asset.current_version
|
|
),
|
|
NULL,
|
|
NULL,
|
|
'SYSTEM',
|
|
'migration:phase-b5-provenance-baseline'
|
|
FROM bumped asset
|
|
LEFT JOIN LATERAL (
|
|
SELECT version.snapshot
|
|
FROM asset_versions version
|
|
WHERE version.asset_id = asset.id
|
|
ORDER BY version.version_number DESC
|
|
LIMIT 1
|
|
) previous ON true
|
|
`);
|
|
|
|
await queryRunner.query(`
|
|
INSERT INTO permissions (code, description)
|
|
VALUES
|
|
('assets.read_provenance', 'Consultar procedencia de datos de activos'),
|
|
('assets.manage_provenance', 'Actualizar procedencia de datos de activos'),
|
|
('assets.verify_provenance', 'Verificar procedencia de datos de activos'),
|
|
('assets.read_temporal', 'Reconstruir el maestro de activos a una fecha')
|
|
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
|
|
`);
|
|
}
|
|
|
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
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(`
|
|
UPDATE asset_versions
|
|
SET change_type = 'UPDATED'
|
|
WHERE change_type IN (
|
|
'PROVENANCE_BASELINE', 'PROVENANCE_UPDATED', 'PROVENANCE_VERIFIED'
|
|
)
|
|
`);
|
|
await queryRunner.query(`
|
|
ALTER TABLE asset_versions
|
|
DROP CONSTRAINT chk_asset_versions_change_type
|
|
`);
|
|
await queryRunner.query(`
|
|
ALTER TABLE asset_versions
|
|
ADD CONSTRAINT chk_asset_versions_change_type CHECK (change_type IN (
|
|
'BASELINE', 'CREATED', 'UPDATED', 'STATUS_CHANGED',
|
|
'GEOMETRY_UPDATED', 'GEOMETRY_REMOVED',
|
|
'MEDIA_UPLOADED', 'MEDIA_UPDATED', 'MEDIA_REMOVED'
|
|
))
|
|
`);
|
|
await queryRunner.query(`
|
|
ALTER TABLE assets
|
|
DROP CONSTRAINT fk_assets_provenance_verified_by,
|
|
DROP CONSTRAINT fk_assets_provenance_updated_by,
|
|
DROP CONSTRAINT chk_assets_data_origin,
|
|
DROP COLUMN data_origin,
|
|
DROP COLUMN source_name,
|
|
DROP COLUMN source_reference,
|
|
DROP COLUMN source_observed_at,
|
|
DROP COLUMN source_notes,
|
|
DROP COLUMN provenance_verified_at,
|
|
DROP COLUMN provenance_verified_by,
|
|
DROP COLUMN provenance_updated_at,
|
|
DROP COLUMN provenance_updated_by
|
|
`);
|
|
}
|
|
}
|