You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
146 lines
5.2 KiB
146 lines
5.2 KiB
from django.db import transaction
|
|
from rest_framework import status
|
|
from rest_framework.authentication import TokenAuthentication
|
|
from rest_framework.authtoken.models import Token
|
|
from rest_framework.permissions import IsAuthenticated
|
|
from rest_framework.response import Response
|
|
from rest_framework.views import APIView
|
|
|
|
from apps.support.models import SupportMessage, SupportRoom
|
|
from apps.support.serializers import (
|
|
SendSupportMessageSerializer,
|
|
SupportMessageSerializer,
|
|
SupportRoomSerializer,
|
|
)
|
|
|
|
|
|
def resolve_user_support_room(request, create_if_missing: bool = False):
|
|
"""
|
|
Resolves the SupportRoom for request.user (works for both logged-in and guest users).
|
|
If a logged-in user does not yet have a room, checks the optional X-Guest-Token header
|
|
to seamlessly migrate their existing guest support conversation.
|
|
"""
|
|
user = request.user
|
|
room = SupportRoom.objects.filter(user=user).first()
|
|
if room:
|
|
return room
|
|
|
|
# Check if user recently logged in from a guest session that already had a support chat
|
|
guest_token_key = request.headers.get('X-Guest-Token', '').strip()
|
|
if guest_token_key and not getattr(user, 'is_guest', False):
|
|
guest_token_obj = (
|
|
Token.objects.select_related('user')
|
|
.filter(key=guest_token_key)
|
|
.first()
|
|
)
|
|
if guest_token_obj and guest_token_obj.user_id != user.id:
|
|
guest_room = SupportRoom.objects.filter(user=guest_token_obj.user).first()
|
|
if guest_room:
|
|
guest_room.user = user
|
|
guest_room.save(update_fields=['user', 'updated_at'])
|
|
return guest_room
|
|
|
|
if create_if_missing:
|
|
room, _ = SupportRoom.objects.get_or_create(user=user)
|
|
return room
|
|
|
|
return None
|
|
|
|
|
|
class SupportChatMessagesView(APIView):
|
|
"""
|
|
GET /api/support/messages/?after_id=<id>
|
|
Returns the user's support room and messages (all or after `after_id` for short polling).
|
|
POST /api/support/messages/
|
|
Sends a new message from the user (or guest user) to support.
|
|
"""
|
|
authentication_classes = [TokenAuthentication]
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
room = resolve_user_support_room(request, create_if_missing=False)
|
|
if not room:
|
|
return Response(
|
|
{
|
|
'room': None,
|
|
'messages': [],
|
|
},
|
|
status=status.HTTP_200_OK,
|
|
)
|
|
|
|
after_id_param = request.query_params.get('after_id')
|
|
messages_qs = room.messages.select_related('sender').order_by('id')
|
|
|
|
if after_id_param is not None:
|
|
try:
|
|
after_id = int(after_id_param)
|
|
if after_id > 0:
|
|
messages_qs = messages_qs.filter(id__gt=after_id)
|
|
except (TypeError, ValueError):
|
|
pass
|
|
|
|
messages_list = list(messages_qs)
|
|
|
|
# Mark support replies as read when user fetches messages in open chat
|
|
mark_read = request.query_params.get('mark_read', 'true').lower() != 'false'
|
|
if mark_read and (room.unread_by_user > 0 or any(
|
|
m.sender_type == SupportMessage.SenderType.SUPPORT and not m.is_read
|
|
for m in messages_list
|
|
)):
|
|
SupportMessage.objects.filter(
|
|
room=room,
|
|
sender_type=SupportMessage.SenderType.SUPPORT,
|
|
is_read=False,
|
|
).update(is_read=True)
|
|
if room.unread_by_user != 0:
|
|
room.unread_by_user = 0
|
|
room.save(update_fields=['unread_by_user', 'updated_at'])
|
|
|
|
return Response(
|
|
{
|
|
'room': SupportRoomSerializer(room).data,
|
|
'messages': SupportMessageSerializer(messages_list, many=True).data,
|
|
},
|
|
status=status.HTTP_200_OK,
|
|
)
|
|
|
|
@transaction.atomic
|
|
def post(self, request, *args, **kwargs):
|
|
serializer = SendSupportMessageSerializer(data=request.data)
|
|
serializer.is_valid(raise_exception=True)
|
|
|
|
room = resolve_user_support_room(request, create_if_missing=True)
|
|
message = SupportMessage.objects.create(
|
|
room=room,
|
|
sender_type=SupportMessage.SenderType.USER,
|
|
sender=request.user,
|
|
content=serializer.validated_data['content'],
|
|
)
|
|
room.refresh_from_db()
|
|
|
|
return Response(
|
|
{
|
|
'room': SupportRoomSerializer(room).data,
|
|
'message': SupportMessageSerializer(message).data,
|
|
},
|
|
status=status.HTTP_201_CREATED,
|
|
)
|
|
|
|
|
|
class SupportUnreadCountView(APIView):
|
|
"""
|
|
GET /api/support/unread/
|
|
Lightweight endpoint to check if the user has unread support specialist replies.
|
|
"""
|
|
authentication_classes = [TokenAuthentication]
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
room = resolve_user_support_room(request, create_if_missing=False)
|
|
return Response(
|
|
{
|
|
'unread_count': room.unread_by_user if room else 0,
|
|
'status': room.status if room else None,
|
|
},
|
|
status=status.HTTP_200_OK,
|
|
)
|