seaislee1209 cec1e5d770 feat(observer): 团管观察者标记 — 可看全局内容资产(不见 ¥)
后端:
- User.is_observer BooleanField (0016 migration, default=False)
- AdminAuditLog 加 user_observer_toggle 操作类型
- UserSerializer fields 含 is_observer (/auth/me 透出)
- IsSuperAdminOrObserver permission 类:超管 + (is_team_admin && is_observer)
- 3 个 assets endpoint (overview/team_members/user_videos) 权限从 IsSuperAdmin 改为 IsSuperAdminOrObserver
- admin_user_observer_toggle_view (PATCH /admin/users/<id>/observer):
  仅超管,只允许打在团管上,拒超管自己 + 拒成员
- admin_users_list_view 返回 is_team_owner/is_observer 字段(前端 row-level 判断用)

前端:
- User/AdminUser/TeamMember type 加 is_observer
- adminApi.toggleUserObserver
- ProtectedRoute 新 requireAdminOrObserver prop + requireAdmin 智能 fallback(团管被拒回 /team/dashboard)
- App.tsx /admin 父路由 requireAdminOrObserver,子路由除 assets 外仍 requireAdmin (race 防御)
- RoleAwareAdminIndexRedirect:观察者团管入 /admin 跳 /admin/assets,超管跳 /admin/dashboard
- AdminLayout sidebar 角色过滤:观察者只见「内容资产」+ 「返回首页」改「返回团队管理」+ logo「观察者」字样
- TeamAdminLayout 观察者团管加「全局资产」入口跳 /admin/assets
- AdminAssetsPage 4 处 ¥ 条件渲染 (hideMoney = role !== 'super_admin')
- UsersPage 行加「设为观察者/取消观察者」按钮(仅 is_team_admin && team_id) + 观察者 badge
- toast 提示「需该用户重新登录后生效」(JWT 不缓存 is_observer claim)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 15:58:18 +08:00

61 lines
1.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from rest_framework.permissions import BasePermission
class IsSuperAdmin(BasePermission):
"""超级管理员is_staff=True 且 team=NULL"""
def has_permission(self, request, view):
return (
request.user
and request.user.is_authenticated
and request.user.is_staff
and request.user.team is None
)
class IsTeamAdmin(BasePermission):
"""团队管理员is_team_admin=True 且 team≠NULL"""
def has_permission(self, request, view):
return (
request.user
and request.user.is_authenticated
and request.user.is_team_admin
and request.user.team is not None
)
class IsTeamAdminOrSuperAdmin(BasePermission):
"""团队管理员或超级管理员"""
def has_permission(self, request, view):
if not (request.user and request.user.is_authenticated):
return False
if request.user.is_staff and request.user.team is None:
return True
if request.user.is_team_admin and request.user.team is not None:
return True
return False
class IsTeamMember(BasePermission):
"""团队成员含团管team≠NULL"""
def has_permission(self, request, view):
return (
request.user
and request.user.is_authenticated
and request.user.team is not None
)
class IsSuperAdminOrObserver(BasePermission):
"""超级管理员,或被标记为观察者的团队管理员(可查看全局内容资产)。"""
def has_permission(self, request, view):
u = request.user
if not (u and u.is_authenticated):
return False
# 超管
if u.is_staff and u.team is None:
return True
# 观察者团管
if u.is_team_admin and u.team is not None and getattr(u, 'is_observer', False):
return True
return False