Spaces:
Runtime error
Runtime error
| 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 | |