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