- Add Model Mixins: TimestampMixin, SoftDeleteMixin, AuditMixin, etc. - Add Base Services: BaseService, BulkOperationsMixin, QueryOptimizerMixin - Add Base ViewSets with bulk operations - Add BackgroundJob model for Celery task tracking - Add BaseAppCommand for management commands - Add permissions, pagination, filters, cache, logging - Migrate tests to factory_boy + faker - Add CHANGELOG.md - 297 tests passing
129 lines
4.9 KiB
Python
129 lines
4.9 KiB
Python
"""
|
||
Базовые классы разрешений для API.
|
||
|
||
Предоставляет переиспользуемые permission classes для контроля доступа.
|
||
"""
|
||
|
||
from rest_framework import permissions
|
||
from rest_framework.request import Request
|
||
from rest_framework.views import APIView
|
||
|
||
|
||
class IsOwner(permissions.BasePermission):
|
||
"""
|
||
Разрешает доступ только владельцу объекта.
|
||
|
||
Объект должен иметь атрибут `user` или `owner`,
|
||
который сравнивается с текущим пользователем.
|
||
|
||
Пример использования:
|
||
class MyView(APIView):
|
||
permission_classes = [IsAuthenticated, IsOwner]
|
||
"""
|
||
|
||
owner_field = "user" # Можно переопределить в подклассах
|
||
|
||
def has_object_permission(self, request: Request, view: APIView, obj) -> bool:
|
||
"""Проверяет, является ли пользователь владельцем объекта."""
|
||
owner = getattr(obj, self.owner_field, None)
|
||
if owner is None:
|
||
owner = getattr(obj, "owner", None)
|
||
return owner == request.user
|
||
|
||
|
||
class IsOwnerOrReadOnly(permissions.BasePermission):
|
||
"""
|
||
Разрешает изменение только владельцу, остальным - только чтение.
|
||
|
||
SAFE_METHODS (GET, HEAD, OPTIONS) доступны всем аутентифицированным.
|
||
Изменяющие методы (POST, PUT, PATCH, DELETE) - только владельцу.
|
||
"""
|
||
|
||
owner_field = "user"
|
||
|
||
def has_object_permission(self, request: Request, view: APIView, obj) -> bool:
|
||
"""Проверяет права на объект."""
|
||
# Чтение разрешено всем
|
||
if request.method in permissions.SAFE_METHODS:
|
||
return True
|
||
|
||
# Изменение - только владельцу
|
||
owner = getattr(obj, self.owner_field, None)
|
||
if owner is None:
|
||
owner = getattr(obj, "owner", None)
|
||
return owner == request.user
|
||
|
||
|
||
class IsAdminOrReadOnly(permissions.BasePermission):
|
||
"""
|
||
Разрешает изменение только админам, остальным - только чтение.
|
||
|
||
SAFE_METHODS доступны всем (включая анонимных).
|
||
Изменяющие методы - только staff/superuser.
|
||
"""
|
||
|
||
def has_permission(self, request: Request, view: APIView) -> bool:
|
||
"""Проверяет права на уровне view."""
|
||
if request.method in permissions.SAFE_METHODS:
|
||
return True
|
||
return request.user and request.user.is_staff
|
||
|
||
|
||
class IsAdmin(permissions.BasePermission):
|
||
"""
|
||
Разрешает доступ только администраторам (is_staff=True).
|
||
"""
|
||
|
||
def has_permission(self, request: Request, view: APIView) -> bool:
|
||
"""Проверяет, является ли пользователь администратором."""
|
||
return request.user and request.user.is_staff
|
||
|
||
|
||
class IsSuperuser(permissions.BasePermission):
|
||
"""
|
||
Разрешает доступ только суперпользователям (is_superuser=True).
|
||
"""
|
||
|
||
def has_permission(self, request: Request, view: APIView) -> bool:
|
||
"""Проверяет, является ли пользователь суперпользователем."""
|
||
return request.user and request.user.is_superuser
|
||
|
||
|
||
class IsVerified(permissions.BasePermission):
|
||
"""
|
||
Разрешает доступ только пользователям с подтверждённым email.
|
||
|
||
Требует наличие поля `is_verified` у модели пользователя.
|
||
"""
|
||
|
||
message = "Email не подтверждён"
|
||
|
||
def has_permission(self, request: Request, view: APIView) -> bool:
|
||
"""Проверяет, подтверждён ли email пользователя."""
|
||
return (
|
||
request.user
|
||
and request.user.is_authenticated
|
||
and getattr(request.user, "is_verified", False)
|
||
)
|
||
|
||
|
||
class IsOwnerOrAdmin(permissions.BasePermission):
|
||
"""
|
||
Разрешает доступ владельцу объекта или администратору.
|
||
|
||
Полезно для случаев, когда админ должен иметь доступ
|
||
к любым объектам, а пользователь - только к своим.
|
||
"""
|
||
|
||
owner_field = "user"
|
||
|
||
def has_object_permission(self, request: Request, view: APIView, obj) -> bool:
|
||
"""Проверяет права на объект."""
|
||
if request.user and request.user.is_staff:
|
||
return True
|
||
|
||
owner = getattr(obj, self.owner_field, None)
|
||
if owner is None:
|
||
owner = getattr(obj, "owner", None)
|
||
return owner == request.user
|