Files
vontor-cz/backend/social/chat/serializers.py
Brunobrno 3d1965e5e6 Add chat settings modal & reply previews
Introduce a full ChatSettingsModal component for managing group chats (rename/icon upload, add/remove members, toggle moderators, leave/delete) and wire it into ChatRoomPage with a settings button. Add reply preview support end-to-end: new ReplyToSerializer and members_detail in backend serializers, updated frontend Message model (reply_to now contains preview object), and UI changes to Message to render reply excerpts. Improve socket handling to attach reply previews when available. Tweak backend Dockerfile to optionally install Windows/corporate CA bundle only if present and move pip install after copying source. Add Czech translations and small tooling/.claude config enhancements.
2026-05-29 00:41:43 +02:00

119 lines
4.2 KiB
Python

from django.contrib.auth import get_user_model
from rest_framework import serializers
from drf_spectacular.utils import extend_schema_field
from .models import Chat, ChatReadStatus, Message, MessageFile, MessageHistory, MessageReaction
class MessageSenderSerializer(serializers.ModelSerializer):
avatar = serializers.SerializerMethodField()
def get_avatar(self, obj):
from django.conf import settings
if obj.avatar:
return settings.MEDIA_URL + obj.avatar.name
return None
class Meta:
model = get_user_model()
fields = ['id', 'username', 'avatar']
read_only_fields = ['id', 'username']
class MessageFileSerializer(serializers.ModelSerializer):
class Meta:
model = MessageFile
fields = ['id', 'file', 'media_type', 'uploaded_at']
read_only_fields = ['uploaded_at']
class MessageReactionSerializer(serializers.ModelSerializer):
class Meta:
model = MessageReaction
fields = ['id', 'user', 'emoji', 'created_at']
read_only_fields = ['user', 'created_at']
class MessageHistorySerializer(serializers.ModelSerializer):
class Meta:
model = MessageHistory
fields = ['id', 'old_content', 'archived_at']
read_only_fields = ['archived_at']
class ReplyToSerializer(serializers.ModelSerializer):
sender = MessageSenderSerializer(read_only=True)
class Meta:
model = Message
fields = ['id', 'content', 'sender']
read_only_fields = ['id', 'content', 'sender']
class MessageSerializer(serializers.ModelSerializer):
sender = MessageSenderSerializer(read_only=True)
reply_to = ReplyToSerializer(read_only=True)
media_files = MessageFileSerializer(many=True, read_only=True)
reactions = MessageReactionSerializer(many=True, read_only=True)
class Meta:
model = Message
fields = [
'id', 'chat', 'sender', 'reply_to',
'content', 'is_edited', 'edited_at',
'created_at', 'updated_at',
'media_files', 'reactions',
]
read_only_fields = ['sender', 'chat', 'reply_to', 'is_edited', 'edited_at', 'created_at', 'updated_at']
class MessageSendSerializer(serializers.Serializer):
"""Used for the HTTP send endpoint (text + optional files)."""
chat = serializers.PrimaryKeyRelatedField(queryset=Chat.objects.all())
content = serializers.CharField(required=False, allow_blank=True, default='')
reply_to = serializers.PrimaryKeyRelatedField(
queryset=Message.objects.all(), required=False, allow_null=True
)
# files come via request.FILES - declared here for schema documentation only
files = serializers.ListField(
child=serializers.FileField(allow_empty_file=False, use_url=False),
required=False,
default=list,
write_only=True,
)
def validate(self, attrs):
if not attrs.get('content') and not attrs.get('files'):
raise serializers.ValidationError('A message must have content or at least one file.')
return attrs
class ChatSerializer(serializers.ModelSerializer):
unread_count = serializers.SerializerMethodField(read_only=True)
members_detail = MessageSenderSerializer(source='members', many=True, read_only=True)
@extend_schema_field(serializers.IntegerField())
def get_unread_count(self, obj):
request = self.context.get('request')
if not request or not request.user.is_authenticated:
return 0
last_read = ChatReadStatus.objects.filter(
user=request.user, chat=obj
).values_list('last_read_at', flat=True).first()
if last_read is None:
return obj.messages.filter(is_deleted=False).count()
return obj.messages.filter(created_at__gt=last_read, is_deleted=False).count()
class Meta:
model = Chat
fields = [
'id', 'chat_type', 'owner', 'name',
'icon', 'banner', 'members', 'moderators',
'hub', 'created_at', 'updated_at', 'unread_count',
'members_detail',
]
read_only_fields = ['owner', 'created_at', 'updated_at', 'unread_count', 'members_detail']
class ChatMemberSerializer(serializers.Serializer):
user_id = serializers.IntegerField(help_text='PK of the user to add or remove.')