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