From e8cfed8427015f99500ce8460866881a646083cf Mon Sep 17 00:00:00 2001 From: Shavkatjon Odamboyev <153182519+Shavkatjon-O@users.noreply.github.com> Date: Wed, 28 Aug 2024 13:49:33 +0500 Subject: [PATCH] fix: chats --- apps/chats/__init__.py | 0 apps/chats/admin.py | 7 +++++ apps/chats/apps.py | 6 ++++ apps/chats/migrations/0001_initial.py | 45 +++++++++++++++++++++++++++ apps/chats/migrations/__init__.py | 0 apps/chats/models.py | 25 +++++++++++++++ apps/chats/serializers.py | 24 ++++++++++++++ apps/chats/tests.py | 3 ++ apps/chats/urls.py | 17 ++++++++++ apps/chats/views.py | 25 +++++++++++++++ core/consumers.py | 38 ++++++++++++++++++++-- core/routing.py | 4 +-- core/settings/base.py | 1 + core/urls.py | 1 + 14 files changed, 191 insertions(+), 5 deletions(-) create mode 100644 apps/chats/__init__.py create mode 100644 apps/chats/admin.py create mode 100644 apps/chats/apps.py create mode 100644 apps/chats/migrations/0001_initial.py create mode 100644 apps/chats/migrations/__init__.py create mode 100644 apps/chats/models.py create mode 100644 apps/chats/serializers.py create mode 100644 apps/chats/tests.py create mode 100644 apps/chats/urls.py create mode 100644 apps/chats/views.py diff --git a/apps/chats/__init__.py b/apps/chats/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/chats/admin.py b/apps/chats/admin.py new file mode 100644 index 0000000..3ade67c --- /dev/null +++ b/apps/chats/admin.py @@ -0,0 +1,7 @@ +from django.contrib import admin + +from apps.chats.models import Chat, Message + + +admin.site.register(Chat) +admin.site.register(Message) diff --git a/apps/chats/apps.py b/apps/chats/apps.py new file mode 100644 index 0000000..17022be --- /dev/null +++ b/apps/chats/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ChatsConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "apps.chats" diff --git a/apps/chats/migrations/0001_initial.py b/apps/chats/migrations/0001_initial.py new file mode 100644 index 0000000..f4e22de --- /dev/null +++ b/apps/chats/migrations/0001_initial.py @@ -0,0 +1,45 @@ +# Generated by Django 5.0.7 on 2024-08-28 08:37 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Chat', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('title', models.CharField(blank=True, max_length=256, null=True)), + ('is_group', models.BooleanField(default=False)), + ('users', models.ManyToManyField(related_name='chats', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Message', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('content', models.TextField()), + ('chat', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='messages', to='chats.chat')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='messages', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/apps/chats/migrations/__init__.py b/apps/chats/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/chats/models.py b/apps/chats/models.py new file mode 100644 index 0000000..c2695c3 --- /dev/null +++ b/apps/chats/models.py @@ -0,0 +1,25 @@ +from django.db import models +from django.contrib.auth import get_user_model + +from apps.common.models import BaseModel + +User = get_user_model() + + +class Chat(BaseModel): + title = models.CharField(max_length=256, blank=True, null=True) + is_group = models.BooleanField(default=False) + users = models.ManyToManyField(User, related_name="chats") + + def __str__(self): + return self.title + + +class Message(BaseModel): + chat = models.ForeignKey(Chat, on_delete=models.CASCADE, related_name="messages") + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="messages") + + content = models.TextField() + + def __str__(self): + return self.content diff --git a/apps/chats/serializers.py b/apps/chats/serializers.py new file mode 100644 index 0000000..37b6b07 --- /dev/null +++ b/apps/chats/serializers.py @@ -0,0 +1,24 @@ +from rest_framework import serializers +from .models import Chat, Message + + +class MessageSerializer(serializers.ModelSerializer): + class Meta: + model = Message + fields = [ + "id", + "chat", + "user", + "content", + ] + + +class ChatSerializer(serializers.ModelSerializer): + class Meta: + model = Chat + fields = [ + "id", + "title", + "is_group", + "users", + ] diff --git a/apps/chats/tests.py b/apps/chats/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/apps/chats/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/chats/urls.py b/apps/chats/urls.py new file mode 100644 index 0000000..63afae0 --- /dev/null +++ b/apps/chats/urls.py @@ -0,0 +1,17 @@ +from django.urls import path, include +from rest_framework.routers import DefaultRouter +from . import views + +# router = DefaultRouter() +# router.register(r"chats", views.ChatViewSet) +# router.register(r"messages", views.MessageViewSet) + +# urlpatterns = [ +# path("", include(router.urls)), +# ] + + +urlpatterns = [ + path("chats//", views.ChatViewSet.as_view(), name="chat"), + path("messages//", views.MessageViewSet.as_view(), name="message"), +] diff --git a/apps/chats/views.py b/apps/chats/views.py new file mode 100644 index 0000000..940de11 --- /dev/null +++ b/apps/chats/views.py @@ -0,0 +1,25 @@ +from rest_framework import viewsets +from .models import Chat, Message +from .serializers import ChatSerializer, MessageSerializer +from rest_framework.generics import ListAPIView, RetrieveAPIView + + +# class ChatViewSet(RetrieveAPIView): +# queryset = Chat.objects.all() +# serializer_class = ChatSerializer + + +class ChatViewSet(RetrieveAPIView): + queryset = Chat.objects.all() + serializer_class = ChatSerializer + + +class MessageViewSet(ListAPIView): + queryset = Message.objects.all() + serializer_class = MessageSerializer + + def get_queryset(self): + chat_id = self.kwargs["chat_id"] + + print(self.queryset.filter(chat__id=chat_id)) + return self.queryset.filter(chat__id=chat_id) diff --git a/core/consumers.py b/core/consumers.py index 6b91fa3..7fce3e7 100644 --- a/core/consumers.py +++ b/core/consumers.py @@ -1,16 +1,48 @@ -import json from channels.generic.websocket import AsyncWebsocketConsumer +import json class ChatConsumer(AsyncWebsocketConsumer): async def connect(self): + self.chat_id = self.scope["url_route"]["kwargs"]["chat_id"] + self.chat_group_name = f"chat_{self.chat_id}" + + # Join chat room group + await self.channel_layer.group_add(self.chat_group_name, self.channel_name) + await self.accept() async def disconnect(self, close_code): - pass + # Leave chat room group + await self.channel_layer.group_discard(self.chat_group_name, self.channel_name) + # Receive message from WebSocket async def receive(self, text_data): text_data_json = json.loads(text_data) message = text_data_json["message"] + sender = self.scope["user"].username + + # Send message to chat room group + await self.channel_layer.group_send( + self.chat_group_name, + { + "message": message, + "type": "chat_message", + "sender": sender, + }, + ) + + # Receive message from chat room group + async def chat_message(self, event): + message = event["message"] + sender = event["sender"] - await self.send(text_data=json.dumps({"message": message})) + # Send message to WebSocket + await self.send( + text_data=json.dumps( + { + "message": message, + "sender": sender, + }, + ), + ) diff --git a/core/routing.py b/core/routing.py index a6b804b..3fd31be 100644 --- a/core/routing.py +++ b/core/routing.py @@ -1,6 +1,6 @@ from django.urls import re_path -from core import consumers +from . import consumers websocket_urlpatterns = [ - re_path(r"ws/messenger/$", consumers.ChatConsumer.as_asgi()), + re_path(r"ws/chat/(?P\d+)/$", consumers.ChatConsumer.as_asgi()), ] diff --git a/core/settings/base.py b/core/settings/base.py index 72356ce..84ecab1 100644 --- a/core/settings/base.py +++ b/core/settings/base.py @@ -24,6 +24,7 @@ "apps.bot", "apps.common", "apps.users", + "apps.chats", ] THIRD_PARTY_APPS = [ diff --git a/core/urls.py b/core/urls.py index 981ed58..f342d38 100644 --- a/core/urls.py +++ b/core/urls.py @@ -29,6 +29,7 @@ path("api/users/", include("apps.users.urls")), # path("api/bot/", include("apps.bot.urls")), path("api/common/", include("apps.common.urls")), + path("api/chats/", include("apps.chats.urls")), ] if not settings.DEBUG: