Permisos por pestana de reportes y ruido de serializacion en presencia
Auditoria de 260 visitas (26 rutas x 10 roles) sobre el build actual: 0 hallazgos.
Dos defectos reales que salieron del barrido anterior se corrigen aqui.
1) Reportes: la matriz guarda claves '/reportes?tab=x' y puede conceder una
pestana suelta (Horas agenda al medico, Exportar a cosmetologia) sin dar el
modulo. Nadie la respetaba:
- App.tsx: nuevo ReportesRoute que evalua la pestana del URL; si el rol no
tiene '/reportes' pero si alguna pestana, aterriza en la primera permitida.
- Reportes.tsx: familias, favoritos y el boton "Exportar datos" se filtran
por canSee('/reportes?tab=x'). 'exportar' no pertenece a ninguna familia,
por eso se lista en TABS_FUERA_DE_FAMILIA (si no, el guard lo reescribia a
'general' y admin perdia la vista). El query se sincroniza con lo renderizado.
- SkeenLayout/HomeNestLayout: "Horas agenda" y "Exportar datos" aparecen en
Analitica para que el permiso sea alcanzable desde el menu, no solo a
mano. Clasico ya los traia.
- auth.py: _medico_reporte_permitido consulta la matriz antes de vetar
/reports/ al medico. Sin ese puente el menu ofrecia la opcion y la API
respondia 403. Las demas rutas vetadas (sales, payments, wallets, pos)
siguen cerradas: verificado comisiones=403, horas-agenda=200.
2) skeen_chat/_touch: 211 "could not serialize access due to concurrent update"
en un barrido. Bandeja, badge y heartbeat salen en paralelo y cada uno
emitia el UPDATE de last_seen aunque no aplicara cambios, abortando la
transaccion de otra peticion. Se corta antes de tocar la fila cuando el
registro es reciente; el savepoint queda para el caso de empate exacto.
Ráfaga de 128 peticiones concurrentes: todas 200, presencia sigue
actualizando (online=true, last_seen avanza) y el ruido bajo de 211 a 5.
This commit is contained in:
@@ -15,7 +15,7 @@ import time
|
||||
|
||||
from odoo.http import request, Response
|
||||
|
||||
from ..roles import ROLE_RANKS
|
||||
from ..roles import ROLE_RANKS, get_menu_roles
|
||||
|
||||
TTL_SECONDS = 60 * 60 * 12 # 12 horas
|
||||
SECRET_KEY = 'skeen.frontend.secret'
|
||||
@@ -36,6 +36,26 @@ MEDICO_BLOCKED_PREFIXES = (
|
||||
)
|
||||
|
||||
|
||||
def _medico_reporte_permitido(env, path):
|
||||
"""True si la matriz de menus concede al medico ESA pestana de reportes.
|
||||
|
||||
El veto de 'medico' sobre /reports/ es por diseno (no ve dinero), pero la
|
||||
matriz permite habilitar pestañas puntuales (/reportes?tab=horas-agenda).
|
||||
Sin este puente el menu mostraria la opcion y la API la rechazaria con 403.
|
||||
Las demas rutas vetadas (sales, payments, wallets...) siguen cerradas.
|
||||
"""
|
||||
prefijo = '/skeen/frontend/v1/reports/'
|
||||
if not path.startswith(prefijo):
|
||||
return False
|
||||
tab = path[len(prefijo):].strip('/')
|
||||
if not tab or '/' in tab:
|
||||
return False
|
||||
matriz = get_menu_roles(env)
|
||||
if 'medico' in (matriz.get('/reportes') or []):
|
||||
return True
|
||||
return 'medico' in (matriz.get('/reportes?tab=%s' % tab) or [])
|
||||
|
||||
|
||||
def _cors_headers():
|
||||
return {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
@@ -156,7 +176,7 @@ def require_role(min_role='lectura'):
|
||||
request.httprequest.path == p or request.httprequest.path.startswith(
|
||||
p if p.endswith('/') else p + '/')
|
||||
for p in MEDICO_BLOCKED_PREFIXES
|
||||
):
|
||||
) and not _medico_reporte_permitido(request.env, request.httprequest.path):
|
||||
return _json({'status': 'error', 'message': 'Sin permiso'}, 403)
|
||||
request.frontend_user = user
|
||||
return func(self, *args, **kw)
|
||||
|
||||
Reference in New Issue
Block a user