feat(core): add core module with mixins, services, and background jobs
- 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
This commit is contained in:
128
src/apps/core/permissions.py
Normal file
128
src/apps/core/permissions.py
Normal file
@@ -0,0 +1,128 @@
|
||||
"""
|
||||
Базовые классы разрешений для 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
|
||||
Reference in New Issue
Block a user