Copilot/sub pr 257#267
Conversation
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
💡 Codex Reviewhttps://github.com/2-Coatl/IACT/blob/fdf754a2bd17193869442ef7b19367a318a02f4b/api/callcentersite/callcentersite/apps/dashboard/services.py#L37-L38 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 https://github.com/2-Coatl/IACT/blob/fdf754a2bd17193869442ef7b19367a318a02f4b/api/callcentersite/callcentersite/apps/dashboard/services.py#L143-L147 The new ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
There was a problem hiding this comment.
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_auditoriahelper method andcompartir_dashboardmethod - 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")
| recurso_tipo='dashboard', | ||
| accion='exportar', | ||
| resultado='permitido', | ||
| detalles=f'Dashboard exportado a {formato}', |
There was a problem hiding this comment.
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,
},
)| 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, | |
| }, |
| recurso_tipo='dashboard', | ||
| accion='personalizar', | ||
| recurso_id=config.id, | ||
| resultado='permitido', | ||
| detalles=f'Dashboard personalizado. Widgets: {len(configuracion.get("widgets", []))}', |
There was a problem hiding this comment.
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', []),
},
)| 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", []))}', | |
| }, |
| recurso_tipo='dashboard', | ||
| accion='compartir', | ||
| resultado='permitido', | ||
| detalles=f'Dashboard compartido con {tipo}: {compartido_con}', |
There was a problem hiding this comment.
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,
},
)| 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}', | |
| }, |
| 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. |
There was a problem hiding this comment.
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:
- Restoring the fallback behavior for better user experience
- Documenting this breaking change if it's intentional
- Adding validation to prevent saving empty widget configurations in
personalizar_dashboard
No description provided.