128 lines
5.3 KiB
Python
128 lines
5.3 KiB
Python
"""
|
||
Permissions для communications API
|
||
"""
|
||
|
||
import rules
|
||
from rest_framework import permissions
|
||
|
||
from ..utils import user_can_access_chat
|
||
|
||
|
||
class ChatPermission(permissions.BasePermission):
|
||
"""
|
||
Проверка прав доступа к чатам
|
||
|
||
Правила:
|
||
- GET/HEAD/OPTIONS - проверка через user_can_access_chat
|
||
(учитывает participants)
|
||
- PUT/PATCH - владелец или админ (change_chat через django-rules)
|
||
- DELETE - только владелец (delete_chat через django-rules)
|
||
"""
|
||
|
||
def has_permission(self, request, view):
|
||
"""Базовая проверка - пользователь авторизован"""
|
||
return request.user and request.user.is_authenticated
|
||
|
||
def has_object_permission(self, request, view, obj):
|
||
"""Проверка прав на конкретный объект (чат)"""
|
||
# Custom actions имеют свои проверки прав внутри
|
||
if hasattr(view, "action") and view.action in [
|
||
"add_member",
|
||
"remove_member",
|
||
"pin",
|
||
"notifications",
|
||
"change_role",
|
||
"leave",
|
||
"mark_read",
|
||
"messages",
|
||
"messages_around",
|
||
]:
|
||
# Для mark_read и загрузки сообщений достаточно иметь доступ к чату
|
||
if view.action in ["mark_read", "messages", "messages_around"]:
|
||
return user_can_access_chat(obj, request.user)
|
||
return True
|
||
|
||
# Безопасные методы - проверяем доступ через user_can_access_chat
|
||
# (это обходит prefetch cache и делает прямой запрос)
|
||
if request.method in permissions.SAFE_METHODS:
|
||
return user_can_access_chat(obj, request.user)
|
||
|
||
# Изменение чата - только владелец или админ
|
||
if request.method in ["PUT", "PATCH"]:
|
||
return rules.test_rule("communications.change_chat", request.user, obj)
|
||
|
||
# Удаление чата - только владелец
|
||
if request.method == "DELETE":
|
||
return rules.test_rule("communications.delete_chat", request.user, obj)
|
||
|
||
return False
|
||
|
||
|
||
class MessagePermission(permissions.BasePermission):
|
||
"""
|
||
Проверка прав доступа к сообщениям через django-rules
|
||
|
||
Правила:
|
||
- GET - доступ к чату сообщения
|
||
- POST создание - участник чата + can_send_messages
|
||
- POST react/unreact - участник чата (включая гостей)
|
||
- PUT/PATCH - автор сообщения
|
||
- DELETE - автор или админ чата
|
||
"""
|
||
|
||
def has_permission(self, request, view):
|
||
"""Базовая проверка - пользователь авторизован"""
|
||
if not (request.user and request.user.is_authenticated):
|
||
return False
|
||
|
||
# При создании сообщения проверяем права на отправку в чат
|
||
if request.method == "POST" and view.action in ["create", "upload"]:
|
||
# Получаем chat_id из данных запроса
|
||
chat_id = request.data.get("chat") or request.data.get("chat_id")
|
||
|
||
if not chat_id:
|
||
# Если нет chat_id, DRF вернет ошибку валидации позже
|
||
return True
|
||
|
||
# Проверяем права на отправку сообщений
|
||
try:
|
||
from ..models import Chat
|
||
|
||
chat = Chat.objects.get(pk=chat_id)
|
||
|
||
# Используем django-rules проверку
|
||
return rules.test_rule(
|
||
"communications.send_message", request.user, chat
|
||
)
|
||
except Chat.DoesNotExist:
|
||
# Если чат не найден, сам view вернет 404.
|
||
return True
|
||
|
||
return True
|
||
|
||
def has_object_permission(self, request, view, obj):
|
||
"""Проверка прав на конкретное сообщение"""
|
||
# Custom actions с POST (react, unreact) - доступны всем участникам
|
||
if hasattr(view, "action") and view.action in [
|
||
"react",
|
||
"unreact",
|
||
"attachment_playback",
|
||
]:
|
||
# Для реакций достаточно быть участником чата
|
||
# (даже гость может ставить реакции)
|
||
return rules.test_rule("communications.view_message", request.user, obj)
|
||
|
||
# Просмотр - доступ к чату
|
||
if request.method in permissions.SAFE_METHODS:
|
||
return rules.test_rule("communications.view_message", request.user, obj)
|
||
|
||
# Редактирование - автор
|
||
if request.method in ["PUT", "PATCH"]:
|
||
return rules.test_rule("communications.change_message", request.user, obj)
|
||
|
||
# Удаление - автор или админ
|
||
if request.method == "DELETE":
|
||
return rules.test_rule("communications.delete_message", request.user, obj)
|
||
|
||
return False
|