from sqlalchemy import func from sqlalchemy.orm import Session, selectinload from app.models.department import Department from app.models.user import User from app.schemas.admin import AdminDepartmentUpdate, AdminUserUpdate from app.services.auth_service import get_department_by_name, resolve_signup_target def _department_exists_with_name_or_code( db: Session, *, name: str | None = None, code: str | None = None, exclude_id: int | None = None, ) -> bool: query = db.query(Department) if exclude_id is not None: query = query.filter(Department.id != exclude_id) if name is not None: query = query.filter(func.lower(Department.name) == name.lower()) if code is not None: query = query.filter(func.lower(Department.code) == code.lower()) return query.first() is not None def list_departments(db: Session) -> list[Department]: return ( db.query(Department) .filter(Department.is_active.is_(True)) .order_by(Department.name) .all() ) def create_department( db: Session, *, name: str, code: str, description: str | None = None, keywords: str | None = None, ) -> Department: if _department_exists_with_name_or_code(db, name=name): raise ValueError("Department name is already registered") if _department_exists_with_name_or_code(db, code=code): raise ValueError("Department code is already registered") department = Department( name=name, code=code, description=description, keywords=keywords, ) db.add(department) db.commit() db.refresh(department) return department def update_department( db: Session, *, department_id: int, payload: AdminDepartmentUpdate, ) -> Department: department = db.get(Department, department_id) if department is None: raise ValueError("Department not found") if payload.name is not None and _department_exists_with_name_or_code( db, name=payload.name, exclude_id=department_id, ): raise ValueError("Department name is already registered") if payload.code is not None and _department_exists_with_name_or_code( db, code=payload.code, exclude_id=department_id, ): raise ValueError("Department code is already registered") if payload.name is not None: department.name = payload.name if payload.code is not None: department.code = payload.code if payload.description is not None: department.description = payload.description if payload.keywords is not None: department.keywords = payload.keywords if payload.is_active is not None: department.is_active = payload.is_active db.commit() db.refresh(department) return department def deactivate_department(db: Session, *, department_id: int) -> Department: return update_department( db, department_id=department_id, payload=AdminDepartmentUpdate(is_active=False), ) def get_department(db: Session, *, department_id: int) -> Department | None: return db.get(Department, department_id) def list_users(db: Session) -> list[User]: return ( db.query(User) .options(selectinload(User.department)) .order_by(User.id) .all() ) def get_user(db: Session, *, user_id: int) -> User | None: return ( db.query(User) .options(selectinload(User.department)) .filter(User.id == user_id) .first() ) def update_user( db: Session, *, user_id: int, payload: AdminUserUpdate, ) -> User: user = ( db.query(User) .options(selectinload(User.department)) .filter(User.id == user_id) .first() ) if user is None: raise ValueError("User not found") if payload.email is not None: existing_user = ( db.query(User) .filter(func.lower(User.email) == payload.email.lower(), User.id != user_id) .first() ) if existing_user is not None: raise ValueError("Email is already registered") user.email = payload.email.lower() if payload.full_name is not None: user.full_name = payload.full_name if payload.department_name is not None: role, department_id = resolve_signup_target(db, payload.department_name) user.role = role user.department_id = department_id if payload.is_active is not None: user.is_active = payload.is_active db.commit() db.refresh(user) return user def deactivate_user(db: Session, *, user_id: int) -> User: return update_user( db, user_id=user_id, payload=AdminUserUpdate(is_active=False), )