mirror of
https://github.com/dartdavros/chatballs.git
synced 2026-10-05 09:14:58 +03:00
Бренд, 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>
38 lines
1.4 KiB
Python
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"
|