155 lines
5.3 KiB
Python
155 lines
5.3 KiB
Python
from uuid import UUID
|
|
|
|
from drf_spectacular.utils import OpenApiParameter, extend_schema
|
|
from rest_framework import status
|
|
from rest_framework.response import Response
|
|
from rest_framework.views import APIView
|
|
|
|
from apps.chat.models import ConversationParticipant
|
|
from apps.chat.serializers.conversations import (
|
|
ConversationListSerializer,
|
|
ConversationSerializer,
|
|
ConversationUserActionSerializer,
|
|
CreateConversationSerializer,
|
|
build_participants_info,
|
|
)
|
|
from apps.chat.services.account import AccountService
|
|
from apps.chat.services.conversation import ConversationService
|
|
from apps.chat.services.message import MessageService
|
|
from apps.chat.services.read_state import ReadStateService
|
|
|
|
|
|
class ConversationCreateView(APIView):
|
|
authentication_classes = []
|
|
permission_classes = []
|
|
|
|
@extend_schema(
|
|
request=CreateConversationSerializer,
|
|
responses={201: ConversationSerializer},
|
|
)
|
|
def post(self, request):
|
|
serializer = CreateConversationSerializer(data=request.data)
|
|
serializer.is_valid(raise_exception=True)
|
|
|
|
conversation = ConversationService().create(
|
|
serializer.validated_data["user_1_uuid"],
|
|
serializer.validated_data["user_2_uuid"],
|
|
title=serializer.validated_data.get("title"),
|
|
)
|
|
|
|
return Response(
|
|
ConversationSerializer(conversation).data,
|
|
status=status.HTTP_201_CREATED,
|
|
)
|
|
|
|
|
|
class UserConversationListView(APIView):
|
|
authentication_classes = []
|
|
permission_classes = []
|
|
|
|
@extend_schema(
|
|
parameters=[
|
|
OpenApiParameter("page", int, description="0-based page number", default=0),
|
|
OpenApiParameter("page_size", int, description="Results per page", default=20),
|
|
],
|
|
responses={200: ConversationListSerializer(many=True)},
|
|
)
|
|
def get(self, request, user_uuid):
|
|
uid = UUID(str(user_uuid))
|
|
page = int(request.query_params.get("page", 0))
|
|
page_size = int(request.query_params.get("page_size", 20))
|
|
|
|
conv_svc = ConversationService()
|
|
read_svc = ReadStateService()
|
|
msg_svc = MessageService()
|
|
|
|
conversations = conv_svc.list_for_user(uid, page, page_size)
|
|
|
|
participants_by_conv = {
|
|
conv.uuid: list(
|
|
ConversationParticipant.objects.filter(conversation_id=conv.uuid)
|
|
.order_by("joined_at")
|
|
.values_list("user_uuid", flat=True)
|
|
)
|
|
for conv in conversations
|
|
}
|
|
all_participant_uuids = {
|
|
p for participants in participants_by_conv.values() for p in participants
|
|
}
|
|
# Single bulk lookup (cache-backed) across the whole page, instead of
|
|
# one accounts-service round trip per conversation.
|
|
info_map = AccountService().get_public_info(list(all_participant_uuids))
|
|
|
|
result = []
|
|
for conv in conversations:
|
|
participants = participants_by_conv[conv.uuid]
|
|
participants_info = build_participants_info(participants, info_map=info_map)
|
|
|
|
try:
|
|
has_unread = read_svc.has_unread(conv.uuid, uid)
|
|
except Exception:
|
|
has_unread = False
|
|
|
|
try:
|
|
last_msgs = msg_svc.list_messages(conv.uuid, page=0, per_page=1)
|
|
last_message = last_msgs[0] if last_msgs else None
|
|
except Exception:
|
|
last_message = None
|
|
|
|
result.append(
|
|
{
|
|
"uuid": conv.uuid,
|
|
"type": conv.type,
|
|
"status": conv.status,
|
|
"title": conv.title,
|
|
"closed_by_uuid": conv.closed_by_uuid,
|
|
"created_at": conv.created_at,
|
|
"participants": participants,
|
|
"participants_info": participants_info,
|
|
"has_unread": has_unread,
|
|
"last_message": last_message,
|
|
}
|
|
)
|
|
|
|
return Response(ConversationListSerializer(result, many=True).data)
|
|
|
|
|
|
class ConversationCloseView(APIView):
|
|
authentication_classes = []
|
|
permission_classes = []
|
|
|
|
@extend_schema(
|
|
request=ConversationUserActionSerializer,
|
|
responses={200: ConversationSerializer},
|
|
)
|
|
def post(self, request, chat_uuid):
|
|
serializer = ConversationUserActionSerializer(data=request.data)
|
|
serializer.is_valid(raise_exception=True)
|
|
|
|
conversation = ConversationService().close(
|
|
UUID(str(chat_uuid)), serializer.validated_data["user_uuid"]
|
|
)
|
|
|
|
return Response(ConversationSerializer(conversation).data)
|
|
|
|
|
|
class ConversationReopenView(APIView):
|
|
authentication_classes = []
|
|
permission_classes = []
|
|
|
|
@extend_schema(
|
|
request=ConversationUserActionSerializer,
|
|
responses={200: ConversationSerializer, 403: None},
|
|
)
|
|
def post(self, request, chat_uuid):
|
|
serializer = ConversationUserActionSerializer(data=request.data)
|
|
serializer.is_valid(raise_exception=True)
|
|
|
|
try:
|
|
conversation = ConversationService().reopen(
|
|
UUID(str(chat_uuid)), serializer.validated_data["user_uuid"]
|
|
)
|
|
except PermissionError as exc:
|
|
return Response({"detail": str(exc)}, status=status.HTTP_403_FORBIDDEN)
|
|
|
|
return Response(ConversationSerializer(conversation).data)
|