gateway/modules/interfaces/serviceAppModel.py
2025-05-28 01:51:10 +02:00

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"})
}