222 lines
No EOL
11 KiB
Python
222 lines
No EOL
11 KiB
Python
"""
|
|
Models for User Service
|
|
"""
|
|
|
|
import uuid
|
|
from pydantic import BaseModel, Field, EmailStr
|
|
from typing import List, Dict, Any, Optional
|
|
from datetime import datetime
|
|
from enum import Enum
|
|
|
|
from modules.shared.attributeUtils import Label, BaseModelWithUI
|
|
|
|
class AttributeDefinition(BaseModel):
|
|
"""Definition of an attribute for UI forms"""
|
|
name: str = Field(..., description="Name of the attribute")
|
|
label: str = Field(..., description="Display label for the attribute")
|
|
type: str = Field(..., description="Type of the attribute (string, number, boolean, etc.)")
|
|
required: bool = Field(default=False, description="Whether the attribute is required")
|
|
placeholder: Optional[str] = Field(None, description="Placeholder text for the input")
|
|
editable: bool = Field(default=True, description="Whether the attribute can be edited")
|
|
visible: bool = Field(default=True, description="Whether the attribute should be visible in forms")
|
|
order: int = Field(default=0, description="Order in which to display the attribute")
|
|
|
|
class AuthAuthority(str, Enum):
|
|
"""Authentication authorities"""
|
|
LOCAL = "local"
|
|
MICROSOFT = "microsoft"
|
|
GOOGLE = "google"
|
|
EXTERNAL = "external"
|
|
|
|
class UserPrivilege(str, Enum):
|
|
"""User privilege levels"""
|
|
SYSADMIN = "sysadmin"
|
|
ADMIN = "admin"
|
|
USER = "user"
|
|
|
|
class ConnectionStatus(str, Enum):
|
|
"""Connection status"""
|
|
ACTIVE = "active"
|
|
EXPIRED = "expired"
|
|
REVOKED = "revoked"
|
|
PENDING = "pending"
|
|
|
|
class Mandate(BaseModelWithUI):
|
|
"""Data model for a mandate"""
|
|
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Unique ID of the mandate")
|
|
name: str = Field(description="Name of the mandate")
|
|
language: str = Field(default="en", description="Default language of the mandate")
|
|
|
|
label: Label = Field(
|
|
default=Label(default="Mandate", translations={"en": "Mandate", "fr": "Mandat"}),
|
|
description="Label for the class"
|
|
)
|
|
|
|
fieldLabels: Dict[str, Label] = {
|
|
"id": Label(default="ID", translations={}),
|
|
"name": Label(default="Name of the mandate", translations={"en": "Mandate name", "fr": "Nom du mandat"}),
|
|
"language": Label(default="Language", translations={"en": "Language", "fr": "Langue"})
|
|
}
|
|
|
|
@classmethod
|
|
def get_validations(cls) -> Dict[str, Any]:
|
|
"""Get validation rules for frontend"""
|
|
return {
|
|
"name": {
|
|
"required": True,
|
|
"minLength": 2,
|
|
"maxLength": 100
|
|
},
|
|
"language": {
|
|
"required": True,
|
|
"pattern": "^[a-z]{2}$"
|
|
}
|
|
}
|
|
|
|
class UserConnection(BaseModelWithUI):
|
|
"""Data model for a user's connection to an external service"""
|
|
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Unique ID of the connection")
|
|
authority: AuthAuthority = Field(description="Authentication authority")
|
|
externalId: str = Field(description="User ID in the external system")
|
|
externalUsername: str = Field(description="Username in the external system")
|
|
externalEmail: Optional[EmailStr] = Field(None, description="Email in the external system")
|
|
status: ConnectionStatus = Field(default=ConnectionStatus.ACTIVE, description="Connection status")
|
|
connectedAt: datetime = Field(default_factory=datetime.now, description="When the connection was established")
|
|
lastChecked: datetime = Field(default_factory=datetime.now, description="When the connection was last verified")
|
|
expiresAt: Optional[datetime] = Field(None, description="When the connection expires")
|
|
|
|
label: Label = Field(
|
|
default=Label(default="User Connection", translations={"en": "User Connection", "fr": "Connexion utilisateur"}),
|
|
description="Label for the class"
|
|
)
|
|
|
|
fieldLabels: Dict[str, Label] = {
|
|
"id": Label(default="ID", translations={}),
|
|
"authority": Label(default="Authority", translations={"en": "Authority", "fr": "Autorité"}),
|
|
"externalId": Label(default="External ID", translations={"en": "External ID", "fr": "ID externe"}),
|
|
"externalUsername": Label(default="External Username", translations={"en": "External Username", "fr": "Nom d'utilisateur externe"}),
|
|
"externalEmail": Label(default="External Email", translations={"en": "External Email", "fr": "Email externe"}),
|
|
"status": Label(default="Status", translations={"en": "Status", "fr": "Statut"}),
|
|
"connectedAt": Label(default="Connected At", translations={"en": "Connected At", "fr": "Connecté le"}),
|
|
"lastChecked": Label(default="Last Checked", translations={"en": "Last Checked", "fr": "Dernière vérification"}),
|
|
"expiresAt": Label(default="Expires At", translations={"en": "Expires At", "fr": "Expire le"})
|
|
}
|
|
|
|
class Session(BaseModelWithUI):
|
|
"""Data model for user sessions"""
|
|
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Unique session ID")
|
|
userId: str = Field(description="ID of the user")
|
|
tokenId: str = Field(description="ID of the associated token")
|
|
lastActivity: datetime = Field(default_factory=datetime.now, description="Last activity timestamp")
|
|
expiresAt: datetime = Field(description="When the session expires")
|
|
ipAddress: Optional[str] = Field(None, description="IP address of the session")
|
|
userAgent: Optional[str] = Field(None, description="User agent of the session")
|
|
|
|
label: Label = Field(
|
|
default=Label(default="Session", translations={"en": "Session", "fr": "Session"}),
|
|
description="Label for the class"
|
|
)
|
|
|
|
fieldLabels: Dict[str, Label] = {
|
|
"id": Label(default="ID", translations={}),
|
|
"userId": Label(default="User ID", translations={"en": "User ID", "fr": "ID utilisateur"}),
|
|
"tokenId": Label(default="Token ID", translations={"en": "Token ID", "fr": "ID du token"}),
|
|
"lastActivity": Label(default="Last Activity", translations={"en": "Last Activity", "fr": "Dernière activité"}),
|
|
"expiresAt": Label(default="Expires At", translations={"en": "Expires At", "fr": "Expire le"}),
|
|
"ipAddress": Label(default="IP Address", translations={"en": "IP Address", "fr": "Adresse IP"}),
|
|
"userAgent": Label(default="User Agent", translations={"en": "User Agent", "fr": "User Agent"})
|
|
}
|
|
|
|
class AuthEvent(BaseModelWithUI):
|
|
"""Data model for authentication events"""
|
|
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Unique event ID")
|
|
userId: str = Field(description="ID of the user")
|
|
eventType: str = Field(description="Type of event (login, logout, etc.)")
|
|
details: Dict[str, Any] = Field(description="Event details")
|
|
timestamp: datetime = Field(default_factory=datetime.now, description="When the event occurred")
|
|
ipAddress: Optional[str] = Field(None, description="IP address of the event")
|
|
userAgent: Optional[str] = Field(None, description="User agent of the event")
|
|
|
|
label: Label = Field(
|
|
default=Label(default="Auth Event", translations={"en": "Auth Event", "fr": "Événement d'authentification"}),
|
|
description="Label for the class"
|
|
)
|
|
|
|
fieldLabels: Dict[str, Label] = {
|
|
"id": Label(default="ID", translations={}),
|
|
"userId": Label(default="User ID", translations={"en": "User ID", "fr": "ID utilisateur"}),
|
|
"eventType": Label(default="Event Type", translations={"en": "Event Type", "fr": "Type d'événement"}),
|
|
"details": Label(default="Details", translations={"en": "Details", "fr": "Détails"}),
|
|
"timestamp": Label(default="Timestamp", translations={"en": "Timestamp", "fr": "Horodatage"}),
|
|
"ipAddress": Label(default="IP Address", translations={"en": "IP Address", "fr": "Adresse IP"}),
|
|
"userAgent": Label(default="User Agent", translations={"en": "User Agent", "fr": "User Agent"})
|
|
}
|
|
|
|
class User(BaseModelWithUI):
|
|
"""Data model for a user"""
|
|
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Unique ID of the user")
|
|
username: str = Field(description="Username for login")
|
|
email: Optional[EmailStr] = Field(None, description="Email address of the user")
|
|
fullName: Optional[str] = Field(None, description="Full name of the user")
|
|
language: str = Field(default="en", description="Preferred language of the user")
|
|
disabled: bool = Field(default=False, description="Indicates whether the user is disabled")
|
|
privilege: UserPrivilege = Field(default=UserPrivilege.USER, description="Permission level")
|
|
authenticationAuthority: AuthAuthority = Field(default=AuthAuthority.LOCAL, description="Primary authentication authority")
|
|
mandateId: Optional[str] = Field(None, description="ID of the mandate this user belongs to")
|
|
connections: List[UserConnection] = Field(default_factory=list, description="List of external service connections")
|
|
|
|
label: Label = Field(
|
|
default=Label(default="User", translations={"en": "User", "fr": "Utilisateur"}),
|
|
description="Label for the class"
|
|
)
|
|
|
|
fieldLabels: Dict[str, Label] = {
|
|
"id": Label(default="ID", translations={}),
|
|
"username": Label(default="Username", translations={"en": "Username", "fr": "Nom d'utilisateur"}),
|
|
"email": Label(default="Email", translations={"en": "Email", "fr": "Email"}),
|
|
"fullName": Label(default="Full Name", translations={"en": "Full Name", "fr": "Nom complet"}),
|
|
"language": Label(default="Language", translations={"en": "Language", "fr": "Langue"}),
|
|
"disabled": Label(default="Disabled", translations={"en": "Disabled", "fr": "Désactivé"}),
|
|
"privilege": Label(default="Privilege", translations={"en": "Privilege", "fr": "Privilège"}),
|
|
"authenticationAuthority": Label(default="Auth Authority", translations={"en": "Auth Authority", "fr": "Autorité d'authentification"}),
|
|
"mandateId": Label(default="Mandate ID", translations={"en": "Mandate ID", "fr": "ID de mandat"}),
|
|
"connections": Label(default="Connections", translations={"en": "Connections", "fr": "Connexions"})
|
|
}
|
|
|
|
@classmethod
|
|
def get_validations(cls) -> Dict[str, Any]:
|
|
"""Get validation rules for frontend"""
|
|
return {
|
|
"username": {
|
|
"required": True,
|
|
"minLength": 3,
|
|
"maxLength": 50,
|
|
"pattern": "^[a-zA-Z0-9_-]+$"
|
|
},
|
|
"email": {
|
|
"required": False,
|
|
"pattern": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
|
|
},
|
|
"fullName": {
|
|
"required": False,
|
|
"maxLength": 100
|
|
},
|
|
"language": {
|
|
"required": True,
|
|
"pattern": "^[a-z]{2}$"
|
|
}
|
|
}
|
|
|
|
class UserInDB(User):
|
|
"""Extended user class with password hash"""
|
|
hashedPassword: Optional[str] = Field(None, description="Hash of the user password")
|
|
|
|
label: Label = Field(
|
|
default=Label(default="User Access", translations={"en": "User Access", "fr": "Accès de l'utilisateur"}),
|
|
description="Label for the class"
|
|
)
|
|
|
|
fieldLabels: Dict[str, Label] = {
|
|
"hashedPassword": Label(default="Password hash", translations={"en": "Password hash", "fr": "Hachage de mot de passe"})
|
|
}
|
|
|