fix(org): 机构/企业成员统一返回格式(补齐姓名、头像)
- _normalize_org_member 统一 user_id/name/username/avatar/role/is_admin - 机构成员无头像时批量从 users 表补查
This commit is contained in:
@@ -6,11 +6,14 @@ import logging
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy import select
|
||||
|
||||
from ..dependencies import get_db, get_user_organizations, get_user_primary_org
|
||||
from ..schemas.org import OrgMemberAdd
|
||||
from ...rbac import require_roles
|
||||
from ...infrastructure.repositories import Database
|
||||
from ...infrastructure.oss import resolve_url
|
||||
from ...infrastructure.models import User
|
||||
from ...park import tenants as tnt
|
||||
|
||||
log = logging.getLogger("rbac.org")
|
||||
@@ -18,6 +21,28 @@ log = logging.getLogger("rbac.org")
|
||||
router = APIRouter(tags=["org"])
|
||||
|
||||
|
||||
async def _normalize_org_member(raw: dict) -> dict:
|
||||
"""统一机构/企业成员返回格式,确保前端 OrgMember 类型字段齐全。
|
||||
|
||||
前端期望字段:user_id, name, username, avatar, role, is_admin
|
||||
企业成员(tnt.company_members)返回:id, username, nickname, avatar, role, is_admin
|
||||
机构成员(db.org_members.list_for_org)返回:user_id, username, nickname, role, is_admin(无avatar)
|
||||
"""
|
||||
user_id = str(raw.get("user_id") or raw.get("id") or "")
|
||||
username = raw.get("username") or ""
|
||||
nickname = raw.get("nickname") or ""
|
||||
name = nickname or username or user_id
|
||||
avatar = raw.get("avatar") or ""
|
||||
return {
|
||||
"user_id": user_id,
|
||||
"name": name,
|
||||
"username": username,
|
||||
"avatar": resolve_url(avatar),
|
||||
"role": raw.get("role") or "",
|
||||
"is_admin": bool(raw.get("is_admin", False)),
|
||||
}
|
||||
|
||||
|
||||
@router.get("/org/me", summary="当前组织信息")
|
||||
async def org_me(
|
||||
db: Database = Depends(get_db),
|
||||
@@ -75,20 +100,55 @@ async def org_members(
|
||||
# 叠加制权限:operator 全量;本 org 的载体机构管理员;本企业的企业成员(org_id 亦可能是 company_id)
|
||||
caps = user.get("capabilities") or []
|
||||
if "operator" in caps:
|
||||
pass
|
||||
log.info(f"[org_members] operator access, org_id={org_id}, user_id={user['id']}")
|
||||
elif await db.org_members.is_admin(org_id, user["id"]):
|
||||
pass
|
||||
log.info(f"[org_members] org admin access, org_id={org_id}, user_id={user['id']}")
|
||||
elif await db.company_members.get(user["id"], org_id):
|
||||
pass
|
||||
log.info(f"[org_members] company member access, org_id={org_id}, user_id={user['id']}")
|
||||
else:
|
||||
log.warning(f"[org_members] 403 forbidden, org_id={org_id}, user_id={user['id']}, caps={caps}")
|
||||
raise HTTPException(status_code=403, detail="无权查看该组织成员")
|
||||
|
||||
# org_id 可能是 organization_members.org_id(载体机构),也可能被前端当作 company_id 传入:
|
||||
# 优先返回企业成员(命中企业时),否则回退到机构成员。
|
||||
company_members = await tnt.company_members(org_id)
|
||||
try:
|
||||
company_members = await tnt.company_members(org_id)
|
||||
log.info(f"[org_members] tnt.company_members returned {len(company_members)} members for org_id={org_id}")
|
||||
except Exception as e:
|
||||
log.error(f"[org_members] tnt.company_members failed for org_id={org_id}: {e}", exc_info=True)
|
||||
company_members = []
|
||||
|
||||
if company_members:
|
||||
return {"items": company_members}
|
||||
return {"items": await db.org_members.list_for_org(org_id)}
|
||||
items = [await _normalize_org_member(m) for m in company_members]
|
||||
log.info(f"[org_members] returning {len(items)} company members for org_id={org_id}")
|
||||
return {"items": items}
|
||||
|
||||
try:
|
||||
org_members_list = await db.org_members.list_for_org(org_id)
|
||||
log.info(f"[org_members] db.org_members.list_for_org returned {len(org_members_list)} members for org_id={org_id}")
|
||||
except Exception as e:
|
||||
log.error(f"[org_members] db.org_members.list_for_org failed for org_id={org_id}: {e}", exc_info=True)
|
||||
org_members_list = []
|
||||
|
||||
# 机构成员没有 avatar 字段,批量从 users 表补查
|
||||
user_ids = [str(m.get("user_id") or "") for m in org_members_list if m.get("user_id")]
|
||||
avatar_map = {}
|
||||
if user_ids:
|
||||
try:
|
||||
users = (await db.session.execute(
|
||||
select(User).where(User.id.in_(user_ids))
|
||||
)).scalars().all()
|
||||
avatar_map = {u.id: (u.avatar or "") for u in users}
|
||||
except Exception as e:
|
||||
log.error(f"[org_members] failed to fetch avatars: {e}", exc_info=True)
|
||||
avatar_map = {}
|
||||
for m in org_members_list:
|
||||
uid = str(m.get("user_id") or "")
|
||||
if uid and not m.get("avatar"):
|
||||
m["avatar"] = avatar_map.get(uid, "")
|
||||
items = [await _normalize_org_member(m) for m in org_members_list]
|
||||
log.info(f"[org_members] returning {len(items)} org members for org_id={org_id}")
|
||||
return {"items": items}
|
||||
|
||||
|
||||
@router.post("/org/{org_id}/members", summary="添加机构成员(子账号)")
|
||||
|
||||
Reference in New Issue
Block a user