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.
 
 

180 lines
6.4 KiB

from django.conf import settings
from django.contrib.auth import get_user_model
from rest_framework import serializers
from drf_spectacular.utils import extend_schema_field
from apps.chat.models.chat import ChatRoom, ChatMessage
from apps.profiles.models.institution import Institution
User = get_user_model()
class CentrifugoTokenResponseSerializer(serializers.Serializer):
token = serializers.CharField(help_text="Signed HMAC-SHA256 JWT for Centrifugo WebSocket connection")
ws_url = serializers.CharField(help_text="WebSocket endpoint URL for frontend client")
user_id = serializers.IntegerField(help_text="Authenticated user ID")
expires_in = serializers.IntegerField(help_text="Token lifetime in seconds")
class ChatUserMiniSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'email', 'fullname', 'avatar', 'user_type']
read_only_fields = fields
class ChatInstitutionMiniSerializer(serializers.ModelSerializer):
type_display = serializers.CharField(source='get_type_display', read_only=True)
class Meta:
model = Institution
fields = ['id', 'name', 'slug', 'type', 'type_display', 'avatar', 'city', 'country']
read_only_fields = fields
class ChatMessageSerializer(serializers.ModelSerializer):
sender = ChatUserMiniSerializer(read_only=True)
sender_institution = ChatInstitutionMiniSerializer(read_only=True)
is_read_by_me = serializers.SerializerMethodField()
read_by_count = serializers.SerializerMethodField()
class Meta:
model = ChatMessage
fields = [
'id',
'room',
'sender',
'sender_institution',
'content',
'attachment',
'attachment_name',
'is_read_by_me',
'read_by_count',
'created_at',
]
read_only_fields = fields
@extend_schema_field(serializers.BooleanField)
def get_is_read_by_me(self, obj) -> bool:
request = self.context.get('request')
if not request or not request.user.is_authenticated:
return False
return obj.read_by.filter(id=request.user.id).exists()
@extend_schema_field(serializers.IntegerField)
def get_read_by_count(self, obj) -> int:
return obj.read_by.count()
class ChatMessageCreateSerializer(serializers.Serializer):
content = serializers.CharField(required=False, allow_blank=True)
attachment = serializers.FileField(required=False, allow_null=True)
sender_institution_id = serializers.IntegerField(required=False, allow_null=True)
def validate(self, attrs):
if not attrs.get('content') and not attrs.get('attachment'):
raise serializers.ValidationError("Message must contain either text content or an attachment.")
return attrs
class ChatRoomListSerializer(serializers.ModelSerializer):
display_title = serializers.SerializerMethodField()
participant_users = ChatUserMiniSerializer(many=True, read_only=True)
participant_institutions = ChatInstitutionMiniSerializer(many=True, read_only=True)
last_message = serializers.SerializerMethodField()
unread_count = serializers.SerializerMethodField()
centrifugo_channel = serializers.CharField(read_only=True)
class Meta:
model = ChatRoom
fields = [
'id',
'room_type',
'title',
'display_title',
'participant_users',
'participant_institutions',
'last_message',
'unread_count',
'centrifugo_channel',
'updated_at',
]
read_only_fields = fields
@extend_schema_field(serializers.CharField)
def get_display_title(self, obj) -> str:
request = self.context.get('request')
user = request.user if request else None
return obj.get_display_title(user)
@extend_schema_field(ChatMessageSerializer(allow_null=True))
def get_last_message(self, obj):
last_msg = obj.get_last_message()
if not last_msg:
return None
return ChatMessageSerializer(last_msg, context=self.context).data
@extend_schema_field(serializers.IntegerField)
def get_unread_count(self, obj) -> int:
request = self.context.get('request')
if not request or not request.user.is_authenticated:
return 0
return obj.get_unread_count(request.user)
class ChatRoomDetailSerializer(serializers.ModelSerializer):
display_title = serializers.SerializerMethodField()
participant_users = ChatUserMiniSerializer(many=True, read_only=True)
participant_institutions = ChatInstitutionMiniSerializer(many=True, read_only=True)
centrifugo_channel = serializers.CharField(read_only=True)
unread_count = serializers.SerializerMethodField()
class Meta:
model = ChatRoom
fields = [
'id',
'room_type',
'title',
'display_title',
'participant_users',
'participant_institutions',
'unread_count',
'centrifugo_channel',
'created_at',
'updated_at',
]
read_only_fields = fields
@extend_schema_field(serializers.CharField)
def get_display_title(self, obj) -> str:
request = self.context.get('request')
user = request.user if request else None
return obj.get_display_title(user)
@extend_schema_field(serializers.IntegerField)
def get_unread_count(self, obj) -> int:
request = self.context.get('request')
if not request or not request.user.is_authenticated:
return 0
return obj.get_unread_count(request.user)
class ChatRoomCreateSerializer(serializers.Serializer):
room_type = serializers.ChoiceField(
choices=ChatRoom.RoomType.choices,
default=ChatRoom.RoomType.DIRECT
)
title = serializers.CharField(required=False, allow_blank=True, max_length=255)
target_user_id = serializers.IntegerField(required=False, allow_null=True)
target_institution_id = serializers.IntegerField(required=False, allow_null=True)
participant_user_ids = serializers.ListField(
child=serializers.IntegerField(),
required=False,
default=list
)
participant_institution_ids = serializers.ListField(
child=serializers.IntegerField(),
required=False,
default=list
)
initial_message = serializers.CharField(required=False, allow_blank=True)