dockered
This commit is contained in:
0
django/chat/__init__.py
Normal file
0
django/chat/__init__.py
Normal file
6
django/chat/admin.py
Normal file
6
django/chat/admin.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.contrib import admin
|
||||
from .models import ChatChannelModel, ChatMemberModel, ChatMessageModel
|
||||
|
||||
admin.site.register(ChatChannelModel)
|
||||
admin.site.register(ChatMemberModel)
|
||||
admin.site.register(ChatMessageModel)
|
6
django/chat/apps.py
Normal file
6
django/chat/apps.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ChatConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'chat'
|
72
django/chat/consumersChat.py
Normal file
72
django/chat/consumersChat.py
Normal file
@ -0,0 +1,72 @@
|
||||
from channels.generic.websocket import WebsocketConsumer
|
||||
from asgiref.sync import async_to_sync
|
||||
from .models import ChatMemberModel, ChatMessageModel
|
||||
|
||||
import time
|
||||
import json
|
||||
|
||||
|
||||
class ChatConsumer(WebsocketConsumer):
|
||||
|
||||
def connect(self):
|
||||
|
||||
self.user = self.scope["user"]
|
||||
if not self.user.is_authenticated:
|
||||
return
|
||||
|
||||
self.channel_id: int = int(self.scope['url_route']['kwargs']['chat_id'])
|
||||
|
||||
if not ChatMemberModel.objects.filter(member_id=self.user.pk, channel_id=self.channel_id).exists():
|
||||
return
|
||||
|
||||
if self.channel_layer is None:
|
||||
return
|
||||
|
||||
self.room_group_name = f'chat{self.channel_id}'
|
||||
|
||||
async_to_sync(self.channel_layer.group_add)(
|
||||
self.room_group_name,
|
||||
self.channel_name
|
||||
)
|
||||
self.accept()
|
||||
|
||||
def receive(self, text_data=None, bytes_data=None):
|
||||
if text_data is None:
|
||||
return
|
||||
|
||||
user = self.scope["user"]
|
||||
if (user.is_anonymous or not user.is_authenticated):
|
||||
return
|
||||
|
||||
text_data_json: dict = json.loads(text_data)
|
||||
|
||||
message = text_data_json.get('message')
|
||||
if message is None:
|
||||
return
|
||||
|
||||
message_time: int = int(time.time() * 1000)
|
||||
|
||||
async_to_sync(self.channel_layer.group_send)(
|
||||
self.room_group_name,
|
||||
{
|
||||
'type': 'chat_message',
|
||||
'author_id': user.pk,
|
||||
'content': message,
|
||||
'time': message_time,
|
||||
}
|
||||
)
|
||||
|
||||
ChatMessageModel(
|
||||
channel_id=self.channel_id,
|
||||
author_id=user.pk,
|
||||
content=message,
|
||||
time=message_time
|
||||
).save()
|
||||
|
||||
def chat_message(self, event):
|
||||
self.send(text_data=json.dumps({
|
||||
'type': 'chat',
|
||||
'author_id': event['author_id'],
|
||||
'content': event['content'],
|
||||
'time': event['time'],
|
||||
}))
|
41
django/chat/models.py
Normal file
41
django/chat/models.py
Normal file
@ -0,0 +1,41 @@
|
||||
from django.db.models import Model, IntegerField, ForeignKey, CharField, CASCADE
|
||||
from django.db.models.signals import post_delete
|
||||
from django.dispatch import receiver
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
|
||||
class ChatChannelModel(Model):
|
||||
def create(self, members: [User]):
|
||||
self.save()
|
||||
for member in members:
|
||||
ChatMemberModel(channel=self, member=member).save()
|
||||
return self
|
||||
|
||||
def get_members(self):
|
||||
return [member_channel.member for member_channel in ChatMemberModel.objects.filter(channel=self)]
|
||||
|
||||
|
||||
class ChatMemberModel(Model):
|
||||
member = ForeignKey(User, on_delete=CASCADE)
|
||||
channel = ForeignKey(ChatChannelModel, on_delete=CASCADE)
|
||||
|
||||
|
||||
@receiver(post_delete, sender=ChatMemberModel)
|
||||
def delete_channel_when_member_deleted(sender, instance, **kwargs):
|
||||
print(sender, instance)
|
||||
|
||||
|
||||
class ChatMessageModel(Model):
|
||||
channel = ForeignKey(ChatChannelModel, on_delete=CASCADE)
|
||||
author = ForeignKey(User, on_delete=CASCADE)
|
||||
content = CharField(max_length=255)
|
||||
time = IntegerField(primary_key=False)
|
||||
|
||||
|
||||
class AskModel(Model):
|
||||
asker_id = IntegerField(primary_key=False)
|
||||
asked_id = IntegerField(primary_key=False)
|
||||
|
||||
# return if the asker ask the asked to play a game
|
||||
def is_asked(self, asker_id, asked_id):
|
||||
return AskModel.objects.get(asker_id=asker_id, asked_id=asked_id) is not None
|
7
django/chat/routing.py
Normal file
7
django/chat/routing.py
Normal file
@ -0,0 +1,7 @@
|
||||
from django.urls import re_path
|
||||
|
||||
from . import consumersChat
|
||||
|
||||
websocket_urlpatterns = [
|
||||
re_path(r'ws/chat/(?P<chat_id>\d+)$', consumersChat.ChatConsumer.as_asgi()),
|
||||
]
|
10
django/chat/serializers/ask.py
Normal file
10
django/chat/serializers/ask.py
Normal file
@ -0,0 +1,10 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from profiles.models import ProfileModel
|
||||
from ..models import ChatChannelModel, ChatMessageModel
|
||||
|
||||
class AskSerializer(serializers.ModelSerializer):
|
||||
|
||||
members_id = serializers.ListField(child=serializers.IntegerField())
|
40
django/chat/serializers/chat.py
Normal file
40
django/chat/serializers/chat.py
Normal file
@ -0,0 +1,40 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from django.utils.translation import gettext as _
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from ..models import ChatChannelModel, ChatMessageModel
|
||||
|
||||
|
||||
class ChatChannelSerializer(serializers.ModelSerializer):
|
||||
|
||||
members_id = serializers.ListField(child=serializers.IntegerField(), required=True, write_only=True)
|
||||
messages = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = ChatChannelModel
|
||||
fields = ["members_id", "id", 'messages']
|
||||
|
||||
def validate_members_id(self, value):
|
||||
members_id: [int] = value
|
||||
if len(members_id) < 2:
|
||||
raise serializers.ValidationError(_('There is not enough members to create the channel.'))
|
||||
if len(set(members_id)) != len(members_id):
|
||||
raise serializers.ValidationError(_('Duplicate in members list.'))
|
||||
if self.context.get('user').pk not in members_id:
|
||||
raise serializers.ValidationError(_('You are trying to create a group chat without you.'))
|
||||
for member_id in members_id:
|
||||
if not User.objects.filter(pk=member_id).exists():
|
||||
raise serializers.ValidationError(_(f"The profile {member_id} doesn't exist."))
|
||||
return members_id
|
||||
|
||||
def get_messages(self, obj: ChatChannelModel):
|
||||
messages = ChatMessageModel.objects.filter(channel=obj).order_by('time')
|
||||
return ChatMessageSerializer(messages, many=True).data
|
||||
|
||||
|
||||
class ChatMessageSerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = ChatMessageModel
|
||||
fields = ["channel", "author", "content", "time"]
|
30
django/chat/tests.py
Normal file
30
django/chat/tests.py
Normal file
@ -0,0 +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.'})
|
10
django/chat/urls.py
Normal file
10
django/chat/urls.py
Normal file
@ -0,0 +1,10 @@
|
||||
from django.urls import path
|
||||
|
||||
from .views import chat
|
||||
from .views import ask
|
||||
|
||||
urlpatterns = [
|
||||
path("", chat.ChannelView.as_view(), name="chats_page"),
|
||||
path("ask/", ask.AskView.as_view(), name="chats_ask"),
|
||||
path("ask/accept", ask.AskAcceptView.as_view(), name="chats_ask_accept"),
|
||||
]
|
74
django/chat/views/ask.py
Normal file
74
django/chat/views/ask.py
Normal file
@ -0,0 +1,74 @@
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.response import Response
|
||||
from rest_framework import permissions, status
|
||||
from rest_framework.authentication import SessionAuthentication
|
||||
|
||||
from chat.models import AskModel
|
||||
|
||||
from ..serializers.ask import AskSerializer
|
||||
|
||||
from notice.consumers import notice_manager
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
|
||||
class AskView(APIView):
|
||||
|
||||
serializer_class = AskSerializer
|
||||
permission_classes = (permissions.IsAuthenticated,)
|
||||
authentication_classes = (SessionAuthentication,)
|
||||
|
||||
def post(self, request):
|
||||
data: dict = request.data
|
||||
if (data["asked"] is None):
|
||||
return
|
||||
|
||||
asker_id = request.user.pk
|
||||
asked_id = data["asked"]
|
||||
|
||||
if AskModel().is_asked(asker_id, asked_id):
|
||||
return Response(status=status.HTTP_208_ALREADY_REPORTED)
|
||||
|
||||
AskModel(asker_id=asker_id, asked_id=asked_id).save()
|
||||
return Response(status=status.HTTP_201_CREATED)
|
||||
|
||||
def delete(self, request):
|
||||
data: dict = request.data
|
||||
if (data["asker"] is None):
|
||||
return
|
||||
|
||||
asker_id = data["asker"]
|
||||
asked_id = request.user.pk
|
||||
|
||||
if not AskModel().is_asked(asker_id, asked_id):
|
||||
return Response(status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
asker = User.objects.filter(pk=asked_id)[0]
|
||||
notice_manager.refuse_game(request.user, asker)
|
||||
|
||||
AskModel(asker_id=asker_id, asked_id=asked_id).delete()
|
||||
|
||||
return Response(status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
class AskAcceptView(APIView):
|
||||
|
||||
serializer_class = AskSerializer
|
||||
permission_classes = (permissions.IsAuthenticated,)
|
||||
authentication_classes = (SessionAuthentication,)
|
||||
|
||||
def post(self, request):
|
||||
data: dict = request.data
|
||||
if (data["asker"] is None):
|
||||
return
|
||||
|
||||
asker_id = data["asker"]
|
||||
asked_id = request.user.pk
|
||||
|
||||
if not AskModel().is_asked(asker_id, asked_id):
|
||||
return Response(status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
notice_manager.accept_game(asker=User.objects.filter(pk=asker_id)[0], asked=User.objects.filter(pk=asked_id)[0])
|
||||
|
||||
AskModel(asker_id=asker_id, asked_id=asked_id).delete()
|
||||
return Response(status=status.HTTP_200_OK)
|
31
django/chat/views/chat.py
Normal file
31
django/chat/views/chat.py
Normal file
@ -0,0 +1,31 @@
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.response import Response
|
||||
from rest_framework import permissions
|
||||
from rest_framework.authentication import SessionAuthentication
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from ..models import ChatChannelModel, ChatMemberModel
|
||||
from ..serializers.chat import ChatChannelSerializer
|
||||
|
||||
|
||||
class ChannelView(APIView):
|
||||
|
||||
serializer_class = ChatChannelSerializer
|
||||
permission_classes = (permissions.IsAuthenticated,)
|
||||
authentication_classes = (SessionAuthentication,)
|
||||
|
||||
def post(self, request):
|
||||
serializer = self.serializer_class(data=request.data, context={'user': request.user})
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
members_id = serializer.validated_data.get('members_id')
|
||||
member_list = [User.objects.get(pk=member_id) for member_id in members_id]
|
||||
|
||||
for member_channel in ChatMemberModel.objects.filter(member=member_list[0]):
|
||||
channel: ChatChannelModel = member_channel.channel
|
||||
if set(channel.get_members()) == set(member_list):
|
||||
break
|
||||
else:
|
||||
channel = ChatChannelModel().create(member_list)
|
||||
return Response(self.serializer_class(channel).data)
|
Reference in New Issue
Block a user