Files / app /services /auth.py
lea97338's picture
Upload 100 files (#1)
680fa2b
Raw
History Blame Contribute Delete
5.47 kB
from typing import Optional
from sqlalchemy.orm import Session
from fastapi import HTTPException, status
from backend.app.core.security import get_password_hash, verify_password, create_access_token
from backend.app.repositories.users import UserRepository
from backend.app.schemas.auth import UserRegister, UserLogin
from backend.app.models.users import User
class AuthService:
def __init__(self, db: Session):
self.db = db
self.user_repo = UserRepository(db)
def signup(self, data: UserRegister) -> User:
"""Register a new customer or worker."""
# Check if phone already exists
existing_user = self.user_repo.get_by_phone(data.phone)
if existing_user:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="A user with this phone number is already registered."
)
# Hash password if provided
hashed_password = None
if data.password:
hashed_password = get_password_hash(data.password)
if data.role == "worker":
# For workers, ensure rate and skill are provided
if not data.skill or data.rate is None:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Workers must provide a skill and a daily rate."
)
# Create worker and worker profile
user = self.user_repo.create_worker(
name=data.name,
phone=data.phone,
skill=data.skill,
rate=data.rate,
city=data.city
)
# Set hashed password if provided
if hashed_password:
user.password_hash = hashed_password
self.db.commit()
elif data.role in ("customer", "mediator", "admin"):
# Create customer/mediator/admin
user = self.user_repo.create_customer(
name=data.name,
phone=data.phone,
city=data.city
)
# Override default role if not customer
user.role = data.role
if hashed_password:
user.password_hash = hashed_password
self.db.commit()
else:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Invalid registration role: {data.role}"
)
return user
def login(self, data: UserLogin) -> dict:
"""Authenticate user and return a JWT access token."""
user = self.user_repo.get_by_phone(data.phone)
# Bypass for demo OTP 123456
if data.otp == "123456":
if not user:
# Dynamically create the user for demo convenience if they don't exist
if data.role == "worker":
user = self.user_repo.create_worker(
name="Ramesh Kumar",
phone=data.phone,
skill="Mason",
rate=650
)
else:
user = self.user_repo.create_customer(
name="Harsh",
phone=data.phone
)
user.role = data.role
self.db.commit()
else:
# Update role if user log in with a different role in the demo selector
user.role = data.role
self.db.commit()
else:
# If not using demo OTP, check password/credentials
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid credentials. Use demo OTP 123456."
)
if not user.is_active:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="User account is suspended. Contact admin."
)
# Create access token
token = create_access_token(subject=user.phone)
return {
"access_token": token,
"token_type": "bearer",
"role": user.role
}
def get_current_user_by_token(self, token: str) -> User:
"""Decode JWT token and get the user."""
from jose import jwt, JWTError
from backend.app.core.config import settings
try:
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
phone: str = payload.get("sub")
if phone is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid credentials token signature."
)
except JWTError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid token. Please log in again."
)
user = self.user_repo.get_by_phone(phone)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="User not found."
)
if not user.is_active:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Account is suspended."
)
return user