fix(campaigns): preserve modification-request audit row after test deletion

Approving a remove_test modification request deletes the underlying Test
row, which was cascading through test_id's ON DELETE CASCADE and wiping
out the request row itself before it could be read back. Changed to
ON DELETE SET NULL so the audit record (justification, reviewer,
decision) survives. Adds regression coverage plus double-approve/reject
idempotency tests.
This commit is contained in:
kitos
2026-07-03 10:48:42 +02:00
parent dc5f206bf5
commit 12a5484003
3 changed files with 101 additions and 4 deletions
@@ -0,0 +1,50 @@
"""Change campaign_modification_requests.test_id to nullable with ON DELETE SET NULL.
Approving a "remove_test" modification request deletes the underlying Test
row. With the original ON DELETE CASCADE, that delete cascaded and wiped
out the modification-request row itself, destroying the audit record
(justification, reviewer, decision) the request exists to preserve.
Revision ID: b056
Revises: b055
Create Date: 2026-07-03
"""
from alembic import op
import sqlalchemy as sa
revision = "b056"
down_revision = "b055"
branch_labels = None
depends_on = None
_FK_NAME = "campaign_modification_requests_test_id_fkey"
def upgrade() -> None:
op.alter_column(
"campaign_modification_requests", "test_id",
existing_type=sa.dialects.postgresql.UUID(as_uuid=True),
nullable=True,
)
op.drop_constraint(_FK_NAME, "campaign_modification_requests", type_="foreignkey")
op.create_foreign_key(
_FK_NAME,
"campaign_modification_requests", "tests",
["test_id"], ["id"],
ondelete="SET NULL",
)
def downgrade() -> None:
op.drop_constraint(_FK_NAME, "campaign_modification_requests", type_="foreignkey")
op.create_foreign_key(
_FK_NAME,
"campaign_modification_requests", "tests",
["test_id"], ["id"],
ondelete="CASCADE",
)
op.alter_column(
"campaign_modification_requests", "test_id",
existing_type=sa.dialects.postgresql.UUID(as_uuid=True),
nullable=False,
)