diff --git a/chat/admin.py b/chat/admin.py index 8f38a1d..2778881 100644 --- a/chat/admin.py +++ b/chat/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from .models import ChannelModel, MemberModel, MessageModel +from .models import ChatChannelModel, ChatMemberModel, ChatMessageModel -admin.site.register(ChannelModel) -admin.site.register(MemberModel) -admin.site.register(MessageModel) +admin.site.register(ChatChannelModel) +admin.site.register(ChatMemberModel) +admin.site.register(ChatMessageModel) diff --git a/chat/consumers.py b/chat/consumers.py index 9f07678..9ac7d9d 100644 --- a/chat/consumers.py +++ b/chat/consumers.py @@ -1,21 +1,25 @@ -import json from channels.generic.websocket import WebsocketConsumer from asgiref.sync import async_to_sync -from .models import MemberModel, MessageModel + +from .models import ChatMemberModel, ChatMessageModel from profiles.models import BlockModel + import time +import json class ChatConsumer(WebsocketConsumer): + def connect(self): - channel_id : str = self.scope['path'].split('/')[3] - - self.room_group_name = 'chat' + channel_id - + user = self.scope["user"] if (user.is_anonymous or not user.is_authenticated): 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 if (self.channel_layer == None): @@ -30,27 +34,33 @@ class ChatConsumer(WebsocketConsumer): def receive(self, text_data=None, bytes_data=None): + if text_data == None: 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"] if (user.is_anonymous or not user.is_authenticated): 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 if (self.channel_layer == None): return - message_time : int = int(time.time() * 1000) + message_time: int = int(time.time() * 1000) if (len(receivers_id) == 1 and BlockModel.objects.filter(blocker=user.pk, blocked=receivers_id[0]) or @@ -68,22 +78,17 @@ class ChatConsumer(WebsocketConsumer): } ) - new_message = MessageModel() - new_message.channel_id = channel_id - new_message.author_id = user.pk - new_message.content = message - new_message.time = message_time - new_message.save() - + new_message = ChatMessageModel(channel_id = channel_id, author_id = user.pk, content = message, time = message_time).save() def chat_message(self, event): - channel_id : int = int(self.scope['path'].split('/')[3]) user = self.scope["user"] if (user.is_anonymous or not user.is_authenticated): 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 self.send(text_data=json.dumps({ diff --git a/chat/models.py b/chat/models.py index bc72b90..852ced7 100644 --- a/chat/models.py +++ b/chat/models.py @@ -4,21 +4,28 @@ from django.contrib.auth.models import User from django.contrib import admin # Create your models here. -class ChannelModel(models.Model): - pass +class ChatChannelModel(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() -class MemberModel(models.Model): + 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) channel_id = IntegerField(primary_key=False) def __str__(self): 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) author_id = IntegerField(primary_key=False) content = models.CharField(max_length=255) time = IntegerField(primary_key=False) def __str__(self): - return "author_id: " + str(self.author_id) + ", channel_id: " + str(self.channel_id) + ", content: " + self.content + return "author_id: " + str(self.author_id) + ", channel_id: " + str(self.channel_id) + ", content: " + self.content \ No newline at end of file diff --git a/chat/serializers.py b/chat/serializers.py index 2d62490..3eedadf 100644 --- a/chat/serializers.py +++ b/chat/serializers.py @@ -1,8 +1,30 @@ 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: - model = ChannelModel - fields = [] + model = ChatChannelModel + 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"] \ No newline at end of file diff --git a/chat/tests.py b/chat/tests.py index 7ce503c..cf0ee9f 100644 --- a/chat/tests.py +++ b/chat/tests.py @@ -1,3 +1,30 @@ 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. +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.'}) diff --git a/chat/urls.py b/chat/urls.py index f6a905e..4dce2f3 100644 --- a/chat/urls.py +++ b/chat/urls.py @@ -5,6 +5,5 @@ from django.conf.urls.static import static from . import views urlpatterns = [ - path("", views.ChatView.as_view(), name="chat_page"), - path("", views.ChatsView.as_view(), name="chats_page"), + path("", views.ChannelView.as_view(), name="chats_page"), ] diff --git a/chat/views.py b/chat/views.py index 23e51ea..bdee932 100644 --- a/chat/views.py +++ b/chat/views.py @@ -1,79 +1,45 @@ from rest_framework.views import APIView 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 .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 -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,) - 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) + authentication_classes = (SessionAuthentication,) - 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): - data: dict = 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) + serializer = self.serializer_class(data = request.data) + + serializer.is_valid(raise_exception=True) - 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: - continue - for member2 in MemberModel.objects.filter(member_id=user_id2): - if (member1.channel_id == member2.channel_id): - messages = MessageModel.objects.filter(channel_id=member1.channel_id).order_by("time") - messages = serializers.serialize("json", messages) - return Response({'channel_id': member1.channel_id, 'messages':messages}, status=status.HTTP_200_OK) - - new_channel = ChannelModel() - new_channel.save() + data: dict = serializer.validated_data - for user_id in users_id: + 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) - new_member = MemberModel() - new_member.channel_id = new_channel.pk - new_member.member_id = user_id - new_member.save() + 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 + channel: ChatChannelModel = ChatChannelModel.objects.get(pk = channel_id) + if set(channel.get_members_id()) == set(members_id): + messages = ChatMessageModel.objects.filter(channel_id = channel_id).order_by("time") + messages = serializers.serialize("json", messages) + return Response({'channel_id': channel_id, 'messages': messages}, status=status.HTTP_200_OK) - 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) + new_channel_id = ChatChannelModel().create(members_id) + return Response({'channel_id': new_channel_id}, status=status.HTTP_201_CREATED) \ No newline at end of file diff --git a/frontend/static/js/api/chat/channel.js b/frontend/static/js/api/chat/channel.js index 32f63f9..881b0bd 100644 --- a/frontend/static/js/api/chat/channel.js +++ b/frontend/static/js/api/chat/channel.js @@ -35,7 +35,9 @@ class Channel { this.chatSocket.close(); } - updateMessages(messages) { + updateMessages(messages) + { + console.log(messages); messages = JSON.parse(messages); let new_messages = []; diff --git a/frontend/static/js/api/chat/channels.js b/frontend/static/js/api/chat/channels.js index 5fad6fc..4d6bcc4 100644 --- a/frontend/static/js/api/chat/channels.js +++ b/frontend/static/js/api/chat/channels.js @@ -6,18 +6,18 @@ class Channels { this.client = client; } - async createChannel(users_id, reload) { + async createChannel(members_id, reload) { let null_id = false; - users_id.forEach(user_id => { - if (user_id == null) + members_id.forEach(member_id => { + if (member_id == null) null_id = true; }); 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/", { - users_id:users_id + members_id:members_id }); let data = await response.json(); @@ -28,12 +28,13 @@ class Channels { let messages = undefined; if (exit_code == 200) 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/", { - users_id:users_id + members_id:members_id }); let data = await response.json(); diff --git a/tournament/serializers.py b/tournament/serializers.py index 7e06053..c1aba61 100644 --- a/tournament/serializers.py +++ b/tournament/serializers.py @@ -27,7 +27,6 @@ class TournamentSerializer(serializers.ModelSerializer): if (value < 2): raise serializers.ValidationError("The numbers of players must be greather than 2.") return value - def validate_nb_players_by_game(self, value: int): if (value < 2): raise serializers.ValidationError("The numbers of players by game must be greather than 2.")