Files
ctms/backend/alembic/versions/20260527_07_rename_knowledge_notes_permissions.py
2026-05-28 10:52:05 +08:00

110 lines
3.8 KiB
Python

"""rename knowledge note permissions to precautions
Revision ID: 20260527_07_permissions
Revises: 20260527_06
Create Date: 2026-05-27 16:35:00.000000
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
revision: str = "20260527_07_permissions"
down_revision: Union[str, None] = "20260527_06"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
PERMISSION_KEY_RENAMES = (
("knowledge_notes:create", "precautions:create"),
("knowledge_notes:list", "precautions:list"),
("knowledge_notes:read", "precautions:read"),
("knowledge_notes:update", "precautions:update"),
("knowledge_notes:delete", "precautions:delete"),
("knowledge_notes_attachments:create", "precautions_attachments:create"),
("knowledge_notes_attachments:read", "precautions_attachments:read"),
("knowledge_notes_attachments:delete", "precautions_attachments:delete"),
)
def _table_exists(inspector: sa.Inspector, table_name: str) -> bool:
return table_name in inspector.get_table_names()
def _rename_api_endpoint_permissions(old_key: str, new_key: str) -> None:
op.execute(
f"""
DELETE FROM api_endpoint_permissions AS old_permissions
WHERE old_permissions.endpoint_key = '{old_key}'
AND EXISTS (
SELECT 1
FROM api_endpoint_permissions AS new_permissions
WHERE new_permissions.study_id = old_permissions.study_id
AND new_permissions.role = old_permissions.role
AND new_permissions.endpoint_key = '{new_key}'
)
"""
)
op.execute(
f"""
UPDATE api_endpoint_permissions
SET endpoint_key = '{new_key}'
WHERE endpoint_key = '{old_key}'
"""
)
def _rename_template_permission_key(table_name: str, old_key: str, new_key: str, *, touch_updated_at: bool = False) -> None:
updated_at_assignment = ", updated_at = NOW()" if touch_updated_at else ""
op.execute(
f"""
UPDATE {table_name}
SET permissions = (
SELECT jsonb_object_agg(
role_key,
CASE
WHEN role_permissions ? '{old_key}' AND NOT role_permissions ? '{new_key}'
THEN (role_permissions - '{old_key}') || jsonb_build_object('{new_key}', role_permissions -> '{old_key}')
WHEN role_permissions ? '{old_key}'
THEN role_permissions - '{old_key}'
ELSE role_permissions
END
)
FROM jsonb_each(permissions::jsonb) AS role_entries(role_key, role_permissions)
){updated_at_assignment}
WHERE EXISTS (
SELECT 1
FROM jsonb_each(permissions::jsonb) AS role_entries(role_key, role_permissions)
WHERE role_permissions ? '{old_key}'
)
"""
)
def _rename_permission_keys(mapping: tuple[tuple[str, str], ...]) -> None:
bind = op.get_bind()
inspector = sa.inspect(bind)
if _table_exists(inspector, "api_endpoint_permissions"):
for old_key, new_key in mapping:
_rename_api_endpoint_permissions(old_key, new_key)
if _table_exists(inspector, "permission_templates"):
for old_key, new_key in mapping:
_rename_template_permission_key("permission_templates", old_key, new_key, touch_updated_at=True)
if _table_exists(inspector, "permission_template_versions"):
for old_key, new_key in mapping:
_rename_template_permission_key("permission_template_versions", old_key, new_key)
def upgrade() -> None:
_rename_permission_keys(PERMISSION_KEY_RENAMES)
def downgrade() -> None:
_rename_permission_keys(tuple((new_key, old_key) for old_key, new_key in PERMISSION_KEY_RENAMES))