fix(ai-suggestions): mejora manejo de errores y permisos

Mejoras en frontend TypeScript:
- Agrega notificaciones de error al usuario usando ToastService cuando falla
  la carga de metadatos (tags, correspondents, document types, etc.)
- Mantiene console.error para debugging pero ahora también muestra mensajes
  visibles al usuario
- Mensajes localizados con $localize para soporte multiidioma

Mejoras en backend Python:
- Agrega CanApplyAISuggestionsPermission al action apply_suggestion
- Mejora logging de errores con información específica sobre qué objeto
  no se encontró y qué usuario intentó aplicar la sugerencia
- Separa las excepciones DoesNotExist para proporcionar mensajes de error
  más específicos (Tag, Correspondent, DocumentType, StoragePath)
- Agrega comentarios explicativos sobre validación de permisos

Estos cambios aseguran que:
1. Los usuarios reciben feedback visible cuando algo falla
2. Se verifican permisos apropiados antes de aplicar sugerencias AI
3. Los logs contienen información detallada para debugging
4. Los mensajes de error son específicos y útiles

Relacionado con: mejoras de CI/CD y calidad de código
This commit is contained in:
Claude 2025-11-18 06:53:33 +00:00
parent c61a000597
commit b3969464b1
No known key found for this signature in database
2 changed files with 56 additions and 8 deletions

View file

@ -140,6 +140,9 @@ export class AiSuggestionsPanelComponent implements OnChanges, OnDestroy {
takeUntil(this.destroy$),
catchError((error) => {
console.error('Failed to load tags:', error)
this.toastService.showError(
$localize`Failed to load tags for AI suggestions. Please refresh the page.`
)
return of({ results: [] })
})
)
@ -160,6 +163,9 @@ export class AiSuggestionsPanelComponent implements OnChanges, OnDestroy {
takeUntil(this.destroy$),
catchError((error) => {
console.error('Failed to load correspondents:', error)
this.toastService.showError(
$localize`Failed to load correspondents for AI suggestions. Please refresh the page.`
)
return of({ results: [] })
})
)
@ -180,6 +186,9 @@ export class AiSuggestionsPanelComponent implements OnChanges, OnDestroy {
takeUntil(this.destroy$),
catchError((error) => {
console.error('Failed to load document types:', error)
this.toastService.showError(
$localize`Failed to load document types for AI suggestions. Please refresh the page.`
)
return of({ results: [] })
})
)
@ -200,6 +209,9 @@ export class AiSuggestionsPanelComponent implements OnChanges, OnDestroy {
takeUntil(this.destroy$),
catchError((error) => {
console.error('Failed to load storage paths:', error)
this.toastService.showError(
$localize`Failed to load storage paths for AI suggestions. Please refresh the page.`
)
return of({ results: [] })
})
)
@ -220,6 +232,9 @@ export class AiSuggestionsPanelComponent implements OnChanges, OnDestroy {
takeUntil(this.destroy$),
catchError((error) => {
console.error('Failed to load custom fields:', error)
this.toastService.showError(
$localize`Failed to load custom fields for AI suggestions. Please refresh the page.`
)
return of({ results: [] })
})
)

View file

@ -1413,17 +1413,24 @@ class UnifiedSearchViewSet(DocumentViewSet):
status=500,
)
@action(detail=True, methods=["POST"], name="Apply AI Suggestion")
@action(
detail=True,
methods=["POST"],
name="Apply AI Suggestion",
permission_classes=[IsAuthenticated, CanApplyAISuggestionsPermission],
)
def apply_suggestion(self, request, pk=None):
"""
Apply an AI suggestion to a document.
Records user feedback and applies the suggested change.
Requires 'can_apply_ai_suggestions' permission.
"""
from documents.models import AISuggestionFeedback
from documents.serializers.ai_suggestions import ApplySuggestionSerializer
try:
# Check permissions - get_object() validates object-level permissions
document = self.get_object()
# Validate input
@ -1496,14 +1503,40 @@ class UnifiedSearchViewSet(DocumentViewSet):
status=400,
)
except (
Tag.DoesNotExist,
Correspondent.DoesNotExist,
DocumentType.DoesNotExist,
StoragePath.DoesNotExist,
):
except Tag.DoesNotExist:
logger.error(
f"Tag {value_id} not found when applying suggestion to document {pk} "
f"by user {request.user.username}",
)
return Response(
{"detail": "Referenced object not found"},
{"detail": f"Tag with ID {value_id} not found"},
status=404,
)
except Correspondent.DoesNotExist:
logger.error(
f"Correspondent {value_id} not found when applying suggestion to document {pk} "
f"by user {request.user.username}",
)
return Response(
{"detail": f"Correspondent with ID {value_id} not found"},
status=404,
)
except DocumentType.DoesNotExist:
logger.error(
f"DocumentType {value_id} not found when applying suggestion to document {pk} "
f"by user {request.user.username}",
)
return Response(
{"detail": f"Document type with ID {value_id} not found"},
status=404,
)
except StoragePath.DoesNotExist:
logger.error(
f"StoragePath {value_id} not found when applying suggestion to document {pk} "
f"by user {request.user.username}",
)
return Response(
{"detail": f"Storage path with ID {value_id} not found"},
status=404,
)
except Exception as e: