""" Permissions для subscriptions модуля. """ from rest_framework import permissions from rest_framework.exceptions import PermissionDenied import logging logger = logging.getLogger(__name__) class IsSubscriptionOwner(permissions.BasePermission): """ Проверка что пользователь - владелец подписки. """ message = 'Только владелец подписки может выполнить это действие.' def has_object_permission(self, request, view, obj): """Проверка доступа к объекту.""" return obj.user == request.user class RequiresActiveSubscription(permissions.BasePermission): """ Проверка наличия активной подписки. Блокирует POST, PUT, PATCH, DELETE запросы, если подписка не активна. """ message = 'Требуется активная подписка' def has_permission(self, request, view): """Проверка разрешения на уровне запроса.""" # Разрешаем GET запросы (чтение) if request.method in permissions.SAFE_METHODS: return True # Проверяем только для менторов if not hasattr(request.user, 'role') or request.user.role != 'mentor': return True # Получаем активную подписку from .services import SubscriptionService from .models import Subscription from django.utils import timezone # Получаем все подписки пользователя all_subscriptions = Subscription.objects.filter( user=request.user, status__in=['trial', 'active'] ).order_by('-end_date') # Также проверяем истекшие подписки для диагностики expired_subscriptions = Subscription.objects.filter( user=request.user, status__in=['expired', 'past_due', 'cancelled'] ).order_by('-end_date') # Проверяем, есть ли действительно активная подписка active_subscription = None for sub in all_subscriptions: if sub.is_active(): active_subscription = sub break # Логируем для отладки logger.error( f"RequiresActiveSubscription: {request.method} {request.path}, " f"user={request.user.id}, has_active={active_subscription is not None}" ) # Если нет активной подписки, блокируем запрос if not active_subscription: # Получаем информацию о подписке для сообщения об ошибке from apps.users.models import Client current_clients_count = Client.objects.filter(mentors=request.user).count() # Если подписка есть, но истекла expired_subscription = expired_subscriptions.first() if expired_subscriptions.exists() else None if expired_subscription: logger.error( f"❌ BLOCKING: {request.method} {request.path}, " f"user={request.user.id} - subscription expired (id={expired_subscription.id})" ) # Используем стандартный формат DRF для PermissionDenied # PermissionDenied принимает detail как строку, дополнительные данные добавляем через атрибуты error = PermissionDenied( detail='Ваша подписка истекла. Для продолжения работы необходимо продлить подписку.' ) # Добавляем дополнительные данные в error для обработки в exception handler error.detail_dict = { 'error': 'Подписка истекла', 'detail': 'Ваша подписка истекла. Для продолжения работы необходимо продлить подписку.', 'subscription_id': expired_subscription.id, 'end_date': expired_subscription.end_date.strftime('%Y-%m-%d') if expired_subscription.end_date else None, 'current_students': current_clients_count, 'paid_students': expired_subscription.student_count if expired_subscription.plan.subscription_type == 'per_student' else None, 'requires_renewal': True } raise error else: logger.error( f"❌ BLOCKING: {request.method} {request.path}, " f"user={request.user.id} - no active subscription" ) error = PermissionDenied( detail='Для использования платформы необходимо оформить подписку. Пожалуйста, перейдите на страницу подписок и выберите подходящий тариф.' ) error.detail_dict = { 'error': 'Требуется активная подписка', 'detail': 'Для использования платформы необходимо оформить подписку. Пожалуйста, перейдите на страницу подписок и выберите подходящий тариф.' } raise error return True