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.
151 lines
4.3 KiB
Python
151 lines
4.3 KiB
Python
# chat/consumers.py
|
|
import json
|
|
|
|
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"] == "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 --
|
|
|
|
def send_message_to_chat_group(self, event):
|
|
message = event["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_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 |