Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added chat&validation #261

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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: 20 additions & 0 deletions application/analytics_project/asgi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import os

import django
from channels.http import AsgiHandler
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from chat.routing import websocket_urlpatterns

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'analytics_project.settings')
django.setup()

application = ProtocolTypeRouter({
"http": AsgiHandler(),
"websocket": AuthMiddlewareStack(
URLRouter(
websocket_urlpatterns
)
),
# Just HTTP for now. (We can add other protocols later.)
})
Empty file added application/chat/__init__.py
Empty file.
8 changes: 8 additions & 0 deletions application/chat/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from django.contrib import admin

from .models import Conversation, ConversationMember, Message, UserMessageStatus

admin.site.register(Conversation)
admin.site.register(ConversationMember)
admin.site.register(Message)
admin.site.register(UserMessageStatus)
5 changes: 5 additions & 0 deletions application/chat/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from django.apps import AppConfig


class ChatConfig(AppConfig):
name = 'chat'
72 changes: 72 additions & 0 deletions application/chat/consumers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import json
from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer
from .views import send_message_to_conversation
from dataprocessing.models import User

import datetime


class ChatConsumer(WebsocketConsumer):
def __init__(self, *args, **kwargs):
super().__init__(args, kwargs)
self.user = None
self.chat_group_name = None
self.user_id = None
self.chat_id = None

def connect(self):
self.chat_id = self.scope['url_route']['kwargs']['chat_id']
self.user_id = self.scope['url_route']['kwargs']['user_id']
self.chat_group_name = 'chat_%s' % self.chat_id
self.user = User.objects.get(id=self.user_id)

# Join room group
async_to_sync(self.channel_layer.group_add)(
self.chat_group_name,
self.channel_name
)

self.accept()

def disconnect(self, close_code):
# Leave room group
async_to_sync(self.channel_layer.group_discard)(
self.chat_group_name,
self.channel_name
)

# Receive message from WebSocket
def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
send_message_to_conversation(self.chat_id, message, self.user_id)
# Send message to room group
async_to_sync(self.channel_layer.group_send)(
self.chat_group_name,
{
'type': 'chat_message',
'message': message,
'user_id': self.user_id,
'first_name': self.user.first_name,
'last_name': self.user.last_name,
}
)

# Receive message from room group
def chat_message(self, event):
message = event['message']
user_id = event['user_id']
first_name = event['first_name']
last_name = event['last_name']
# Send message to WebSocket
self.send(text_data=json.dumps({
'text': message,
'conversation': self.chat_id,
'sent_datetime': datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%SZ'),
'user': {
'id': user_id,
'first_name': first_name,
'last_name': last_name,
}
}))
67 changes: 67 additions & 0 deletions application/chat/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from django.db import models
from django.conf import settings

class Conversation(models.Model):
'''
Модель для диалогов
'''

conversation_name = models.CharField(max_length=128, blank=True, verbose_name='Название')

def __str__(self):
return self.conversation_name


class Message(models.Model):
'''
Модель для сообщений
'''

text = models.TextField(verbose_name='Текст сообщения', blank=False, null=False)
sent_datetime = models.DateTimeField(editable=False, auto_now_add=True, blank=True, null=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, blank=True, null=True)
conversation = models.ForeignKey('Conversation', on_delete=models.CASCADE, verbose_name="Диалог", blank=False,
null=False)

def __str__(self):
return self.text


class ConversationMember(models.Model):
'''
Модель для участника диалога
'''

class Meta:
constraints = [
models.UniqueConstraint(fields=['user', 'conversation'], name='conversation member')
]

user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, blank=True, null=True)
conversation = models.ForeignKey('Conversation', on_delete=models.CASCADE, verbose_name="Диалог", blank=False,
null=False)
joined_datetime = models.DateTimeField(editable=False, auto_now_add=True, blank=True, null=True)
left_datetime = models.DateTimeField(editable=False, auto_now_add=False, blank=True, null=True)
is_admin = models.BooleanField(default=False)

def __str__(self):
return str(self.user)


class UserMessageStatus(models.Model):
'''
Модель для статуса сообщения
'''

class Meta:
constraints = [
models.UniqueConstraint(fields=['user', 'message'], name='unique message user')
]

user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, blank=True, null=True)
message = models.ForeignKey('Message', on_delete=models.CASCADE, verbose_name="Сообщение", blank=False,
null=False)
read = models.BooleanField(default=False)

def __str__(self):
return str(self.user) + " " + str(self.message) + " " + str(self.read)
7 changes: 7 additions & 0 deletions application/chat/routing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from django.urls import path

from . import consumers

websocket_urlpatterns = [
path('ws/chat/<int:user_id>/<int:chat_id>/', consumers.ChatConsumer.as_asgi())
]
43 changes: 43 additions & 0 deletions application/chat/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from rest_framework import serializers
from .models import Conversation, ConversationMember, Message, UserMessageStatus
from dataprocessing.serializers import userProfileSerializer

class ConversationSerializer(serializers.ModelSerializer):
"""
Сериализатор диалогов
"""

class Meta:
model = Conversation
fields = "__all__"


class ConversationMemberSerializer(serializers.ModelSerializer):
"""
Сериализатор участников чата
"""
user = userProfileSerializer()
class Meta:
model = ConversationMember
fields = '__all__'


class MessageSerializer(serializers.ModelSerializer):
"""
Сериализатор Сообщений
"""
user = userProfileSerializer()
class Meta:
model = Message
fields = '__all__'


class UserMessageStatusSerializer(serializers.ModelSerializer):
"""
Сериализатор Статуса Сообщений
"""
user = userProfileSerializer()
message = MessageSerializer()
class Meta:
model = UserMessageStatus
fields = '__all__'
3 changes: 3 additions & 0 deletions application/chat/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.test import TestCase

# Create your tests here.
17 changes: 17 additions & 0 deletions application/chat/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# chat/urls.py
from django.urls import path

from . import views

urlpatterns = [
path('chat', views.index, name='index'),
path('chat/<int:user_id>/<int:chat_id>/', views.room, name='room'),
path('api/chat/conversation/<int:conversation_id>', views.MessageListConversationIdAPIView.as_view()),
path('api/chat/conversation/<int:conversation_id>/members', views.MemberListAPIView.as_view()),
path('api/chat/conversation/<int:conversation_id>/<int:user_id>', views.ConversationMemberAPIView.as_view()),
path('api/chat/conversations', views.ConversationListUserIdAPIView.as_view()),
path('api/chat/unread_messages', views.UserMessageStatusAPIView.as_view()),
path('api/chat/unread_messages/<int:message_id>', views.UserMessageStatusAPIView.as_view()),
# path('api/chat/message_status/<int:user_id>/', views.UserUnreadConversationListAPIView.as_view()),
path('api/chat/unread_messages/<int:conversation_id>/read', views.UserReadConversationMessageAPIView.as_view()),
]
Loading