from fastapi import APIRouter, HTTPException, Depends, Body, Path from typing import List, Dict, Any from fastapi import status from datetime import datetime from dataclasses import dataclass # Import interfaces from modules.auth import get_current_active_user, get_user_context from modules.gateway_interface import get_gateway_interface from modules.gateway_model import Mandate # Determine all attributes of the model (except internal/special attributes) def get_model_attributes(model_class): return [attr for attr in dir(model_class) if not callable(getattr(model_class, attr)) and not attr.startswith('_') and attr != 'metadata' and attr != 'query' and attr != 'query_class' and attr != 'label' and attr != 'field_labels'] # Model attributes for Mandate mandate_attributes = get_model_attributes(Mandate) @dataclass class AppContext: """Context object for all required connections and user information""" mandate_id: int user_id: int interface_data: Any # Gateway Interface async def get_context(current_user: Dict[str, Any]) -> AppContext: """ Creates a central context object with all required interfaces Args: current_user: Current user from authentication Returns: AppContext object with all required connections """ mandate_id, user_id = await get_user_context(current_user) interface_data = get_gateway_interface(mandate_id, user_id) return AppContext( mandate_id=mandate_id, user_id=user_id, interface_data=interface_data ) # Create router for mandate endpoints router = APIRouter( prefix="/api/mandates", tags=["Mandates"], responses={404: {"description": "Not found"}} ) @router.get("", response_model=List[Dict[str, Any]]) async def get_mandates(current_user: Dict[str, Any] = Depends(get_current_active_user)): """Get all available mandates (only for SysAdmin users)""" context = await get_context(current_user) # Permission check if current_user.get("privilege") != "sysadmin": raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Only system administrators can access all mandates" ) # Get mandates generically return context.interface_data.get_all_mandates() @router.post("", response_model=Dict[str, Any]) async def create_mandate( mandate: Dict[str, Any] = Body(...), current_user: Dict[str, Any] = Depends(get_current_active_user) ): """Create a new mandate (only for SysAdmin users)""" context = await get_context(current_user) # Permission check if current_user.get("privilege") != "sysadmin": raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Only system administrators can create mandates" ) # Set attributes from the request dynamically mandate_data = {} for attr in mandate_attributes: if attr in mandate: mandate_data[attr] = mandate[attr] # Default values for missing fields if "name" not in mandate_data: mandate_data["name"] = "New Mandate" if "language" not in mandate_data: mandate_data["language"] = "de" # Create mandate new_mandate = context.interface_data.create_mandate(**mandate_data) return new_mandate @router.get("/{mandate_id}", response_model=Dict[str, Any]) async def get_mandate( mandate_id: int, current_user: Dict[str, Any] = Depends(get_current_active_user) ): """Get a specific mandate""" context = await get_context(current_user) # Permission check # Admin can only see their own mandate, SysAdmin can see all is_admin = current_user.get("privilege") == "admin" is_sysadmin = current_user.get("privilege") == "sysadmin" is_own_mandate = context.mandate_id == mandate_id if (is_admin and not is_own_mandate) and not is_sysadmin: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="No permission to access this mandate" ) # Get mandate generically mandate = context.interface_data.get_mandate(mandate_id) if not mandate: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Mandate with ID {mandate_id} not found" ) return mandate @router.put("/{mandate_id}", response_model=Dict[str, Any]) async def update_mandate( mandate_id: int = Path(..., description="ID of the mandate to update"), mandate_data: Dict[str, Any] = Body(..., description="Updated mandate data"), current_user: Dict[str, Any] = Depends(get_current_active_user) ): """Update an existing mandate""" context = await get_context(current_user) # Mandate exists? mandate = context.interface_data.get_mandate(mandate_id) if not mandate: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Mandate with ID {mandate_id} not found" ) # Permission check is_admin = current_user.get("privilege") == "admin" is_sysadmin = current_user.get("privilege") == "sysadmin" is_own_mandate = context.mandate_id == mandate_id if (is_admin and not is_own_mandate) and not is_sysadmin: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="No permission to update this mandate" ) # Dynamically filter attributes from the request into update_data update_data = {} for attr in mandate_attributes: if attr in mandate_data: update_data[attr] = mandate_data[attr] # Update mandate updated_mandate = context.interface_data.update_mandate( mandate_id=mandate_id, mandate_data=update_data ) return updated_mandate @router.delete("/{mandate_id}", status_code=status.HTTP_204_NO_CONTENT) async def delete_mandate( mandate_id: int = Path(..., description="ID of the mandate to delete"), current_user: Dict[str, Any] = Depends(get_current_active_user) ): """Delete a mandate, including all associated users and referenced objects""" context = await get_context(current_user) # Mandate exists? mandate = context.interface_data.get_mandate(mandate_id) if not mandate: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Mandate with ID {mandate_id} not found" ) # Permission check is_admin = current_user.get("privilege") == "admin" is_sysadmin = current_user.get("privilege") == "sysadmin" is_own_mandate = context.mandate_id == mandate_id if (is_admin and not is_own_mandate) and not is_sysadmin: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="No permission to delete this mandate" ) # Delete mandate success = context.interface_data.delete_mandate(mandate_id) if not success: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Error deleting mandate with ID {mandate_id}" ) # Return no content on successful deletion return None