Skip to content

Copilot/sub pr 257#267

Merged
2-Coatl merged 5 commits into
developfrom
copilot/sub-pr-257
Nov 18, 2025
Merged

Copilot/sub pr 257#267
2-Coatl merged 5 commits into
developfrom
copilot/sub-pr-257

Conversation

@2-Coatl
Copy link
Copy Markdown
Collaborator

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

No description provided.

2-Coatl and others added 4 commits November 18, 2025 07:02
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings November 18, 2025 14:13
@2-Coatl 2-Coatl merged commit a9003a5 into develop Nov 18, 2025
6 of 32 checks passed
@2-Coatl 2-Coatl deleted the copilot/sub-pr-257 branch November 18, 2025 14:14
@chatgpt-codex-connector
Copy link
Copy Markdown

💡 Codex Review

https://github.com/2-Coatl/IACT/blob/fdf754a2bd17193869442ef7b19367a318a02f4b/api/callcentersite/callcentersite/apps/dashboard/services.py#L37-L38
P1 Badge ver_dashboard crashes on configs with widget dicts

Personalized dashboards saved via the REST endpoint store widget entries as dictionaries (views.py lines 83-87 persist the request payload directly). Lines 37-38 assume configuracion["widgets"] is a list of registry keys and do if widget in WIDGET_REGISTRY, which raises TypeError: unhashable type: 'dict' when the stored widgets are dicts, so any user who customized through the existing API will hit a 500 when calling ver_dashboard.


https://github.com/2-Coatl/IACT/blob/fdf754a2bd17193869442ef7b19367a318a02f4b/api/callcentersite/callcentersite/apps/dashboard/services.py#L143-L147
P1 Badge exportar_dashboard bypasses permission enforcement

The new exportar_dashboard entry point begins formatting at lines 143-147 and never calls UserManagementService.usuario_tiene_permiso or records an AuditoriaPermiso, unlike the existing exportar method above. Any caller—even one without sistema.vistas.dashboards.exportar—can export CSV/PDF without being blocked or audited.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

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 refactors the dashboard service by removing unused code, simplifying audit logging, and fixing a spelling error. However, it introduces critical bugs in the audit logging implementation.

Key changes:

  • Removed the _registrar_auditoria helper method and compartir_dashboard method
  • Replaced audit logging with direct AuditoriaPermiso.objects.create() calls
  • Changed widget serialization from a helper method to direct __dict__ access on dataclass instances
  • Fixed spelling error in validation message ("invalido" → "inválido")

Comment on lines +112 to +115
recurso_tipo='dashboard',
accion='exportar',
resultado='permitido',
detalles=f'Dashboard exportado a {formato}',
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 AuditoriaPermiso.objects.create() call uses fields (recurso_tipo, accion, resultado, detalles) that don't exist in the AuditoriaPermiso model. According to the model definition in callcentersite/apps/users/models_permisos_granular.py, the model has fields: usuario, capacidad_codigo, accion (with specific ACCION_CHOICES), resultado (with specific RESULTADO_CHOICES), ip_address, user_agent, contexto_adicional, and timestamp.

The correct approach would be to use the existing fields:

AuditoriaPermiso.objects.create(
    usuario_id=usuario_id,
    capacidad_codigo='sistema.vistas.dashboards.exportar',
    accion='acceso_permitido',  # from ACCION_CHOICES
    resultado='exito',  # from RESULTADO_CHOICES
    contexto_adicional={
        'recurso_tipo': 'dashboard',
        'accion_especifica': 'exportar',
        'formato': formato,
    },
)
Suggested change
recurso_tipo='dashboard',
accion='exportar',
resultado='permitido',
detalles=f'Dashboard exportado a {formato}',
accion='acceso_permitido', # must match ACCION_CHOICES
resultado='exito', # must match RESULTADO_CHOICES
contexto_adicional={
'recurso_tipo': 'dashboard',
'accion_especifica': 'exportar',
'formato': formato,
},

