from fastapi import APIRouter, HTTPException, status from .Schema import ( RegisterUserRequest, LoginUserRequest, AccessTokenResponse, ForgotPasswordRequest, VerifyResetTokenRequest, ResetPasswordRequest, BaseResponse, ) from .Model import User from jose import jwt from datetime import datetime, timedelta # JWT Configurations SECRET_KEY = "your_secret_key_here" ALGORITHM = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES = 30 user_router = APIRouter(tags=["User"]) def create_access_token(data: dict, expires_delta: timedelta = None): to_encode = data.copy() expire = datetime.utcnow() + ( expires_delta or timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) ) to_encode.update({"exp": expire}) return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) @user_router.post( "/user/register", response_model=BaseResponse, status_code=status.HTTP_201_CREATED ) async def register_user(request: RegisterUserRequest): existing_user = await User.filter(phoneNumber=request.phoneNumber).first() if existing_user: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="User already exists." ) request.hash_password() new_user = await User.create(**request.dict()) return BaseResponse( code=200, message="User created successfully", payload={"user_id": new_user.id} ) @user_router.post( "/user/login", response_model=AccessTokenResponse, status_code=status.HTTP_200_OK ) async def login_user(request: LoginUserRequest): db_user = await User.filter(phoneNumber=request.phoneNumber).first() if db_user and db_user.verify_password(request.password): access_token = create_access_token(data={"sub": db_user.phoneNumber}) return AccessTokenResponse(access_token=access_token, token_type="bearer") raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid credentials" ) @user_router.post( "/user/forgot-password", response_model=BaseResponse, status_code=status.HTTP_200_OK ) async def forgot_password(request: ForgotPasswordRequest): user = await User.filter(phoneNumber=request.phoneNumber).first() if not user: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="User not found." ) await user.initiate_password_reset() return BaseResponse(code=200, message="Password reset token sent to your phone.") @user_router.post( "/user/verify-reset-token", response_model=BaseResponse, status_code=status.HTTP_200_OK, ) async def verify_reset_token(request: VerifyResetTokenRequest): user = await User.filter( phoneNumber=request.phoneNumber, reset_token=request.reset_token ).first() if not user or datetime.utcnow() > user.reset_token_expiration: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid or expired token." ) return BaseResponse(code=200, message="Token verified. Proceed to reset password.") @user_router.post( "/user/reset-password", response_model=BaseResponse, status_code=status.HTTP_200_OK ) async def reset_password(request: ResetPasswordRequest): user = await User.filter(phoneNumber=request.phoneNumber).first() if not user: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="User not found." ) if not await user.reset_password(request.reset_token, request.new_password): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid or expired token." ) return BaseResponse(code=200, message="Password has been reset successfully.")