From 8d0683c8589b0bd1dd33f46c7e0f077ccc31d11a Mon Sep 17 00:00:00 2001 From: dimalright Date: Sun, 20 Aug 2023 21:30:53 +0300 Subject: [PATCH 01/10] upd message and chat --- backend/chats/admin.py | 2 +- backend/chats/models.py | 19 ++++++++++++--- backend/chats/serializers.py | 47 +++++++++++++++++++++++++++--------- backend/chats/views.py | 27 +++++++++++++++++---- backend/core/permissions.py | 35 +++++++++++++-------------- 5 files changed, 91 insertions(+), 39 deletions(-) diff --git a/backend/chats/admin.py b/backend/chats/admin.py index 69c2a34..9e84fe9 100644 --- a/backend/chats/admin.py +++ b/backend/chats/admin.py @@ -3,7 +3,7 @@ from django.contrib import admin from django.contrib.auth import get_user_model -from .models import Attachment, Chat, PersonalChat, GroupChat, Message +from .models import Attachment, Chat, GroupChat, Message, PersonalChat User = get_user_model() diff --git a/backend/chats/models.py b/backend/chats/models.py index b2e6a6e..902ec34 100644 --- a/backend/chats/models.py +++ b/backend/chats/models.py @@ -3,8 +3,6 @@ from django.contrib.auth import get_user_model # from django.core.exceptions import ValidationError from django.db import models -from django.db.models.signals import post_save -from django.dispatch import receiver # from polymorphic.models import PolymorphicModel from model_utils.managers import InheritanceManager @@ -33,7 +31,7 @@ class Chat(DateCreatedModel, DateEditedModel): def get_members_count(self): return self.members.count() - + def __str__(self): return f'{self.name} ({self.get_members_count()})' @@ -102,6 +100,19 @@ class Message(DateCreatedModel, DateEditedModel): verbose_name='Фото для отправки', help_text='Фото для отправки' ) + voice_message = models.FileField( + upload_to='voice_messages/', + blank=True, + null=True, + verbose_name='Голосовое сообщение', + help_text='Голосовое сообщение' + ) + emojis = models.CharField( + max_length=255, + blank=True, + verbose_name='Смайлы', + help_text='Текстовые символы смайлов' + ) responding_to = models.ForeignKey( 'self', on_delete=models.CASCADE, @@ -172,7 +183,7 @@ class Meta: class ChatRequest(DateCreatedModel): """Модель для запросов и приглашений.""" - + from_user = models.ForeignKey( User, on_delete=models.CASCADE, related_name="requests_from_me" ) diff --git a/backend/chats/serializers.py b/backend/chats/serializers.py index a9283ed..5b9bbb5 100644 --- a/backend/chats/serializers.py +++ b/backend/chats/serializers.py @@ -4,12 +4,14 @@ from django.shortcuts import get_object_or_404 from rest_framework import serializers -# from rest_framework.exceptions import PermissionDenied -# from rest_framework.generics import get_object_or_404 from chats.models import Attachment, Chat, GroupChat, Message from users.serializers import UserShortSerializer +# from rest_framework.exceptions import PermissionDenied +# from rest_framework.generics import get_object_or_404 + + User = get_user_model() @@ -26,20 +28,29 @@ class MessageSerializer(serializers.ModelSerializer): # many=False, # read_only=True # ) + is_read = serializers.SerializerMethodField() read_by = UserShortSerializer( many=True, read_only=True ) file_to_send = serializers.FileField( - write_only=True, required=False, allow_empty_file=True ) + photo_to_send = serializers.ImageField( - write_only=True, required=False, allow_empty_file=True ) + voice_message = serializers.FileField( + required=False, + allow_empty_file=True + ) + emojis = serializers.CharField(max_length=255, required=False) + + def get_is_read(self, instance): + user = self.context['request'].user + return instance.read_by.filter(id=user.id).exists() and user != instance.sender class Meta: model = Message @@ -50,6 +61,8 @@ class Meta: 'text', 'file_to_send', 'photo_to_send', + 'voice_message', + 'emojis', 'responding_to', 'sender_keep', 'is_read', @@ -63,15 +76,12 @@ class Meta: def create(self, validated_data): file_to_send = validated_data.pop('file_to_send', None) photo_to_send = validated_data.pop('photo_to_send', None) - # chatname = validated_data['chat'] - # chat = get_object_or_404(Chat, name=chatname) - - # if not chat.messages.exists() and (file_to_send or photo_to_send): - # raise serializers.ValidationError( - # "Нельзя отправить фото или файл первым сообщением" - # ) + voice_message = validated_data.pop('voice_message', None) + emojis = validated_data.pop('emojis', None) + text = validated_data.get('text', '') validated_data['sender'] = self.context['request'].user + validated_data['sender_keep'] = True message = Message.objects.create(**validated_data) if file_to_send: @@ -87,16 +97,31 @@ def create(self, validated_data): content=photo_to_send.read(), message=message ) + if voice_message: + text += f" [Voice Message: {voice_message.name}]" + if emojis: + text += f" {emojis}" + validated_data['text'] = text return message def update(self, instance, validated_data): file_to_send = validated_data.pop('file_to_send', None) photo_to_send = validated_data.pop('photo_to_send', None) + voice_message = validated_data.pop('voice_message', None) + emojis = validated_data.pop('emojis', None) + text = validated_data.get('text', '') for key, value in validated_data.items(): setattr(instance, key, value) + if voice_message: + text += f" [Voice Message: {voice_message.name}]" + if emojis: + text += f" {emojis}" + + validated_data['text'] = text + if file_to_send: Attachment.objects.create( name=file_to_send.name, diff --git a/backend/chats/views.py b/backend/chats/views.py index 39582cb..e974040 100644 --- a/backend/chats/views.py +++ b/backend/chats/views.py @@ -1,6 +1,7 @@ """View-функции приложения chats.""" from django.contrib.auth import get_user_model +from django.utils import timezone from django_filters.rest_framework import DjangoFilterBackend from drf_spectacular.utils import extend_schema @@ -11,10 +12,10 @@ from chats.models import Chat from chats.serializers import (ChatListSerializer, ChatSerializer, - GroupChatCreateSerializer, - MessageSerializer) + GroupChatCreateSerializer, MessageSerializer) from core.pagination import LimitPagination -from core.permissions import ActiveChatOrReceiverOnly + +# from core.permissions import ActiveChatOrReceiverOnly User = get_user_model() @@ -41,8 +42,8 @@ def get_queryset(self): return Chat.objects.none() def get_permissions(self): - if self.action == 'send_message': - return (ActiveChatOrReceiverOnly(),) + # if self.action == 'send_message': + # return (ActiveChatOrReceiverOnly(),) return super().get_permissions() def get_serializer_class(self): @@ -88,3 +89,19 @@ def send_message(self, request, pk=None): return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + @action(detail=True, methods=['get']) + def view_chat(self, request, pk=None): + """Просмотреть чат и обновить статус 'прочитано' для получателя""" + chat = self.get_object() + + # Получаем текущего пользователя + user = self.request.user + + # Обновляем статус 'прочитано' для всех сообщений в чате, если текущий пользователь не отправитель + if chat.members.filter(id=user.id).exists(): + for message in chat.messages.exclude(read_by=user): + message.read_by.add(user) + return Response({"detail": "Chat read status updated."}) + else: + return Response(status=status.HTTP_403_FORBIDDEN) diff --git a/backend/core/permissions.py b/backend/core/permissions.py index 7b02690..f4a26ad 100644 --- a/backend/core/permissions.py +++ b/backend/core/permissions.py @@ -2,24 +2,23 @@ from rest_framework import permissions - -class ActiveChatOrReceiverOnly(permissions.BasePermission): - """ - Разрешение на отправку сообщений для участников активного чата - или только для получателя. - """ - - def has_permission(self, request, view): - return request.user.is_authenticated - - def has_object_permission(self, request, view, obj): - return ( - obj.members.filter(id=request.user.id).exists() - and ( - obj.is_active - or not obj.members_info.get(member=request.user).is_creator - ) - ) +# class ActiveChatOrReceiverOnly(permissions.BasePermission): +# """ +# Разрешение на отправку сообщений для участников активного чата +# или только для получателя. +# """ + +# def has_permission(self, request, view): +# return request.user.is_authenticated + +# def has_object_permission(self, request, view, obj): +# return ( +# obj.members.filter(id=request.user.id).exists() +# and ( +# obj.is_active +# or not obj.members_info.get(member=request.user).is_creator +# ) +# ) class IsAdminOrModeratorReadOnly(permissions.BasePermission): From 25907310b138ef6cc34cb2d51c39280d02f035fd Mon Sep 17 00:00:00 2001 From: dimalright Date: Wed, 23 Aug 2023 21:28:11 +0300 Subject: [PATCH 02/10] update messages --- backend/chats/admin.py | 30 +++++++++++++++++++++++------- backend/chats/serializers.py | 27 +++++++++++++++++++-------- backend/chats/validators.py | 25 +++++++++++++++++++++++++ backend/chats/views.py | 32 +++++++++++++++++++++++++++++--- 4 files changed, 96 insertions(+), 18 deletions(-) create mode 100644 backend/chats/validators.py diff --git a/backend/chats/admin.py b/backend/chats/admin.py index 9e84fe9..5a38e17 100644 --- a/backend/chats/admin.py +++ b/backend/chats/admin.py @@ -1,5 +1,3 @@ -"""Административные настройки приложения chats.""" - from django.contrib import admin from django.contrib.auth import get_user_model @@ -8,8 +6,26 @@ User = get_user_model() -admin.site.register(Chat) -admin.site.register(Attachment) -admin.site.register(Message) -admin.site.register(PersonalChat) -admin.site.register(GroupChat) +@admin.register(Chat) +class ChatAdmin(admin.ModelAdmin): + pass + + +@admin.register(Attachment) +class AttachmentAdmin(admin.ModelAdmin): + pass + + +@admin.register(Message) +class MessageAdmin(admin.ModelAdmin): + list_display = ('id', 'sender', 'chat', 'text') + + +@admin.register(PersonalChat) +class PersonalChatAdmin(admin.ModelAdmin): + pass + + +@admin.register(GroupChat) +class GroupChatAdmin(admin.ModelAdmin): + pass diff --git a/backend/chats/serializers.py b/backend/chats/serializers.py index e1565b2..a922749 100644 --- a/backend/chats/serializers.py +++ b/backend/chats/serializers.py @@ -7,6 +7,9 @@ from chats.models import Attachment, Chat, GroupChat, Message from users.serializers import UserShortSerializer +from .validators import (validate_audio_extension, validate_file_size, + validate_image_extension, validate_pdf_extension) + # from django.shortcuts import get_object_or_404 # from rest_framework.exceptions import PermissionDenied @@ -33,22 +36,28 @@ class MessageSerializer(serializers.ModelSerializer): ) file_to_send = serializers.FileField( required=False, - allow_empty_file=True + allow_empty_file=True, + validators=[validate_file_size, validate_pdf_extension] ) photo_to_send = serializers.ImageField( required=False, - allow_empty_file=True + allow_empty_file=True, + validators=[validate_file_size, validate_image_extension] ) voice_message = serializers.FileField( required=False, - allow_empty_file=True + allow_empty_file=True, + validators=[validate_file_size, validate_audio_extension] ) emojis = serializers.CharField(max_length=255, required=False) def get_is_read(self, instance): user = self.context['request'].user - return instance.read_by.filter(id=user.id).exists() and user != instance.sender + return ( + instance.read_by.filter(id=user.id).exists() and + user != instance.sender + ) class Meta: model = Message @@ -75,7 +84,7 @@ def create(self, validated_data): file_to_send = validated_data.pop('file_to_send', None) photo_to_send = validated_data.pop('photo_to_send', None) voice_message = validated_data.pop('voice_message', None) - emojis = validated_data.pop('emojis', None) + emojis = validated_data.get('emojis', None) text = validated_data.get('text', '') validated_data['sender'] = self.context['request'].user @@ -98,16 +107,17 @@ def create(self, validated_data): if voice_message: text += f" [Voice Message: {voice_message.name}]" if emojis: - text += f" {emojis}" + text += f"{emojis}" validated_data['text'] = text + message.text = text return message def update(self, instance, validated_data): file_to_send = validated_data.pop('file_to_send', None) photo_to_send = validated_data.pop('photo_to_send', None) voice_message = validated_data.pop('voice_message', None) - emojis = validated_data.pop('emojis', None) + emojis = validated_data.get('emojis', None) text = validated_data.get('text', '') for key, value in validated_data.items(): @@ -116,9 +126,10 @@ def update(self, instance, validated_data): if voice_message: text += f" [Voice Message: {voice_message.name}]" if emojis: - text += f" {emojis}" + text += f"{emojis}" validated_data['text'] = text + instance.text = text if file_to_send: Attachment.objects.create( diff --git a/backend/chats/validators.py b/backend/chats/validators.py new file mode 100644 index 0000000..1dd9c67 --- /dev/null +++ b/backend/chats/validators.py @@ -0,0 +1,25 @@ +from django.core.exceptions import ValidationError + + +def validate_file_size(value): + max_size = 20 * 1024 * 1024 # 20 MB + if value.size > max_size: + raise ValidationError( + 'Файл слишком большой. Максимальный размер: 20 МБ.') + + +def validate_file_extension(value, allowed_extensions): + if not value.name.lower().endswith(allowed_extensions): + raise ValidationError('Недопустимый формат файла.') + + +def validate_pdf_extension(value): + validate_file_extension(value, ('.pdf',)) + + +def validate_image_extension(value): + validate_file_extension(value, ('.jpg', '.jpeg', '.png', '.gif')) + + +def validate_audio_extension(value): + validate_file_extension(value, ('.mp3', '.m4a')) diff --git a/backend/chats/views.py b/backend/chats/views.py index 650eda3..4d041e1 100644 --- a/backend/chats/views.py +++ b/backend/chats/views.py @@ -1,7 +1,6 @@ """View-функции приложения chats.""" from django.contrib.auth import get_user_model -from django.utils import timezone from django_filters.rest_framework import DjangoFilterBackend from drf_spectacular.utils import extend_schema @@ -10,7 +9,7 @@ from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response -from chats.models import Chat +from chats.models import Chat, Message from chats.serializers import (ChatListSerializer, ChatSerializer, GroupChatCreateSerializer, MessageSerializer) from core.pagination import LimitPagination @@ -23,7 +22,7 @@ @extend_schema(tags=['chats']) class ChatViewSet(viewsets.ModelViewSet): serializer_class = ChatSerializer - http_method_names = ['get', 'post', 'head'] + http_method_names = ['get', 'post', 'head', 'put'] permission_classes = [ IsAuthenticated, ] @@ -89,6 +88,33 @@ def send_message(self, request, pk=None): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + @action(detail=True, methods=['put']) + def update_message(self, request, pk=None): + """Обновить сообщение в чате""" + message_id = request.data.get('message_id') + chat = self.get_object() + + try: + message = chat.messages.get(id=message_id) + except Message.DoesNotExist: + return Response( + {"detail": "Message not found"}, + status=status.HTTP_404_NOT_FOUND + ) + + serializer = MessageSerializer( + instance=message, + data=request.data, + context={'request': request}, + partial=True + ) + + if serializer.is_valid(): + serializer.save() + return Response(serializer.data, status=status.HTTP_200_OK) + + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + @action(detail=True, methods=['get']) def view_chat(self, request, pk=None): """Просмотреть чат и обновить статус 'прочитано' для получателя""" From 846eb612a66af78ae2b254060bc643e4707605a3 Mon Sep 17 00:00:00 2001 From: dimalright Date: Wed, 23 Aug 2023 22:24:10 +0300 Subject: [PATCH 03/10] upd seria --- backend/chats/serializers.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/backend/chats/serializers.py b/backend/chats/serializers.py index a922749..7e95676 100644 --- a/backend/chats/serializers.py +++ b/backend/chats/serializers.py @@ -81,14 +81,20 @@ class Meta: } def create(self, validated_data): - file_to_send = validated_data.pop('file_to_send', None) - photo_to_send = validated_data.pop('photo_to_send', None) - voice_message = validated_data.pop('voice_message', None) + file_to_send = validated_data.get('file_to_send', None) + photo_to_send = validated_data.get('photo_to_send', None) + voice_message = validated_data.get('voice_message', None) emojis = validated_data.get('emojis', None) text = validated_data.get('text', '') validated_data['sender'] = self.context['request'].user validated_data['sender_keep'] = True + + if voice_message: # Если есть голосовое сообщение, заменяем текст на информацию о голосовом сообщении + text = f'[Voice Message: {voice_message.name}]' + if emojis: + text += emojis + message = Message.objects.create(**validated_data) if file_to_send: @@ -104,19 +110,14 @@ def create(self, validated_data): content=photo_to_send.read(), message=message ) - if voice_message: - text += f" [Voice Message: {voice_message.name}]" - if emojis: - text += f"{emojis}" - validated_data['text'] = text message.text = text return message def update(self, instance, validated_data): - file_to_send = validated_data.pop('file_to_send', None) - photo_to_send = validated_data.pop('photo_to_send', None) - voice_message = validated_data.pop('voice_message', None) + file_to_send = validated_data.get('file_to_send', None) + photo_to_send = validated_data.get('photo_to_send', None) + voice_message = validated_data.get('voice_message', None) emojis = validated_data.get('emojis', None) text = validated_data.get('text', '') @@ -124,11 +125,10 @@ def update(self, instance, validated_data): setattr(instance, key, value) if voice_message: - text += f" [Voice Message: {voice_message.name}]" + text = f'[Voice Message: {voice_message.name}]' if emojis: - text += f"{emojis}" + text += emojis - validated_data['text'] = text instance.text = text if file_to_send: From 18ee25361d4bed9e0198d0b841994e5b202f4b64 Mon Sep 17 00:00:00 2001 From: dimalright Date: Wed, 23 Aug 2023 22:29:44 +0300 Subject: [PATCH 04/10] flake8 --- backend/chats/serializers.py | 2 +- backend/chats/views.py | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/backend/chats/serializers.py b/backend/chats/serializers.py index 7e95676..ba5e19b 100644 --- a/backend/chats/serializers.py +++ b/backend/chats/serializers.py @@ -90,7 +90,7 @@ def create(self, validated_data): validated_data['sender'] = self.context['request'].user validated_data['sender_keep'] = True - if voice_message: # Если есть голосовое сообщение, заменяем текст на информацию о голосовом сообщении + if voice_message: text = f'[Voice Message: {voice_message.name}]' if emojis: text += emojis diff --git a/backend/chats/views.py b/backend/chats/views.py index 4d041e1..595b9af 100644 --- a/backend/chats/views.py +++ b/backend/chats/views.py @@ -120,13 +120,11 @@ def view_chat(self, request, pk=None): """Просмотреть чат и обновить статус 'прочитано' для получателя""" chat = self.get_object() - # Получаем текущего пользователя user = self.request.user - # Обновляем статус 'прочитано' для всех сообщений в чате, если текущий пользователь не отправитель if chat.members.filter(id=user.id).exists(): for message in chat.messages.exclude(read_by=user): message.read_by.add(user) return Response({"detail": "Chat read status updated."}) - else: - return Response(status=status.HTTP_403_FORBIDDEN) + + return Response(status=status.HTTP_403_FORBIDDEN) From ee1847b2ff328085db63b923c1c5319630b39ddd Mon Sep 17 00:00:00 2001 From: dimalright Date: Fri, 25 Aug 2023 22:19:29 +0300 Subject: [PATCH 05/10] upd func send_message --- backend/backend/settings.py | 20 +++++++- backend/chats/serializers.py | 97 ++++++++++++++---------------------- backend/chats/views.py | 19 ++++--- 3 files changed, 65 insertions(+), 71 deletions(-) diff --git a/backend/backend/settings.py b/backend/backend/settings.py index f79f809..587aa08 100644 --- a/backend/backend/settings.py +++ b/backend/backend/settings.py @@ -14,8 +14,24 @@ DEBUG = os.getenv('DEBUG', default=False) -ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', default='localhost,127.0.0.1,').split(',') - +ALLOWED_HOSTS = os.getenv( + 'ALLOWED_HOSTS', default='localhost,127.0.0.1,').split(',') + +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'handlers': { + 'file': { + 'level': 'DEBUG', + 'class': 'logging.FileHandler', + 'filename': 'debug.log', + }, + }, + 'root': { + 'handlers': ['file'], + 'level': 'DEBUG', + }, +} INSTALLED_APPS = [ "daphne", 'django.contrib.admin', diff --git a/backend/chats/serializers.py b/backend/chats/serializers.py index e225005..6a5467e 100644 --- a/backend/chats/serializers.py +++ b/backend/chats/serializers.py @@ -1,19 +1,22 @@ """Сериализаторы приложения chats.""" from django.contrib.auth import get_user_model - +import logging from rest_framework import serializers from chats.models import Attachment, GroupChat, Message, PersonalChat from core.constants import MAX_MESSAGE_LENGTH from users.serializers import UserShortSerializer +from .validators import (validate_file_size, validate_pdf_extension, + validate_image_extension, validate_audio_extension) # from django.shortcuts import get_object_or_404 # from rest_framework.exceptions import PermissionDenied -from django.shortcuts import get_object_or_404 -from .models import Chat +# from django.shortcuts import get_object_or_404 +# from .models import Chat User = get_user_model() +logger = logging.getLogger(__name__) class MessageSerializer(serializers.ModelSerializer): @@ -23,13 +26,7 @@ class MessageSerializer(serializers.ModelSerializer): allow_null=True, max_length=10000 ) - # chat = serializers.CharField(source='chat.name') - # chat = serializers.SlugRelatedField( - # slug_field='name', - # many=False, - # read_only=True - # ) - is_read = serializers.SerializerMethodField() + # is_read = serializers.SerializerMethodField() read_by = UserShortSerializer( many=True, read_only=True @@ -54,18 +51,19 @@ class MessageSerializer(serializers.ModelSerializer): ) emojis = serializers.CharField(max_length=255, required=False) - def get_is_read(self, instance): - user = self.context['request'].user - return ( - instance.read_by.filter(id=user.id).exists() and - user != instance.sender - ) sender = serializers.SlugRelatedField( slug_field='slug', read_only=True ) chat = serializers.HiddenField(default=None) + # def get_is_read(self, instance): + # user = self.context['request'].user + # return ( + # instance.read_by.filter(id=user.id).exists() and + # user != instance.sender + # ) + class Meta: model = Message fields = [ @@ -97,35 +95,25 @@ class Meta: 'timestamp', ) - # def create(self, validated_data): - # file_to_send = validated_data.get('file_to_send', None) - # photo_to_send = validated_data.get('photo_to_send', None) - # voice_message = validated_data.get('voice_message', None) - # emojis = validated_data.get('emojis', None) - # text = validated_data.get('text', '') - - # validated_data['sender'] = self.context['request'].user - # validated_data['sender_keep'] = True - - # if voice_message: - # text = f'[Voice Message: {voice_message.name}]' - # if emojis: - # text += emojis - - # message = Message.objects.create(**validated_data) - def create(self, validated_data): + logger.info("Creating a new message") + file_to_send = validated_data.get('file_to_send', None) photo_to_send = validated_data.get('photo_to_send', None) voice_message = validated_data.get('voice_message', None) emojis = validated_data.get('emojis', None) text = validated_data.get('text', '') - chatname = validated_data['chat'] + # chatname = validated_data['chat'] validated_data['sender_keep'] = True + # Получение объекта чата из контекста представления + chat = self.context.get('chat') - chat = get_object_or_404(Chat, name=chatname) - + if not chat: + raise serializers.ValidationError( + "Chat object is missing in the context") + # chat = get_object_or_404(Chat, pk=chat_id) + validated_data['chat'] = chat if not chat.messages.exists() and (file_to_send or photo_to_send): raise serializers.ValidationError( "Нельзя отправить фото или файл первым сообщением" @@ -134,6 +122,7 @@ def create(self, validated_data): text = f'[Voice Message: {voice_message.name}]' if emojis: text += emojis + validated_data['sender'] = self.context['request'].user message = Message.objects.create(**validated_data) @@ -152,6 +141,7 @@ def create(self, validated_data): ) message.text = text + message.save() return message def update(self, instance, validated_data): @@ -160,14 +150,9 @@ def update(self, instance, validated_data): voice_message = validated_data.get('voice_message', None) emojis = validated_data.get('emojis', None) text = validated_data.get('text', '') - # return message - - # def update(self, instance, validated_data): - # file_to_send = validated_data.pop('file_to_send', None) - # photo_to_send = validated_data.pop('photo_to_send', None) - # for key, value in validated_data.items(): - # setattr(instance, key, value) + for key, value in validated_data.items(): + setattr(instance, key, value) if voice_message: text = f'[Voice Message: {voice_message.name}]' @@ -182,12 +167,6 @@ def update(self, instance, validated_data): content=file_to_send.read(), message=instance ) - # if file_to_send: - # Attachment.objects.create( - # name=file_to_send.name, - # content=file_to_send.read(), - # message=instance - # ) if photo_to_send: Attachment.objects.create( @@ -311,15 +290,15 @@ class Meta: # return chat -class AttachmentSerializer(serializers.ModelSerializer): - """Сериализатор модели Attachment.""" +# class AttachmentSerializer(serializers.ModelSerializer): +# """Сериализатор модели Attachment.""" - content = serializers.CharField(write_only=True) +# content = serializers.CharField(write_only=True) - class Meta: - model = Attachment - fields = [ - 'name', - 'content', - 'message' - ] +# class Meta: +# model = Attachment +# fields = [ +# 'name', +# 'content', +# 'message' +# ] diff --git a/backend/chats/views.py b/backend/chats/views.py index 384adda..7af5819 100644 --- a/backend/chats/views.py +++ b/backend/chats/views.py @@ -143,17 +143,22 @@ def start_personal_chat(self, request, slug=None): def send_message(self, request, pk=None): """Отправить сообщение в чат""" chat = self.get_object() - serializer = self.get_serializer(data={ - **request.data - }) + + serializer = self.get_serializer( + data={**request.data}, + # Передаем chat через контекст + context={'request': request, 'chat': chat} + ) + serializer.is_valid(raise_exception=True) + serializer.save() # Сохраняем сообщение и получаем его объект channel_layer = get_channel_layer() async_to_sync(channel_layer.group_send)( "general", { "type": "chat_message", - "message": serializer.validated_data['text'] + "message": serializer['text'] } ) return Response( @@ -161,12 +166,6 @@ def send_message(self, request, pk=None): status=status.HTTP_201_CREATED ) - if serializer.is_valid(): - serializer.save(chat=chat) - return Response(serializer.data, status=status.HTTP_201_CREATED) - - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - @action(detail=True, methods=['put']) def update_message(self, request, pk=None): """Обновить сообщение в чате""" From 5c530b891272993b3d46d6dc980092f5e480d7d1 Mon Sep 17 00:00:00 2001 From: dimalright Date: Fri, 25 Aug 2023 22:30:31 +0300 Subject: [PATCH 06/10] isort --- backend/chats/serializers.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/backend/chats/serializers.py b/backend/chats/serializers.py index 6a5467e..684e312 100644 --- a/backend/chats/serializers.py +++ b/backend/chats/serializers.py @@ -1,14 +1,17 @@ """Сериализаторы приложения chats.""" -from django.contrib.auth import get_user_model import logging + +from django.contrib.auth import get_user_model + from rest_framework import serializers from chats.models import Attachment, GroupChat, Message, PersonalChat from core.constants import MAX_MESSAGE_LENGTH from users.serializers import UserShortSerializer -from .validators import (validate_file_size, validate_pdf_extension, - validate_image_extension, validate_audio_extension) + +from .validators import (validate_audio_extension, validate_file_size, + validate_image_extension, validate_pdf_extension) # from django.shortcuts import get_object_or_404 # from rest_framework.exceptions import PermissionDenied @@ -150,6 +153,10 @@ def update(self, instance, validated_data): voice_message = validated_data.get('voice_message', None) emojis = validated_data.get('emojis', None) text = validated_data.get('text', '') + chat = self.context.get('chat') + if not chat: + raise serializers.ValidationError( + "Chat object is missing in the context") for key, value in validated_data.items(): setattr(instance, key, value) From 0c1467e5a63b70a48a90192b0314fe0dd380f8c2 Mon Sep 17 00:00:00 2001 From: dimalright Date: Fri, 25 Aug 2023 23:12:49 +0300 Subject: [PATCH 07/10] modify is_read --- backend/chats/serializers.py | 23 +++++++++++------------ backend/chats/views.py | 9 ++++++--- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/backend/chats/serializers.py b/backend/chats/serializers.py index 684e312..e1c6889 100644 --- a/backend/chats/serializers.py +++ b/backend/chats/serializers.py @@ -1,6 +1,5 @@ """Сериализаторы приложения chats.""" -import logging from django.contrib.auth import get_user_model @@ -19,7 +18,6 @@ # from django.shortcuts import get_object_or_404 # from .models import Chat User = get_user_model() -logger = logging.getLogger(__name__) class MessageSerializer(serializers.ModelSerializer): @@ -29,7 +27,7 @@ class MessageSerializer(serializers.ModelSerializer): allow_null=True, max_length=10000 ) - # is_read = serializers.SerializerMethodField() + is_read = serializers.SerializerMethodField() read_by = UserShortSerializer( many=True, read_only=True @@ -60,12 +58,15 @@ class MessageSerializer(serializers.ModelSerializer): ) chat = serializers.HiddenField(default=None) - # def get_is_read(self, instance): - # user = self.context['request'].user - # return ( - # instance.read_by.filter(id=user.id).exists() and - # user != instance.sender - # ) + def get_is_read(self, instance): + user = self.context.get( + 'request').user if self.context.get('request') else None + if user is None: + return False + return ( + instance.read_by.filter(id=user.id).exists() and + user != instance.sender + ) class Meta: model = Message @@ -99,7 +100,6 @@ class Meta: ) def create(self, validated_data): - logger.info("Creating a new message") file_to_send = validated_data.get('file_to_send', None) photo_to_send = validated_data.get('photo_to_send', None) @@ -109,13 +109,12 @@ def create(self, validated_data): # chatname = validated_data['chat'] validated_data['sender_keep'] = True - # Получение объекта чата из контекста представления + chat = self.context.get('chat') if not chat: raise serializers.ValidationError( "Chat object is missing in the context") - # chat = get_object_or_404(Chat, pk=chat_id) validated_data['chat'] = chat if not chat.messages.exists() and (file_to_send or photo_to_send): raise serializers.ValidationError( diff --git a/backend/chats/views.py b/backend/chats/views.py index 7af5819..0626357 100644 --- a/backend/chats/views.py +++ b/backend/chats/views.py @@ -2,6 +2,7 @@ from django.contrib.auth import get_user_model from django.db.models import Q +from django.http import HttpResponseForbidden from django.shortcuts import get_object_or_404 from asgiref.sync import async_to_sync @@ -200,9 +201,11 @@ def view_chat(self, request, pk=None): user = self.request.user - if chat.members.filter(id=user.id).exists(): + if chat.initiator == user or chat.receiver == user: for message in chat.messages.exclude(read_by=user): message.read_by.add(user) return Response({"detail": "Chat read status updated."}) - - return Response(status=status.HTTP_403_FORBIDDEN) + else: + return HttpResponseForbidden( + "You don't have permission to access this chat." + ) From 94a992feca9a3d8aeeaad25f5ec56567c3bb69ae Mon Sep 17 00:00:00 2001 From: dimalright Date: Sat, 26 Aug 2023 19:11:26 +0300 Subject: [PATCH 08/10] upd r504 --- backend/chats/views.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/chats/views.py b/backend/chats/views.py index 539f7fc..174b455 100644 --- a/backend/chats/views.py +++ b/backend/chats/views.py @@ -205,7 +205,7 @@ def view_chat(self, request, pk=None): for message in chat.messages.exclude(read_by=user): message.read_by.add(user) return Response({"detail": "Chat read status updated."}) - else: - return HttpResponseForbidden( - "You don't have permission to access this chat." - ) + + return HttpResponseForbidden( + "You don't have permission to access this chat." + ) From d0d471e8405a9d20b8228b86733ee1bd6f6235fb Mon Sep 17 00:00:00 2001 From: Marina Date: Thu, 31 Aug 2023 21:00:28 +0300 Subject: [PATCH 09/10] update user profile field `country`; update user filters field `country` --- backend/users/filters.py | 2 +- backend/users/serializers.py | 2 +- backend/users/views.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/users/filters.py b/backend/users/filters.py index 39e1726..13e71d7 100644 --- a/backend/users/filters.py +++ b/backend/users/filters.py @@ -44,7 +44,7 @@ class UserFilter(df.FilterSet): age = AgeFilter() country = CustomFilterList( - field_name='country__code', lookup_expr='in') + field_name='country__name', lookup_expr='in') languages = CustomFilterList( field_name='languages__isocode', lookup_expr='in') skill_level = df.ChoiceFilter( diff --git a/backend/users/serializers.py b/backend/users/serializers.py index c32f9fb..15e9ce2 100644 --- a/backend/users/serializers.py +++ b/backend/users/serializers.py @@ -174,7 +174,7 @@ class UserProfileSerializer(DjoserSerializer, UserReprSerializer): many=False, read_only=False, required=False, - slug_field='code', + slug_field='name', queryset=Country.objects.all() ) interests = CreatableSlugRelatedField( diff --git a/backend/users/views.py b/backend/users/views.py index 2ad2b90..c343afd 100644 --- a/backend/users/views.py +++ b/backend/users/views.py @@ -126,7 +126,7 @@ def get_queryset(self): @extend_schema( summary='Просмотреть свой профиль', description='Просмотреть свой профиль', - methods=["get"], + methods=["get"] ) @extend_schema( summary='Удалить свой аккаунт', From 20f377cfe1eae2fef5767278e4751e0634362c83 Mon Sep 17 00:00:00 2001 From: dimalright Date: Sat, 16 Sep 2023 21:52:09 +0300 Subject: [PATCH 10/10] upd correct func view blocked user in chats --- backend/chats/views.py | 1 + backend/users/views.py | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/backend/chats/views.py b/backend/chats/views.py index 5e3fc2d..b687ad2 100644 --- a/backend/chats/views.py +++ b/backend/chats/views.py @@ -253,6 +253,7 @@ def view_chat(self, request, pk=None): return HttpResponseForbidden( "You don't have permission to access this chat." + ) @action(detail=True, methods=['post']) def block_user(self, request, pk=None): diff --git a/backend/users/views.py b/backend/users/views.py index 990d5a9..ae54739 100644 --- a/backend/users/views.py +++ b/backend/users/views.py @@ -124,6 +124,10 @@ def retrieve(self, request, *args, **kwargs): instance = self.get_object() current_user = request.user + if instance == current_user: + serializer = self.get_serializer(instance) + return Response(serializer.data) + blocked_chats = PersonalChat.objects.filter( Q(initiator=instance, blocked_users=current_user) | Q(receiver=instance, blocked_users=current_user)