Implement chat backend and frontend scaffolding

Expanded chat backend with message reply, edit, delete, and reaction support in consumers and models. Updated routing to use chat_id. Added chat-related view stubs. On the frontend, introduced ChatLayout and ChatPage scaffolding, and routed protected routes through ChatLayout.
This commit is contained in:
2025-12-26 17:39:11 +01:00
parent deb853b564
commit f7605812c1
7 changed files with 177 additions and 11 deletions

View File

@@ -5,38 +5,147 @@ from account.models import UserProfile
from channels.db import database_sync_to_async
from channels.generic.websocket import AsyncWebsocketConsumer
from asgiref.sync import sync_to_async, async_to_sync
class ChatConsumer(AsyncWebsocketConsumer):
# -- CONNECT --
async def connect(self):
self.chat_id = self.scope["url_route"]["kwargs"]["chat_id"]
self.chat_name = f"chat_{self.chat_id}"
user = self.scope["user"]
if not user.is_authenticated:
await self.close(code=4401) # unauthorized
return
#join chat group
async_to_sync(self.channel_layer.group_add)(
self.chat_name,
)
await self.accept()
# -- DISCONNECT --
async def disconnect(self, close_code):
async_to_sync(self.channel_layer.group_discard)(
self.chat_name
)
self.disconnect()
pass
# -- RECIVE --
async def receive(self, data):
if data["type"] == "chat_message":
pass
if data["type"] == "new_chat_message":
message = data["message"]
# Send message to room group
async_to_sync(self.channel_layer.group_send)(
self.chat_name, {"type": "chat.message", "message": message}
)
elif data["type"] == "new_reply_chat_message":
message = data["message"]
reply_to_id = data["reply_to_id"]
# Send message to room group
async_to_sync(self.channel_layer.group_send)(
self.chat_name, {"type": "reply.chat.message", "message": message, "reply_to_id": reply_to_id}
)
elif data["type"] == "edit_chat_message":
message = data["message"]
# Send message to room group
async_to_sync(self.channel_layer.group_send)(
self.chat_name, {"type": "edit.message", "message": message}
)
elif data["type"] == "delete_chat_message":
message_id = data["message_id"]
# Send message to room group
async_to_sync(self.channel_layer.group_send)(
self.chat_name, {"type": "delete.message", "message_id": message_id}
)
elif data["type"] == "typing":
is_typing = data["is_typing"]
# Send typing status to room group
async_to_sync(self.channel_layer.group_send)(
self.chat_name, {"type": "typing.status", "user": self.scope["user"].username, "is_typing": is_typing}
)
elif data["type"] == "stop_typing":
# Send stop typing status to room group
async_to_sync(self.channel_layer.group_send)(
self.chat_name, {"type": "stop.typing", "user": self.scope["user"].username}
)
elif data["type"] == "reaction":
message_id = data["message_id"]
emoji = data["emoji"]
# Send reaction to room group
async_to_sync(self.channel_layer.group_send)(
self.chat_name, {"type": "message.reaction", "message_id": message_id, "emoji": emoji, "user": self.scope["user"].username}
)
elif data["type"] == "unreaction":
message_id = data["message_id"]
emoji = data["emoji"]
# Send unreaction to room group
async_to_sync(self.channel_layer.group_send)(
self.chat_name, {"type": "message.unreaction", "message_id": message_id, "emoji": emoji, "user": self.scope["user"].username}
)
else:
self.close(reason="Unsupported message type")
# -- CUSTOM METHODS --
async def send_message_to_chat_group(self, event):
def send_message_to_chat_group(self, event):
message = event["message"]
await create_new_message()
await self.send(text_data=json.dumps({"message": message}))
create_new_message()
self.send(text_data=json.dumps({"message": message}))
def edit_message_in_chat_group(self, event):
message = event["message"]
self.send(text_data=json.dumps({"message": message}))
# -- MESSAGES --
@database_sync_to_async
def create_new_message():
return None
@database_sync_to_async
def create_new_message(user_id):
def create_new_reply_message():
return None
@database_sync_to_async
def edit_message():
return None
@database_sync_to_async
def delete_message():
return None
# -- REACTIONS --
@database_sync_to_async
def react_to_message():
return None
@database_sync_to_async
def unreact_to_message():
return None

View File

@@ -47,6 +47,15 @@ class Message(models.Model):
on_delete=models.CASCADE,
related_name='sent_messages'
)
#odpověď na jinou zprávu
reply_to = models.ForeignKey(
'self',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='replies'
)
content = models.TextField(blank=True)

View File

@@ -4,5 +4,5 @@ from django.urls import re_path
from . import consumers
websocket_urlpatterns = [
re_path(r"ws/chat/(?P<room_name>\w+)/$", consumers.ChatConsumer.as_asgi()),
re_path(r"ws/chat/(?P<chat_id>\w+)/$", consumers.ChatConsumer.as_asgi()),
]

View File

@@ -1,3 +1,25 @@
from django.shortcuts import render
# Create your views here.
def get_users_chats(request):
return None
def create_chat(request):
return None
def invite_user_to_chat(request, chat_id: int, user_ids: list):
return None
def delete_chat(request, chat_id: int):
return None
def leave_chat(request, chat_id: int):
return None
def edit_chat(request, chat_object):
return None
def get_chat_messages(request, chat_id: int, limit: int = 50, offset: int = 0):
return None