From d59bb75dcec9bbe493342477080fe2b87209b5ca Mon Sep 17 00:00:00 2001 From: Emmy D'Anello Date: Sat, 27 Apr 2024 13:27:27 +0200 Subject: [PATCH] Fetching last messages is working Signed-off-by: Emmy D'Anello --- chat/consumers.py | 29 +++++++++++++-- chat/static/chat.js | 87 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 101 insertions(+), 15 deletions(-) diff --git a/chat/consumers.py b/chat/consumers.py index c356089..c4e7bb6 100644 --- a/chat/consumers.py +++ b/chat/consumers.py @@ -62,6 +62,8 @@ class ChatConsumer(AsyncJsonWebsocketConsumer): await self.fetch_channels() case 'send_message': await self.receive_message(content) + case 'fetch_messages': + await self.fetch_messages(content['channel_id']) case unknown: print("Unknown message type:", unknown) @@ -101,11 +103,34 @@ class ChatConsumer(AsyncJsonWebsocketConsumer): await self.channel_layer.group_send(f'chat-{channel.id}', { 'type': 'chat.send_message', 'id': message.id, + 'channel_id': channel.id, 'timestamp': message.created_at.isoformat(), 'author': await message.aget_author_name(), 'content': message.content, }) + async def fetch_messages(self, channel_id: int, offset: int = 0, limit: int = 50) -> None: + channel = await Channel.objects.aget(id=channel_id) + read_channels = await Channel.get_accessible_channels(self.scope['user'], 'read') + if not await read_channels.acontains(channel): + return + + messages = Message.objects.filter(channel=channel).order_by('created_at')[offset:offset + limit].all() + await self.send_json({ + 'type': 'fetch_messages', + 'channel_id': channel_id, + 'messages': [ + { + 'id': message.id, + 'timestamp': message.created_at.isoformat(), + 'author': await message.aget_author_name(), + 'content': message.content, + } + async for message in messages + ] + }) + async def chat_send_message(self, message) -> None: - await self.send_json({'type': 'send_message', 'id': message['id'], 'timestamp': message['timestamp'], - 'author': message['author'], 'content': message['content']}) + await self.send_json({'type': 'send_message', 'id': message['id'], 'channel_id': message['channel_id'], + 'timestamp': message['timestamp'], 'author': message['author'], + 'content': message['content']}) diff --git a/chat/static/chat.js b/chat/static/chat.js index 2265508..8557008 100644 --- a/chat/static/chat.js +++ b/chat/static/chat.js @@ -5,6 +5,7 @@ })() let channels = {} +let messages = {} let selected_channel_id = null /** @@ -35,6 +36,8 @@ function selectChannel(channel_id) { let messageInput = document.getElementById('input-message') messageInput.disabled = !channel['write_access'] + + redrawMessages() } function sendMessage() { @@ -57,28 +60,84 @@ function setChannels(new_channels) { channels = {} for (let channel of new_channels) { channels[channel['id']] = channel + if (!messages[channel['id']]) + messages[channel['id']] = [] + + socket.send(JSON.stringify({ + 'type': 'fetch_messages', + 'channel_id': channel['id'], + })) } - if (new_channels && (!selected_channel_id || !channels[selected_channel_id])) { + if (new_channels && (!selected_channel_id || !channels[selected_channel_id])) selectChannel(Object.keys(channels)[0]) - } } function receiveMessage(message) { + messages[message['channel_id']].push(message) + redrawMessages() +} + +function fetchMessages(data) { + let channel_id = data['channel_id'] + let new_messages = data['messages'] + + if (!messages[channel_id]) + messages[channel_id] = [] + + for (let message of new_messages) { + messages[channel_id].push(message) + } + + redrawMessages() +} + +function redrawMessages() { let messageList = document.getElementById('message-list') + messageList.innerHTML = '' - let messageElement = document.createElement('li') - messageElement.classList.add('list-group-item') - messageList.appendChild(messageElement) + let lastMessage = null + let lastContentDiv = null - let authorDiv = document.createElement('div') - authorDiv.classList.add('text-muted', 'fw-bold') - authorDiv.innerText = message['author'] - messageElement.appendChild(authorDiv) + for (let message of messages[selected_channel_id]) { + if (lastMessage && lastMessage['author'] === message['author']) { + let lastTimestamp = new Date(lastMessage['timestamp']) + let newTimestamp = new Date(message['timestamp']) + if ((newTimestamp - lastTimestamp) / 1000 < 60 * 10) { + let messageContentDiv = document.createElement('div') + messageContentDiv.innerText = message['content'] + lastContentDiv.appendChild(messageContentDiv) + continue + } + } - let contentDiv = document.createElement('div') - contentDiv.innerText = message['content'] - messageElement.appendChild(contentDiv) + let messageElement = document.createElement('li') + messageElement.classList.add('list-group-item') + messageList.appendChild(messageElement) + + let authorDiv = document.createElement('div') + messageElement.appendChild(authorDiv) + + let authorSpan = document.createElement('span') + authorSpan.classList.add('text-muted', 'fw-bold') + authorSpan.innerText = message['author'] + authorDiv.appendChild(authorSpan) + + let dateSpan = document.createElement('span') + dateSpan.classList.add('text-muted', 'float-end') + dateSpan.innerText = new Date(message['timestamp']).toLocaleString() + authorDiv.appendChild(dateSpan) + + let contentDiv = document.createElement('div') + messageElement.appendChild(contentDiv) + + let messageContentDiv = document.createElement('div') + messageContentDiv.innerText = message['content'] + contentDiv.appendChild(messageContentDiv) + + lastMessage = message + lastContentDiv = contentDiv + } } document.addEventListener('DOMContentLoaded', () => { @@ -87,7 +146,6 @@ document.addEventListener('DOMContentLoaded', () => { * @param data The received message */ function processMessage(data) { - // TODO Implement chat protocol switch (data['type']) { case 'fetch_channels': setChannels(data['channels']) @@ -95,6 +153,9 @@ document.addEventListener('DOMContentLoaded', () => { case 'send_message': receiveMessage(data) break + case 'fetch_messages': + fetchMessages(data) + break default: console.log(data) console.error('Unknown message type:', data['type'])