mirror of
				https://gitlab.com/animath/si/plateforme.git
				synced 2025-11-01 00:24:29 +01:00 
			
		
		
		
	Properly sort messages and add fetch previous messages ability
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
This commit is contained in:
		| @@ -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: | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -35,6 +35,12 @@ | ||||
|             </h3> | ||||
|         </div> | ||||
|         <div class="card-body overflow-y-scroll mw-100 h-100 flex-grow-0" id="chat-messages"> | ||||
|             <div class="text-center d-none" id="fetch-previous-messages"> | ||||
|                 <a href="#" class="nav-link" onclick="event.preventDefault(); fetchPreviousMessages()"> | ||||
|                     {% trans "Fetch previous messages…" %} | ||||
|                 </a> | ||||
|                 <hr> | ||||
|             </div> | ||||
|             <ul class="list-group list-group-flush" id="message-list"></ul> | ||||
|         </div> | ||||
|         <div class="card-footer mt-auto"> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user