Skip to content

fix: safeguard dashboard audit logging#258

Merged
2-Coatl merged 1 commit intodevelopfrom
feature/analyze-and-implement-api-according-to-docs/backend-13-23-28
Nov 18, 2025
Merged

fix: safeguard dashboard audit logging#258
2-Coatl merged 1 commit intodevelopfrom
feature/analyze-and-implement-api-according-to-docs/backend-13-23-28

Conversation

@2-Coatl
Copy link
Copy Markdown
Collaborator

@2-Coatl 2-Coatl commented Nov 18, 2025

Summary

  • add a reusable audit helper in dashboard services to skip logging when the audit table is unavailable
  • update dashboard export, personalize, and sharing flows to log using supported fields and structured context

Testing

  • pytest tests/dashboard/test_casos_uso_dashboard.py -q
  • pytest tests/dashboard/test_api_rest_dashboard.py -q

Codex Task

Copilot AI review requested due to automatic review settings November 18, 2025 13:23
@2-Coatl 2-Coatl merged commit 41cc11a into develop Nov 18, 2025
8 of 34 checks passed
@2-Coatl 2-Coatl deleted the feature/analyze-and-implement-api-according-to-docs/backend-13-23-28 branch November 18, 2025 13:23
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR safeguards dashboard audit logging by introducing a reusable helper method that safely handles cases where the audit table is unavailable. It also adds new dashboard functionality and refactors existing audit logging calls to use a more structured context-based approach.

Key changes:

  • New _registrar_auditoria helper method with table existence check
  • Addition of ver_dashboard, personalizar_dashboard, compartir_dashboard, and exportar_dashboard methods
  • Refactored exportar, personalizar, and compartir methods to use new audit helper and structured context

) -> None:
"""Registra auditoría de forma segura sólo si la tabla existe."""

if AuditoriaPermiso._meta.db_table not in connection.introspection.table_names():
Copy link

Copilot AI Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The connection.introspection.table_names() call queries the database on every audit log attempt. This can become a performance bottleneck. Consider caching the result or using a try-except block with AuditoriaPermiso.objects.create() instead, which will be more efficient in production where the table typically exists.

Copilot uses AI. Check for mistakes.

widgets_invalidos = [widget for widget in widgets if widget not in WIDGET_REGISTRY]
if widgets_invalidos:
raise ValidationError(f"Widget invalido: {', '.join(widgets_invalidos)}")
Copy link

Copilot AI Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected spelling of 'invalido' to 'inválido'.

Suggested change
raise ValidationError(f"Widget invalido: {', '.join(widgets_invalidos)}")
raise ValidationError(f"Widget inválido: {', '.join(widgets_invalidos)}")

Copilot uses AI. Check for mistakes.
ValidationError: Si el formato es inválido.
"""
if formato not in {"csv", "pdf"}:
raise ValidationError("Formato invalido. Use csv o pdf")
Copy link

Copilot AI Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected spelling of 'invalido' to 'inválido'.

Suggested change
raise ValidationError("Formato invalido. Use csv o pdf")
raise ValidationError("Formato inválido. Use csv o pdf")

Copilot uses AI. Check for mistakes.
Comment on lines +218 to +220
def exportar_dashboard(usuario_id: int, formato: str = 'csv') -> Union[str, bytes]:
"""Exporta el dashboard del usuario en formato CSV o PDF.

Copy link

Copilot AI Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exportar_dashboard method (lines 218-253) and the existing exportar method (lines 94-146) provide overlapping export functionality but with different implementations. The exportar method returns metadata with a file path, while exportar_dashboard returns the actual file content. This duplication creates confusion about which method to use. Consider consolidating these methods or clearly documenting their different use cases and renaming them to reflect their distinct purposes (e.g., exportar_metadata vs exportar_contenido).

Suggested change
def exportar_dashboard(usuario_id: int, formato: str = 'csv') -> Union[str, bytes]:
"""Exporta el dashboard del usuario en formato CSV o PDF.
def exportar_contenido(usuario_id: int, formato: str = 'csv') -> Union[str, bytes]:
"""
Exporta el contenido del dashboard del usuario en formato CSV o PDF.
Este método retorna el contenido directamente (CSV como str, PDF como bytes).
Úselo cuando se requiera el archivo para descarga directa o envío.
Para obtener sólo metadatos o la ruta del archivo exportado, use `exportar_metadata`.

Copilot uses AI. Check for mistakes.

if formato == "csv":
output = StringIO()
writer = csv.DictWriter(output, fieldnames=["type", "title", "value", "change", "period"])
Copy link

Copilot AI Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CSV fieldnames are hardcoded, making this code fragile if the Widget dataclass structure changes. Consider deriving fieldnames dynamically from the Widget dataclass fields (e.g., using Widget.__dataclass_fields__.keys() or asdict(Widget(...)).keys()) to maintain consistency with the Widget definition.

Suggested change
writer = csv.DictWriter(output, fieldnames=["type", "title", "value", "change", "period"])
writer = csv.DictWriter(output, fieldnames=list(Widget.__dataclass_fields__.keys()))

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants