MukeshKapoor25's picture
forget password flow
cc73d86
Raw History Blame Contribute Delete
6.6 kB
"""
System User model for authentication and authorization.
Represents a system user with login credentials and permissions.
"""
from datetime import datetime
from typing import Optional, Dict, Any, List
from uuid import UUID
from pydantic import BaseModel, Field, EmailStr, model_validator
from enum import Enum
class UserStatus(str, Enum):
"""User account status options."""
ACTIVE = "active"
INACTIVE = "inactive"
SUSPENDED = "suspended"
LOCKED = "locked"
PENDING_ACTIVATION = "pending_activation"
class UserRole(str, Enum):
"""System user roles."""
SUPER_ADMIN = "super_admin"
ADMIN = "admin"
MANAGER = "manager"
USER = "user"
READ_ONLY = "read_only"
class LoginAttemptModel(BaseModel):
"""Login attempt tracking."""
timestamp: datetime = Field(default_factory=datetime.utcnow)
ip_address: Optional[str] = Field(None, description="IP address of login attempt")
user_agent: Optional[str] = Field(None, description="User agent string")
success: bool = Field(..., description="Whether login was successful")
failure_reason: Optional[str] = Field(None, description="Reason for failure if unsuccessful")
class SecuritySettingsModel(BaseModel):
"""User security settings."""
require_password_change: bool = Field(default=False, description="Force password change on next login")
password_expires_at: Optional[datetime] = Field(None, description="Password expiry date")
failed_login_attempts: int = Field(default=0, description="Count of consecutive failed login attempts")
last_failed_login: Optional[datetime] = Field(None, description="Timestamp of last failed login")
account_locked_until: Optional[datetime] = Field(None, description="Account lock expiry time")
last_password_change: Optional[datetime] = Field(None, description="Last password change timestamp")
login_attempts: List[LoginAttemptModel] = Field(default_factory=list, description="Recent login attempts (last 10)")
password_reset_token: Optional[str] = Field(None, description="Password reset token (stored securely)")
password_reset_token_created_at: Optional[datetime] = Field(None, description="When reset token was created")
forgot_pwd_otp: Optional[str] = Field(None, description="Temporary OTP for forgot-password flow")
forgot_pwd_otp_expires_at: Optional[datetime] = Field(None, description="Expiry of forgot-password OTP")
forgot_pwd_otp_attempts: int = Field(default=0, description="Failed OTP verification attempts")
class SystemUserModel(BaseModel):
"""
System User data model for authentication and authorization.
Represents the complete user document in MongoDB.
"""
user_id: UUID = Field(..., description="Unique user identifier (UUID/ULID)")
username: str = Field(..., description="Unique username (lowercase alphanumeric)")
email: EmailStr = Field(..., description="User email address")
merchant_id: str = Field(..., description="User Merchant Information")
merchant_type: Optional[str] = Field(None, description="Merchant type (ncnf, cnf, distributor, retail)")
# Authentication
password_hash: str = Field(..., description="Bcrypt hashed password")
# Personal information
first_name: Optional[str] = Field(None, description="User first name")
last_name: Optional[str] = Field(None, description="User last name")
full_name: Optional[str] = Field(None, description="User full name")
phone: Optional[str] = Field(None, description="User phone number (E.164 format)")
# Authorization
role_id: str = Field(default="user", description="User role identifier")
permissions: Dict[str, List[str]] = Field(default_factory=dict, description="Grouped permissions by module")
# Status and security
status: UserStatus = Field(default=UserStatus.PENDING_ACTIVATION, description="Account status")
security_settings: SecuritySettingsModel = Field(
default_factory=SecuritySettingsModel,
description="Security and login settings"
)
# Session management
last_login_at: Optional[datetime] = Field(None, description="Last successful login timestamp")
last_login_ip: Optional[str] = Field(None, description="IP address of last login")
current_session_token: Optional[str] = Field(None, description="Current JWT token hash for session management")
# Profile information
profile_picture_url: Optional[str] = Field(None, description="URL to profile picture")
timezone: str = Field(default="UTC", description="User timezone")
language: str = Field(default="en", description="Preferred language code")
# Audit fields
created_by: str = Field(..., description="User ID who created this user account")
created_at: datetime = Field(default_factory=datetime.utcnow, description="Account creation timestamp")
updated_at: Optional[datetime] = Field(None, description="Last update timestamp")
updated_by: Optional[str] = Field(None, description="User ID who last updated this record")
# Additional metadata
metadata: Optional[Dict[str, Any]] = Field(None, description="Additional metadata (employee_user_id, employee_code, designation, etc.)")
class Config:
populate_by_name = True
json_schema_extra = {
"example": {
"user_id": "usr_01HZQX5K3N2P8R6T4V9W",
"username": "john.doe",
"email": "john.doe@company.com",
"merchant_id": "mch_retail_001",
"merchant_type": "retail",
"password_hash": "$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LeVMstdMT6jmDQrji",
"first_name": "John",
"last_name": "Doe",
"phone": "+919876543210",
"role_id": "admin",
"permissions": {
"customers": ["view", "create", "update"],
"orders": ["view", "create", "update"],
"settings": ["view", "update"]
},
"status": "active",
"security_settings": {
"require_password_change": False,
"failed_login_attempts": 0,
"login_attempts": []
},
"last_login_at": "2024-11-30T10:30:00Z",
"last_login_ip": "192.168.1.100",
"timezone": "Asia/Kolkata",
"language": "en",
"created_by": "system",
"created_at": "2024-01-15T08:00:00Z"
}
}