Files
chatballs/apps/backend/hub_platform/api/permissions.py
T
AndreyandClaude Fable 5.1 dbd7ae3150 🚚 chore: переименование Chatbolls → Chatballs во всём проекте
Бренд, API-схема, TOTP issuer, письма, тексты бота уведомлений, загрузчик виджета
(window.ChatballsChat, типы postMessage), ключи localStorage, id/параметры
виджета помощи, health-service, README, скрипты, демо (пароль
Chatballs-Demo-2026). Макеты в design/baseline не тронуты — это файлы владельца.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-05 21:43:33 +03:00

38 lines
1.4 KiB
Python

from django.conf import settings
from rest_framework.permissions import BasePermission
from rest_framework.request import Request
from rest_framework.views import APIView
from hub_platform.identity.policy import has_capability_any_scope
class HasCapability(BasePermission):
"""DRF entry-point guard backed by the shared role policy (SPEC-HUB-0031 §3).
Views declare ``required_capability`` or a method keyed
``required_capabilities`` mapping. Object/resource scope is still checked by the
view after loading the canonical resource.
"""
message = "Required capability is missing"
def has_permission(self, request: Request, view: APIView) -> bool:
capability = getattr(view, "required_capability", None)
by_method = getattr(view, "required_capabilities", {})
capability = by_method.get(request.method, capability)
if not capability:
return False
context = getattr(request, "tenant_context", None)
if context is None or context.membership is None:
return False
return has_capability_any_scope(context.membership, capability)
class CloudDeliveryOnly(BasePermission):
"""Guard tenant APIs that exist only in the managed Chatballs Cloud."""
message = "This operation is available only in Chatballs Cloud"
def has_permission(self, request: Request, view: APIView) -> bool:
return settings.CUS_DELIVERY_MODE == "CLOUD"