Spaces:
Runtime error
Runtime error
File size: 5,467 Bytes
680fa2b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | 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
|