fix(#558): migration幂等处理,phone字段已在029中存在
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 23s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 1m30s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m32s
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Failing after 2m2s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m30s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 2m29s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 3m32s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 1m49s
AI Code Review / AI Code Review (pull_request) Successful in 5m41s

This commit is contained in:
CI Bot
2026-07-21 09:06:14 +08:00
parent 54e04302cf
commit d594a7a273
+61 -25
View File
@@ -1,17 +1,18 @@
"""#558 - 微信登录:用户手机号字段 + 验证码表
"""#558 - 微信登录:手机号绑定字段 + 验证码表
Revision ID: 049
Revises: 048
Create Date: 2026-07-21
Changes:
1. users 表新增 phone / phone_verified / binding_completed_at 字段
2. 新建 verification_codes 表(统一管理邮箱+手机验证码
1. users 表新增 phone_verified / binding_completed_at 字段(phone 字段已在 029 中添加)
2. users 表 phone 字段添加唯一索引(幂等
3. 新建 verification_codes 表(统一管理邮箱+手机验证码)
"""
import sqlalchemy as sa
from alembic import op
from alembic import context, op
revision = "049_wechat_login_phone"
down_revision = "048_cleanup_result_count"
@@ -19,26 +20,59 @@ branch_labels = None
depends_on = None
def upgrade() -> None:
# 1. users 表新增手机号相关字段
op.add_column("users", sa.Column("phone", sa.String(32), nullable=True))
op.add_column(
"users",
sa.Column(
"phone_verified",
sa.Boolean,
nullable=False,
server_default=sa.text("false"),
def _column_exists(table: str, column: str) -> bool:
"""检查列是否已存在。离线模式下返回 False。"""
if context.is_offline_mode():
return False
conn = op.get_bind()
result = conn.execute(
sa.text(
"SELECT 1 FROM information_schema.columns "
"WHERE table_name = :table AND column_name = :column"
),
{"table": table, "column": column},
)
op.add_column(
"users",
sa.Column("binding_completed_at", sa.DateTime, nullable=True),
)
# phone 唯一索引(已验证的手机号唯一,未验证的不做唯一约束)
op.create_index("ix_users_phone", "users", ["phone"], unique=True)
return result.first() is not None
# 2. verification_codes 表
def _index_exists(index_name: str) -> bool:
"""检查索引是否已存在。离线模式下返回 False。"""
if context.is_offline_mode():
return False
conn = op.get_bind()
result = conn.execute(
sa.text(
"SELECT 1 FROM pg_indexes WHERE indexname = :index_name"
),
{"index_name": index_name},
)
return result.first() is not None
def upgrade() -> None:
# 1. users 表新增手机号验证状态字段(幂等)
if not _column_exists("users", "phone_verified"):
op.add_column(
"users",
sa.Column(
"phone_verified",
sa.Boolean,
nullable=False,
server_default=sa.text("false"),
),
)
if not _column_exists("users", "binding_completed_at"):
op.add_column(
"users",
sa.Column("binding_completed_at", sa.DateTime, nullable=True),
)
# 2. phone 字段唯一索引(幂等 - 029 加了字段但没加索引)
if not _index_exists("ix_users_phone"):
op.create_index("ix_users_phone", "users", ["phone"], unique=True)
# 3. verification_codes 表
op.create_table(
"verification_codes",
sa.Column("id", sa.String(36), primary_key=True),
@@ -60,7 +94,9 @@ def upgrade() -> None:
def downgrade() -> None:
op.drop_table("verification_codes")
op.drop_index("ix_users_phone", table_name="users")
op.drop_column("users", "binding_completed_at")
op.drop_column("users", "phone_verified")
op.drop_column("users", "phone")
if _index_exists("ix_users_phone"):
op.drop_index("ix_users_phone", table_name="users")
if _column_exists("users", "binding_completed_at"):
op.drop_column("users", "binding_completed_at")
if _column_exists("users", "phone_verified"):
op.drop_column("users", "phone_verified")