From d617dd77c1efed93b713092f3d5cd7527234ccaf Mon Sep 17 00:00:00 2001 From: Emmy D'Anello Date: Sat, 27 Apr 2024 14:12:08 +0200 Subject: [PATCH] Properly sort messages and add fetch previous messages ability Signed-off-by: Emmy D'Anello --- chat/consumers.py | 12 +++++--- chat/static/chat.js | 48 +++++++++++++++++++++-------- chat/templates/chat/chat.html | 6 ++++ locale/fr/LC_MESSAGES/django.po | 54 ++++++++++++++++++--------------- 4 files changed, 78 insertions(+), 42 deletions(-) diff --git a/chat/consumers.py b/chat/consumers.py index c4e7bb6..1f7441c 100644 --- a/chat/consumers.py +++ b/chat/consumers.py @@ -63,7 +63,7 @@ class ChatConsumer(AsyncJsonWebsocketConsumer): case 'send_message': await self.receive_message(content) case 'fetch_messages': - await self.fetch_messages(content['channel_id']) + await self.fetch_messages(**content) case unknown: print("Unknown message type:", unknown) @@ -109,17 +109,19 @@ class ChatConsumer(AsyncJsonWebsocketConsumer): 'content': message.content, }) - async def fetch_messages(self, channel_id: int, offset: int = 0, limit: int = 50) -> None: + async def fetch_messages(self, channel_id: int, offset: int = 0, limit: int = 50, **_kwargs) -> 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() + limit = min(limit, 200) # Fetch only maximum 200 messages at the time + + 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': [ + 'messages': list(reversed([ { 'id': message.id, 'timestamp': message.created_at.isoformat(), @@ -127,7 +129,7 @@ class ChatConsumer(AsyncJsonWebsocketConsumer): 'content': message.content, } async for message in messages - ] + ])) }) async def chat_send_message(self, message) -> None: diff --git a/chat/static/chat.js b/chat/static/chat.js index 8557008..68d0c04 100644 --- a/chat/static/chat.js +++ b/chat/static/chat.js @@ -4,6 +4,8 @@ await Notification.requestPermission() })() +const MAX_MESSAGES = 50 + let channels = {} let messages = {} let selected_channel_id = null @@ -61,12 +63,9 @@ function setChannels(new_channels) { for (let channel of new_channels) { channels[channel['id']] = channel if (!messages[channel['id']]) - messages[channel['id']] = [] + messages[channel['id']] = new Map() - socket.send(JSON.stringify({ - 'type': 'fetch_messages', - 'channel_id': channel['id'], - })) + fetchMessages(channel['id']) } if (new_channels && (!selected_channel_id || !channels[selected_channel_id])) @@ -78,16 +77,35 @@ function receiveMessage(message) { redrawMessages() } -function fetchMessages(data) { +function fetchMessages(channel_id, offset = 0, limit = MAX_MESSAGES) { + socket.send(JSON.stringify({ + 'type': 'fetch_messages', + 'channel_id': channel_id, + 'offset': offset, + 'limit': limit, + })) +} + +function fetchPreviousMessages() { + let channel_id = selected_channel_id + let offset = messages[channel_id].size + fetchMessages(channel_id, offset, MAX_MESSAGES) +} + +function receiveFetchedMessages(data) { let channel_id = data['channel_id'] let new_messages = data['messages'] if (!messages[channel_id]) - messages[channel_id] = [] + messages[channel_id] = new Map() - for (let message of new_messages) { - messages[channel_id].push(message) - } + for (let message of new_messages) + messages[channel_id].set(message['id'], message) + + // Sort messages by timestamp + messages[channel_id] = new Map([...messages[channel_id].values()] + .sort((a, b) => new Date(a['timestamp']) - new Date(b['timestamp'])) + .map(message => [message['id'], message])) redrawMessages() } @@ -99,7 +117,7 @@ function redrawMessages() { let lastMessage = null let lastContentDiv = null - for (let message of messages[selected_channel_id]) { + for (let message of messages[selected_channel_id].values()) { if (lastMessage && lastMessage['author'] === message['author']) { let lastTimestamp = new Date(lastMessage['timestamp']) let newTimestamp = new Date(message['timestamp']) @@ -138,6 +156,12 @@ function redrawMessages() { lastMessage = message lastContentDiv = contentDiv } + + let fetchMoreButton = document.getElementById('fetch-previous-messages') + if (!messages[selected_channel_id] || messages[selected_channel_id].size % MAX_MESSAGES !== 0) + fetchMoreButton.classList.add('d-none') + else + fetchMoreButton.classList.remove('d-none') } document.addEventListener('DOMContentLoaded', () => { @@ -154,7 +178,7 @@ document.addEventListener('DOMContentLoaded', () => { receiveMessage(data) break case 'fetch_messages': - fetchMessages(data) + receiveFetchedMessages(data) break default: console.log(data) diff --git a/chat/templates/chat/chat.html b/chat/templates/chat/chat.html index b3d293a..4318f36 100644 --- a/chat/templates/chat/chat.html +++ b/chat/templates/chat/chat.html @@ -35,6 +35,12 @@