Files
ljwx-health/ljwx-bigscreen/app/services/admin_helper.py
T
brunoandClaude Sonnet 4.5 6fcf4b4d83
CI/CD Pipeline / build-push (ljwx-admin) (push) Blocked by required conditions
CI/CD Pipeline / build-push (ljwx-bigscreen) (push) Blocked by required conditions
CI/CD Pipeline / build-push (ljwx-boot) (push) Blocked by required conditions
CI/CD Pipeline / update-deploy (push) Blocked by required conditions
CI/CD Pipeline / security-scan (push) Successful in 54s
CI/CD Pipeline / test-build-boot (push) Successful in 5m15s
CI/CD Pipeline / build-pr (ljwx-admin) (push) Has been skipped
CI/CD Pipeline / build-pr (ljwx-bigscreen) (push) Has been skipped
CI/CD Pipeline / build-pr (ljwx-boot) (push) Has been skipped
CI/CD Pipeline / test-admin (push) Successful in 7m16s
CI/CD Pipeline / test-bigscreen (push) Failing after 29m38s
docs: 深度分析 API 架构并准备激进式重构
## 主要变更

### 1. API 架构分析文档
- 创建 api-architecture-analysis.md:深度分析当前 API 架构混乱问题
- 发现核心问题:93% API 无版本号,命名规范混乱,功能重复
- 提供渐进式和激进式两种重构方案

### 2. OpenAPI 契约维护文档
- 创建 openapi-maintenance-workflow.md:OpenAPI 维护流程规范
- 创建 v1-api-contract-validation.md:V1 API 契约验证报告
- 创建 v1-api-quick-reference.md:V1 API 快速参考指南

### 3. ljwx-bigscreen API 迁移
- 修复 BigscreenApiV1Controller 中 userId 参数 required 问题
- 更新 ljwx-bigscreen 调用正确的 API 路径
- 修复 session key 不一致问题(customer_id vs customerId)
- 添加 boot_api_client 统一 HTTP 客户端

### 4. 日志和配置优化
- 添加 StaticFileFilter 过滤 304 日志
- 修复 SQLAlchemy ROLLBACK 警告
- 优化 ljwx-bigscreen 日志格式

### 5. 数据库迁移
- 添加 V1.9.0 Flyway 迁移脚本(geofence alert 字段)
- 创建本地数据库迁移指南

### 6. Claude Code 配置
- 添加 context-guard.md 和 task-type-detector.md
- 创建 QUICK_REFERENCE.md 决策流程图
- 优化 CLAUDE.md 文档管理规范

## 下一步
- 启动激进式 API 重构
- 统一 ljwx-admin、ljwx-watch、ljwx-phone API
- 维护 OpenAPI 契约

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-24 23:27:02 +08:00

356 lines
12 KiB
Python

