"""Remove Slack-specific copy from the generic manual_notify template. Migration 056 seeded ``platform_settings`` key ``email_template.provisioning.manual_notify`` with a GENERIC manual-task template that nonetheless hard-coded a Slack-only sentence: "如果该软件后续升级到可自动 provision 的档位(如 Slack 升级到 Business+),把绑定的 execution_mode 改为 auto_api …" Because every ``manual_notify`` task (any provider) renders through this one template, that Slack sentence leaked onto unrelated pushes — Jira leaver-revoke notifications carried Slack upgrade advice. The seeded row was also zh-only. Fix: delete the polluted seeded row so the lookup falls back to the built-in default in ``_DEFAULT_TEMPLATES["provisioning.manual_notify"]`` — which is bilingual (zh + en), channel-aware (``{cta_line}``), and carries no provider-specific copy. The built-in default then becomes the single source of truth and tracks code instead of a frozen DB copy. Guarded by a ``LIKE`` on the Slack sentence so a row an admin has already cleaned / customised is left untouched. Idempotent: re-run is a no-op once the polluted row is gone. """ from __future__ import annotations import sqlalchemy as sa from alembic import op revision = "208" down_revision = "207" branch_labels = None depends_on = None _KEY = "email_template.provisioning.manual_notify" # The exact Slack-only phrase the seeded template carried. Specific # enough that it only matches the migration-056 seed (or a near-copy # still containing it), never an admin rewrite that removed it. _SLACK_PHRASE = "%Slack 升级到 %" def upgrade() -> None: op.get_bind().execute( sa.text( "DELETE FROM platform_settings " "WHERE `key` = :k AND value LIKE :p" ), {"k": _KEY, "p": _SLACK_PHRASE}, ) def downgrade() -> None: # No-op: this is a data correction. Re-seeding the Slack-polluted # copy would reintroduce the bug, and the clean built-in default # already covers the lookup, so there is nothing to restore. pass