0023_admin_permissions.py 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. """管理类权限:sys_user 增加分类/机构/用户编辑权限位与管理范围锚点部门。
  2. Revision ID: 0023_admin_permissions
  3. Revises: 0022_login_lockout
  4. Create Date: 2026-09-02
  5. 变更要点:
  6. 1. sys_user 增加 perm_category_edit / perm_org_edit / perm_user_edit
  7. TINYINT(1) NOT NULL DEFAULT 0(管理类权限开关,仅 ADMIN 类别生效);
  8. 2. sys_user 增加 managed_org_id BIGINT NULL(管理范围锚点部门,
  9. NULL=不受范围约束即全局;机构/用户编辑权限限定锚点部门及其下级);
  10. 3. 存量初始化:ADMIN 类别用户三权限默认开启;admin 账号锚点保持 NULL(全局),
  11. 其余 ADMIN 用户锚点置为所在部门;
  12. 4. 升级幂等:列已存在时跳过加列;数据初始化可重复执行(结果一致)。
  13. """
  14. from __future__ import annotations
  15. from collections.abc import Sequence
  16. import sqlalchemy as sa
  17. from alembic import op
  18. revision: str = "0023_admin_permissions"
  19. down_revision: str | None = "0022_login_lockout"
  20. branch_labels: str | Sequence[str] | None = None
  21. depends_on: str | Sequence[str] | None = None
  22. _TABLE = "sys_user"
  23. _FLAG_COLUMNS = ("perm_category_edit", "perm_org_edit", "perm_user_edit")
  24. def _existing_columns() -> set[str]:
  25. inspector = sa.inspect(op.get_bind())
  26. return {column["name"] for column in inspector.get_columns(_TABLE)}
  27. def upgrade() -> None:
  28. existing = _existing_columns()
  29. for name in _FLAG_COLUMNS:
  30. if name not in existing:
  31. op.add_column(
  32. _TABLE,
  33. sa.Column(
  34. name,
  35. sa.Boolean(),
  36. nullable=False,
  37. server_default=sa.text("0"),
  38. ),
  39. )
  40. if "managed_org_id" not in existing:
  41. op.add_column(
  42. _TABLE,
  43. sa.Column("managed_org_id", sa.BigInteger(), nullable=True),
  44. )
  45. # 存量初始化:管理员类别默认开启三权限;admin 账号锚点 NULL(全局),其余锚点=所在部门
  46. op.execute(
  47. "UPDATE sys_user SET perm_category_edit = 1, perm_org_edit = 1, "
  48. "perm_user_edit = 1 WHERE role_code = 'ADMIN' AND is_deleted = 0"
  49. )
  50. op.execute(
  51. "UPDATE sys_user SET managed_org_id = organization_id "
  52. "WHERE role_code = 'ADMIN' AND is_deleted = 0 "
  53. "AND username <> 'admin' AND organization_id IS NOT NULL"
  54. )
  55. def downgrade() -> None:
  56. existing = _existing_columns()
  57. if "managed_org_id" in existing:
  58. op.drop_column(_TABLE, "managed_org_id")
  59. for name in reversed(_FLAG_COLUMNS):
  60. if name in existing:
  61. op.drop_column(_TABLE, name)