from pydantic import BaseModel, Field, constr from typing import Optional from datetime import datetime from passlib.context import CryptContext pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") # Constants for phone and MAC address patterns PHONE_PATTERN = r"^(?:\+255|0)\d{9}$" MAC_PATTERN = r"^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$" # Register User Request class RegisterUserRequest(BaseModel): name: str = Field(..., max_length=100) password: str = Field(..., max_length=100) phoneNumber: str = Field( ..., pattern=PHONE_PATTERN, description="Tanzanian phone number starting with +255 or 0 followed by 9 digits", ) mac_address: str = Field( ..., pattern=MAC_PATTERN, description="MAC address in standard format" ) def hash_password(self): self.password = pwd_context.hash(self.password) class Config: schema_extra = { "example": { "name": "John Doe", "password": "StrongPassword1!", "phoneNumber": "+255123456789", "mac_address": "00:1A:2B:3C:4D:5E", } } # Login User Request class LoginUserRequest(BaseModel): phoneNumber: str = Field(..., pattern=PHONE_PATTERN) password: str mac_address: str = Field(..., pattern=MAC_PATTERN) # Access Token Response class AccessTokenResponse(BaseModel): access_token: str token_type: str = "bearer" # Base Response Schema class BaseResponse(BaseModel): code: int message: str payload: Optional[dict] = None # Forgot Password Request class ForgotPasswordRequest(BaseModel): phoneNumber: str = Field(..., pattern=PHONE_PATTERN) # Verify Reset Token Request class VerifyResetTokenRequest(BaseModel): phoneNumber: str = Field(..., pattern=PHONE_PATTERN) reset_token: str = Field(..., max_length=6) # Reset Password Request class ResetPasswordRequest(BaseModel): phoneNumber: str = Field(..., pattern=PHONE_PATTERN) new_password: str = Field(..., max_length=100)