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

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,
)