Merge pull request #710 from wanxunyang/feature/tenant-billing-user-management
feat: Add feature_billing and feature_user_management fields to tenan…
This commit is contained in:
@@ -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;否则返回 "all" 表示拥有所有权限
|
||||
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 = ["all"]
|
||||
|
||||
return success(data=result_schema, msg=t("users.info.get_success"))
|
||||
|
||||
|
||||
@@ -135,7 +147,6 @@ def get_tenant_superusers(
|
||||
return success(data=superusers_schema, msg=t("users.list.superusers_success"))
|
||||
|
||||
|
||||
|
||||
@router.get("/{user_id}", response_model=ApiResponse)
|
||||
def get_user_info_by_id(
|
||||
user_id: uuid.UUID,
|
||||
|
||||
@@ -19,9 +19,12 @@ class User(Base):
|
||||
last_login_at = Column(DateTime, nullable=True) # 最后登录时间,可为空
|
||||
|
||||
# SSO 外部关联字段
|
||||
external_id = Column(String(100), nullable=True) # 外部用户ID
|
||||
external_id = Column(String(100), nullable=True) # 外部用户 ID
|
||||
external_source = Column(String(50), nullable=True) # 来源系统
|
||||
|
||||
# 用户联系方式
|
||||
phone = Column(String(50), nullable=True) # 用户电话
|
||||
|
||||
# 用户语言偏好
|
||||
preferred_language = Column(String(10), server_default=text("'zh'"), default='zh', nullable=False, index=True) # 用户偏好语言,默认中文
|
||||
|
||||
|
||||
@@ -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)}")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -20,6 +20,7 @@ class UserCreate(UserBase):
|
||||
class UserUpdate(BaseModel):
|
||||
username: Optional[str] = None
|
||||
email: Optional[EmailStr] = None
|
||||
phone: Optional[str] = None
|
||||
is_active: Optional[bool] = None
|
||||
is_superuser: Optional[bool] = None
|
||||
|
||||
@@ -85,6 +86,8 @@ class User(UserBase):
|
||||
current_workspace_name: Optional[str] = None
|
||||
role: Optional[WorkspaceRole] = None
|
||||
preferred_language: Optional[str] = "zh" # 用户语言偏好
|
||||
phone: Optional[str] = None # 用户电话
|
||||
permissions: Optional[List[str]] = None # 用户权限列表,由 external_source 的 permissions 控制
|
||||
|
||||
# 将 datetime 转换为毫秒时间戳
|
||||
@validator("created_at", pre=True)
|
||||
|
||||
@@ -138,7 +138,7 @@ class TenantService:
|
||||
|
||||
except Exception as e:
|
||||
business_logger.error(f"删除租户失败: {str(e)}")
|
||||
raise BusinessException(f"删除租户失败: {str(e)}", code=BizCode.DB_ERROR)
|
||||
raise BusinessException(f"删除租户失败:{str(e)}", code=BizCode.DB_ERROR)
|
||||
|
||||
# 租户用户管理
|
||||
def get_tenant_users(
|
||||
@@ -147,6 +147,7 @@ class TenantService:
|
||||
skip: int = 0,
|
||||
limit: int = 100,
|
||||
is_active: Optional[bool] = None,
|
||||
is_superuser: Optional[bool] = None,
|
||||
search: Optional[str] = None
|
||||
) -> List[UserModel]:
|
||||
"""获取租户下的用户列表"""
|
||||
@@ -155,6 +156,7 @@ class TenantService:
|
||||
skip=skip,
|
||||
limit=limit,
|
||||
is_active=is_active,
|
||||
is_superuser=is_superuser,
|
||||
search=search
|
||||
)
|
||||
|
||||
@@ -162,12 +164,14 @@ class TenantService:
|
||||
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
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user