mirror of
				https://gitlab.com/animath/si/plateforme.git
				synced 2025-11-04 08:22:10 +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">
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: TFJM\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: \n"
 | 
			
		||||
"POT-Creation-Date: 2024-04-27 11:02+0200\n"
 | 
			
		||||
"POT-Creation-Date: 2024-04-27 14:10+0200\n"
 | 
			
		||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 | 
			
		||||
"Last-Translator: Emmy D'Anello <emmy.danello@animath.fr>\n"
 | 
			
		||||
"Language-Team: LANGUAGE <LL@li.org>\n"
 | 
			
		||||
@@ -21,20 +21,20 @@ msgstr ""
 | 
			
		||||
msgid "API"
 | 
			
		||||
msgstr "API"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:17 participation/models.py:35 participation/models.py:263
 | 
			
		||||
#: chat/models.py:18 participation/models.py:35 participation/models.py:263
 | 
			
		||||
#: participation/tables.py:18 participation/tables.py:34
 | 
			
		||||
msgid "name"
 | 
			
		||||
msgstr "nom"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:22
 | 
			
		||||
#: chat/models.py:23
 | 
			
		||||
msgid "read permission"
 | 
			
		||||
msgstr "permission de lecture"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:28
 | 
			
		||||
#: chat/models.py:29
 | 
			
		||||
msgid "write permission"
 | 
			
		||||
msgstr "permission d'écriture"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:38 draw/admin.py:53 draw/admin.py:71 draw/admin.py:88
 | 
			
		||||
#: chat/models.py:39 draw/admin.py:53 draw/admin.py:71 draw/admin.py:88
 | 
			
		||||
#: draw/models.py:26 participation/admin.py:79 participation/admin.py:140
 | 
			
		||||
#: participation/admin.py:171 participation/models.py:693
 | 
			
		||||
#: participation/models.py:717 participation/models.py:935
 | 
			
		||||
@@ -43,7 +43,7 @@ msgstr "permission d'écriture"
 | 
			
		||||
msgid "tournament"
 | 
			
		||||
msgstr "tournoi"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:40
 | 
			
		||||
#: chat/models.py:41
 | 
			
		||||
msgid ""
 | 
			
		||||
"For a permission that concerns a tournament, indicates what is the concerned "
 | 
			
		||||
"tournament."
 | 
			
		||||
@@ -51,21 +51,21 @@ msgstr ""
 | 
			
		||||
"Pour une permission qui concerne un tournoi, indique quel est le tournoi "
 | 
			
		||||
"concerné."
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:49 draw/models.py:429 draw/models.py:456
 | 
			
		||||
#: chat/models.py:50 draw/models.py:429 draw/models.py:456
 | 
			
		||||
#: participation/admin.py:136 participation/admin.py:155
 | 
			
		||||
#: participation/models.py:1434 participation/models.py:1443
 | 
			
		||||
#: participation/tables.py:84
 | 
			
		||||
msgid "pool"
 | 
			
		||||
msgstr "poule"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:51
 | 
			
		||||
#: chat/models.py:52
 | 
			
		||||
msgid ""
 | 
			
		||||
"For a permission that concerns a pool, indicates what is the concerned pool."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Pour une permission qui concerne une poule, indique quelle est la poule "
 | 
			
		||||
"concernée."
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:60 draw/templates/draw/tournament_content.html:277
 | 
			
		||||
#: chat/models.py:61 draw/templates/draw/tournament_content.html:277
 | 
			
		||||
#: participation/admin.py:167 participation/models.py:252
 | 
			
		||||
#: participation/models.py:708
 | 
			
		||||
#: participation/templates/participation/tournament_harmonize.html:15
 | 
			
		||||
@@ -75,18 +75,18 @@ msgstr ""
 | 
			
		||||
msgid "team"
 | 
			
		||||
msgstr "équipe"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:62
 | 
			
		||||
#: chat/models.py:63
 | 
			
		||||
msgid ""
 | 
			
		||||
