feat(admin): Add API monitoring, debug console, and system health templates for enhanced admin interface docs: Add AI system cleanup summary and audit report detailing architecture, token management, and recommendations docs: Introduce credits and tokens system guide outlining configuration, data flow, and monitoring strategies
141 lines
5.4 KiB
Python
141 lines
5.4 KiB
Python
"""
|
|
Standardized Permission Classes
|
|
Provides consistent permission checking across all endpoints
|
|
"""
|
|
from rest_framework import permissions
|
|
from rest_framework.exceptions import PermissionDenied
|
|
|
|
|
|
class IsAuthenticatedAndActive(permissions.BasePermission):
|
|
"""
|
|
Permission class that requires user to be authenticated and active
|
|
Base permission for most endpoints
|
|
"""
|
|
def has_permission(self, request, view):
|
|
import logging
|
|
logger = logging.getLogger(__name__)
|
|
|
|
if not request.user or not request.user.is_authenticated:
|
|
logger.warning(f"[IsAuthenticatedAndActive] DENIED: User not authenticated")
|
|
return False
|
|
|
|
# Check if user is active
|
|
if hasattr(request.user, 'is_active'):
|
|
is_active = request.user.is_active
|
|
if is_active:
|
|
logger.info(f"[IsAuthenticatedAndActive] ALLOWED: User {request.user.email} is active")
|
|
else:
|
|
logger.warning(f"[IsAuthenticatedAndActive] DENIED: User {request.user.email} is inactive")
|
|
return is_active
|
|
|
|
logger.info(f"[IsAuthenticatedAndActive] ALLOWED: User {request.user.email} (no is_active check)")
|
|
return True
|
|
|
|
|
|
class HasTenantAccess(permissions.BasePermission):
|
|
"""
|
|
Permission class that requires user to belong to the tenant/account
|
|
Ensures tenant isolation
|
|
Superusers, developers, and system account users bypass this check.
|
|
|
|
CRITICAL: Every authenticated user MUST have an account.
|
|
The middleware sets request.account from request.user.account.
|
|
If a user doesn't have an account, it's a data integrity issue.
|
|
"""
|
|
def has_permission(self, request, view):
|
|
import logging
|
|
logger = logging.getLogger(__name__)
|
|
|
|
if not request.user or not request.user.is_authenticated:
|
|
logger.warning(f"[HasTenantAccess] DENIED: User not authenticated")
|
|
return False
|
|
|
|
# SIMPLIFIED LOGIC: Every authenticated user MUST have an account
|
|
# Middleware already set request.account from request.user.account
|
|
# Just verify it exists
|
|
if not hasattr(request.user, 'account'):
|
|
logger.warning(f"[HasTenantAccess] DENIED: User {request.user.email} has no account attribute")
|
|
return False
|
|
|
|
try:
|
|
# Access the account to trigger any lazy loading
|
|
user_account = request.user.account
|
|
if not user_account:
|
|
logger.warning(f"[HasTenantAccess] DENIED: User {request.user.email} has NULL account")
|
|
return False
|
|
|
|
# Success - user has a valid account
|
|
logger.info(f"[HasTenantAccess] ALLOWED: User {request.user.email} has account {user_account.name} (ID: {user_account.id})")
|
|
return True
|
|
except (AttributeError, Exception) as e:
|
|
# User doesn't have account relationship - data integrity issue
|
|
logger.warning(f"[HasTenantAccess] DENIED: User {request.user.email} account access failed: {e}")
|
|
return False
|
|
|
|
|
|
class IsViewerOrAbove(permissions.BasePermission):
|
|
"""
|
|
Permission class that requires viewer, editor, admin, or owner role
|
|
For read-only operations
|
|
"""
|
|
def has_permission(self, request, view):
|
|
import logging
|
|
logger = logging.getLogger(__name__)
|
|
|
|
if not request.user or not request.user.is_authenticated:
|
|
logger.warning(f"[IsViewerOrAbove] DENIED: User not authenticated")
|
|
return False
|
|
|
|
# Check user role
|
|
if hasattr(request.user, 'role'):
|
|
role = request.user.role
|
|
# viewer, editor, admin, owner all have access
|
|
allowed = role in ['viewer', 'editor', 'admin', 'owner']
|
|
if allowed:
|
|
logger.info(f"[IsViewerOrAbove] ALLOWED: User {request.user.email} has role {role}")
|
|
else:
|
|
logger.warning(f"[IsViewerOrAbove] DENIED: User {request.user.email} has invalid role {role}")
|
|
return allowed
|
|
|
|
# If no role system, allow authenticated users
|
|
logger.info(f"[IsViewerOrAbove] ALLOWED: User {request.user.email} (no role system)")
|
|
return True
|
|
|
|
|
|
class IsEditorOrAbove(permissions.BasePermission):
|
|
"""
|
|
Permission class that requires editor, admin, or owner role
|
|
For content operations
|
|
"""
|
|
def has_permission(self, request, view):
|
|
if not request.user or not request.user.is_authenticated:
|
|
return False
|
|
|
|
# Check user role
|
|
if hasattr(request.user, 'role'):
|
|
role = request.user.role
|
|
# editor, admin, owner have access
|
|
return role in ['editor', 'admin', 'owner']
|
|
|
|
# If no role system, allow authenticated users
|
|
return True
|
|
|
|
|
|
class IsAdminOrOwner(permissions.BasePermission):
|
|
"""
|
|
Permission class that requires admin or owner role only
|
|
For settings, keys, billing operations
|
|
"""
|
|
def has_permission(self, request, view):
|
|
if not request.user or not request.user.is_authenticated:
|
|
return False
|
|
|
|
# Check user role
|
|
if hasattr(request.user, 'role'):
|
|
role = request.user.role
|
|
# admin, owner have access
|
|
return role in ['admin', 'owner']
|
|
|
|
# If no role system, deny by default for security
|
|
return False
|