feat: Add feature_billing and feature_user_management fields to tenant model

This commit is contained in:
wxy
2026-03-27 12:20:03 +08:00
parent cc58c7333c
commit f30260939a
4 changed files with 98 additions and 16 deletions

View File

@@ -111,6 +111,18 @@ def get_current_user_info(
break
api_logger.info(f"当前用户信息获取成功: {result.username}, 角色: {result_schema.role}, 工作空间: {result_schema.current_workspace_name}")
# 设置权限:如果用户来自 SSO Source则使用该 Source 的 permissions否则返回全部权限
if current_user.external_source:
from premium.sso.models import SSOSource
source = db.query(SSOSource).filter(SSOSource.source_code == current_user.external_source).first()
if source and source.permissions:
result_schema.permissions = source.permissions
else:
result_schema.permissions = []
else:
result_schema.permissions = ["pricing", "user"]
return success(data=result_schema, msg=t("users.info.get_success"))
@@ -135,6 +147,63 @@ def get_tenant_superusers(
return success(data=superusers_schema, msg=t("users.list.superusers_success"))
@router.get("/tenant/users", response_model=ApiResponse)
def get_tenant_users(
page: int = 1,
size: int = 20,
is_active: bool = None,
is_superuser: bool = None,
search: str = None,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
t: Callable = Depends(get_translator)
):
"""获取当前用户所在租户的用户列表(普通用户可访问)"""
api_logger.info(f"获取租户用户列表请求: tenant_id={current_user.tenant_id}, 操作者: {current_user.username}")
if not current_user.tenant_id:
raise BusinessException("用户没有租户信息", code=BizCode.TENANT_NOT_FOUND)
from app.services.tenant_service import TenantService
tenant_service = TenantService(db)
skip = (page - 1) * size
users = tenant_service.get_tenant_users(
tenant_id=current_user.tenant_id,
skip=skip,
limit=size,
is_active=is_active,
is_superuser=is_superuser,
search=search
)
total = tenant_service.count_tenant_users(
tenant_id=current_user.tenant_id,
is_active=is_active,
is_superuser=is_superuser,
search=search
)
users_schema = [user_schema.User.model_validate(u) for u in users]
for u_schema in users_schema:
user = users[[s.id for s in users_schema].index(u_schema.id)]
if user.external_source:
from premium.sso.models import SSOSource
source = db.query(SSOSource).filter(SSOSource.source_code == user.external_source).first()
u_schema.permissions = source.permissions if source and source.permissions else []
else:
u_schema.permissions = ["pricing", "user"]
return success(
data={
"users": users_schema,
"total": total,
"page": page,
"size": size,
},
msg=t("users.list.get_success")
)
@router.get("/{user_id}", response_model=ApiResponse)
def get_user_info_by_id(

View File

@@ -158,22 +158,26 @@ class UserRepository:
raise
def get_users_by_tenant(
self,
tenant_id: uuid.UUID,
skip: int = 0,
self,
tenant_id: uuid.UUID,
skip: int = 0,
limit: int = 100,
is_active: Optional[bool] = None,
is_superuser: Optional[bool] = None,
search: Optional[str] = None
) -> List[User]:
"""获取租户下的用户列表"""
db_logger.debug(f"查询租户用户: tenant_id={tenant_id}")
try:
query = self.db.query(User).options(joinedload(User.tenant)).filter(User.tenant_id == tenant_id)
if is_active is not None:
query = query.filter(User.is_active == is_active)
if is_superuser is not None:
query = query.filter(User.is_superuser == is_superuser)
if search:
query = query.filter(
or_(
@@ -181,7 +185,7 @@ class UserRepository:
User.email.ilike(f"%{search}%")
)
)
users = query.offset(skip).limit(limit).all()
db_logger.debug(f"租户用户查询成功: tenant_id={tenant_id}, count={len(users)}")
return users
@@ -190,18 +194,22 @@ class UserRepository:
raise
def count_users_by_tenant(
self,
self,
tenant_id: uuid.UUID,
is_active: Optional[bool] = None,
is_superuser: Optional[bool] = None,
search: Optional[str] = None
) -> int:
"""统计租户下的用户数量"""
try:
query = self.db.query(func.count(User.id)).filter(User.tenant_id == tenant_id)
if is_active is not None:
query = query.filter(User.is_active == is_active)
if is_superuser is not None:
query = query.filter(User.is_superuser == is_superuser)
if search:
query = query.filter(
or_(
@@ -209,7 +217,7 @@ class UserRepository:
User.email.ilike(f"%{search}%")
)
)
return query.scalar()
except Exception as e:
db_logger.error(f"统计租户用户失败: tenant_id={tenant_id} - {str(e)}")

View File

@@ -1,6 +1,6 @@
from dataclasses import field
from pydantic import BaseModel, EmailStr, Field, field_validator, validator, ConfigDict
from typing import Optional
from typing import Optional, List
import datetime
import uuid
@@ -85,6 +85,7 @@ class User(UserBase):
current_workspace_name: Optional[str] = None
role: Optional[WorkspaceRole] = None
preferred_language: Optional[str] = "zh" # 用户语言偏好
permissions: Optional[List[str]] = None # 用户权限列表,由 external_source 的 permissions 控制
# 将 datetime 转换为毫秒时间戳
@validator("created_at", pre=True)

View File

@@ -142,11 +142,12 @@ class TenantService:
# 租户用户管理
def get_tenant_users(
self,
tenant_id: uuid.UUID,
skip: int = 0,
self,
tenant_id: uuid.UUID,
skip: int = 0,
limit: int = 100,
is_active: Optional[bool] = None,
is_superuser: Optional[bool] = None,
search: Optional[str] = None
) -> List[UserModel]:
"""获取租户下的用户列表"""
@@ -155,19 +156,22 @@ class TenantService:
skip=skip,
limit=limit,
is_active=is_active,
is_superuser=is_superuser,
search=search
)
def count_tenant_users(
self,
self,
tenant_id: uuid.UUID,
is_active: Optional[bool] = None,
is_superuser: Optional[bool] = None,
search: Optional[str] = None
) -> int:
"""统计租户下的用户数量"""
return self.user_repo.count_users_by_tenant(
tenant_id=tenant_id,
is_active=is_active,
is_superuser=is_superuser,
search=search
)