from rest_framework import serializers from apps.support.models import SupportRoom, SupportMessage from utils import absolute_https_url class SupportMessageSerializer(serializers.ModelSerializer): sender_name = serializers.SerializerMethodField() timestamp_ms = serializers.SerializerMethodField() class Meta: model = SupportMessage fields = ( 'id', 'room', 'sender_type', 'sender_name', 'content', 'is_read', 'created_at', 'timestamp_ms', ) read_only_fields = fields def get_sender_name(self, obj: SupportMessage) -> str: if obj.sender_type == SupportMessage.SenderType.SUPPORT: if obj.sender and obj.sender.fullname: return obj.sender.fullname return 'Support Specialist' if obj.sender and obj.sender.fullname: return obj.sender.fullname return 'You' def get_timestamp_ms(self, obj: SupportMessage) -> int: if not obj.created_at: return 0 return int(obj.created_at.timestamp() * 1000) class SendSupportMessageSerializer(serializers.Serializer): content = serializers.CharField( required=True, allow_blank=False, max_length=4000, trim_whitespace=True, ) class SupportRoomSerializer(serializers.ModelSerializer): class Meta: model = SupportRoom fields = ( 'id', 'status', 'unread_by_user', 'last_message_at', 'created_at', ) read_only_fields = fields def serialize_admin_chat_user(user, request=None) -> dict: if not user: return { 'id': 0, 'email': '', 'fullname': 'Unknown User', 'avatar': '', 'phone_number': '', 'language': '', 'gender': '', 'user_type': 'client', 'is_guest': True, } is_guest = getattr(user, 'is_guest', False) or not bool(user.email) fullname = (user.fullname or '').strip() if not fullname: if user.email: fullname = user.email.split('@')[0] else: fullname = f"Guest #{user.id}" avatar_url = '' if getattr(user, 'avatar', None): try: avatar_url = ( absolute_https_url(user.avatar.url, request) if request else user.avatar.url ) or '' except Exception: avatar_url = '' return { 'id': user.id, 'email': user.email or '', 'fullname': fullname, 'avatar': avatar_url, 'phone_number': str(user.phone_number) if getattr(user, 'phone_number', None) else '', 'language': str(user.language) if getattr(user, 'language', None) else '', 'gender': user.gender or '', 'user_type': 'guest' if is_guest else (user.user_type or 'client'), 'is_guest': is_guest, } def detect_content_type(content: str) -> str: if not content: return 'text' lower = content.lower().strip() if lower.startswith(('http://', 'https://', '/media/')): if any(lower.endswith(ext) for ext in ('.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg')): return 'image' if any(lower.endswith(ext) for ext in ('.mp3', '.wav', '.ogg', '.webm', '.m4a')): return 'audio' if any(lower.endswith(ext) for ext in ('.mp4', '.mov', '.mkv')): return 'video' return 'text' class AdminSupportMessageSerializer(serializers.ModelSerializer): room_id = serializers.IntegerField(read_only=True) sender = serializers.SerializerMethodField() content_type = serializers.SerializerMethodField() sent_at = serializers.SerializerMethodField() updated_at = serializers.SerializerMethodField() is_deleted = serializers.SerializerMethodField() class Meta: model = SupportMessage fields = ( 'id', 'room_id', 'sender_type', 'sender', 'content', 'content_type', 'sent_at', 'updated_at', 'is_read', 'is_deleted', ) read_only_fields = fields def get_sender(self, obj: SupportMessage) -> dict: request = self.context.get('request') if obj.sender_type == SupportMessage.SenderType.SUPPORT: sender_user = obj.sender or (request.user if request and request.user.is_authenticated else None) data = serialize_admin_chat_user(sender_user, request=request) if not sender_user: data['fullname'] = 'Support Specialist' return data sender_user = obj.sender or (obj.room.user if obj.room_id else None) return serialize_admin_chat_user(sender_user, request=request) def get_content_type(self, obj: SupportMessage) -> str: return detect_content_type(obj.content) def get_sent_at(self, obj: SupportMessage) -> str: return obj.created_at.isoformat() if obj.created_at else '' def get_updated_at(self, obj: SupportMessage) -> str: return obj.created_at.isoformat() if obj.created_at else '' def get_is_deleted(self, obj: SupportMessage) -> bool: return False class AdminSupportRoomSerializer(serializers.ModelSerializer): name = serializers.SerializerMethodField() room_type = serializers.SerializerMethodField() initiator = serializers.SerializerMethodField() recipient = serializers.SerializerMethodField() participants = serializers.SerializerMethodField() unread_messages_count = serializers.IntegerField(source='unread_by_admin', read_only=True) last_message = serializers.SerializerMethodField() class Meta: model = SupportRoom fields = ( 'id', 'name', 'room_type', 'status', 'initiator', 'recipient', 'participants', 'unread_messages_count', 'last_message', 'created_at', 'updated_at', ) read_only_fields = fields def get_name(self, obj: SupportRoom) -> str: request = self.context.get('request') user_data = serialize_admin_chat_user(obj.user, request=request) return user_data['fullname'] def get_room_type(self, obj: SupportRoom) -> str: return 'private' def get_initiator(self, obj: SupportRoom) -> dict: request = self.context.get('request') return serialize_admin_chat_user(obj.user, request=request) def get_recipient(self, obj: SupportRoom) -> dict: request = self.context.get('request') specialist = obj.assigned_to or (request.user if request and request.user.is_authenticated else None) return serialize_admin_chat_user(specialist, request=request) def get_participants(self, obj: SupportRoom) -> list: return [self.get_initiator(obj), self.get_recipient(obj)] def get_last_message(self, obj: SupportRoom): last_msg = getattr(obj, '_prefetched_last_message', None) if last_msg is None: last_msg = obj.messages.order_by('-id').first() if not last_msg: return None return { 'id': last_msg.id, 'content': last_msg.content, 'content_type': detect_content_type(last_msg.content), 'sent_at': last_msg.created_at.isoformat() if last_msg.created_at else '', 'sender_type': last_msg.sender_type, }