gateway/modules/interfaces/interfaceAppModel.py
2025-06-13 00:41:51 +02:00

230 lines
No EOL
9.4 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 register_model_labels, AttributeDefinition, ModelMixin
class AuthAuthority(str, Enum):
"""Authentication authority enum"""
LOCAL = "local"
GOOGLE = "google"
MSFT = "msft"
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(BaseModel, ModelMixin):
"""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")
enabled: bool = Field(default=True, description="Indicates whether the mandate is enabled")
# Register labels for Mandate
register_model_labels(
"Mandate",
{"en": "Mandate", "fr": "Mandat"},
{
"id": {"en": "ID", "fr": "ID"},
"name": {"en": "Name", "fr": "Nom"},
"language": {"en": "Language", "fr": "Langue"},
"enabled": {"en": "Enabled", "fr": "Activé"}
}
)
class UserConnection(BaseModel, ModelMixin):
"""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")
userId: str = Field(description="ID of the user this connection belongs to")
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")
def to_dict(self) -> Dict[str, Any]:
"""Convert the model to a dictionary with proper datetime serialization"""
data = super().to_dict()
# Convert datetime fields to ISO format strings
for field in ['connectedAt', 'lastChecked', 'expiresAt']:
if field in data and data[field] is not None:
if isinstance(data[field], datetime):
data[field] = data[field].isoformat()
elif isinstance(data[field], (int, float)):
try:
data[field] = datetime.fromtimestamp(data[field]).isoformat()
except (ValueError, TypeError):
data[field] = None
return data
# Register labels for UserConnection
register_model_labels(
"UserConnection",
{"en": "User Connection", "fr": "Connexion utilisateur"},
{
"id": {"en": "ID", "fr": "ID"},
"userId": {"en": "User ID", "fr": "ID utilisateur"},
"authority": {"en": "Authority", "fr": "Autorité"},
"externalId": {"en": "External ID", "fr": "ID externe"},
"externalUsername": {"en": "External Username", "fr": "Nom d'utilisateur externe"},
"externalEmail": {"en": "External Email", "fr": "Email externe"},
"status": {"en": "Status", "fr": "Statut"},
"connectedAt": {"en": "Connected At", "fr": "Connecté le"},
"lastChecked": {"en": "Last Checked", "fr": "Dernière vérification"},
"expiresAt": {"en": "Expires At", "fr": "Expire le"}
}
)
class Session(BaseModel, ModelMixin):
"""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")
# Register labels for Session
register_model_labels(
"Session",
{"en": "Session", "fr": "Session"},
{
"id": {"en": "ID", "fr": "ID"},
"userId": {"en": "User ID", "fr": "ID utilisateur"},
"tokenId": {"en": "Token ID", "fr": "ID du token"},
"lastActivity": {"en": "Last Activity", "fr": "Dernière activité"},
"expiresAt": {"en": "Expires At", "fr": "Expire le"},
"ipAddress": {"en": "IP Address", "fr": "Adresse IP"},
"userAgent": {"en": "User Agent", "fr": "User Agent"}
}
)
class AuthEvent(BaseModel, ModelMixin):
"""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")
# Register labels for AuthEvent
register_model_labels(
"AuthEvent",
{"en": "Auth Event", "fr": "Événement d'authentification"},
{
"id": {"en": "ID", "fr": "ID"},
"userId": {"en": "User ID", "fr": "ID utilisateur"},
"eventType": {"en": "Event Type", "fr": "Type d'événement"},
"details": {"en": "Details", "fr": "Détails"},
"timestamp": {"en": "Timestamp", "fr": "Horodatage"},
"ipAddress": {"en": "IP Address", "fr": "Adresse IP"},
"userAgent": {"en": "User Agent", "fr": "User Agent"}
}
)
class User(BaseModel, ModelMixin):
"""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")
enabled: bool = Field(default=True, description="Indicates whether the user is enabled")
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")
# Register labels for User
register_model_labels(
"User",
{"en": "User", "fr": "Utilisateur"},
{
"id": {"en": "ID", "fr": "ID"},
"username": {"en": "Username", "fr": "Nom d'utilisateur"},
"email": {"en": "Email", "fr": "Email"},
"fullName": {"en": "Full Name", "fr": "Nom complet"},
"language": {"en": "Language", "fr": "Langue"},
"enabled": {"en": "Enabled", "fr": "Activé"},
"privilege": {"en": "Privilege", "fr": "Privilège"},
"authenticationAuthority": {"en": "Auth Authority", "fr": "Autorité d'authentification"},
"mandateId": {"en": "Mandate ID", "fr": "ID de mandat"}
}
)
class UserInDB(User):
"""Extended user class with password hash"""
hashedPassword: Optional[str] = Field(None, description="Hash of the user password")
# Register labels for UserInDB
register_model_labels(
"UserInDB",
{"en": "User Access", "fr": "Accès de l'utilisateur"},
{
"hashedPassword": {"en": "Password hash", "fr": "Hachage de mot de passe"}
}
)
# Token Models
class Token(BaseModel, ModelMixin):
"""Token model for all authentication types"""
id: Optional[str] = None
userId: str
authority: AuthAuthority
tokenAccess: str
tokenType: str = "bearer"
expiresAt: float
tokenRefresh: Optional[str] = None
createdAt: Optional[datetime] = None
class Config:
useEnumValues = True
# Register labels for Token
register_model_labels(
"Token",
{"en": "Token", "fr": "Jeton"},
{
"id": {"en": "ID", "fr": "ID"},
"userId": {"en": "User ID", "fr": "ID utilisateur"},
"authority": {"en": "Authority", "fr": "Autorité"},
"tokenAccess": {"en": "Access Token", "fr": "Jeton d'accès"},
"tokenType": {"en": "Token Type", "fr": "Type de jeton"},
"expiresAt": {"en": "Expires At", "fr": "Expire le"},
"tokenRefresh": {"en": "Refresh Token", "fr": "Jeton de rafraîchissement"},
"createdAt": {"en": "Created At", "fr": "Créé le"}
}
)
class LocalToken(Token):
"""Local authentication token model"""
pass
class GoogleToken(Token):
"""Google OAuth token model"""
pass
class MsftToken(Token):
"""Microsoft OAuth token model"""
pass