Files
2026-08-21 16:00:13 +08:00

161 lines
6.7 KiB
Python

"""默认数据初始化。"""
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.config import settings
from app.core.ids import new_permission_id, new_role_id
from app.core.logging import log_with_context
from app.db.governance_seed import ensure_governance_seed
from app.models.rbac import Permission, Role, RolePermission, UserRole
from app.models.user import User
from app.services.auth import create_user
from app.services.characters import (
ensure_all_system_templates,
ensure_default_character_for_owner,
)
# ── 默认权限清单 ──────────────────────────────────────────
# resource:action 格式。前端 PermissionGuard 使用同一套字符串。
DEFAULT_PERMISSIONS: list[dict[str, str]] = [
# 用户管理
{"resource": "users", "action": "read", "description": "查看用户列表"},
{"resource": "users", "action": "create", "description": "创建用户"},
{"resource": "users", "action": "update", "description": "更新用户信息"},
{"resource": "users", "action": "delete", "description": "删除用户"},
# 工具管理
{"resource": "tools", "action": "read", "description": "查看工具列表"},
{"resource": "tools", "action": "admin", "description": "管理工具权限策略"},
# 人物模板管理
{"resource": "character_templates", "action": "read", "description": "查看系统人物模板"},
{"resource": "character_templates", "action": "create", "description": "创建系统人物模板"},
{"resource": "character_templates", "action": "update", "description": "更新系统人物模板"},
{"resource": "character_templates", "action": "delete", "description": "删除系统人物模板"},
# 安全审计
{"resource": "audit", "action": "read", "description": "查看审计日志"},
# 司命台治理
{"resource": "goals", "action": "read", "description": "查看目标"},
{"resource": "goals", "action": "update", "description": "修改目标"},
{"resource": "perception", "action": "read", "description": "查看感知通道"},
{"resource": "perception", "action": "update", "description": "修改感知授权"},
{"resource": "world", "action": "read", "description": "查看世界实体"},
{"resource": "world", "action": "update", "description": "修改世界实体"},
{"resource": "plans", "action": "read", "description": "查看计划"},
{"resource": "plans", "action": "update", "description": "修改计划"},
{"resource": "traces", "action": "read", "description": "查看链路追踪"},
{"resource": "tenants", "action": "read", "description": "查看多租户概览"},
{"resource": "agents", "action": "read", "description": "查看天工阁"},
{"resource": "agents", "action": "update", "description": "管理天工阁角色"},
# 系统管理
{"resource": "system", "action": "admin", "description": "系统配置管理"},
]
async def seed_default_data(session: AsyncSession) -> None:
# 1) 确保系统模板
templates = await ensure_all_system_templates(session)
log_with_context("已确保系统模板", count=len(templates))
# 2) 创建默认管理员用户(仅首次启动)
result = await session.execute(select(User).limit(1))
admin_user = result.scalar_one_or_none()
if admin_user is None:
admin_username = settings.default_admin_username or "admin"
admin_email = settings.default_admin_email or "admin@hunjing.local"
admin_password = settings.default_admin_password or "admin123"
admin_user = await create_user(
session,
username=admin_username,
email=admin_email,
password=admin_password,
is_admin=True,
)
await session.flush()
log_with_context(
"已创建默认管理员用户",
username=admin_username,
user_id=admin_user.id,
)
# 3) RBAC 种子数据
await _seed_rbac(session, admin_user)
# 4) 使用 admin_user 的 owner_scope 创建默认人物
owner_scope = admin_user.id
character = await ensure_default_character_for_owner(session, owner_scope)
log_with_context(
"已确保默认用户人物",
character_id=character.id,
source_template_id=character.source_template_id,
owner_scope=owner_scope,
)
# 4b) 兼容测试环境:确保 default_owner_scope 也有激活人物
# repo/service 测试通过 get_active_character_model(session) 查找人物,
# 其默认 owner_scope 来自 settings.default_owner_scope,与 admin_user.id 不一致。
if settings.default_owner_scope and settings.default_owner_scope != owner_scope:
await ensure_default_character_for_owner(session, settings.default_owner_scope)
await session.commit()
await ensure_governance_seed(session)
log_with_context("已确保司命台治理种子")
async def _seed_rbac(session: AsyncSession, admin_user: User) -> None:
"""创建默认角色、权限,并为 admin 用户分配管理员角色。"""
# 检查是否已初始化
existing = await session.execute(select(Role).limit(1))
if existing.scalar_one_or_none() is not None:
return
# 创建所有权限
perm_records: dict[str, Permission] = {}
for p in DEFAULT_PERMISSIONS:
perm = Permission(
id=new_permission_id(),
resource=p["resource"],
action=p["action"],
description=p["description"],
)
session.add(perm)
perm_records[perm.code] = perm
# 创建角色
admin_role = Role(
id=new_role_id(),
name="admin",
description="管理员 — 拥有所有权限",
is_system=True,
)
user_role = Role(
id=new_role_id(),
name="user",
description="普通用户 — 基础操作权限",
is_system=True,
)
session.add(admin_role)
session.add(user_role)
# admin 角色:所有权限
for perm in perm_records.values():
session.add(RolePermission(role_id=admin_role.id, permission_id=perm.id))
# user 角色:仅基础读取权限
user_perms = [p for p in DEFAULT_PERMISSIONS if p["action"] in ("read",)]
for p in user_perms:
perm = perm_records.get(f"{p['resource']}:{p['action']}")
if perm:
session.add(RolePermission(role_id=user_role.id, permission_id=perm.id))
# 分配 admin 角色给当前管理员用户
session.add(UserRole(user_id=admin_user.id, role_id=admin_role.id))
await session.flush()
log_with_context(
"RBAC 种子数据已初始化",
roles=2,
permissions=len(perm_records),
admin_user=admin_user.username,
)