Sep 16 - Optimize code, part 1
This commit is contained in:
+57
-1
@@ -16,7 +16,7 @@ from datetime import datetime, date, time, timedelta
|
||||
from functools import wraps
|
||||
|
||||
import qrcode
|
||||
from flask import session, redirect, flash, request, url_for
|
||||
from flask import session, redirect, flash, request, url_for, jsonify
|
||||
from user_agents import parse
|
||||
|
||||
from extensions import logger_handler
|
||||
@@ -323,6 +323,62 @@ def staff_or_admin_required(f):
|
||||
return decorated_function
|
||||
|
||||
|
||||
# Role sets for areas the sidebar only offers to some roles. Enforced on the
|
||||
# server so a user cannot reach them by typing the URL (base_authenticated.html
|
||||
# is the reference for who sees what).
|
||||
PAYROLL_AREA_ROLES = ('admin', 'payroll', 'accounting') # Time Attendance, Legacy, Employees, Statistics
|
||||
QR_MANAGEMENT_ROLES = ('admin', 'staff', 'payroll', 'accounting') # create / edit / bulk-import QR codes
|
||||
|
||||
|
||||
def _wants_json_response():
|
||||
"""API and fetch() callers get JSON errors instead of a redirect to an HTML page."""
|
||||
return (request.path.startswith('/api/')
|
||||
or request.headers.get('X-Requested-With') == 'XMLHttpRequest'
|
||||
or request.accept_mimetypes.best == 'application/json')
|
||||
|
||||
|
||||
def _role_denied_response(allowed_roles):
|
||||
"""None when the logged-in user's role is allowed; otherwise the response to return."""
|
||||
if 'user_id' not in session:
|
||||
if _wants_json_response():
|
||||
return jsonify({'success': False, 'error': 'Authentication required'}), 401
|
||||
flash('Please log in to access this page.', 'error')
|
||||
return redirect(url_for('auth.login'))
|
||||
|
||||
role = session.get('role')
|
||||
if role in allowed_roles:
|
||||
return None
|
||||
|
||||
logger_handler.logger.warning(
|
||||
f"Access denied: user {session.get('username')} (role {role}) -> {request.endpoint}"
|
||||
)
|
||||
if _wants_json_response():
|
||||
return jsonify({'success': False, 'error': 'Access denied'}), 403
|
||||
flash('You do not have permission to access that page.', 'error')
|
||||
return redirect(url_for('dashboard.dashboard'))
|
||||
|
||||
|
||||
def roles_required(*allowed_roles):
|
||||
"""Decorator: the user must be logged in with one of allowed_roles."""
|
||||
def decorator(f):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
denied = _role_denied_response(allowed_roles)
|
||||
if denied is not None:
|
||||
return denied
|
||||
return f(*args, **kwargs)
|
||||
return decorated_function
|
||||
return decorator
|
||||
|
||||
|
||||
def restrict_blueprint_to_roles(blueprint, allowed_roles):
|
||||
"""Apply the role check to every route of a blueprint (one line per module)."""
|
||||
@blueprint.before_request
|
||||
def _enforce_blueprint_roles():
|
||||
return _role_denied_response(allowed_roles)
|
||||
return blueprint
|
||||
|
||||
|
||||
def is_admin_user(user_id):
|
||||
"""Helper function to safely check if user is admin"""
|
||||
from extensions import db
|
||||
|
||||
Reference in New Issue
Block a user