Copilot uses AI. Check for mistakes.
Comment on lines +228 to +232
recurso_tipo='dashboard',
accion='personalizar',
recurso_id=config.id,
resultado='permitido',
detalles=f'Dashboard personalizado. Widgets: {len(configuracion.get("widgets", []))}',
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 AuditoriaPermiso.objects.create() call uses fields (recurso_tipo, accion, recurso_id, resultado, detalles) that don't exist in the AuditoriaPermiso model. According to the model definition, the correct fields should be used with contexto_adicional for extra information:

AuditoriaPermiso.objects.create(
    usuario_id=usuario_id,
    capacidad_codigo='sistema.vistas.dashboards.personalizar',
    accion='acceso_permitido',  # from ACCION_CHOICES
    resultado='exito',  # from RESULTADO_CHOICES
    contexto_adicional={
        'recurso_tipo': 'dashboard',
        'accion_especifica': 'personalizar',
        'config_id': config.id,
        'widgets': configuracion.get('widgets', []),
    },
)
Suggested change
recurso_tipo='dashboard',
accion='personalizar',
recurso_id=config.id,
resultado='permitido',
detalles=f'Dashboard personalizado. Widgets: {len(configuracion.get("widgets", []))}',
accion='acceso_permitido', # from ACCION_CHOICES
resultado='exito', # from RESULTADO_CHOICES
contexto_adicional={
'recurso_tipo': 'dashboard',
'accion_especifica': 'personalizar',
'config_id': config.id,
'widgets': configuracion.get('widgets', []),
'detalles': f'Dashboard personalizado. Widgets: {len(configuracion.get("widgets", []))}',
},

Copilot uses AI. Check for mistakes.
Comment on lines +311 to +314
recurso_tipo='dashboard',
accion='compartir',
resultado='permitido',
detalles=f'Dashboard compartido con {tipo}: {compartido_con}',
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 AuditoriaPermiso.objects.create() call uses fields (recurso_tipo, accion, resultado, detalles) that don't exist in the AuditoriaPermiso model. According to the model definition, the correct fields should be used with contexto_adicional for extra information:

AuditoriaPermiso.objects.create(
    usuario_id=usuario_id,
    capacidad_codigo='sistema.vistas.dashboards.compartir',
    accion='acceso_permitido',  # from ACCION_CHOICES
    resultado='exito',  # from RESULTADO_CHOICES
    contexto_adicional={
        'recurso_tipo': 'dashboard',
        'accion_especifica': 'compartir',
        'destino_tipo': tipo,
        'destino': compartido_con,
    },
)
Suggested change
recurso_tipo='dashboard',
accion='compartir',
resultado='permitido',
detalles=f'Dashboard compartido con {tipo}: {compartido_con}',
accion='acceso_permitido', # from ACCION_CHOICES
resultado='exito', # from RESULTADO_CHOICES
contexto_adicional={
'recurso_tipo': 'dashboard',
'accion_especifica': 'compartir',
'destino_tipo': tipo,
'destino': compartido_con,
'detalles': f'Dashboard compartido con {tipo}: {compartido_con}',
},

Copilot uses AI. Check for mistakes.
Comment on lines +39 to +41
widgets = [WIDGET_REGISTRY[widget].__dict__ for widget in widget_keys if widget in WIDGET_REGISTRY]

if not widgets:
widgets = DashboardService._serialize_widgets(list(WIDGET_REGISTRY.keys()))
# No fallback to defaults if user's config exists but is invalid; respect explicit selection.
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 previous implementation had a fallback mechanism: if a user's configuration existed but was invalid (no widgets), it would fall back to default widgets. The new implementation removes this fallback (line 41 comment states "No fallback to defaults if user's config exists but is invalid").

This is a behavior change that could affect users with empty widget configurations. When widget_keys is an empty list and user has a configuration, widgets will be an empty list [] instead of falling back to defaults. This could result in users seeing an empty dashboard.

Consider either:

  1. Restoring the fallback behavior for better user experience
  2. Documenting this breaking change if it's intentional
  3. Adding validation to prevent saving empty widget configurations in personalizar_dashboard

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants