"""微信 clawbot 改成"扫码登录 + 长轮询" Revision ID: 0013 Revises: 0012 Create Date: 2026-11-05 上一版(0012)做成了"clawbot 往我们这 POST webhook"。真实协议是腾讯 iLink Bot: 我们先扫码登录拿 `bot_token`,再由我们长轮询 `getupdates` 拉消息(见 `app/services/wechat_ilink.py` 文件头的出处说明)。所以这张表要补登录态与游标: - `bot_token_enc`:加密后的登录态(密钥由 JWT_SECRET 派生),换 secret 就要重新扫码; - `ilink_user_id`:扫码的微信号,界面上显示"谁扫的"; - `base_url`:服务端可能下发新基址; - `sync_buf`:长轮询游标,丢了会重复收消息; - `context_token`:回复必须带对方上一条消息的 context_token。 `bot_channel.status` 增加 `pending`(等扫码)与 `expired`(登录态失效)两个取值; `token_hash` 是上一版遗留列,改成可空、不再使用。 """ from __future__ import annotations from collections.abc import Sequence from alembic import op from app.roles import APP_ROLE revision: str = "0013" down_revision: str = "0012" branch_labels: Sequence[str] | None = None depends_on: Sequence[str] | None = None STATEMENTS = ( "ALTER TABLE bot_channel ADD COLUMN IF NOT EXISTS bot_token_enc text", "ALTER TABLE bot_channel ADD COLUMN IF NOT EXISTS ilink_user_id varchar(64)", "ALTER TABLE bot_channel ADD COLUMN IF NOT EXISTS base_url text", "ALTER TABLE bot_channel ADD COLUMN IF NOT EXISTS sync_buf text", "ALTER TABLE bot_channel ADD COLUMN IF NOT EXISTS context_token text", "ALTER TABLE bot_channel ALTER COLUMN token_hash DROP NOT NULL", "ALTER TABLE bot_channel ALTER COLUMN status SET DEFAULT 'pending'", "COMMENT ON COLUMN bot_channel.bot_token_enc IS 'iLink 登录态,Fernet 加密(密钥由 JWT_SECRET 派生)'", "COMMENT ON COLUMN bot_channel.sync_buf IS 'getupdates 游标,丢了会重复收消息'", f"GRANT SELECT, INSERT, UPDATE, DELETE ON bot_channel TO {APP_ROLE}", ) DOWN_STATEMENTS = ( "ALTER TABLE bot_channel DROP COLUMN IF EXISTS context_token", "ALTER TABLE bot_channel DROP COLUMN IF EXISTS sync_buf", "ALTER TABLE bot_channel DROP COLUMN IF EXISTS base_url", "ALTER TABLE bot_channel DROP COLUMN IF EXISTS ilink_user_id", "ALTER TABLE bot_channel DROP COLUMN IF EXISTS bot_token_enc", ) def upgrade() -> None: for statement in STATEMENTS: op.execute(statement) def downgrade() -> None: for statement in DOWN_STATEMENTS: op.execute(statement)