chat: fix and opti

This commit is contained in:
starnakin 2023-12-27 16:14:39 +01:00
parent cfb14be945
commit 9f7b813292
10 changed files with 144 additions and 116 deletions

View File

@ -1,6 +1,6 @@
from django.contrib import admin from django.contrib import admin
from .models import ChannelModel, MemberModel, MessageModel from .models import ChatChannelModel, ChatMemberModel, ChatMessageModel
admin.site.register(ChannelModel) admin.site.register(ChatChannelModel)
admin.site.register(MemberModel) admin.site.register(ChatMemberModel)
admin.site.register(MessageModel) admin.site.register(ChatMessageModel)

View File

@ -1,21 +1,25 @@
import json
from channels.generic.websocket import WebsocketConsumer from channels.generic.websocket import WebsocketConsumer
from asgiref.sync import async_to_sync from asgiref.sync import async_to_sync
from .models import MemberModel, MessageModel
from .models import ChatMemberModel, ChatMessageModel
from profiles.models import BlockModel from profiles.models import BlockModel
import time import time
import json
class ChatConsumer(WebsocketConsumer): class ChatConsumer(WebsocketConsumer):
def connect(self):
channel_id : str = self.scope['path'].split('/')[3]
self.room_group_name = 'chat' + channel_id def connect(self):
user = self.scope["user"] user = self.scope["user"]
if (user.is_anonymous or not user.is_authenticated): if (user.is_anonymous or not user.is_authenticated):
return return
if MemberModel.objects.filter(member_id=user.pk, channel_id=int(channel_id)).count() != 1: channel_id : int = int(self.scope['url_route']['kwargs']['chat_id'])
self.room_group_name = f'chat{channel_id}'
if ChatMemberModel.objects.filter(member_id=user.pk, channel_id=int(channel_id)).count() != 1:
return return
if (self.channel_layer == None): if (self.channel_layer == None):
@ -30,27 +34,33 @@ class ChatConsumer(WebsocketConsumer):
def receive(self, text_data=None, bytes_data=None): def receive(self, text_data=None, bytes_data=None):
if text_data == None: if text_data == None:
return return
text_data_json = json.loads(text_data)
message = text_data_json['message']
receivers_id = text_data_json['receivers_id']
print(text_data)
channel_id : int = int(self.scope['path'].split('/')[3])
user = self.scope["user"] user = self.scope["user"]
if (user.is_anonymous or not user.is_authenticated): if (user.is_anonymous or not user.is_authenticated):
return return
if MemberModel.objects.filter(member_id=user.pk, channel_id=channel_id).count() != 1: text_data_json: dict = json.loads(text_data)
message = text_data_json.get('message')
if (message is None):
return
receivers_id = text_data_json.get('receivers_id')
if (receivers_id is None):
return
channel_id : int = int(self.scope['url_route']['kwargs']['chat_id'])
if ChatMemberModel.objects.filter(member_id = user.pk, channel_id = channel_id).count() != 1:
return return
if (self.channel_layer == None): if (self.channel_layer == None):
return return
message_time : int = int(time.time() * 1000) message_time: int = int(time.time() * 1000)
if (len(receivers_id) == 1 and if (len(receivers_id) == 1 and
BlockModel.objects.filter(blocker=user.pk, blocked=receivers_id[0]) or BlockModel.objects.filter(blocker=user.pk, blocked=receivers_id[0]) or
@ -68,22 +78,17 @@ class ChatConsumer(WebsocketConsumer):
} }
) )
new_message = MessageModel() new_message = ChatMessageModel(channel_id = channel_id, author_id = user.pk, content = message, time = message_time).save()
new_message.channel_id = channel_id
new_message.author_id = user.pk
new_message.content = message
new_message.time = message_time
new_message.save()
def chat_message(self, event): def chat_message(self, event):
channel_id : int = int(self.scope['path'].split('/')[3])
user = self.scope["user"] user = self.scope["user"]
if (user.is_anonymous or not user.is_authenticated): if (user.is_anonymous or not user.is_authenticated):
return return
if MemberModel.objects.filter(member_id=user.pk, channel_id=channel_id).count() != 1: channel_id : int = int(self.scope['url_route']['kwargs']['chat_id'])
if ChatMemberModel.objects.filter(member_id = user.pk, channel_id = channel_id).count() != 1:
return return
self.send(text_data=json.dumps({ self.send(text_data=json.dumps({

View File

@ -4,17 +4,24 @@ from django.contrib.auth.models import User
from django.contrib import admin from django.contrib import admin
# Create your models here. # Create your models here.
class ChannelModel(models.Model): class ChatChannelModel(models.Model):
pass
class MemberModel(models.Model): def create(self, users_id: [int]):
self.save()
for user_id in users_id:
ChatMemberModel(channel_id = self.pk, member_id = user_id).save()
def get_members_id(self):
return [member_channel.member_id for member_channel in ChatMemberModel.objects.filter(channel_id = self.pk)]
class ChatMemberModel(models.Model):
member_id = IntegerField(primary_key=False) member_id = IntegerField(primary_key=False)
channel_id = IntegerField(primary_key=False) channel_id = IntegerField(primary_key=False)
def __str__(self): def __str__(self):
return "member_id: " + str(self.member_id) + ", channel_id: " + str(self.channel_id) return "member_id: " + str(self.member_id) + ", channel_id: " + str(self.channel_id)
class MessageModel(models.Model): class ChatMessageModel(models.Model):
channel_id = IntegerField(primary_key=False) channel_id = IntegerField(primary_key=False)
author_id = IntegerField(primary_key=False) author_id = IntegerField(primary_key=False)
content = models.CharField(max_length=255) content = models.CharField(max_length=255)

View File

@ -1,8 +1,30 @@
from rest_framework import serializers from rest_framework import serializers
from .models import ChannelModel
class ChannelSerializer(serializers.ModelSerializer): from profiles.models import ProfileModel
from .models import ChatChannelModel, ChatMessageModel
class ChatChannelSerializer(serializers.ModelSerializer):
members_id = serializers.ListField(child = serializers.IntegerField())
class Meta: class Meta:
model = ChannelModel model = ChatChannelModel
fields = [] fields = ["members_id", "pk"]
def validate_members_id(self, value):
members_id: [int] = value
if len(members_id) < 2:
raise serializers.ValidationError('Not enought members to create the channel')
if len(set(members_id)) != len(members_id):
raise serializers.ValidationError('Same member')
for member_id in members_id:
if not ProfileModel.objects.filter(pk = member_id).exists():
raise serializers.ValidationError(f"The profile {member_id} doesn't exists.")
return members_id
class ChatMessageSerializer(serializers.Serializer):
class Meta:
model = ChatMessageModel
fields = ["channel_id", "author_id", "content", "time"]

View File

@ -1,3 +1,30 @@
from django.test import TestCase from django.test import TestCase
from django.test.client import Client
from django.http import HttpResponse, HttpRequest
from django.contrib.auth.models import User
# Create your tests here. # Create your tests here.
class ChatTest(TestCase):
def setUp(self):
self.client = Client()
self.username='bozo1'
self.password='password'
self.user: User = User.objects.create_user(username=self.username, password=self.password)
self.dest: User = User.objects.create_user(username="bozo2", password=self.password)
self.url = "/api/chat/"
def test_create_chat(self):
self.client.login(username=self.username, password=self.password)
response: HttpResponse = self.client.post(self.url + str(self.user.pk), {"members_id": [self.user.pk, self.dest.pk]})
response_dict: dict = eval(response.content)
self.assertDictEqual(response_dict, {})
def test_create_chat_unlogged(self):
response: HttpResponse = self.client.post(self.url + str(self.user.pk), {"members_id": [self.user.pk, self.dest.pk]})
response_dict: dict = eval(response.content)
self.assertDictEqual(response_dict, {'detail': 'Authentication credentials were not provided.'})

View File

@ -5,6 +5,5 @@ from django.conf.urls.static import static
from . import views from . import views
urlpatterns = [ urlpatterns = [
path("<int:pk>", views.ChatView.as_view(), name="chat_page"), path("", views.ChannelView.as_view(), name="chats_page"),
path("", views.ChatsView.as_view(), name="chats_page"),
] ]

View File

@ -1,79 +1,45 @@
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework import authentication, permissions, status from rest_framework import permissions, status
from rest_framework.authentication import SessionAuthentication from rest_framework.authentication import SessionAuthentication
from .models import ChannelModel, MemberModel, MessageModel
from django.http import HttpRequest
from django.contrib.auth import login
from django.db.models import QuerySet
from django.core import serializers from django.core import serializers
class ChatView(APIView):
from .models import ChatChannelModel, ChatMemberModel, ChatMessageModel
from .serializers import ChatChannelSerializer, ChatMessageSerializer
class ChannelView(APIView):
queryset = ChatChannelModel.objects
serializer_class = ChatChannelSerializer
permission_classes = (permissions.IsAuthenticated,) permission_classes = (permissions.IsAuthenticated,)
authentication_classes = (SessionAuthentication,) authentication_classes = (SessionAuthentication,)
def get(self, request, pk):
if (ChannelModel.objects.filter(pk=pk)):
return Response({'channel_id': pk}, status=status.HTTP_200_OK)
else:
return Response("Channel doesn't exist", status=status.HTTP_404_NOT_FOUND)
def delete(self, request, pk):
ChannelModel.objects.filter(pk=pk).delete()
MessageModel.objects.filter(pk=pk).delete()
MemberModel.objects.filter(pk=pk).delete()
return Response({'channel_id': pk}, status=status.HTTP_200_OK)
class ChatsView(APIView):
def post(self, request): def post(self, request):
data: dict = request.data serializer = self.serializer_class(data = request.data)
users_id = request.data.get("users_id", [])
if len(users_id) < 2:
return Response('Not enought members to create the channel', status=status.HTTP_400_BAD_REQUEST)
if users_id[0] == users_id[1]:
return Response('Same member', status=status.HTTP_400_BAD_REQUEST)
for user_id1 in users_id: serializer.is_valid(raise_exception=True)
for member1 in MemberModel.objects.filter(member_id=user_id1):
for user_id2 in users_id: data: dict = serializer.validated_data
if user_id1 == user_id2:
members_id = data.get("members_id")
if self.request.user.pk not in members_id:
return Response({"detail": "You are trying to create a chat group without you."}, status = status.HTTP_400_BAD_REQUEST)
for member_channel in ChatMemberModel.objects.filter(member_id = members_id[0]):
channel_id: int = member_channel.channel_id
if not ChatChannelModel.objects.filter(pk = channel_id).exists():
continue continue
for member2 in MemberModel.objects.filter(member_id=user_id2): channel: ChatChannelModel = ChatChannelModel.objects.get(pk = channel_id)
if (member1.channel_id == member2.channel_id): if set(channel.get_members_id()) == set(members_id):
messages = MessageModel.objects.filter(channel_id=member1.channel_id).order_by("time") messages = ChatMessageModel.objects.filter(channel_id = channel_id).order_by("time")
messages = serializers.serialize("json", messages) messages = serializers.serialize("json", messages)
return Response({'channel_id': member1.channel_id, 'messages':messages}, status=status.HTTP_200_OK) return Response({'channel_id': channel_id, 'messages': messages}, status=status.HTTP_200_OK)
new_channel = ChannelModel() new_channel_id = ChatChannelModel().create(members_id)
new_channel.save() return Response({'channel_id': new_channel_id}, status=status.HTTP_201_CREATED)
for user_id in users_id:
new_member = MemberModel()
new_member.channel_id = new_channel.pk
new_member.member_id = user_id
new_member.save()
return Response({'channel_id': new_channel.pk}, status=status.HTTP_201_CREATED)
def delete(self, request):
data: dict = request.data
users_id = request.data.get("users_id", [])
#print(list(MemberModel.objects.all()))
for user_id1 in users_id:
for member1 in MemberModel.objects.filter(member_id=user_id1):
for user_id2 in users_id:
if user_id1 == user_id2:
break
for member2 in MemberModel.objects.filter(member_id=user_id2):
if (member1.channel_id == member2.channel_id):
MessageModel.objects.filter(channel_id=member1.channel_id).delete()
member1.delete()
member2.delete()
ChannelModel.objects.get(pk=member1.channel_id).delete()
return Response("Channel removed", status=status.HTTP_200_OK)
return Response("Channel doesn't exist", status=status.HTTP_404_NOT_FOUND)

View File

@ -35,7 +35,9 @@ class Channel {
this.chatSocket.close(); this.chatSocket.close();
} }
updateMessages(messages) { updateMessages(messages)
{
console.log(messages);
messages = JSON.parse(messages); messages = JSON.parse(messages);
let new_messages = []; let new_messages = [];

View File

@ -6,18 +6,18 @@ class Channels {
this.client = client; this.client = client;
} }
async createChannel(users_id, reload) { async createChannel(members_id, reload) {
let null_id = false; let null_id = false;
users_id.forEach(user_id => { members_id.forEach(member_id => {
if (user_id == null) if (member_id == null)
null_id = true; null_id = true;
}); });
if (null_id) if (null_id)
return console.log(users_id, "createChannel error, null id;"); return console.log(members_id, "createChannel error, null id;");
let response = await this.client._post("/api/chat/", { let response = await this.client._post("/api/chat/", {
users_id:users_id members_id:members_id
}); });
let data = await response.json(); let data = await response.json();
@ -28,12 +28,13 @@ class Channels {
let messages = undefined; let messages = undefined;
if (exit_code == 200) if (exit_code == 200)
messages = data.messages; messages = data.messages;
return new Channel(this.client, data.channel_id, users_id, messages, reload);
return new Channel(this.client, data.channel_id, members_id, messages, reload);
} }
async deleteChannel(users_id) { async deleteChannel(members_id) {
let response = await this.client._delete("/api/chat/", { let response = await this.client._delete("/api/chat/", {
users_id:users_id members_id:members_id
}); });
let data = await response.json(); let data = await response.json();

View File

@ -27,7 +27,6 @@ class TournamentSerializer(serializers.ModelSerializer):
if (value < 2): if (value < 2):
raise serializers.ValidationError("The numbers of players must be greather than 2.") raise serializers.ValidationError("The numbers of players must be greather than 2.")
return value return value
def validate_nb_players_by_game(self, value: int): def validate_nb_players_by_game(self, value: int):
if (value < 2): if (value < 2):
raise serializers.ValidationError("The numbers of players by game must be greather than 2.") raise serializers.ValidationError("The numbers of players by game must be greather than 2.")