78 lines
2.7 KiB
Python
78 lines
2.7 KiB
Python
"""Credential-scoped streaming endpoints for protected chat media."""
|
|
|
|
from django.contrib.auth import get_user_model
|
|
from django.http import Http404
|
|
from django.shortcuts import get_object_or_404
|
|
from drf_spectacular.utils import OpenApiParameter, OpenApiTypes, extend_schema
|
|
from rest_framework.permissions import AllowAny
|
|
from rest_framework.views import APIView
|
|
|
|
from communications.media_delivery import chat_file_response
|
|
from communications.media_tickets import (
|
|
ChatMediaTicketError,
|
|
consume_chat_media_ticket,
|
|
)
|
|
from communications.models import Message, MessageAttachment
|
|
from communications.utils import user_can_access_chat
|
|
|
|
User = get_user_model()
|
|
|
|
|
|
class ChatAttachmentMediaAPIView(APIView):
|
|
"""Serve inline audio/video after validating a short-lived scoped ticket."""
|
|
|
|
authentication_classes = []
|
|
permission_classes = [AllowAny]
|
|
|
|
@extend_schema(
|
|
parameters=[
|
|
OpenApiParameter(
|
|
"ticket",
|
|
OpenApiTypes.STR,
|
|
OpenApiParameter.QUERY,
|
|
required=True,
|
|
)
|
|
],
|
|
responses={(200, "application/octet-stream"): OpenApiTypes.BINARY},
|
|
)
|
|
def get(self, request, message_id: int, attachment_id: int):
|
|
raw_ticket = request.query_params.get("ticket")
|
|
if not isinstance(raw_ticket, str) or not raw_ticket:
|
|
raise Http404("Медиафайл недоступен")
|
|
try:
|
|
identity = consume_chat_media_ticket(
|
|
raw_ticket,
|
|
message_id=message_id,
|
|
attachment_id=attachment_id,
|
|
)
|
|
except ChatMediaTicketError as error:
|
|
raise Http404("Медиафайл недоступен") from error
|
|
|
|
user = get_object_or_404(User, pk=identity.user_id, is_active=True)
|
|
message = get_object_or_404(
|
|
Message.objects.select_related("chat"),
|
|
pk=message_id,
|
|
is_deleted=False,
|
|
)
|
|
if not user_can_access_chat(message.chat, user):
|
|
raise Http404("Медиафайл недоступен")
|
|
|
|
attachment = get_object_or_404(
|
|
MessageAttachment,
|
|
pk=attachment_id,
|
|
message=message,
|
|
)
|
|
if attachment.file_type not in {"audio", "video"} or not attachment.file:
|
|
raise Http404("Медиафайл недоступен")
|
|
|
|
try:
|
|
response = chat_file_response(
|
|
attachment.file,
|
|
filename=attachment.file_name,
|
|
as_attachment=False,
|
|
)
|
|
except (OSError, ValueError) as error:
|
|
raise Http404("Медиафайл недоступен") from error
|
|
response["Referrer-Policy"] = "no-referrer"
|
|
return response
|