""" Prompt Service for Translation Story 3.12: Custom Prompts - Application lors Traduction LLM Provides functions to retrieve prompt content and validate access. """ import uuid import logging from typing import Optional, Tuple from database.connection import get_sync_session from database.models import CustomPrompt from utils.exceptions import PromptNotFoundError logger = logging.getLogger(__name__) def _validate_uuid(id_str: str, id_name: str = "ID") -> None: """ Validate that a string is a valid UUID. Args: id_str: String to validate id_name: Name of the ID for error messages Raises: PromptNotFoundError: If the string is not a valid UUID """ try: uuid.UUID(id_str) except (ValueError, AttributeError): raise PromptNotFoundError( message=f"{id_name} invalide.", details={id_name.lower(): id_str} ) def _get_prompt_record(prompt_id: str, user_id: str) -> Tuple[CustomPrompt, bool]: """ Internal helper to fetch a prompt record from the database. This is a shared function to avoid code duplication between get_prompt_content and validate_prompt_access. Args: prompt_id: UUID of the prompt user_id: UUID of the user (must own the prompt) Returns: Tuple of (CustomPrompt, was_logged) - was_logged indicates if access was already logged Raises: PromptNotFoundError: If prompt doesn't exist or doesn't belong to user """ # Validate UUIDs before querying database _validate_uuid(prompt_id, "prompt_id") _validate_uuid(user_id, "user_id") try: with get_sync_session() as session: prompt = ( session.query(CustomPrompt) .filter(CustomPrompt.id == prompt_id, CustomPrompt.user_id == user_id) .first() ) if not prompt: raise PromptNotFoundError( message="Prompt introuvable ou vous n'avez pas accès à cette ressource.", details={"prompt_id": prompt_id} ) return prompt, False except PromptNotFoundError: raise except Exception as e: logger.error(f"Error fetching prompt {prompt_id}: {e}") raise PromptNotFoundError( message="Erreur lors de la récupération du prompt.", details={"prompt_id": prompt_id, "error": str(e)} ) def get_prompt_content(prompt_id: str, user_id: str) -> str: """ Retrieve prompt content for a specific prompt owned by a user. Args: prompt_id: UUID of the prompt user_id: UUID of the user (must own the prompt) Returns: The prompt content string Raises: PromptNotFoundError: If prompt doesn't exist or doesn't belong to user """ prompt, _ = _get_prompt_record(prompt_id, user_id) logger.info( f"Retrieved prompt '{prompt.name}' ({prompt_id}) for user {user_id}" ) return prompt.content def validate_prompt_access(prompt_id: str, user_id: str) -> bool: """ Validate that a prompt exists and belongs to the user. Lightweight check before starting a translation job. Does NOT log to avoid duplicate log entries when followed by get_prompt_content. Args: prompt_id: UUID of the prompt user_id: UUID of the user (must own the prompt) Returns: True if prompt exists and belongs to user Raises: PromptNotFoundError: If prompt doesn't exist or doesn't belong to user """ _get_prompt_record(prompt_id, user_id) return True