mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-05-03 10:50:10 -05:00
90dde470da
- Normalize line endings from CRLF to LF across all files to match .editorconfig - Standardize quote style from single quotes to double quotes - Normalize whitespace and formatting throughout codebase - Apply consistent code style across 372 files including: * Application code (models, routes, services, utils) * Test files * Configuration files * CI/CD workflows This ensures consistency with the project's .editorconfig settings and improves code maintainability.
186 lines
5.0 KiB
Python
186 lines
5.0 KiB
Python
"""Utilities for permission checking and decorators"""
|
|
|
|
from functools import wraps
|
|
from flask import flash, redirect, url_for, abort
|
|
from flask_login import current_user
|
|
from flask_babel import gettext as _
|
|
|
|
|
|
def permission_required(*permissions, require_all=False):
|
|
"""
|
|
Decorator to require one or more permissions.
|
|
|
|
Args:
|
|
*permissions: Permission name(s) required
|
|
require_all: If True, user must have ALL permissions. If False, user needs ANY permission.
|
|
|
|
Example:
|
|
@permission_required('edit_projects')
|
|
def edit_project():
|
|
...
|
|
|
|
@permission_required('view_reports', 'export_reports', require_all=True)
|
|
def export_report():
|
|
...
|
|
"""
|
|
|
|
def decorator(f):
|
|
@wraps(f)
|
|
def decorated_function(*args, **kwargs):
|
|
if not current_user.is_authenticated:
|
|
flash(_("Please log in to access this page"), "error")
|
|
return redirect(url_for("auth.login"))
|
|
|
|
# Check if user has required permissions
|
|
if require_all:
|
|
has_access = current_user.has_all_permissions(*permissions)
|
|
else:
|
|
has_access = current_user.has_any_permission(*permissions)
|
|
|
|
if not has_access:
|
|
flash(_("You do not have permission to access this page"), "error")
|
|
abort(403)
|
|
|
|
return f(*args, **kwargs)
|
|
|
|
return decorated_function
|
|
|
|
return decorator
|
|
|
|
|
|
def admin_or_permission_required(*permissions):
|
|
"""
|
|
Decorator that allows access if user is an admin OR has any of the specified permissions.
|
|
This is useful for gradual migration from admin-only to permission-based access.
|
|
|
|
Example:
|
|
@admin_or_permission_required('delete_projects')
|
|
def delete_project():
|
|
...
|
|
"""
|
|
|
|
def decorator(f):
|
|
@wraps(f)
|
|
def decorated_function(*args, **kwargs):
|
|
if not current_user.is_authenticated:
|
|
flash(_("Please log in to access this page"), "error")
|
|
return redirect(url_for("auth.login"))
|
|
|
|
# Allow access if user is admin or has any of the required permissions
|
|
if current_user.is_admin or current_user.has_any_permission(*permissions):
|
|
return f(*args, **kwargs)
|
|
|
|
flash(_("You do not have permission to access this page"), "error")
|
|
abort(403)
|
|
|
|
return decorated_function
|
|
|
|
return decorator
|
|
|
|
|
|
def check_permission(user, permission_name):
|
|
"""
|
|
Check if a user has a specific permission.
|
|
|
|
Args:
|
|
user: User object
|
|
permission_name: Name of the permission to check
|
|
|
|
Returns:
|
|
bool: True if user has the permission, False otherwise
|
|
"""
|
|
if not user or not user.is_authenticated:
|
|
return False
|
|
|
|
return user.has_permission(permission_name)
|
|
|
|
|
|
def check_any_permission(user, *permission_names):
|
|
"""
|
|
Check if a user has any of the specified permissions.
|
|
|
|
Args:
|
|
user: User object
|
|
*permission_names: Names of permissions to check
|
|
|
|
Returns:
|
|
bool: True if user has any of the permissions, False otherwise
|
|
"""
|
|
if not user or not user.is_authenticated:
|
|
return False
|
|
|
|
return user.has_any_permission(*permission_names)
|
|
|
|
|
|
def check_all_permissions(user, *permission_names):
|
|
"""
|
|
Check if a user has all of the specified permissions.
|
|
|
|
Args:
|
|
user: User object
|
|
*permission_names: Names of permissions to check
|
|
|
|
Returns:
|
|
bool: True if user has all of the permissions, False otherwise
|
|
"""
|
|
if not user or not user.is_authenticated:
|
|
return False
|
|
|
|
return user.has_all_permissions(*permission_names)
|
|
|
|
|
|
def get_user_permissions(user):
|
|
"""
|
|
Get all permissions for a user.
|
|
|
|
Args:
|
|
user: User object
|
|
|
|
Returns:
|
|
list: List of Permission objects
|
|
"""
|
|
if not user:
|
|
return []
|
|
|
|
return user.get_all_permissions()
|
|
|
|
|
|
def get_user_permission_names(user):
|
|
"""
|
|
Get all permission names for a user.
|
|
|
|
Args:
|
|
user: User object
|
|
|
|
Returns:
|
|
list: List of permission name strings
|
|
"""
|
|
if not user:
|
|
return []
|
|
|
|
permissions = user.get_all_permissions()
|
|
return [p.name for p in permissions]
|
|
|
|
|
|
# Template helper functions (register these in app context)
|
|
def init_permission_helpers(app):
|
|
"""
|
|
Initialize permission helper functions for use in templates.
|
|
|
|
Usage in templates:
|
|
{% if has_permission('edit_projects') %}
|
|
<button>Edit Project</button>
|
|
{% endif %}
|
|
"""
|
|
|
|
@app.context_processor
|
|
def inject_permission_helpers():
|
|
return {
|
|
"has_permission": lambda perm: check_permission(current_user, perm),
|
|
"has_any_permission": lambda *perms: check_any_permission(current_user, *perms),
|
|
"has_all_permissions": lambda *perms: check_all_permissions(current_user, *perms),
|
|
"get_user_permissions": lambda: (
|
|
get_user_permission_names(current_user) if current_user.is_authenticated else []
|
|
),
|
|
}
|