from sqlalchemy.orm import Session from app.models.user import PasswordResetToken, User from app.schemas.user import UserCreate, UserUpdate from app.utils.security import hash_password, verify_password def get_user_by_id(db: Session, user_id: int) -> User | None: return db.query(User).filter(User.id == user_id).first() def get_user_by_email(db: Session, email: str) -> User | None: return db.query(User).filter(User.email == email).first() def get_user_by_username(db: Session, username: str) -> User | None: return db.query(User).filter(User.username == username).first() def get_user_by_email_or_username(db: Session, identifier: str) -> User | None: return ( db.query(User) .filter((User.email == identifier) | (User.username == identifier)) .first() ) def create_user(db: Session, data: UserCreate) -> User: user = User( email=data.email.lower(), username=data.username.lower(), full_name=data.full_name, employee_id=data.employee_id, phone=data.phone, occupation=data.occupation, hashed_password=hash_password(data.password), ) db.add(user) db.commit() db.refresh(user) return user def update_user(db: Session, user: User, data: UserUpdate) -> User: update_data = data.model_dump(exclude_unset=True) for field, value in update_data.items(): setattr(user, field, value) db.commit() db.refresh(user) return user def authenticate_user(db: Session, identifier: str, password: str) -> User | None: user = get_user_by_email_or_username(db, identifier) if user is None or not verify_password(password, user.hashed_password): return None return user def create_password_reset_token(db: Session, user: User, token: str, expires_at) -> PasswordResetToken: reset = PasswordResetToken(user_id=user.id, token=token, expires_at=expires_at) db.add(reset) db.commit() db.refresh(reset) return reset def get_valid_reset_token(db: Session, token: str) -> PasswordResetToken | None: from datetime import UTC, datetime reset = ( db.query(PasswordResetToken) .filter( PasswordResetToken.token == token, PasswordResetToken.used.is_(False), PasswordResetToken.expires_at > datetime.now(UTC), ) .first() ) return reset