"""
Admin Helper Module
提供管理员用户判断和查询功能
基于 sys_user 表的字段:
- admin_level: 管理员级别(0=普通员工, 1=部门/租户管理员, 3=超级管理员)
- customer_id: 租户ID
- org_id: 所属组织/部门ID
- level: 通过 sys_org_units 表关联获取组织层级
"""
import logging
from typing import List, Optional, Dict, Any
logger = logging.getLogger(__name__)
class AdminHelper:
"""管理员辅助工具类"""
# 管理员级别常量
SUPER_ADMIN_LEVEL = 3 # 超级管理员
TENANT_ADMIN_LEVEL = 1 # 租户/部门管理员
NORMAL_USER_LEVEL = 0 # 普通用户
def __init__(self):
"""初始化"""
pass
def is_admin_user(self, user_id: int) -> bool:
"""
判断用户是否为管理员(任何级别)
Args:
user_id: 用户ID
Returns:
bool: True表示是管理员,False表示不是
"""
try:
from app.models import db, UserInfo
user = db.session.query(UserInfo).filter(
UserInfo.id == user_id,
UserInfo.is_deleted == False
).first()
if user and hasattr(user, 'admin_level'):
is_admin = user.admin_level > self.NORMAL_USER_LEVEL
logger.debug(f"User {user_id} admin_level={user.admin_level}, is_admin={is_admin}")
return is_admin
logger.debug(f"User {user_id} not found or has no admin_level field")
return False
except Exception as e:
logger.error(f"Failed to check if user {user_id} is admin: {e}")
return False
def is_super_admin(self, user_id: int) -> bool:
"""
判断用户是否为超级管理员
Args:
user_id: 用户ID
Returns:
bool: True表示是超级管理员
"""
try:
from app.models import db, UserInfo
user = db.session.query(UserInfo).filter(
UserInfo.id == user_id,
UserInfo.is_deleted == False
).first()
if user and hasattr(user, 'admin_level'):
return user.admin_level == self.SUPER_ADMIN_LEVEL
return False
except Exception as e:
logger.error(f"Failed to check if user {user_id} is super admin: {e}")
return False
def is_tenant_admin(self, user_id: int, customer_id: int) -> bool:
"""
判断用户是否为指定租户的管理员
Args:
user_id: 用户ID
customer_id: 租户ID
Returns:
bool: True表示是该租户的管理员
"""
try:
from app.models import db, UserInfo
user = db.session.query(UserInfo).filter(
UserInfo.id == user_id,
UserInfo.is_deleted == False
).first()
if not user or not hasattr(user, 'admin_level'):
return False
# 超级管理员有所有租户的管理权限
if user.admin_level == self.SUPER_ADMIN_LEVEL:
return True
# 租户管理员需要匹配 customer_id
if user.admin_level >= self.TENANT_ADMIN_LEVEL:
return user.customer_id == customer_id
return False
except Exception as e:
logger.error(f"Failed to check if user {user_id} is admin of tenant {customer_id}: {e}")
return False
def is_org_admin(self, user_id: int, org_id: int, include_parent: bool = True) -> bool:
"""
判断用户是否为指定组织/部门的管理员
Args:
user_id: 用户ID
org_id: 组织/部门ID
include_parent: 是否包含上级组织的管理员(默认True)
Returns:
bool: True表示是该组织的管理员
"""
try:
from app.models import db, UserInfo, OrgInfo
user = db.session.query(UserInfo).filter(
UserInfo.id == user_id,
UserInfo.is_deleted == False
).first()
if not user or not hasattr(user, 'admin_level'):
return False
# 超级管理员有所有组织的管理权限
if user.admin_level == self.SUPER_ADMIN_LEVEL:
return True
# 非管理员直接返回False
if user.admin_level < self.TENANT_ADMIN_LEVEL:
return False
# 管理员用户,检查组织权限
user_org_id = user.org_id
# 直接匹配
if user_org_id == org_id:
return True
# 如果需要检查上级组织权限
if include_parent:
# 获取目标组织信息
target_org = db.session.query(OrgInfo).filter(
OrgInfo.id == org_id,
OrgInfo.is_deleted == False
).first()
# 获取用户组织信息
user_org = db.session.query(OrgInfo).filter(
OrgInfo.id == user_org_id,
OrgInfo.is_deleted == False
).first()
if target_org and user_org:
# 如果用户组织层级更高(数字更小),且是目标组织的祖先
# 通过检查 target_org 的 ancestors 字段或递归查询 parent_id
if user_org.level < target_org.level:
# 检查用户组织是否是目标组织的祖先
current_org = target_org
while current_org.parent_id and current_org.parent_id != 0:
if current_org.parent_id == user_org_id:
return True
current_org = db.session.query(OrgInfo).filter(
OrgInfo.id == current_org.parent_id,
OrgInfo.is_deleted == False
).first()
if not current_org:
break
return False
except Exception as e:
logger.error(f"Failed to check if user {user_id} is admin of org {org_id}: {e}")
return False
def get_admin_user_ids(
self,
customer_id: Optional[int] = None,
org_id: Optional[int] = None,
min_admin_level: int = TENANT_ADMIN_LEVEL,
include_super_admin: bool = True
) -> List[str]:
"""
获取管理员用户的ID列表
Args:
customer_id: 可选的租户ID,用于过滤特定租户的管理员
org_id: 可选的组织ID,用于过滤特定组织的管理员
min_admin_level: 最低管理员级别(默认1)
include_super_admin: 是否包含超级管理员(默认True)
Returns:
List[str]: 管理员用户ID列表(字符串格式,用于SQL拼接)
"""
try:
from app.models import db, UserInfo
# 构建基础查询
query = db.session.query(UserInfo.id).filter(
UserInfo.is_deleted == False,
UserInfo.status == '1' # 只查询启用的用户
)
# 管理员级别过滤
if include_super_admin:
# 包含超级管理员和指定级别以上的管理员
query = query.filter(UserInfo.admin_level >= min_admin_level)
else:
# 只包含指定级别的管理员(排除超级管理员)
query = query.filter(
UserInfo.admin_level >= min_admin_level,
UserInfo.admin_level < self.SUPER_ADMIN_LEVEL
)
# 租户过滤
if customer_id is not None and not include_super_admin:
query = query.filter(UserInfo.customer_id == customer_id)
# 组织过滤
if org_id is not None:
query = query.filter(UserInfo.org_id == org_id)
admin_users = query.distinct().all()
admin_ids = [str(user.id) for user in admin_users]
logger.debug(
f"Found {len(admin_ids)} admin users "
f"(customerId={customer_id}, orgId={org_id}, minLevel={min_admin_level})"
)
return admin_ids
except Exception as e:
logger.error(f"Failed to get admin user IDs: {e}")
return []
def get_user_admin_info(self, user_id: int) -> Dict[str, Any]:
"""
获取用户的完整管理员信息
Args:
user_id: 用户ID
Returns:
Dict: 包含用户管理员相关信息的字典
"""
try:
from app.models import db, UserInfo, OrgInfo
user = db.session.query(UserInfo).filter(
UserInfo.id == user_id,
UserInfo.is_deleted == False
).first()
if not user:
return {
'user_id': user_id,
'is_admin': False,
'admin_level': 0,
'customer_id': None,
'org_id': None,
'org_name': None,
'org_level': None
}
# 获取组织信息
org_info = None
org_level = None
if user.org_id:
org_info = db.session.query(OrgInfo).filter(
OrgInfo.id == user.org_id,
OrgInfo.is_deleted == False
).first()
if org_info:
org_level = org_info.level
return {
'user_id': user_id,
'is_admin': user.admin_level > self.NORMAL_USER_LEVEL,
'is_super_admin': user.admin_level == self.SUPER_ADMIN_LEVEL,
'admin_level': user.admin_level,
'customer_id': user.customer_id,
'org_id': user.org_id,
'org_name': user.org_name or (org_info.name if org_info else None),
'org_level': org_level
}
except Exception as e:
logger.error(f"Failed to get admin info for user {user_id}: {e}")
return {
'user_id': user_id,
'is_admin': False,
'admin_level': 0,
'error': str(e)
}
# 创建全局单例实例
admin_helper = AdminHelper()
# 便捷函数
def is_admin_user(user_id: int) -> bool:
"""判断用户是否为管理员(便捷函数)"""
return admin_helper.is_admin_user(user_id)
def is_super_admin(user_id: int) -> bool:
"""判断用户是否为超级管理员(便捷函数)"""
return admin_helper.is_super_admin(user_id)
def is_tenant_admin(user_id: int, customer_id: int) -> bool:
"""判断用户是否为指定租户的管理员(便捷函数)"""
return admin_helper.is_tenant_admin(user_id, customer_id)
def is_org_admin(user_id: int, org_id: int, include_parent: bool = True) -> bool:
"""判断用户是否为指定组织的管理员(便捷函数)"""
return admin_helper.is_org_admin(user_id, org_id, include_parent)
def get_admin_user_ids(
customer_id: Optional[int] = None,
org_id: Optional[int] = None,
min_admin_level: int = 1,
include_super_admin: bool = True
) -> List[str]:
"""获取管理员用户ID列表(便捷函数)"""
return admin_helper.get_admin_user_ids(customer_id, org_id, min_admin_level, include_super_admin)
def get_user_admin_info(user_id: int) -> Dict[str, Any]:
"""获取用户的完整管理员信息(便捷函数)"""
return admin_helper.get_user_admin_info(user_id)