"""Network notifications kill switch — default OFF. Revision ID: 174 Revises: 173 Create Date: 2026-05-17 Why this exists --------------- The network module (domains / DNS / CDN) ships to ~500 users imminently and a pre-launch audit flagged three system-push notification paths that, in their current shape, would burn user trust on day one: * ``cmdb.domain_expiry_alert`` — broadcasts the same expired/expiring list to a shared Feishu group every cron tick, no per-domain dedup, no owner routing, no payload size cap. * ``cmdb.dns_owner_recertify`` — never stamps ``cmdb_dns_records.last_owner_review_at`` after the DM, so every cron tick re-nags the same owner with the same record list. * ``cmdb.dns_pre_leaver_handover`` — no idempotency log, so a leaver in the 7-day window gets the same handover card daily. Until those bugs are fixed AND admin verifies one cycle end-to-end on a tame allowlist of recipients, we want a single boolean to keep the three handlers silent. The handlers themselves check this setting at entry and short-circuit with ``status="skipped"``; user-initiated flows (DNS request submit → Feishu approval, domain registration submit → Feishu approval) are NOT gated — those are not nags, they are the human approval path the user explicitly invoked. Flip to ``true`` via the admin Settings UI (``Settings → 平台设置``) or direct SQL once the bug-fix PRs land and a dry-run verifies the content/dedup behaviour. Idempotency ----------- ``INSERT ... ON DUPLICATE KEY UPDATE description`` so re-running the migration refreshes the description without overwriting an admin's flipped value. """ from __future__ import annotations import json import sqlalchemy as sa from alembic import op revision = "174" down_revision = "173" branch_labels = None depends_on = None SETTING_KEY = "network.user_notifications_enabled" DEFAULT_VALUE = False DESCRIPTION = ( "网络模块(域名 / DNS / CDN) 系统侧推送告警总开关。false 时,以下" "三个定时任务在进入处理器后立即 short-circuit,不会向员工/共享群" "推送任何 Feishu 消息:cmdb.domain_expiry_alert / " "cmdb.dns_owner_recertify / cmdb.dns_pre_leaver_handover。" "用户主动发起的 DNS / 域名审批流程不受影响。上线前先 false 静默," "验证完一轮内容 + 去重再翻 true 正式启用。" ) def _table_exists(bind, name: str) -> bool: return bind.execute( sa.text( "SELECT 1 FROM information_schema.TABLES " "WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = :n" ), {"n": name}, ).scalar() is not None def upgrade() -> None: bind = op.get_bind() if not _table_exists(bind, "platform_settings"): return bind.execute( sa.text( "INSERT INTO platform_settings (`key`, value, description, " "created_at, updated_at) " "VALUES (:k, :v, :d, NOW(), NOW()) " "ON DUPLICATE KEY UPDATE " "description = VALUES(description), updated_at = NOW()" ), { "k": SETTING_KEY, "v": json.dumps(DEFAULT_VALUE), "d": DESCRIPTION, }, ) def downgrade() -> None: bind = op.get_bind() if not _table_exists(bind, "platform_settings"): return bind.execute( sa.text("DELETE FROM platform_settings WHERE `key` = :k"), {"k": SETTING_KEY}, )