Arch/middleware/permission_check.py

230 lines
9.6 KiB
Python

from functools import wraps
from flask import render_template, abort, current_app
from flask_login import current_user
def permission_required(min_level):
"""
Decorador para verificar nivel de permisos en rutas web.
Args:
min_level (int): Nivel mínimo requerido
Returns:
function: Decorador configurado
"""
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if not current_user.is_authenticated:
return current_app.login_manager.unauthorized()
if not current_user.has_permission(min_level):
return render_template('error.html',
error_code=403,
error_message="No tiene permisos suficientes para acceder a esta página."), 403
return f(*args, **kwargs)
return decorated_function
return decorator
def project_access_required(access_type='view'):
"""
Decorador para verificar acceso a un proyecto específico.
Args:
access_type (str): Tipo de acceso ('view' o 'edit')
Returns:
function: Decorador configurado
"""
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if not current_user.is_authenticated:
return current_app.login_manager.unauthorized()
# Obtener ID del proyecto de los argumentos
project_id = kwargs.get('project_id')
if not project_id:
abort(400, description="ID de proyecto no proporcionado")
# Verificar permisos específicos del proyecto
from services.project_service import get_project
project = get_project(project_id)
if not project:
abort(404, description="Proyecto no encontrado")
# Verificar si el proyecto está activo
if project.get('estado') != 'activo' and not current_user.has_permission(9000):
return render_template('error.html',
error_code=403,
error_message="El proyecto no está activo."), 403
# Verificar permisos específicos
# Administradores siempre tienen acceso
if current_user.has_permission(9000):
return f(*args, **kwargs)
# Verificar permisos en el archivo de permisos del proyecto
from utils.file_utils import load_json_file
import os
storage_path = current_app.config['STORAGE_PATH']
project_dir = os.path.join(storage_path, 'projects', project.get('directory', ''))
permissions_file = os.path.join(project_dir, 'permissions.json')
permissions = load_json_file(permissions_file, {})
# Verificar permisos específicos del usuario
user_permissions = permissions.get(current_user.id, {})
if access_type == 'edit' and user_permissions.get('can_edit', False):
return f(*args, **kwargs)
if access_type == 'view' and user_permissions.get('can_view', False):
return f(*args, **kwargs)
# Verificar nivel general requerido según el esquema
schema_code = project.get('esquema')
if not schema_code:
return render_template('error.html',
error_code=403,
error_message="No tiene permisos para acceder a este proyecto."), 403
from services.schema_service import get_schema
schema = get_schema(schema_code)
if not schema:
return render_template('error.html',
error_code=403,
error_message="Esquema no encontrado."), 403
# Nivel mínimo para ver/editar según el esquema
min_level_view = 0 # Por defecto, cualquier usuario autenticado puede ver
min_level_edit = 5000 # Por defecto, se requiere nivel de gestor para editar
# Si hay configuración específica en el esquema, usarla
if 'nivel_ver' in schema:
min_level_view = schema.get('nivel_ver', 0)
if 'nivel_editar' in schema:
min_level_edit = schema.get('nivel_editar', 5000)
# Verificar nivel según tipo de acceso
if access_type == 'edit' and current_user.has_permission(min_level_edit):
return f(*args, **kwargs)
if access_type == 'view' and current_user.has_permission(min_level_view):
return f(*args, **kwargs)
# Si llega aquí, no tiene permisos
return render_template('error.html',
error_code=403,
error_message="No tiene permisos para acceder a este proyecto."), 403
return decorated_function
return decorator
def document_access_required(access_type='view'):
"""
Decorador para verificar acceso a un documento específico.
Args:
access_type (str): Tipo de acceso ('view' o 'edit')
Returns:
function: Decorador configurado
"""
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if not current_user.is_authenticated:
return current_app.login_manager.unauthorized()
# Obtener IDs de proyecto y documento
project_id = kwargs.get('project_id')
document_id = kwargs.get('document_id')
if not project_id or not document_id:
abort(400, description="ID de proyecto o documento no proporcionado")
# Verificar permisos del proyecto primero
from services.project_service import get_project
project = get_project(project_id)
if not project:
abort(404, description="Proyecto no encontrado")
# Verificar si el proyecto está activo
if project.get('estado') != 'activo' and not current_user.has_permission(9000):
return render_template('error.html',
error_code=403,
error_message="El proyecto no está activo."), 403
# Administradores siempre tienen acceso
if current_user.has_permission(9000):
return f(*args, **kwargs)
# Obtener información del documento
from services.document_service import get_document
document = get_document(project_id, document_id)
if not document:
abort(404, description="Documento no encontrado")
# Obtener el esquema del proyecto
schema_code = project.get('esquema')
if not schema_code:
return render_template('error.html',
error_code=403,
error_message="No tiene permisos para acceder a este documento."), 403
# Cargar el esquema específico del proyecto
from utils.file_utils import load_json_file
import os
storage_path = current_app.config['STORAGE_PATH']
project_dir = os.path.join(storage_path, 'projects', project.get('directory', ''))
project_schema_file = os.path.join(project_dir, 'schema.json')
schema = load_json_file(project_schema_file)
if not schema:
# Si no hay esquema específico, usar el general
from services.schema_service import get_schema
schema = get_schema(schema_code)
if not schema:
return render_template('error.html',
error_code=403,
error_message="Esquema no encontrado."), 403
# Obtener el tipo de documento
document_name = document.get('document_id', '').split('_', 1)[1] if '_' in document.get('document_id', '') else ''
# Buscar configuración de permisos para este tipo de documento
for doc_type in schema.get('documentos', []):
if doc_type.get('nombre', '').lower().replace(' ', '_') == document_name:
# Verificar nivel según tipo de acceso
if access_type == 'edit' and current_user.has_permission(doc_type.get('nivel_editar', 5000)):
return f(*args, **kwargs)
if access_type == 'view' and current_user.has_permission(doc_type.get('nivel_ver', 0)):
return f(*args, **kwargs)
# Si no se encontró configuración específica o no tiene permisos
return render_template('error.html',
error_code=403,
error_message="No tiene permisos para acceder a este documento."), 403
return decorated_function
return decorator