# Copyright (c) 2025 Patrick Motsch # All rights reserved. """ Dynamic Options API feature module. Provides dynamic options for frontend select/multiselect fields. """ import logging from typing import List, Dict, Any, Optional from modules.datamodels.datamodelUam import User logger = logging.getLogger(__name__) # Standard role definitions (fallback if database is not available) STANDARD_ROLES = [ {"value": "sysadmin", "label": {"en": "System Administrator", "fr": "Administrateur système"}}, {"value": "admin", "label": {"en": "Administrator", "fr": "Administrateur"}}, {"value": "user", "label": {"en": "User", "fr": "Utilisateur"}}, {"value": "viewer", "label": {"en": "Viewer", "fr": "Visualiseur"}}, ] # Authentication authority options AUTH_AUTHORITY_OPTIONS = [ {"value": "local", "label": {"en": "Local", "fr": "Local"}}, {"value": "google", "label": {"en": "Google", "fr": "Google"}}, {"value": "msft", "label": {"en": "Microsoft", "fr": "Microsoft"}}, ] # Connection status options # Note: Matches ConnectionStatus enum values (active, expired, revoked, pending) # Plus "error" for error states (not in enum but used in UI) CONNECTION_STATUS_OPTIONS = [ {"value": "active", "label": {"en": "Active", "fr": "Actif"}}, {"value": "expired", "label": {"en": "Expired", "fr": "Expiré"}}, {"value": "revoked", "label": {"en": "Revoked", "fr": "Révoqué"}}, {"value": "pending", "label": {"en": "Pending", "fr": "En attente"}}, {"value": "error", "label": {"en": "Error", "fr": "Erreur"}}, ] def getOptions(optionsName: str, services, currentUser: Optional[User] = None) -> List[Dict[str, Any]]: """ Get options for a given options name. Args: optionsName: Name of the options set to retrieve (e.g., "user.role", "user.connection") services: Services instance for data access currentUser: Optional current user for context-aware options Returns: List of option dictionaries with "value" and "label" keys Raises: ValueError: If optionsName is not recognized """ optionsNameLower = optionsName.lower() if optionsNameLower == "user.role": # Fetch roles from database if currentUser: try: roles = services.interfaceDbApp.getAllRoles() # Convert Role objects to options format options = [] for role in roles: # Use English description as label, fallback to roleLabel # Handle TextMultilingual object if hasattr(role.description, 'get_text'): # TextMultilingual object label = role.description.get_text('en') elif isinstance(role.description, dict): # Dict format (backward compatibility) label = role.description.get("en", role.roleLabel) else: # Fallback to roleLabel label = role.roleLabel options.append({ "value": role.roleLabel, "label": label }) # If no roles in database, return standard roles as fallback if options: return options except Exception as e: logger.warning(f"Error fetching roles from database, using fallback: {e}") # Fallback to standard roles if database fetch fails or no user context return STANDARD_ROLES elif optionsNameLower == "auth.authority": return AUTH_AUTHORITY_OPTIONS elif optionsNameLower == "connection.status": return CONNECTION_STATUS_OPTIONS elif optionsNameLower == "user.connection": # Dynamic options: Get user connections from database if not currentUser: return [] try: connections = services.interfaceDbApp.getUserConnections(currentUser.id) return [ { "value": conn.id, "label": { "en": f"{conn.authority.value} - {conn.externalUsername or conn.externalId}", "fr": f"{conn.authority.value} - {conn.externalUsername or conn.externalId}" } } for conn in connections ] except Exception as e: logger.error(f"Error fetching user connections for options: {e}") return [] else: raise ValueError(f"Unknown options name: {optionsName}") def getAvailableOptionsNames() -> List[str]: """ Get list of all available options names. Returns: List of available options names """ return [ "user.role", "auth.authority", "connection.status", "user.connection", ]