980a2db6d9
- 基础设施层 async:SQLAlchemy 异步引擎/会话、33 Repository async 化、models/security/seed 迁入 infrastructure、新增 cache.py(redis.asyncio) 与 oss.py(aioboto3) - 接口层:routers 迁 api/routers 并全 async,dependencies 迁 api/dependencies(get_db/get_current_user async) - 依赖:sqlalchemy[asyncio]/aiosqlite/asyncmy/redis/aioboto3;config 异步 URL + Redis/OSS 配置 - 删除废弃:旧同步 db/dependencies/repositories/storage - 验证:平台 19 路由 + 培训 48 路由全注册;/health /auth/login /auth/me /admin/tasks /notifications 等接口 async 可用
120 lines
4.4 KiB
Python
120 lines
4.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""组织/租户端点:企业 / 载体 / 服务商(按角色 + 组织作用域)。"""
|
|
from __future__ import annotations
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from pydantic import BaseModel
|
|
|
|
from ..dependencies import get_db
|
|
from ...rbac import require_roles
|
|
from ...infrastructure.repositories import Database
|
|
|
|
router = APIRouter(tags=["org"])
|
|
|
|
|
|
@router.get("/org/me", summary="当前组织信息")
|
|
async def org_me(
|
|
db: Database = Depends(get_db),
|
|
user: dict = Depends(require_roles(
|
|
"opc_member", "carrier", "enterprise", "provider", "government", "operator",
|
|
)),
|
|
):
|
|
org = await db.orgs.get(user["org_id"]) if user.get("org_id") else None
|
|
region = await db.regions.get(user["region_id"]) if user.get("region_id") else None
|
|
return {
|
|
"user_id": user["id"],
|
|
"role": user["role"],
|
|
"sub_role": user["sub_role"],
|
|
"org": org,
|
|
"region": region,
|
|
}
|
|
|
|
|
|
@router.get("/enterprise/profile", summary="企业资料")
|
|
async def enterprise_profile(
|
|
db: Database = Depends(get_db),
|
|
user: dict = Depends(require_roles("enterprise")),
|
|
):
|
|
org = await db.orgs.get(user["org_id"]) if user.get("org_id") else None
|
|
if org is None:
|
|
raise HTTPException(status_code=404, detail="No enterprise bound")
|
|
return org
|
|
|
|
|
|
@router.get("/carrier/enterprises", summary="载体下辖企业")
|
|
async def carrier_enterprises(
|
|
db: Database = Depends(get_db),
|
|
user: dict = Depends(require_roles("carrier")),
|
|
):
|
|
"""返回绑定到当前载体(parent_id == 载体 org_id)的企业。"""
|
|
if not user.get("org_id"):
|
|
return []
|
|
return await db.orgs.list_by_parent(user["org_id"])
|
|
|
|
|
|
@router.get("/provider/orders", summary="服务商订单(骨架)")
|
|
async def provider_orders(
|
|
user: dict = Depends(require_roles("provider")),
|
|
):
|
|
"""占位:服务商仅返回本 org 的订单(业务逻辑后续阶段补齐)。"""
|
|
return {"org_id": user.get("org_id"), "orders": []}
|
|
|
|
|
|
# ── 机构成员(机构主账号 + 机构内子账号,账号可挂多机构)────────────────────
|
|
|
|
@router.get("/org/{org_id}/members", summary="机构成员列表")
|
|
async def org_members(
|
|
org_id: str,
|
|
db: Database = Depends(get_db),
|
|
user: dict = Depends(require_roles("enterprise", "carrier", "provider", "investor", "operator")),
|
|
):
|
|
# 机构管理员本人 或 平台运营 可查看
|
|
if user.get("role") not in ("operator",) and not await db.org_members.is_admin(org_id, user["id"]):
|
|
raise HTTPException(status_code=403, detail="Forbidden: not org admin")
|
|
return {"items": await db.org_members.list_for_org(org_id)}
|
|
|
|
|
|
class OrgMemberAdd(BaseModel):
|
|
user_id: str | None = None
|
|
username: str | None = None # 支持按用户名添加(解析为 user_id)
|
|
role: str = "member"
|
|
is_admin: bool = False
|
|
|
|
|
|
@router.post("/org/{org_id}/members", summary="添加机构成员(子账号)")
|
|
async def org_add_member(
|
|
org_id: str,
|
|
req: OrgMemberAdd,
|
|
db: Database = Depends(get_db),
|
|
user: dict = Depends(require_roles("enterprise", "carrier", "provider", "investor", "operator")),
|
|
):
|
|
if user.get("role") not in ("operator",) and not await db.org_members.is_admin(org_id, user["id"]):
|
|
raise HTTPException(status_code=403, detail="Forbidden: not org admin")
|
|
target_id = req.user_id
|
|
if not target_id and req.username:
|
|
found = await db.users.get_by_username(req.username)
|
|
if found is None:
|
|
raise HTTPException(status_code=404, detail="账号不存在")
|
|
target_id = found["id"]
|
|
if not target_id:
|
|
raise HTTPException(status_code=400, detail="缺少 user_id 或 username")
|
|
return await db.org_members.add_member(org_id, target_id, req.role, req.is_admin)
|
|
|
|
|
|
@router.get("/me/orgs", summary="我加入的机构")
|
|
async def my_orgs(
|
|
db: Database = Depends(get_db),
|
|
user: dict = Depends(require_roles("enterprise", "carrier", "provider", "investor")),
|
|
):
|
|
"""返回当前账号挂靠的所有机构及成员角色(支持一账号多机构)。"""
|
|
out = []
|
|
for org in await db.orgs.all():
|
|
member = None
|
|
for m in await db.org_members.list_for_org(org["id"]):
|
|
if m["user_id"] == user["id"]:
|
|
member = m
|
|
break
|
|
if member:
|
|
out.append({"org": org, "member_role": member["role"], "is_admin": member["is_admin"]})
|
|
return {"items": out}
|