mirror of
				https://gitlab.com/animath/si/plateforme.git
				synced 2025-11-04 08:22:10 +01:00 
			
		
		
		
	@@ -4,6 +4,9 @@
 | 
			
		||||
    await Notification.requestPermission()
 | 
			
		||||
})()
 | 
			
		||||
 | 
			
		||||
let channels = {}
 | 
			
		||||
let selected_channel_id = null
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Display a new notification with the given title and the given body.
 | 
			
		||||
 * @param title The title of the notification
 | 
			
		||||
@@ -18,6 +21,33 @@ function showNotification(title, body, timeout = 5000) {
 | 
			
		||||
    return notif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function selectChannel(channel_id) {
 | 
			
		||||
    let channel = channels[channel_id]
 | 
			
		||||
    if (!channel) {
 | 
			
		||||
        console.error('Channel not found:', channel_id)
 | 
			
		||||
        return
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    selected_channel_id = channel_id
 | 
			
		||||
 | 
			
		||||
    let channelTitle = document.getElementById('channel-title')
 | 
			
		||||
    channelTitle.innerText = channel['name']
 | 
			
		||||
 | 
			
		||||
    let messageInput = document.getElementById('input-message')
 | 
			
		||||
    messageInput.disabled = !channel['write_access']
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function setChannels(new_channels) {
 | 
			
		||||
    channels = {}
 | 
			
		||||
    for (let channel of new_channels) {
 | 
			
		||||
        channels[channel['id']] = channel
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (new_channels && (!selected_channel_id || !channels[selected_channel_id])) {
 | 
			
		||||
        selectChannel(Object.keys(channels)[0])
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
document.addEventListener('DOMContentLoaded', () => {
 | 
			
		||||
    /**
 | 
			
		||||
     * Process the received data from the server.
 | 
			
		||||
@@ -25,7 +55,15 @@ document.addEventListener('DOMContentLoaded', () => {
 | 
			
		||||
     */
 | 
			
		||||
    function processMessage(data) {
 | 
			
		||||
        // TODO Implement chat protocol
 | 
			
		||||
        console.log(data)
 | 
			
		||||
        switch (data['type']) {
 | 
			
		||||
            case 'fetch_channels':
 | 
			
		||||
                setChannels(data['channels'])
 | 
			
		||||
                break
 | 
			
		||||
            default:
 | 
			
		||||
                console.log(data)
 | 
			
		||||
                console.error('Unknown message type:', data['type'])
 | 
			
		||||
                break
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setupSocket(nextDelay = 1000) {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,64 @@
 | 
			
		||||
{% load i18n %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
    <noscript>
 | 
			
		||||
        {% trans "JavaScript must be enabled on your browser to access chat." %}
 | 
			
		||||
    </noscript>
 | 
			
		||||
    <div class="offcanvas offcanvas-start" tabindex="-1" id="channelSelector" aria-labelledby="offcanvasExampleLabel">
 | 
			
		||||
        <div class="offcanvas-header">
 | 
			
		||||
            <h4 class="offcanvas-title" id="offcanvasExampleLabel">{% trans "Chat channels" %}</h4>
 | 
			
		||||
            <button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="offcanvas-body">
 | 
			
		||||
            <ul class="list-group list-group-flush" id="nav-channels-tab">
 | 
			
		||||
                {% for channel in channels %}
 | 
			
		||||
                    <li class="list-group-item" id="tab-channel-{{ channel.id }}" data-bs-dismiss="offcanvas"
 | 
			
		||||
                        onclick="selectChannel({{ channel.id }})">
 | 
			
		||||
                        <button class="nav-link">{{ channel.name }}</button>
 | 
			
		||||
                    </li>
 | 
			
		||||
                {% endfor %}
 | 
			
		||||
            </ul>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="card tab-content w-100 mh-100" style="height: 95vh" id="nav-channels-content">
 | 
			
		||||
        <div class="card-header">
 | 
			
		||||
            <h3>
 | 
			
		||||
                <button class="navbar-toggler" type="button" data-bs-toggle="offcanvas" data-bs-target="#channelSelector"
 | 
			
		||||
                        aria-controls="channelSelector" aria-expanded="false" aria-label="Toggle channel selector">
 | 
			
		||||
                    <span class="navbar-toggler-icon"></span>
 | 
			
		||||
                </button>
 | 
			
		||||
                <span id="channel-title"></span>
 | 
			
		||||
            </h3>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="card-body overflow-y-scroll mw-100 h-100 flex-grow-0" id="chat-messages">
 | 
			
		||||
            <ul class="list-group list-group-flush">
 | 
			
		||||
                <li class="list-group-item">
 | 
			
		||||
                    <div class="fw-bold">Emmy D'Anello (CNO)</div>
 | 
			
		||||
                    Message 1
 | 
			
		||||
                </li>
 | 
			
		||||
                <li class="list-group-item">
 | 
			
		||||
                    <div class="fw-bold">Emmy D'Anello (CNO)</div>
 | 
			
		||||
                    Message 2
 | 
			
		||||
                </li>
 | 
			
		||||
                <li class="list-group-item">
 | 
			
		||||
                    <div class="fw-bold">Emmy D'Anello (CNO)</div>
 | 
			
		||||
                    Message 3
 | 
			
		||||
                </li>
 | 
			
		||||
            </ul>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="card-footer mt-auto">
 | 
			
		||||
            <div class="input-group">
 | 
			
		||||
                <label for="input-message" class="input-group-text">
 | 
			
		||||
                    <i class="fas fa-comment"></i>
 | 
			
		||||
                </label>
 | 
			
		||||
                <input type="text" class="form-control" id="input-message" placeholder="{% trans "Send message…" %}" autocomplete="off">
 | 
			
		||||
                <button class="input-group-text btn btn-success">
 | 
			
		||||
                    <i class="fas fa-paper-plane"></i>
 | 
			
		||||
                </button>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block extrajavascript %}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,8 @@
 | 
			
		||||
from django.contrib.auth.mixins import LoginRequiredMixin
 | 
			
		||||
from django.views.generic import TemplateView
 | 
			
		||||
 | 
			
		||||
from chat.models import Channel
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ChatView(LoginRequiredMixin, TemplateView):
 | 
			
		||||
    """
 | 
			
		||||
@@ -11,3 +13,9 @@ class ChatView(LoginRequiredMixin, TemplateView):
 | 
			
		||||
    with Javascript and websockets.
 | 
			
		||||
    """
 | 
			
		||||
    template_name = "chat/chat.html"
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        context = super().get_context_data(**kwargs)
 | 
			
		||||
        from asgiref.sync import async_to_sync
 | 
			
		||||
        context['channels'] = async_to_sync(Channel.get_accessible_channels)(self.request.user, 'read')
 | 
			
		||||
        return context
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: TFJM\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: \n"
 | 
			
		||||
"POT-Creation-Date: 2024-04-27 08:46+0200\n"
 | 
			
		||||
"POT-Creation-Date: 2024-04-27 11:02+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:13 participation/models.py:35 participation/models.py:263
 | 
			
		||||
#: chat/models.py:17 participation/models.py:35 participation/models.py:263
 | 
			
		||||
#: participation/tables.py:18 participation/tables.py:34
 | 
			
		||||
msgid "name"
 | 
			
		||||
msgstr "nom"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:17
 | 
			
		||||
#: chat/models.py:22
 | 
			
		||||
msgid "read permission"
 | 
			
		||||
msgstr "permission de lecture"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:22
 | 
			
		||||
#: chat/models.py:28
 | 
			
		||||
msgid "write permission"
 | 
			
		||||
msgstr "permission d'écriture"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:32 draw/admin.py:53 draw/admin.py:71 draw/admin.py:88
 | 
			
		||||
#: chat/models.py:38 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:34
 | 
			
		||||
#: chat/models.py:40
 | 
			
		||||
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:43 draw/models.py:429 draw/models.py:456
 | 
			
		||||
#: chat/models.py:49 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:45
 | 
			
		||||
#: chat/models.py:51
 | 
			
		||||
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:54 draw/templates/draw/tournament_content.html:277
 | 
			
		||||
#: chat/models.py:60 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:56
 | 
			
		||||
#: chat/models.py:62
 | 
			
		||||
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:60
 | 
			
		||||
#: chat/models.py:66
 | 
			
		||||
msgid "private"
 | 
			
		||||
msgstr "privé"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:62
 | 
			
		||||
#: chat/models.py:68
 | 
			
		||||
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:67
 | 
			
		||||
#: chat/models.py:73
 | 
			
		||||
msgid "invited users"
 | 
			
		||||
msgstr "Utilisateur⋅rices invité"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:70
 | 
			
		||||
#: chat/models.py:76
 | 
			
		||||
msgid ""
 | 
			
		||||
"Extra users who have been invited to the channel, in addition to the "
 | 
			
		||||
"permitted group of the channel."
 | 
			
		||||
@@ -106,43 +106,55 @@ msgstr ""
 | 
			
		||||
"Utilisateur⋅rices supplémentaires qui ont été invité⋅es au canal, en plus du "
 | 
			
		||||
"groupe autorisé du canal."
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:75
 | 
			
		||||
#: chat/models.py:81
 | 
			
		||||
#, python-brace-format
 | 
			
		||||
msgid "Channel {name}"
 | 
			
		||||
msgstr "Canal {name}"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:78 chat/models.py:87
 | 
			
		||||
#: chat/models.py:150 chat/models.py:159
 | 
			
		||||
msgid "channel"
 | 
			
		||||
msgstr "canal"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:79
 | 
			
		||||
#: chat/models.py:151
 | 
			
		||||
msgid "channels"
 | 
			
		||||
msgstr "canaux"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:93
 | 
			
		||||
#: chat/models.py:165
 | 
			
		||||
msgid "author"
 | 
			
		||||
msgstr "auteur⋅rice"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:100
 | 
			
		||||
#: chat/models.py:172
 | 
			
		||||
msgid "created at"
 | 
			
		||||
msgstr "créé le"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:105
 | 
			
		||||
#: chat/models.py:177
 | 
			
		||||
msgid "updated at"
 | 
			
		||||
msgstr "modifié le"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:110
 | 
			
		||||
#: chat/models.py:182
 | 
			
		||||
msgid "content"
 | 
			
		||||
msgstr "contenu"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:114
 | 
			
		||||
#: chat/models.py:186
 | 
			
		||||
msgid "message"
 | 
			
		||||
msgstr "message"
 | 
			
		||||
 | 
			
		||||
#: chat/models.py:115
 | 
			
		||||
#: chat/models.py:187
 | 
			
		||||
msgid "messages"
 | 
			
		||||
msgstr "messages"
 | 
			
		||||
 | 
			
		||||
#: chat/templates/chat/chat.html:8
 | 
			
		||||
msgid "JavaScript must be enabled on your browser to access chat."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: chat/templates/chat/chat.html:12
 | 
			
		||||
msgid "Chat channels"
 | 
			
		||||
msgstr "Canaux de chat"
 | 
			
		||||
 | 
			
		||||
#: chat/templates/chat/chat.html:43
 | 
			
		||||
msgid "Send message…"
 | 
			
		||||
msgstr "Envoyer un message…"
 | 
			
		||||
 | 
			
		||||
#: draw/admin.py:39 draw/admin.py:57 draw/admin.py:75
 | 
			
		||||
#: participation/admin.py:109 participation/models.py:253
 | 
			
		||||
#: participation/tables.py:88
 | 
			
		||||
@@ -158,68 +170,68 @@ msgstr "tour"
 | 
			
		||||
msgid "Draw"
 | 
			
		||||
msgstr "Tirage au sort"
 | 
			
		||||
 | 
			
		||||
#: draw/consumers.py:30
 | 
			
		||||
#: draw/consumers.py:31
 | 
			
		||||
msgid "You are not an organizer."
 | 
			
		||||
msgstr "Vous n'êtes pas un⋅e organisateur⋅rice."
 | 
			
		||||
 | 
			
		||||
#: draw/consumers.py:162
 | 
			
		||||
#: draw/consumers.py:165
 | 
			
		||||
msgid "The draw is already started."
 | 
			
		||||
msgstr "Le tirage a déjà commencé."
 | 
			
		||||
 | 
			
		||||
#: draw/consumers.py:168
 | 
			
		||||
#: draw/consumers.py:171
 | 
			
		||||
msgid "Invalid format"
 | 
			
		||||
msgstr "Format invalide"
 | 
			
		||||
 | 
			
		||||
#: draw/consumers.py:173
 | 
			
		||||
#: draw/consumers.py:176
 | 
			
		||||
#, python-brace-format
 | 
			
		||||
msgid "The sum must be equal to the number of teams: expected {len}, got {sum}"
 | 
			
		||||
msgstr ""
 | 
			
		||||
"La somme doit être égale au nombre d'équipes : attendu {len}, obtenu {sum}"
 | 
			
		||||
 | 
			
		||||
#: draw/consumers.py:178
 | 
			
		||||
#: draw/consumers.py:181
 | 
			
		||||
msgid "There can be at most one pool with 5 teams."
 | 
			
		||||
msgstr "Il ne peut y avoir au plus qu'une seule poule de 5 équipes."
 | 
			
		||||
 | 
			
		||||
#: draw/consumers.py:218
 | 
			
		||||
#: draw/consumers.py:221
 | 
			
		||||
msgid "Draw started!"
 | 
			
		||||
msgstr "Le tirage a commencé !"
 | 
			
		||||
 | 
			
		||||
#: draw/consumers.py:240
 | 
			
		||||
#: draw/consumers.py:243
 | 
			
		||||
#, python-brace-format
 | 
			
		||||
msgid "The draw for the tournament {tournament} will start."
 | 
			
		||||
msgstr "Le tirage au sort du tournoi {tournament} va commencer."
 | 
			
		||||
 | 
			
		||||
#: draw/consumers.py:251 draw/consumers.py:277 draw/consumers.py:687
 | 
			
		||||
#: draw/consumers.py:904 draw/consumers.py:993 draw/consumers.py:1015
 | 
			
		||||
#: draw/consumers.py:1106 draw/templates/draw/tournament_content.html:5
 | 
			
		||||
#: draw/consumers.py:254 draw/consumers.py:280 draw/consumers.py:690
 | 
			
		||||
#: draw/consumers.py:907 draw/consumers.py:996 draw/consumers.py:1018
 | 
			
		||||
#: draw/consumers.py:1109 draw/templates/draw/tournament_content.html:5
 | 
			
		||||
msgid "The draw has not started yet."
 | 
			
		||||
msgstr "Le tirage au sort n'a pas encore commencé."
 | 
			
		||||
 | 
			
		||||
#: draw/consumers.py:264
 | 
			
		||||
#: draw/consumers.py:267
 | 
			
		||||
#, python-brace-format
 | 
			
		||||
msgid "The draw for the tournament {tournament} is aborted."
 | 
			
		||||
msgstr "Le tirage au sort du tournoi {tournament} est annulé."
 | 
			
		||||
 | 
			
		||||
#: draw/consumers.py:304 draw/consumers.py:325 draw/consumers.py:621
 | 
			
		||||
#: draw/consumers.py:692 draw/consumers.py:909
 | 
			
		||||
#: draw/consumers.py:307 draw/consumers.py:328 draw/consumers.py:624
 | 
			
		||||
#: draw/consumers.py:695 draw/consumers.py:912
 | 
			
		||||
msgid "This is not the time for this."
 | 
			
		||||
msgstr "Ce n'est pas le moment pour cela."
 | 
			
		||||
 | 
			
		||||
#: draw/consumers.py:317 draw/consumers.py:320
 | 
			
		||||
#: draw/consumers.py:320 draw/consumers.py:323
 | 
			
		||||
msgid "You've already launched the dice."
 | 
			
		||||
msgstr "Vous avez déjà lancé le dé."
 | 
			
		||||
 | 
			
		||||
#: draw/consumers.py:323
 | 
			
		||||
#: draw/consumers.py:326
 | 
			
		||||
msgid "It is not your turn."
 | 
			
		||||
msgstr "Ce n'est pas votre tour."
 | 
			
		||||
 | 
			
		||||
#: draw/consumers.py:410
 | 
			
		||||
#: draw/consumers.py:413
 | 
			
		||||
#, python-brace-format
 | 
			
		||||
msgid "Dices from teams {teams} are identical. Please relaunch your dices."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Les dés des équipes {teams} sont identiques. Merci de relancer vos dés."
 | 
			
		||||
 | 
			
		||||
#: draw/consumers.py:1018
 | 
			
		||||
#: draw/consumers.py:1021
 | 
			
		||||
msgid "This is only available for the final tournament."
 | 
			
		||||
msgstr "Cela n'est possible que pour la finale."
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -40,18 +40,18 @@
 | 
			
		||||
<body class="d-flex w-100 h-100 flex-column">
 | 
			
		||||
{% include "navbar.html" %}
 | 
			
		||||
 | 
			
		||||
<div id="body-wrapper" class="row w-100 my-3">
 | 
			
		||||
<div id="body-wrapper" class="row w-100 my-3 flex-grow-1">
 | 
			
		||||
    <aside class="col-lg-2 px-2">
 | 
			
		||||
        {% include "sidebar.html" %}
 | 
			
		||||
    </aside>
 | 
			
		||||
 | 
			
		||||
    <main class="col d-flex flex-column">
 | 
			
		||||
        <div class="container">
 | 
			
		||||
    <main class="col d-flex flex-column flex-grow-1">
 | 
			
		||||
        <div class="container d-flex flex-column flex-grow-1">
 | 
			
		||||
            {% block content-title %}<h1 id="content-title">{{ title }}</h1>{% endblock %}
 | 
			
		||||
 | 
			
		||||
            {% include "messages.html" %}
 | 
			
		||||
 | 
			
		||||
            <div id="content">
 | 
			
		||||
            <div id="content" class="d-flex flex-column flex-grow-1">
 | 
			
		||||
                {% block content %}
 | 
			
		||||
                    <p>Default content...</p>
 | 
			
		||||
                {% endblock content %}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user