Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions backend/backend/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
2 changes: 1 addition & 1 deletion backend/chats/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def display_members(self, obj):

display_members.short_description = 'Участники'


admin.site.register(Chat, ChatAdmin)
admin.site.register(Attachment)
admin.site.register(Message)
Expand Down
13 changes: 13 additions & 0 deletions backend/chats/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,19 @@ class Message(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,
Expand Down
171 changes: 116 additions & 55 deletions backend/chats/serializers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Сериализаторы приложения chats."""


from django.contrib.auth import get_user_model

from rest_framework import serializers
Expand All @@ -8,8 +9,14 @@
from core.constants import MAX_MESSAGE_LENGTH
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

# from django.shortcuts import get_object_or_404
# from .models import Chat
User = get_user_model()


Expand All @@ -20,26 +27,47 @@ class MessageSerializer(serializers.ModelSerializer):
allow_null=True,
max_length=10000
)
is_read = serializers.SerializerMethodField()
read_by = UserShortSerializer(
many=True,
read_only=True
)
file_to_send = serializers.FileField(
write_only=False,
required=False,
allow_empty_file=True
allow_empty_file=True,
validators=[validate_file_size, validate_pdf_extension]
)

photo_to_send = serializers.ImageField(
write_only=False,
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,
validators=[validate_file_size, validate_audio_extension]
)
emojis = serializers.CharField(max_length=255, required=False)

sender = serializers.SlugRelatedField(
slug_field='slug',
read_only=True
)
chat = serializers.HiddenField(default=None)

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
fields = [
Expand All @@ -48,6 +76,8 @@ class Meta:
'text',
'file_to_send',
'photo_to_send',
'voice_message',
'emojis',
'responding_to',
'sender_keep',
'is_read',
Expand All @@ -69,60 +99,91 @@ class Meta:
'timestamp',
)

# 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)
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', '')
# 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(
# "Нельзя отправить фото или файл первым сообщением"
# )

# validated_data['sender'] = self.context['request'].user
# message = Message.objects.create(**validated_data)

# if file_to_send:
# Attachment.objects.create(
# name=file_to_send.name,
# content=file_to_send.read(),
# message=message
# )

# if photo_to_send:
# Attachment.objects.create(
# name=photo_to_send.name,
# content=photo_to_send.read(),
# message=message
# )

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

# 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(
# name=photo_to_send.name,
# content=photo_to_send.read(),
# message=instance
# )

# instance.save()

# return instance

validated_data['sender_keep'] = True

chat = self.context.get('chat')

if not chat:
raise serializers.ValidationError(
"Chat object is missing in the context")
validated_data['chat'] = chat
if not chat.messages.exists() and (file_to_send or photo_to_send):
raise serializers.ValidationError(
"Нельзя отправить фото или файл первым сообщением"
)
if voice_message:
text = f'[Voice Message: {voice_message.name}]'
if emojis:
text += emojis

validated_data['sender'] = self.context['request'].user
message = Message.objects.create(**validated_data)

if file_to_send:
Attachment.objects.create(
name=file_to_send.name,
content=file_to_send.read(),
message=message
)

if photo_to_send:
Attachment.objects.create(
name=photo_to_send.name,
content=photo_to_send.read(),
message=message
)

message.text = text
message.save()
return message

def update(self, instance, 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', '')
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)

if voice_message:
text = f'[Voice Message: {voice_message.name}]'
if emojis:
text += emojis

instance.text = text

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(
name=photo_to_send.name,
content=photo_to_send.read(),
message=instance
)

instance.save()

return instance


class ChatListSerializer(serializers.ModelSerializer):
Expand Down
25 changes: 25 additions & 0 deletions backend/chats/validators.py
Original file line number Diff line number Diff line change
@@ -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'))
52 changes: 51 additions & 1 deletion backend/chats/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -48,7 +49,7 @@
class ChatViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin,
viewsets.GenericViewSet):
serializer_class = ChatSerializer
http_method_names = ['get', 'post', 'head']
http_method_names = ['get', 'post', 'head', 'put']
permission_classes = [
IsAuthenticated,
]
Expand Down Expand Up @@ -177,6 +178,12 @@ def send_message(self, request, pk=None):
"""Отправить сообщение в чат"""
chat = self.get_object()

# serializer = self.get_serializer(
# data={**request.data},
# # Передаем chat через контекст
# context={'request': request, 'chat': chat}
# )

if chat.is_user_blocked(request.user):
return Response(
{
Expand Down Expand Up @@ -205,6 +212,49 @@ def send_message(self, request, pk=None):
status=status.HTTP_201_CREATED
)

@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):
"""Просмотреть чат и обновить статус 'прочитано' для получателя"""
chat = self.get_object()

user = self.request.user

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 HttpResponseForbidden(
"You don't have permission to access this chat."
)

@action(detail=True, methods=['post'])
def block_user(self, request, pk=None):
"""Блокировка пользователя в чате"""
Expand Down
Loading