"For a permission that concerns a team, indicates what is the concerned team."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Pour une permission qui concerne une équipe, indique quelle est l'équipe "
 | 
			
		||||
"concernée."
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:66
 | 
			
		||||
#: chat/models.py:67
 | 
			
		||||
msgid "private"
 | 
			
		||||
msgstr "privé"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:68
 | 
			
		||||
#: chat/models.py:69
 | 
			
		||||
msgid ""
 | 
			
		||||
"If checked, only users who have been explicitly added to the channel will be "
 | 
			
		||||
"able to access it."
 | 
			
		||||
@@ -94,11 +94,11 @@ msgstr ""
 | 
			
		||||
"Si sélectionné, seul⋅es les utilisateur⋅rices qui ont été explicitement "
 | 
			
		||||
"ajouté⋅es au canal pourront y accéder."
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:73
 | 
			
		||||
#: chat/models.py:74
 | 
			
		||||
msgid "invited users"
 | 
			
		||||
msgstr "Utilisateur⋅rices invité"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:76
 | 
			
		||||
#: chat/models.py:77
 | 
			
		||||
msgid ""
 | 
			
		||||
"Extra users who have been invited to the channel, in addition to the "
 | 
			
		||||
"permitted group of the channel."
 | 
			
		||||
@@ -106,52 +106,56 @@ msgstr ""
 | 
			
		||||
"Utilisateur⋅rices supplémentaires qui ont été invité⋅es au canal, en plus du "
 | 
			
		||||
"groupe autorisé du canal."
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:81
 | 
			
		||||
#: chat/models.py:82
 | 
			
		||||
#, python-brace-format
 | 
			
		||||
msgid "Channel {name}"
 | 
			
		||||
msgstr "Canal {name}"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:150 chat/models.py:159
 | 
			
		||||
#: chat/models.py:148 chat/models.py:157
 | 
			
		||||
msgid "channel"
 | 
			
		||||
msgstr "canal"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:151
 | 
			
		||||
#: chat/models.py:149
 | 
			
		||||
msgid "channels"
 | 
			
		||||
msgstr "canaux"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:165
 | 
			
		||||
#: chat/models.py:163
 | 
			
		||||
msgid "author"
 | 
			
		||||
msgstr "auteur⋅rice"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:172
 | 
			
		||||
#: chat/models.py:170
 | 
			
		||||
msgid "created at"
 | 
			
		||||
msgstr "créé le"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:177
 | 
			
		||||
#: chat/models.py:175
 | 
			
		||||
msgid "updated at"
 | 
			
		||||
msgstr "modifié le"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:182
 | 
			
		||||
#: chat/models.py:180
 | 
			
		||||
msgid "content"
 | 
			
		||||
msgstr "contenu"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:186
 | 
			
		||||
#: chat/models.py:243
 | 
			
		||||
msgid "message"
 | 
			
		||||
msgstr "message"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:187
 | 
			
		||||
#: chat/models.py:244
 | 
			
		||||
msgid "messages"
 | 
			
		||||
msgstr "messages"
 | 
			
		||||
 | 
			
		||||
#: chat/templates/chat/chat.html:8
 | 
			
		||||
msgid "JavaScript must be enabled on your browser to access chat."
 | 
			
		||||
msgstr ""
 | 
			
		||||
msgstr "JavaScript doit être activé sur votre navigateur pour accéder au chat."
 | 
			
		||||
 | 
			
		||||
#: chat/templates/chat/chat.html:12
 | 
			
		||||
msgid "Chat channels"
 | 
			
		||||
msgstr "Canaux de chat"
 | 
			
		||||
 | 
			
		||||
#: chat/templates/chat/chat.html:43
 | 
			
		||||
#: chat/templates/chat/chat.html:40
 | 
			
		||||
msgid "Fetch previous messages…"
 | 
			
		||||
msgstr "Récupérer les messages précédents…"
 | 
			
		||||
 | 
			
		||||
#: chat/templates/chat/chat.html:52
 | 
			
		||||
msgid "Send message…"
 | 
			
		||||
msgstr "Envoyer un message…"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user