0016_portal_user_provision.py 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. """门户跳转用户预置:sys_user.external_id + 软删唯一约束。
  2. Revision ID: 0016_portal_user_provision
  3. Revises: 0015_login_ip_restriction
  4. Create Date: 2026-08-23
  5. 变更要点:
  6. 1. sys_user 新增 external_id(对端门户系统的用户唯一标识,NULL=本地原生用户);
  7. 2. 新增 MySQL 生成列 active_marker(未删=1,已删=NULL)与
  8. 唯一约束 uq_sys_user_external_id_active,防止同一门户用户重复落库;
  9. 3. 降级:存在门户用户时拒绝有损降级。
  10. """
  11. from __future__ import annotations
  12. from collections.abc import Sequence
  13. from alembic import op
  14. import sqlalchemy as sa
  15. revision: str = "0016_portal_user_provision"
  16. down_revision: str | None = "0015_login_ip_restriction"
  17. branch_labels: str | Sequence[str] | None = None
  18. depends_on: str | Sequence[str] | None = None
  19. def upgrade() -> None:
  20. op.add_column(
  21. "sys_user",
  22. sa.Column("external_id", sa.String(length=128), nullable=True),
  23. )
  24. op.add_column(
  25. "sys_user",
  26. sa.Column(
  27. "active_marker",
  28. sa.Integer(),
  29. sa.Computed("IF(is_deleted = 0, 1, NULL)", persisted=False),
  30. nullable=True,
  31. ),
  32. )
  33. op.create_unique_constraint(
  34. "uq_sys_user_external_id_active",
  35. "sys_user",
  36. ["external_id", "active_marker"],
  37. )
  38. op.create_index(
  39. "ix_sys_user_external_active",
  40. "sys_user",
  41. ["external_id", "is_deleted"],
  42. )
  43. def downgrade() -> None:
  44. bind = op.get_bind()
  45. portal_users = bind.scalar(
  46. sa.text("SELECT COUNT(*) FROM sys_user WHERE external_id IS NOT NULL")
  47. )
  48. if portal_users:
  49. raise RuntimeError(
  50. "0016已存在门户用户(external_id非空),拒绝有损降级;"
  51. "请先备份并按数据治理流程处理"
  52. )
  53. op.drop_index("ix_sys_user_external_active", table_name="sys_user")
  54. op.drop_constraint(
  55. "uq_sys_user_external_id_active", "sys_user", type_="unique"
  56. )
  57. op.drop_column("sys_user", "active_marker")
  58. op.drop_column("sys_user", "external_id")