refactor: users.role 归一化为默认端口标记
1. 创建 normalize_user_roles.py 迁移脚本 2. 8 个旧角色用户(developer/enterprise/investor/provider)归一化为 opc_member 3. account_types.py 注释明确 role 语义:仅用于默认端口和前端展示 4. 权限判断完全依赖 capabilities 叠加制,role 仅作回退安全网
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""数据迁移:归一化 users.role 字段。
|
||||
|
||||
把旧的角色值(enterprise/provider/government/investor/developer/service 等)
|
||||
归一化为三种账号类型之一(operator/carrier/opc_member)。
|
||||
|
||||
用法:
|
||||
cd code/server-core
|
||||
uv run python scripts/db/normalize_user_roles.py
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
||||
|
||||
from sqlalchemy import select, update
|
||||
from app.infrastructure.db import AsyncSessionLocal
|
||||
from app.infrastructure.models import User
|
||||
from app.domain.account_types import account_type
|
||||
|
||||
|
||||
async def migrate() -> None:
|
||||
async with AsyncSessionLocal() as session:
|
||||
users = (await session.scalars(select(User))).all()
|
||||
stats = {"total": 0, "changed": 0, "unchanged": 0}
|
||||
changes = []
|
||||
|
||||
for u in users:
|
||||
stats["total"] += 1
|
||||
atype = account_type(u.role)
|
||||
if u.role != atype:
|
||||
changes.append((u.id, u.username, u.role, atype))
|
||||
u.role = atype
|
||||
stats["changed"] += 1
|
||||
else:
|
||||
stats["unchanged"] += 1
|
||||
|
||||
await session.commit()
|
||||
|
||||
print(f"归一化完成: {stats}")
|
||||
print(f" - 总用户: {stats['total']}")
|
||||
print(f" - 已变更: {stats['changed']}")
|
||||
print(f" - 未变更: {stats['unchanged']}")
|
||||
if changes:
|
||||
print("\n变更明细:")
|
||||
for uid, username, old, new in changes:
|
||||
print(f" {uid} ({username}): {old} -> {new}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(migrate())
|
||||
Reference in New Issue
Block a user