fase 2.1: roles editables (modelo skeen.role) y permisos por accion (43 claves, 9 grupos) con enforcement en backend y gating en frontend; editor de roles/permisos/menus en Configuracion

This commit is contained in:
2026-10-11 07:32:29 +00:00
parent 75736967ef
commit 28a690aa0f
24 changed files with 1637 additions and 157 deletions

View File

@@ -42,6 +42,42 @@ ROLE_RANKS = {
'lectura': 10,
}
# ------------------------------------------------------------------
# Roles dinámicos (modelo skeen.role). ROLE_SELECTION/ROLE_RANKS quedan como
# respaldo para el arranque (antes de que la semilla XML esté disponible) y para
# no romper instalaciones viejas.
# ------------------------------------------------------------------
def role_records(env):
"""Registros de skeen.role (incluye inactivos) o lista vacía si no existe."""
try:
return env['skeen.role'].sudo().with_context(active_test=False).search([])
except KeyError:
return []
def role_selection(env):
"""[(code, name)] de los roles configurados, con respaldo estático."""
seleccion = [(r.code, r.name) for r in role_records(env) if r.code]
return seleccion or ROLE_SELECTION
def role_keys(env):
"""Códigos de rol válidos (incluye inactivos, para no invalidar históricos)."""
return tuple(k for k, _ in role_selection(env))
def role_rank_map(env):
"""{code: rank} de los roles configurados, con respaldo estático."""
mapa = {r.code: r.rank for r in role_records(env) if r.code}
return mapa or dict(ROLE_RANKS)
def min_rank(env, code):
"""Rango mínimo exigido por un código ('recepcion' -> 50 por defecto)."""
return role_rank_map(env).get(code, ROLE_RANKS.get(code, 10))
MENU_ROLES_KEY = 'skeen.menu_roles'
# ------------------------------------------------------------------
@@ -69,16 +105,30 @@ WRITE_RANK_MIN = 'recepcion'
# rango, no por nombre, para no duplicar la lista de roles.
# Mapa de cada acción de agenda al permiso por rol equivalente. El permiso de
# rol es el default; la lista propia del usuario (agenda_perms) lo pisa.
AGENDA_ROLE_PERM = {
'ver': 'agenda.ver',
'agendar': 'agenda.agendar',
'editar': 'agenda.editar',
'eliminar': 'agenda.eliminar',
'visitas': 'agenda.visitas',
}
def agenda_defaults_for(user):
"""Permisos de agenda por defecto de un usuario (sin lista propia)."""
ver = ['ver']
"""Permisos de agenda por defecto de un usuario (sin lista propia).
Se derivan de los permisos por acción del rol; 'ver' siempre se conserva.
"""
if user is None:
return list(ver)
if user.role == 'admin':
return list(AGENDA_PERM_KEYS)
if user.role_rank() >= ROLE_RANKS.get(WRITE_RANK_MIN, 50):
return list(AGENDA_PERM_KEYS)
return list(ver)
return ['ver']
from .permissions import resolve_role_perms_for_user
role_perms = resolve_role_perms_for_user(user)
acciones = [a for a, key in AGENDA_ROLE_PERM.items() if role_perms.get(key)]
if 'ver' not in acciones:
acciones.insert(0, 'ver')
return acciones
def resolve_agenda_perms(user):