* [fix]Fix the interface for statistics of recent activities and applications * [changes]Modify the code based on the AI review 1.Use the boolean auxiliary methods provided by SQLAlchemy instead of using == True in the is_active filter. 2.The calculation of the "PROJECT_ROOT" has now been hardcoded with five levels of nested os.path.dirname calls. * [fix]Fix the interface for statistics of recent activities and applications * [changes]Modify the code based on the AI review 1.Use the boolean auxiliary methods provided by SQLAlchemy instead of using == True in the is_active filter. 2.The calculation of the "PROJECT_ROOT" has now been hardcoded with five levels of nested os.path.dirname calls.
324 lines
12 KiB
Python
324 lines
12 KiB
Python
from sqlalchemy.orm import Session, joinedload
|
|
from sqlalchemy import and_, or_, func
|
|
from typing import List, Optional
|
|
import uuid
|
|
|
|
from app.models.user_model import User
|
|
from app.models.tenant_model import Tenants
|
|
from app.schemas.user_schema import UserCreate, UserUpdate
|
|
from app.core.logging_config import get_db_logger
|
|
|
|
# 获取数据库专用日志器
|
|
db_logger = get_db_logger()
|
|
|
|
|
|
class UserRepository:
|
|
"""用户数据访问层"""
|
|
|
|
def __init__(self, db: Session):
|
|
self.db = db
|
|
|
|
def get_user_by_id(self, user_id: uuid.UUID) -> Optional[User]:
|
|
"""根据ID获取用户"""
|
|
db_logger.debug(f"根据ID查询用户: user_id={user_id}")
|
|
|
|
try:
|
|
user = self.db.query(User).options(joinedload(User.tenant)).filter(User.id == user_id).first()
|
|
if user:
|
|
db_logger.debug(f"用户查询成功: {user.username} (ID: {user_id})")
|
|
else:
|
|
db_logger.debug(f"用户不存在: user_id={user_id}")
|
|
return user
|
|
except Exception as e:
|
|
db_logger.error(f"根据ID查询用户失败: user_id={user_id} - {str(e)}")
|
|
raise
|
|
|
|
def get_user_by_email(self, email: str) -> Optional[User]:
|
|
"""根据邮箱获取用户"""
|
|
db_logger.debug(f"根据邮箱查询用户: email={email}")
|
|
|
|
try:
|
|
user = self.db.query(User).options(joinedload(User.tenant)).filter(User.email == email).first()
|
|
if user:
|
|
db_logger.debug(f"用户查询成功: {user.username} (email: {email})")
|
|
else:
|
|
db_logger.debug(f"用户不存在: email={email}")
|
|
return user
|
|
except Exception as e:
|
|
db_logger.error(f"根据邮箱查询用户失败: email={email} - {str(e)}")
|
|
raise
|
|
|
|
def get_user_by_username(self, username: str) -> Optional[User]:
|
|
"""根据用户名获取用户"""
|
|
db_logger.debug(f"根据用户名查询用户: username={username}")
|
|
|
|
try:
|
|
user = self.db.query(User).options(joinedload(User.tenant)).filter(User.username == username).first()
|
|
if user:
|
|
db_logger.debug(f"用户查询成功: {user.username} (ID: {user.id})")
|
|
else:
|
|
db_logger.debug(f"用户不存在: username={username}")
|
|
return user
|
|
except Exception as e:
|
|
db_logger.error(f"根据用户名查询用户失败: username={username} - {str(e)}")
|
|
raise
|
|
|
|
def get_superuser(self) -> Optional[User]:
|
|
"""获取超级用户"""
|
|
db_logger.debug("查询超级用户")
|
|
|
|
try:
|
|
user = self.db.query(User).options(joinedload(User.tenant)).filter(User.is_active.is_(True)).filter(User.is_superuser.is_(True)).first()
|
|
if user:
|
|
db_logger.debug(f"超级用户查询成功: {user.username}")
|
|
else:
|
|
db_logger.debug("超级用户不存在")
|
|
return user
|
|
except Exception as e:
|
|
db_logger.error(f"查询超级用户失败: {str(e)}")
|
|
raise
|
|
def check_superuser_only(self) -> bool:
|
|
"""检查是否只有一个超级用户"""
|
|
db_logger.debug("检查是否只有一个超级用户")
|
|
|
|
try:
|
|
count = self.db.query(User).options(joinedload(User.tenant)).filter(User.is_active.is_(True)).filter(User.is_superuser.is_(True)).count()
|
|
return count == 1
|
|
except Exception as e:
|
|
db_logger.error(f"检查超级用户数量失败: {str(e)}")
|
|
raise
|
|
|
|
def create_user(
|
|
self,
|
|
user_data: UserCreate,
|
|
hashed_password: str,
|
|
tenant_id: Optional[uuid.UUID] = None,
|
|
is_superuser: bool = False
|
|
) -> User:
|
|
"""创建用户"""
|
|
db_logger.debug(f"创建用户记录: username={user_data.username}, email={user_data.email}, is_superuser={is_superuser}")
|
|
|
|
try:
|
|
db_user = User(
|
|
username=user_data.username,
|
|
email=user_data.email,
|
|
hashed_password=hashed_password,
|
|
tenant_id=tenant_id,
|
|
is_superuser=is_superuser,
|
|
)
|
|
self.db.add(db_user)
|
|
self.db.flush()
|
|
db_logger.info(f"用户记录创建成功: {user_data.username} (email: {user_data.email})")
|
|
return db_user
|
|
except Exception as e:
|
|
db_logger.error(f"创建用户记录失败: username={user_data.username} - {str(e)}")
|
|
raise
|
|
|
|
def update_user(self, user_id: uuid.UUID, user_data: UserUpdate) -> Optional[User]:
|
|
"""更新用户"""
|
|
db_logger.debug(f"更新用户: user_id={user_id}")
|
|
|
|
try:
|
|
user = self.get_user_by_id(user_id)
|
|
if not user:
|
|
db_logger.debug(f"用户不存在: user_id={user_id}")
|
|
return None
|
|
|
|
for field, value in user_data.dict(exclude_unset=True).items():
|
|
setattr(user, field, value)
|
|
|
|
self.db.flush()
|
|
db_logger.info(f"用户更新成功: {user.username}")
|
|
return user
|
|
except Exception as e:
|
|
db_logger.error(f"更新用户失败: user_id={user_id} - {str(e)}")
|
|
raise
|
|
|
|
def delete_user(self, user_id: uuid.UUID) -> bool:
|
|
"""删除用户"""
|
|
db_logger.debug(f"删除用户: user_id={user_id}")
|
|
|
|
try:
|
|
user = self.get_user_by_id(user_id)
|
|
if not user:
|
|
db_logger.debug(f"用户不存在: user_id={user_id}")
|
|
return False
|
|
|
|
# 逻辑删除用户
|
|
user.is_active = False
|
|
self.db.flush()
|
|
db_logger.info(f"用户删除成功(逻辑删除): {user.username}")
|
|
return True
|
|
except Exception as e:
|
|
db_logger.error(f"删除用户失败: user_id={user_id} - {str(e)}")
|
|
raise
|
|
|
|
def get_users_by_tenant(
|
|
self,
|
|
tenant_id: uuid.UUID,
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
is_active: 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 search:
|
|
query = query.filter(
|
|
or_(
|
|
User.username.ilike(f"%{search}%"),
|
|
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
|
|
except Exception as e:
|
|
db_logger.error(f"查询租户用户失败: tenant_id={tenant_id} - {str(e)}")
|
|
raise
|
|
|
|
def count_users_by_tenant(
|
|
self,
|
|
tenant_id: uuid.UUID,
|
|
is_active: 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 search:
|
|
query = query.filter(
|
|
or_(
|
|
User.username.ilike(f"%{search}%"),
|
|
User.email.ilike(f"%{search}%")
|
|
)
|
|
)
|
|
|
|
return query.scalar()
|
|
except Exception as e:
|
|
db_logger.error(f"统计租户用户失败: tenant_id={tenant_id} - {str(e)}")
|
|
raise
|
|
|
|
def get_superusers_by_tenant(
|
|
self,
|
|
tenant_id: uuid.UUID,
|
|
is_active: Optional[bool] = True
|
|
) -> List[User]:
|
|
"""获取租户下的超管用户列表"""
|
|
db_logger.debug(f"查询租户超管用户: tenant_id={tenant_id}")
|
|
|
|
try:
|
|
query = self.db.query(User).options(joinedload(User.tenant)).filter(
|
|
and_(
|
|
User.tenant_id == tenant_id,
|
|
User.is_superuser == True
|
|
)
|
|
)
|
|
|
|
if is_active is not None:
|
|
query = query.filter(User.is_active == is_active)
|
|
|
|
users = query.all()
|
|
db_logger.debug(f"租户超管用户查询成功: tenant_id={tenant_id}, count={len(users)}")
|
|
return users
|
|
except Exception as e:
|
|
db_logger.error(f"查询租户超管用户失败: tenant_id={tenant_id} - {str(e)}")
|
|
raise
|
|
|
|
def assign_user_to_tenant(self, user_id: uuid.UUID, tenant_id: uuid.UUID) -> bool:
|
|
"""将用户分配给租户"""
|
|
db_logger.debug(f"分配用户到租户: user_id={user_id}, tenant_id={tenant_id}")
|
|
|
|
try:
|
|
user = self.get_user_by_id(user_id)
|
|
if not user:
|
|
db_logger.debug(f"用户不存在: user_id={user_id}")
|
|
return False
|
|
|
|
# 验证租户存在
|
|
tenant = self.db.query(Tenants).filter(Tenants.id == tenant_id).first()
|
|
if not tenant:
|
|
db_logger.debug(f"租户不存在: tenant_id={tenant_id}")
|
|
return False
|
|
|
|
user.tenant_id = tenant_id
|
|
self.db.flush()
|
|
db_logger.info(f"用户分配成功: user={user.username}, tenant={tenant.name}")
|
|
return True
|
|
except Exception as e:
|
|
db_logger.error(f"分配用户到租户失败: user_id={user_id}, tenant_id={tenant_id} - {str(e)}")
|
|
raise
|
|
|
|
def get_users_without_tenant(
|
|
self,
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
is_active: Optional[bool] = None
|
|
) -> List[User]:
|
|
"""获取没有租户的用户列表"""
|
|
try:
|
|
query = self.db.query(User).filter(User.tenant_id.is_(None))
|
|
|
|
if is_active is not None:
|
|
query = query.filter(User.is_active == is_active)
|
|
|
|
return query.offset(skip).limit(limit).all()
|
|
except Exception as e:
|
|
db_logger.error(f"查询无租户用户失败: {str(e)}")
|
|
raise
|
|
|
|
|
|
# 便利函数,保持向后兼容
|
|
def get_user_by_id(db: Session, user_id: uuid.UUID) -> Optional[User]:
|
|
"""根据ID获取用户"""
|
|
return UserRepository(db).get_user_by_id(user_id)
|
|
|
|
def get_user_by_email(db: Session, email: str) -> Optional[User]:
|
|
"""根据邮箱获取用户"""
|
|
return UserRepository(db).get_user_by_email(email)
|
|
|
|
def get_user_by_username(db: Session, username: str) -> Optional[User]:
|
|
"""根据用户名获取用户"""
|
|
return UserRepository(db).get_user_by_username(username)
|
|
|
|
def get_superuser(db: Session) -> Optional[User]:
|
|
"""获取超级用户"""
|
|
return UserRepository(db).get_superuser()
|
|
|
|
def check_superuser_only(db: Session) -> Optional[User]:
|
|
"""检查是否只有一个超级用户"""
|
|
return UserRepository(db).check_superuser_only()
|
|
|
|
def create_user(
|
|
db: Session,
|
|
user: UserCreate,
|
|
hashed_password: str,
|
|
tenant_id: Optional[uuid.UUID] = None,
|
|
is_superuser: bool = False
|
|
) -> User:
|
|
"""创建用户(函数式接口)"""
|
|
repo = UserRepository(db)
|
|
return repo.create_user(user, hashed_password, tenant_id, is_superuser)
|
|
|
|
|
|
def get_superusers_by_tenant(
|
|
db: Session,
|
|
tenant_id: uuid.UUID,
|
|
is_active: Optional[bool] = True
|
|
) -> List[User]:
|
|
"""获取租户下的超管用户列表(函数式接口)"""
|
|
repo = UserRepository(db)
|
|
return repo.get_superusers_by_tenant(tenant_id, is_active)
|