hku-class-hub/backend/app/services/user_service.py
2026-04-11 12:52:23 +08:00

116 lines
3.4 KiB
Python

from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession
from app.db.models import User, Class_
from app.schemas.user import UserOut, UserUpdate
from app.services.email_service import send_registration_notification
async def get_user_by_email(db: AsyncSession, email: str) -> User | None:
result = await db.execute(select(User).where(User.email == email))
return result.scalar_one_or_none()
async def get_user_by_id(db: AsyncSession, user_id: int) -> User | None:
result = await db.execute(select(User).where(User.id == user_id))
return result.scalar_one_or_none()
async def register_user(
db: AsyncSession,
email: str,
password_hash: str,
name: str,
class_id: int,
student_id: str | None = None,
) -> User:
user = User(
email=email,
password_hash=password_hash,
name=name,
student_id=student_id,
role="student",
status="pending",
class_id=class_id,
)
db.add(user)
await db.commit()
await db.refresh(user)
# Notify class admins
admins_result = await db.execute(
select(User).where(
User.class_id == class_id,
User.role.in_(["class_admin", "super_admin"]),
User.status == "approved",
)
)
class_result = await db.execute(select(Class_).where(Class_.id == class_id))
class_ = class_result.scalar_one_or_none()
class_name = class_.name if class_ else "Unknown"
for admin in admins_result.scalars():
await send_registration_notification(admin.email, name, class_name)
return user
async def update_profile(db: AsyncSession, user: User, data: UserUpdate) -> User:
update_data = data.model_dump(exclude_unset=True)
if "skills_tags" in update_data and update_data["skills_tags"] is not None:
import json
user.skills_tags = json.dumps(
update_data.pop("skills_tags"), ensure_ascii=False
)
for field, value in update_data.items():
setattr(user, field, value)
await db.commit()
await db.refresh(user)
return user
async def update_user_status(
db: AsyncSession, user_id: int, status: str, role: str | None = None
) -> User | None:
user = await get_user_by_id(db, user_id)
if user is None:
return None
user.status = status
if role is not None:
user.role = role
await db.commit()
await db.refresh(user)
return user
async def list_users(
db: AsyncSession,
page: int = 1,
page_size: int = 20,
class_id: int | None = None,
status: str | None = None,
role: str | None = None,
) -> tuple[list[User], int]:
query = select(User)
count_query = select(func.count(User.id))
if class_id is not None:
query = query.where(User.class_id == class_id)
count_query = count_query.where(User.class_id == class_id)
if status is not None:
query = query.where(User.status == status)
count_query = count_query.where(User.status == status)
if role is not None:
query = query.where(User.role == role)
count_query = count_query.where(User.role == role)
total_result = await db.execute(count_query)
total = total_result.scalar() or 0
query = query.order_by(User.created_at.desc())
query = query.offset((page - 1) * page_size).limit(page_size)
result = await db.execute(query)
users = list(result.scalars().all())
return users, total