""" 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 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") 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: str = Field(default="user", alias="role_id", 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") 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" } }