mirror of
				https://gitlab.com/animath/si/plateforme.git
				synced 2025-11-04 01:32:05 +01:00 
			
		
		
		
	Drop Matrix support
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
This commit is contained in:
		@@ -54,7 +54,6 @@ SERVER_EMAIL=contact@tfjm.org   # Adresse e-mail expéditrice
 | 
				
			|||||||
SYMPA_URL=lists.example.com     # Serveur Sympa à utiliser
 | 
					SYMPA_URL=lists.example.com     # Serveur Sympa à utiliser
 | 
				
			||||||
SYMPA_EMAIL=                    # Adresse e-mail du compte administrateur de Sympa
 | 
					SYMPA_EMAIL=                    # Adresse e-mail du compte administrateur de Sympa
 | 
				
			||||||
SYMPA_PASSWORD=                 # Mot de passe du compte administrateur de Sympa
 | 
					SYMPA_PASSWORD=                 # Mot de passe du compte administrateur de Sympa
 | 
				
			||||||
SYNAPSE_PASSWORD=               # Mot de passe du robot Matrix 
 | 
					 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Si le type de base de données sélectionné est SQLite, la variable `DJANGO_DB_HOST` sera utilisée en guise de chemin vers
 | 
					Si le type de base de données sélectionné est SQLite, la variable `DJANGO_DB_HOST` sera utilisée en guise de chemin vers
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,477 +0,0 @@
 | 
				
			|||||||
# Copyright (C) 2020 by Animath
 | 
					 | 
				
			||||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import asyncio
 | 
					 | 
				
			||||||
import os
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from django.core.management import BaseCommand
 | 
					 | 
				
			||||||
from django.utils.http import urlencode
 | 
					 | 
				
			||||||
from django.utils.translation import activate
 | 
					 | 
				
			||||||
from participation.models import Team, Tournament
 | 
					 | 
				
			||||||
from registration.models import Registration, VolunteerRegistration
 | 
					 | 
				
			||||||
from tfjm.matrix import Matrix, RoomPreset, RoomVisibility
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Command(BaseCommand):
 | 
					 | 
				
			||||||
    def handle(self, *args, **options):  # noqa: C901
 | 
					 | 
				
			||||||
        activate("fr")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        async def main():
 | 
					 | 
				
			||||||
            await Matrix.set_display_name("Bot du TFJM²")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if not os.getenv("SYNAPSE_PASSWORD"):
 | 
					 | 
				
			||||||
                avatar_uri = "plop"
 | 
					 | 
				
			||||||
            else:  # pragma: no cover
 | 
					 | 
				
			||||||
                if not os.path.isfile(".matrix_avatar"):
 | 
					 | 
				
			||||||
                    avatar_uri = await Matrix.get_avatar()
 | 
					 | 
				
			||||||
                    if isinstance(avatar_uri, str):
 | 
					 | 
				
			||||||
                        with open(".matrix_avatar", "w") as f:
 | 
					 | 
				
			||||||
                            f.write(avatar_uri)
 | 
					 | 
				
			||||||
                    else:
 | 
					 | 
				
			||||||
                        stat_file = os.stat("tfjm/static/logo.png")
 | 
					 | 
				
			||||||
                        with open("tfjm/static/logo.png", "rb") as f:
 | 
					 | 
				
			||||||
                            resp = (await Matrix.upload(f, filename="../../../tfjm/static/logo.png", content_type="image/png",
 | 
					 | 
				
			||||||
                                                        filesize=stat_file.st_size))[0][0]
 | 
					 | 
				
			||||||
                        avatar_uri = resp.content_uri
 | 
					 | 
				
			||||||
                        with open(".matrix_avatar", "w") as f:
 | 
					 | 
				
			||||||
                            f.write(avatar_uri)
 | 
					 | 
				
			||||||
                        await Matrix.set_avatar(avatar_uri)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                with open(".matrix_avatar", "r") as f:
 | 
					 | 
				
			||||||
                    avatar_uri = f.read().rstrip(" \t\r\n")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            # Create basic channels
 | 
					 | 
				
			||||||
            if not await Matrix.resolve_room_alias("#aide-jurys-orgas:tfjm.org"):
 | 
					 | 
				
			||||||
                await Matrix.create_room(
 | 
					 | 
				
			||||||
                    visibility=RoomVisibility.public,
 | 
					 | 
				
			||||||
                    alias="aide-jurys-orgas",
 | 
					 | 
				
			||||||
                    name="Aide jurys & orgas",
 | 
					 | 
				
			||||||
                    topic="Pour discuter de propblèmes d'organisation",
 | 
					 | 
				
			||||||
                    federate=False,
 | 
					 | 
				
			||||||
                    preset=RoomPreset.private_chat,
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if not await Matrix.resolve_room_alias("#annonces:tfjm.org"):
 | 
					 | 
				
			||||||
                await Matrix.create_room(
 | 
					 | 
				
			||||||
                    visibility=RoomVisibility.public,
 | 
					 | 
				
			||||||
                    alias="annonces",
 | 
					 | 
				
			||||||
                    name="Annonces",
 | 
					 | 
				
			||||||
                    topic="Informations importantes du TFJM²",
 | 
					 | 
				
			||||||
                    federate=False,
 | 
					 | 
				
			||||||
                    preset=RoomPreset.public_chat,
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if not await Matrix.resolve_room_alias("#bienvenue:tfjm.org"):
 | 
					 | 
				
			||||||
                await Matrix.create_room(
 | 
					 | 
				
			||||||
                    visibility=RoomVisibility.public,
 | 
					 | 
				
			||||||
                    alias="bienvenue",
 | 
					 | 
				
			||||||
                    name="Bienvenue",
 | 
					 | 
				
			||||||
                    topic="Bienvenue au TFJM² 2023 !",
 | 
					 | 
				
			||||||
                    federate=False,
 | 
					 | 
				
			||||||
                    preset=RoomPreset.public_chat,
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if not await Matrix.resolve_room_alias("#bot:tfjm.org"):
 | 
					 | 
				
			||||||
                await Matrix.create_room(
 | 
					 | 
				
			||||||
                    visibility=RoomVisibility.public,
 | 
					 | 
				
			||||||
                    alias="bot",
 | 
					 | 
				
			||||||
                    name="Bot",
 | 
					 | 
				
			||||||
                    topic="Vive les r0b0ts",
 | 
					 | 
				
			||||||
                    federate=False,
 | 
					 | 
				
			||||||
                    preset=RoomPreset.public_chat,
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if not await Matrix.resolve_room_alias("#cno:tfjm.org"):
 | 
					 | 
				
			||||||
                await Matrix.create_room(
 | 
					 | 
				
			||||||
                    visibility=RoomVisibility.public,
 | 
					 | 
				
			||||||
                    alias="cno",
 | 
					 | 
				
			||||||
                    name="CNO",
 | 
					 | 
				
			||||||
                    topic="Channel des dieux",
 | 
					 | 
				
			||||||
                    federate=False,
 | 
					 | 
				
			||||||
                    preset=RoomPreset.private_chat,
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if not await Matrix.resolve_room_alias("#dev-bot:tfjm.org"):
 | 
					 | 
				
			||||||
                await Matrix.create_room(
 | 
					 | 
				
			||||||
                    visibility=RoomVisibility.public,
 | 
					 | 
				
			||||||
                    alias="dev-bot",
 | 
					 | 
				
			||||||
                    name="Bot - développement",
 | 
					 | 
				
			||||||
                    topic="Vive le bot",
 | 
					 | 
				
			||||||
                    federate=False,
 | 
					 | 
				
			||||||
                    preset=RoomPreset.private_chat,
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if not await Matrix.resolve_room_alias("#faq:tfjm.org"):
 | 
					 | 
				
			||||||
                await Matrix.create_room(
 | 
					 | 
				
			||||||
                    visibility=RoomVisibility.public,
 | 
					 | 
				
			||||||
                    alias="faq",
 | 
					 | 
				
			||||||
                    name="FAQ",
 | 
					 | 
				
			||||||
                    topic="Posez toutes vos questions ici !",
 | 
					 | 
				
			||||||
                    federate=False,
 | 
					 | 
				
			||||||
                    preset=RoomPreset.public_chat,
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if not await Matrix.resolve_room_alias("#flood:tfjm.org"):
 | 
					 | 
				
			||||||
                await Matrix.create_room(
 | 
					 | 
				
			||||||
                    visibility=RoomVisibility.public,
 | 
					 | 
				
			||||||
                    alias="flood",
 | 
					 | 
				
			||||||
                    name="Flood",
 | 
					 | 
				
			||||||
                    topic="Discutez de tout et de rien !",
 | 
					 | 
				
			||||||
                    federate=False,
 | 
					 | 
				
			||||||
                    preset=RoomPreset.public_chat,
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if not await Matrix.resolve_room_alias("#je-cherche-une-equipe:tfjm.org"):
 | 
					 | 
				
			||||||
                await Matrix.create_room(
 | 
					 | 
				
			||||||
                    visibility=RoomVisibility.public,
 | 
					 | 
				
			||||||
                    alias="je-cherche-une-equipe",
 | 
					 | 
				
			||||||
                    name="Je cherche une équipe",
 | 
					 | 
				
			||||||
                    topic="Le Tinder du TFJM²",
 | 
					 | 
				
			||||||
                    federate=False,
 | 
					 | 
				
			||||||
                    preset=RoomPreset.public_chat,
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            # Setup avatars
 | 
					 | 
				
			||||||
            await Matrix.set_room_avatar("#aide-jurys-orgas:tfjm.org", avatar_uri)
 | 
					 | 
				
			||||||
            await Matrix.set_room_avatar("#annonces:tfjm.org", avatar_uri)
 | 
					 | 
				
			||||||
            await Matrix.set_room_avatar("#bienvenue:tfjm.org", avatar_uri)
 | 
					 | 
				
			||||||
            await Matrix.set_room_avatar("#bot:tfjm.org", avatar_uri)
 | 
					 | 
				
			||||||
            await Matrix.set_room_avatar("#cno:tfjm.org", avatar_uri)
 | 
					 | 
				
			||||||
            await Matrix.set_room_avatar("#dev-bot:tfjm.org", avatar_uri)
 | 
					 | 
				
			||||||
            await Matrix.set_room_avatar("#faq:tfjm.org", avatar_uri)
 | 
					 | 
				
			||||||
            await Matrix.set_room_avatar("#flood:tfjm.org", avatar_uri)
 | 
					 | 
				
			||||||
            await Matrix.set_room_avatar("#je-cherche-une-equipe:tfjm.org", avatar_uri)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            # Read-only channels
 | 
					 | 
				
			||||||
            await Matrix.set_room_power_level_event("#annonces:tfjm.org", "events_default", 50)
 | 
					 | 
				
			||||||
            await Matrix.set_room_power_level_event("#bienvenue:tfjm.org", "events_default", 50)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            # Invite everyone to public channels
 | 
					 | 
				
			||||||
            for r in Registration.objects.all():
 | 
					 | 
				
			||||||
                await Matrix.invite("#annonces:tfjm.org", f"@{r.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                await Matrix.invite("#bienvenue:tfjm.org", f"@{r.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                await Matrix.invite("#bot:tfjm.org", f"@{r.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                await Matrix.invite("#faq:tfjm.org", f"@{r.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                await Matrix.invite("#flood:tfjm.org", f"@{r.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                await Matrix.invite("#je-cherche-une-equipe:tfjm.org",
 | 
					 | 
				
			||||||
                                    f"@{r.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                self.stdout.write(f"Invite {r} in most common channels...")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            # Volunteers have access to the help channel
 | 
					 | 
				
			||||||
            for volunteer in VolunteerRegistration.objects.all():
 | 
					 | 
				
			||||||
                await Matrix.invite("#aide-jurys-orgas:tfjm.org", f"@{volunteer.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                self.stdout.write(f"Invite {volunteer} in #aide-jury-orgas...")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            # Admins are admins
 | 
					 | 
				
			||||||
            for admin in VolunteerRegistration.objects.filter(admin=True).all():
 | 
					 | 
				
			||||||
                self.stdout.write(f"Invite {admin} in #cno and #dev-bot...")
 | 
					 | 
				
			||||||
                await Matrix.invite("#cno:tfjm.org", f"@{admin.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                await Matrix.invite("#dev-bot:tfjm.org", f"@{admin.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                self.stdout.write(f"Give admin permissions for {admin}...")
 | 
					 | 
				
			||||||
                await Matrix.set_room_power_level("#aide-jurys-orgas:tfjm.org",
 | 
					 | 
				
			||||||
                                                  f"@{admin.matrix_username}:tfjm.org", 95)
 | 
					 | 
				
			||||||
                await Matrix.set_room_power_level("#annonces:tfjm.org",
 | 
					 | 
				
			||||||
                                                  f"@{admin.matrix_username}:tfjm.org", 95)
 | 
					 | 
				
			||||||
                await Matrix.set_room_power_level("#bienvenue:tfjm.org",
 | 
					 | 
				
			||||||
                                                  f"@{admin.matrix_username}:tfjm.org", 95)
 | 
					 | 
				
			||||||
                await Matrix.set_room_power_level("#bot:tfjm.org",
 | 
					 | 
				
			||||||
                                                  f"@{admin.matrix_username}:tfjm.org", 95)
 | 
					 | 
				
			||||||
                await Matrix.set_room_power_level("#cno:tfjm.org",
 | 
					 | 
				
			||||||
                                                  f"@{admin.matrix_username}:tfjm.org", 95)
 | 
					 | 
				
			||||||
                await Matrix.set_room_power_level("#dev-bot:tfjm.org",
 | 
					 | 
				
			||||||
                                                  f"@{admin.matrix_username}:tfjm.org", 95)
 | 
					 | 
				
			||||||
                await Matrix.set_room_power_level("#faq:tfjm.org",
 | 
					 | 
				
			||||||
                                                  f"@{admin.matrix_username}:tfjm.org", 95)
 | 
					 | 
				
			||||||
                await Matrix.set_room_power_level("#flood:tfjm.org",
 | 
					 | 
				
			||||||
                                                  f"@{admin.matrix_username}:tfjm.org", 95)
 | 
					 | 
				
			||||||
                await Matrix.set_room_power_level("#je-cherche-une-equipe:tfjm.org",
 | 
					 | 
				
			||||||
                                                  f"@{admin.matrix_username}:tfjm.org", 95)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            # Create tournament-specific channels
 | 
					 | 
				
			||||||
            for tournament in Tournament.objects.all():
 | 
					 | 
				
			||||||
                self.stdout.write(f"Managing tournament of {tournament.name}.")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                name = tournament.name
 | 
					 | 
				
			||||||
                slug = name.lower().replace(" ", "-")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if not await Matrix.resolve_room_alias(f"#annonces-{slug}:tfjm.org"):
 | 
					 | 
				
			||||||
                    await Matrix.create_room(
 | 
					 | 
				
			||||||
                        visibility=RoomVisibility.public,
 | 
					 | 
				
			||||||
                        alias=f"annonces-{slug}",
 | 
					 | 
				
			||||||
                        name=f"{name} - Annonces",
 | 
					 | 
				
			||||||
                        topic=f"Annonces du tournoi de {name}",
 | 
					 | 
				
			||||||
                        federate=False,
 | 
					 | 
				
			||||||
                        preset=RoomPreset.private_chat,
 | 
					 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if not await Matrix.resolve_room_alias(f"#general-{slug}:tfjm.org"):
 | 
					 | 
				
			||||||
                    await Matrix.create_room(
 | 
					 | 
				
			||||||
                        visibility=RoomVisibility.public,
 | 
					 | 
				
			||||||
                        alias=f"general-{slug}",
 | 
					 | 
				
			||||||
                        name=f"{name} - Général",
 | 
					 | 
				
			||||||
                        topic=f"Accueil du tournoi de {name}",
 | 
					 | 
				
			||||||
                        federate=False,
 | 
					 | 
				
			||||||
                        preset=RoomPreset.private_chat,
 | 
					 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if not await Matrix.resolve_room_alias(f"#flood-{slug}:tfjm.org"):
 | 
					 | 
				
			||||||
                    await Matrix.create_room(
 | 
					 | 
				
			||||||
                        visibility=RoomVisibility.public,
 | 
					 | 
				
			||||||
                        alias=f"flood-{slug}",
 | 
					 | 
				
			||||||
                        name=f"{name} - Flood",
 | 
					 | 
				
			||||||
                        topic=f"Discussion libre du tournoi de {name}",
 | 
					 | 
				
			||||||
                        federate=False,
 | 
					 | 
				
			||||||
                        preset=RoomPreset.private_chat,
 | 
					 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if not await Matrix.resolve_room_alias(f"#jury-{slug}:tfjm.org"):
 | 
					 | 
				
			||||||
                    await Matrix.create_room(
 | 
					 | 
				
			||||||
                        visibility=RoomVisibility.public,
 | 
					 | 
				
			||||||
                        alias=f"jury-{slug}",
 | 
					 | 
				
			||||||
                        name=f"{name} - Jury",
 | 
					 | 
				
			||||||
                        topic=f"Discussion entre les orgas et jurys du tournoi de {name}",
 | 
					 | 
				
			||||||
                        federate=False,
 | 
					 | 
				
			||||||
                        preset=RoomPreset.private_chat,
 | 
					 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if not await Matrix.resolve_room_alias(f"#orga-{slug}:tfjm.org"):
 | 
					 | 
				
			||||||
                    await Matrix.create_room(
 | 
					 | 
				
			||||||
                        visibility=RoomVisibility.public,
 | 
					 | 
				
			||||||
                        alias=f"orga-{slug}",
 | 
					 | 
				
			||||||
                        name=f"{name} - Organisateurs",
 | 
					 | 
				
			||||||
                        topic=f"Discussion entre les orgas du tournoi de {name}",
 | 
					 | 
				
			||||||
                        federate=False,
 | 
					 | 
				
			||||||
                        preset=RoomPreset.private_chat,
 | 
					 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if not await Matrix.resolve_room_alias(f"#tirage-au-sort-{slug}:tfjm.org"):
 | 
					 | 
				
			||||||
                    await Matrix.create_room(
 | 
					 | 
				
			||||||
                        visibility=RoomVisibility.public,
 | 
					 | 
				
			||||||
                        alias=f"tirage-au-sort-{slug}",
 | 
					 | 
				
			||||||
                        name=f"{name} - Tirage au sort",
 | 
					 | 
				
			||||||
                        topic=f"Tirage au sort du tournoi de {name}",
 | 
					 | 
				
			||||||
                        federate=False,
 | 
					 | 
				
			||||||
                        preset=RoomPreset.private_chat,
 | 
					 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                # Setup avatars
 | 
					 | 
				
			||||||
                await Matrix.set_room_avatar(f"#annonces-{slug}:tfjm.org", avatar_uri)
 | 
					 | 
				
			||||||
                await Matrix.set_room_avatar(f"#flood-{slug}:tfjm.org", avatar_uri)
 | 
					 | 
				
			||||||
                await Matrix.set_room_avatar(f"#general-{slug}:tfjm.org", avatar_uri)
 | 
					 | 
				
			||||||
                await Matrix.set_room_avatar(f"#jury-{slug}:tfjm.org", avatar_uri)
 | 
					 | 
				
			||||||
                await Matrix.set_room_avatar(f"#orga-{slug}:tfjm.org", avatar_uri)
 | 
					 | 
				
			||||||
                await Matrix.set_room_avatar(f"#tirage-au-sort-{slug}:tfjm.org", avatar_uri)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                # Invite admins and give permissions
 | 
					 | 
				
			||||||
                for admin in VolunteerRegistration.objects.filter(admin=True).all():
 | 
					 | 
				
			||||||
                    self.stdout.write(f"Invite {admin} in all channels of the tournament {name}...")
 | 
					 | 
				
			||||||
                    await Matrix.invite(f"#annonces-{slug}:tfjm.org", f"@{admin.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                    await Matrix.invite(f"#flood-{slug}:tfjm.org", f"@{admin.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                    await Matrix.invite(f"#general-{slug}:tfjm.org", f"@{admin.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                    await Matrix.invite(f"#jury-{slug}:tfjm.org", f"@{admin.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                    await Matrix.invite(f"#orga-{slug}:tfjm.org", f"@{admin.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                    await Matrix.invite(f"#tirage-au-sort-{slug}:tfjm.org", f"@{admin.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    self.stdout.write(f"Give permissions to {admin} in all channels of the tournament {name}...")
 | 
					 | 
				
			||||||
                    await Matrix.set_room_power_level(f"#annonces-{slug}:tfjm.org",
 | 
					 | 
				
			||||||
                                                      f"@{admin.matrix_username}:tfjm.org", 95)
 | 
					 | 
				
			||||||
                    await Matrix.set_room_power_level(f"#flood-{slug}:tfjm.org",
 | 
					 | 
				
			||||||
                                                      f"@{admin.matrix_username}:tfjm.org", 95)
 | 
					 | 
				
			||||||
                    await Matrix.set_room_power_level(f"#general-{slug}:tfjm.org",
 | 
					 | 
				
			||||||
                                                      f"@{admin.matrix_username}:tfjm.org", 95)
 | 
					 | 
				
			||||||
                    await Matrix.set_room_power_level(f"#jury-{slug}:tfjm.org",
 | 
					 | 
				
			||||||
                                                      f"@{admin.matrix_username}:tfjm.org", 95)
 | 
					 | 
				
			||||||
                    await Matrix.set_room_power_level(f"#orga-{slug}:tfjm.org",
 | 
					 | 
				
			||||||
                                                      f"@{admin.matrix_username}:tfjm.org", 95)
 | 
					 | 
				
			||||||
                    await Matrix.set_room_power_level(f"#tirage-au-sort-{slug}:tfjm.org",
 | 
					 | 
				
			||||||
                                                      f"@{admin.matrix_username}:tfjm.org", 95)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                # Invite organizers and give permissions
 | 
					 | 
				
			||||||
                for orga in tournament.organizers.all():
 | 
					 | 
				
			||||||
                    self.stdout.write(f"Invite organizer {orga} in all channels of the tournament {name}...")
 | 
					 | 
				
			||||||
                    await Matrix.invite(f"#annonces-{slug}:tfjm.org", f"@{orga.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                    await Matrix.invite(f"#flood-{slug}:tfjm.org", f"@{orga.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                    await Matrix.invite(f"#general-{slug}:tfjm.org", f"@{orga.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                    await Matrix.invite(f"#jury-{slug}:tfjm.org", f"@{orga.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                    await Matrix.invite(f"#orga-{slug}:tfjm.org", f"@{orga.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                    await Matrix.invite(f"#tirage-au-sort-{slug}:tfjm.org", f"@{orga.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if not orga.is_admin:
 | 
					 | 
				
			||||||
                        await Matrix.set_room_power_level(f"#annonces-{slug}:tfjm.org",
 | 
					 | 
				
			||||||
                                                          f"@{orga.matrix_username}:tfjm.org", 50)
 | 
					 | 
				
			||||||
                        await Matrix.set_room_power_level(f"#flood-{slug}:tfjm.org",
 | 
					 | 
				
			||||||
                                                          f"@{orga.matrix_username}:tfjm.org", 50)
 | 
					 | 
				
			||||||
                        await Matrix.set_room_power_level(f"#general-{slug}:tfjm.org",
 | 
					 | 
				
			||||||
                                                          f"@{orga.matrix_username}:tfjm.org", 50)
 | 
					 | 
				
			||||||
                        await Matrix.set_room_power_level(f"#jury-{slug}:tfjm.org",
 | 
					 | 
				
			||||||
                                                          f"@{orga.matrix_username}:tfjm.org", 50)
 | 
					 | 
				
			||||||
                        await Matrix.set_room_power_level(f"#orga-{slug}:tfjm.org",
 | 
					 | 
				
			||||||
                                                          f"@{orga.matrix_username}:tfjm.org", 50)
 | 
					 | 
				
			||||||
                        await Matrix.set_room_power_level(f"#tirage-au-sort-{slug}:tfjm.org",
 | 
					 | 
				
			||||||
                                                          f"@{orga.matrix_username}:tfjm.org", 50)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                # Invite participants
 | 
					 | 
				
			||||||
                for participation in tournament.participations.filter(valid=True).all():
 | 
					 | 
				
			||||||
                    for participant in participation.team.participants.all():
 | 
					 | 
				
			||||||
                        self.stdout.write(f"Invite {participant} in public channels of the tournament {name}...")
 | 
					 | 
				
			||||||
                        await Matrix.invite(f"#annonces-{slug}:tfjm.org",
 | 
					 | 
				
			||||||
                                            f"@{participant.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                        await Matrix.invite(f"#flood-{slug}:tfjm.org",
 | 
					 | 
				
			||||||
                                            f"@{participant.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                        await Matrix.invite(f"#general-{slug}:tfjm.org",
 | 
					 | 
				
			||||||
                                            f"@{participant.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                        await Matrix.invite(f"#tirage-au-sort-{slug}:tfjm.org",
 | 
					 | 
				
			||||||
                                            f"@{participant.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                # Create pool-specific channels
 | 
					 | 
				
			||||||
                for pool in tournament.pools.all():
 | 
					 | 
				
			||||||
                    self.stdout.write(f"Managing {pool}...")
 | 
					 | 
				
			||||||
                    five = pool.participations.count() >= 5
 | 
					 | 
				
			||||||
                    for i in range(2 if five else 1):
 | 
					 | 
				
			||||||
                        # Fix for five teams-pools
 | 
					 | 
				
			||||||
                        suffix = f"-{chr(ord('A') + i)}" if five else ""
 | 
					 | 
				
			||||||
                        if not await Matrix.resolve_room_alias(f"#poule-{slug}-{pool.id}{suffix}:tfjm.org"):
 | 
					 | 
				
			||||||
                            await Matrix.create_room(
 | 
					 | 
				
			||||||
                                visibility=RoomVisibility.public,
 | 
					 | 
				
			||||||
                                alias=f"poule-{slug}-{pool.id}{suffix}",
 | 
					 | 
				
			||||||
                                name=f"{name} - Jour {pool.round} - Poule " +
 | 
					 | 
				
			||||||
                                     ', '.join(participation.team.trigram
 | 
					 | 
				
			||||||
                                               for participation in pool.participations.all()) + suffix,
 | 
					 | 
				
			||||||
                                topic=f"Discussion avec les équipes - {pool}{suffix}",
 | 
					 | 
				
			||||||
                                federate=False,
 | 
					 | 
				
			||||||
                                preset=RoomPreset.private_chat,
 | 
					 | 
				
			||||||
                            )
 | 
					 | 
				
			||||||
                        if not await Matrix.resolve_room_alias(f"#poule-{slug}-{pool.id}{suffix}-jurys:tfjm.org"):
 | 
					 | 
				
			||||||
                            await Matrix.create_room(
 | 
					 | 
				
			||||||
                                visibility=RoomVisibility.public,
 | 
					 | 
				
			||||||
                                alias=f"poule-{slug}-{pool.id}{suffix}-jurys",
 | 
					 | 
				
			||||||
                                name=f"{name} - Jour {pool.round}{suffix} - Jurys poule " +
 | 
					 | 
				
			||||||
                                     ', '.join(participation.team.trigram
 | 
					 | 
				
			||||||
                                               for participation in pool.participations.all()) + suffix,
 | 
					 | 
				
			||||||
                                topic=f"Discussion avec les jurys - {pool}{suffix}",
 | 
					 | 
				
			||||||
                                federate=False,
 | 
					 | 
				
			||||||
                                preset=RoomPreset.private_chat,
 | 
					 | 
				
			||||||
                            )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        await Matrix.set_room_avatar(f"#poule-{slug}-{pool.id}{suffix}:tfjm.org", avatar_uri)
 | 
					 | 
				
			||||||
                        await Matrix.set_room_avatar(f"#poule-{slug}-{pool.id}{suffix}-jurys:tfjm.org", avatar_uri)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        bbb_url = pool.bbb_url.strip()
 | 
					 | 
				
			||||||
                        if five and ';' in bbb_url:
 | 
					 | 
				
			||||||
                            bbb_url = bbb_url.split(";")[i].strip()
 | 
					 | 
				
			||||||
                        url_params = urlencode(dict(url=bbb_url,
 | 
					 | 
				
			||||||
                                                    isAudioConf='false', displayName='$matrix_display_name',
 | 
					 | 
				
			||||||
                                                    avatarUrl='$matrix_avatar_url', userId='$matrix_user_id')) \
 | 
					 | 
				
			||||||
                            .replace("%24", "$")
 | 
					 | 
				
			||||||
                        await Matrix.add_integration(
 | 
					 | 
				
			||||||
                            f"#poule-{slug}-{pool.id}{suffix}:tfjm.org",
 | 
					 | 
				
			||||||
                            f"https://scalar.vector.im/api/widgets/bigbluebutton.html?{url_params}",
 | 
					 | 
				
			||||||
                            f"bbb-{slug}-{pool.id}{suffix}", "bigbluebutton", "BigBlueButton", str(pool))
 | 
					 | 
				
			||||||
                        await Matrix.add_integration(
 | 
					 | 
				
			||||||
                            f"#poule-{slug}-{pool.id}:tfjm.org",
 | 
					 | 
				
			||||||
                            f"https://board.tfjm.org/boards/{slug}-{pool.id}", f"board-{slug}-{pool.id}",
 | 
					 | 
				
			||||||
                            "customwidget", "Tableau", str(pool))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        # Invite admins and give permissions
 | 
					 | 
				
			||||||
                        for admin in VolunteerRegistration.objects.filter(admin=True).all():
 | 
					 | 
				
			||||||
                            await Matrix.invite(f"#poule-{slug}-{pool.id}{suffix}:tfjm.org",
 | 
					 | 
				
			||||||
                                                f"@{admin.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                            await Matrix.invite(f"#poule-{slug}-{pool.id}{suffix}-jurys:tfjm.org",
 | 
					 | 
				
			||||||
                                                f"@{admin.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                            await Matrix.set_room_power_level(f"#poule-{slug}-{pool.id}{suffix}:tfjm.org",
 | 
					 | 
				
			||||||
                                                              f"@{admin.matrix_username}:tfjm.org", 95)
 | 
					 | 
				
			||||||
                            await Matrix.set_room_power_level(f"#poule-{slug}-{pool.id}{suffix}-jurys:tfjm.org",
 | 
					 | 
				
			||||||
                                                              f"@{admin.matrix_username}:tfjm.org", 95)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        # Invite organizers and give permissions
 | 
					 | 
				
			||||||
                        for orga in tournament.organizers.all():
 | 
					 | 
				
			||||||
                            await Matrix.invite(f"#poule-{slug}-{pool.id}{suffix}:tfjm.org",
 | 
					 | 
				
			||||||
                                                f"@{orga.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                            await Matrix.invite(f"#poule-{slug}-{pool.id}{suffix}-jurys:tfjm.org",
 | 
					 | 
				
			||||||
                                                f"@{orga.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                            if not orga.is_admin:
 | 
					 | 
				
			||||||
                                await Matrix.set_room_power_level(f"#poule-{slug}-{pool.id}{suffix}:tfjm.org",
 | 
					 | 
				
			||||||
                                                                  f"@{orga.matrix_username}:tfjm.org", 50)
 | 
					 | 
				
			||||||
                                await Matrix.set_room_power_level(f"#poule-{slug}-{pool.id}{suffix}-jurys:tfjm.org",
 | 
					 | 
				
			||||||
                                                                  f"@{orga.matrix_username}:tfjm.org", 50)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        # Invite the jury, give good permissions
 | 
					 | 
				
			||||||
                        for jury in pool.juries.all():
 | 
					 | 
				
			||||||
                            await Matrix.invite(f"#annonces-{slug}:tfjm.org", f"@{jury.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                            await Matrix.invite(f"#general-{slug}:tfjm.org", f"@{jury.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                            await Matrix.invite(f"#flood-{slug}:tfjm.org", f"@{jury.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                            await Matrix.invite(f"#jury-{slug}:tfjm.org", f"@{jury.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                            await Matrix.invite(f"#orga-{slug}:tfjm.org", f"@{jury.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                            await Matrix.invite(f"#poule-{slug}-{pool.id}{suffix}:tfjm.org",
 | 
					 | 
				
			||||||
                                                f"@{jury.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                            await Matrix.invite(f"#poule-{slug}-{pool.id}{suffix}-jurys:tfjm.org",
 | 
					 | 
				
			||||||
                                                f"@{jury.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                            await Matrix.invite(f"#tirage-au-sort-{slug}:tfjm.org",
 | 
					 | 
				
			||||||
                                                f"@{jury.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                            if not jury.is_admin:
 | 
					 | 
				
			||||||
                                await Matrix.set_room_power_level(f"#jury-{slug}:tfjm.org",
 | 
					 | 
				
			||||||
                                                                  f"@{jury.matrix_username}:tfjm.org", 50)
 | 
					 | 
				
			||||||
                                await Matrix.set_room_power_level(f"#poule-{slug}-{pool.id}{suffix}:tfjm.org",
 | 
					 | 
				
			||||||
                                                                  f"@{jury.matrix_username}:tfjm.org", 50)
 | 
					 | 
				
			||||||
                                await Matrix.set_room_power_level(f"#poule-{slug}-{pool.id}{suffix}-jurys:tfjm.org",
 | 
					 | 
				
			||||||
                                                                  f"@{jury.matrix_username}:tfjm.org", 50)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        # Invite participants to the right pool
 | 
					 | 
				
			||||||
                        for participation in pool.participations.all():
 | 
					 | 
				
			||||||
                            for participant in participation.team.participants.all():
 | 
					 | 
				
			||||||
                                await Matrix.invite(f"#poule-{slug}-{pool.id}{suffix}:tfjm.org",
 | 
					 | 
				
			||||||
                                                    f"@{participant.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            # Create private channels for teams
 | 
					 | 
				
			||||||
            for team in Team.objects.all():
 | 
					 | 
				
			||||||
                self.stdout.write(f"Create private channel for {team}...")
 | 
					 | 
				
			||||||
                if not await Matrix.resolve_room_alias(f"#equipe-{team.trigram.lower()}:tfjm.org"):
 | 
					 | 
				
			||||||
                    await Matrix.create_room(
 | 
					 | 
				
			||||||
                        visibility=RoomVisibility.public,
 | 
					 | 
				
			||||||
                        alias=f"equipe-{team.trigram.lower()}",
 | 
					 | 
				
			||||||
                        name=f"Équipe {team.trigram}",
 | 
					 | 
				
			||||||
                        topic=f"Discussion interne de l'équipe {team.name}",
 | 
					 | 
				
			||||||
                        federate=False,
 | 
					 | 
				
			||||||
                        preset=RoomPreset.private_chat,
 | 
					 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
                for participant in team.participants.all():
 | 
					 | 
				
			||||||
                    await Matrix.invite(f"#equipe-{team.trigram.lower}:tfjm.org",
 | 
					 | 
				
			||||||
                                        f"@{participant.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
                    await Matrix.set_room_power_level(f"#equipe-{team.trigram.lower()}:tfjm.org",
 | 
					 | 
				
			||||||
                                                      f"@{participant.matrix_username}:tfjm.org", 50)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            """
 | 
					 | 
				
			||||||
            # Manage channels to discuss about problems
 | 
					 | 
				
			||||||
            for i in range(9):
 | 
					 | 
				
			||||||
                self.stdout.write(f"Create channel for problem {i}...")
 | 
					 | 
				
			||||||
                if not await Matrix.resolve_room_alias(f"#mec-{i}:tfjm.org"):
 | 
					 | 
				
			||||||
                    await Matrix.create_room(
 | 
					 | 
				
			||||||
                        visibility=RoomVisibility.public,
 | 
					 | 
				
			||||||
                        alias=f"mec-{i}",
 | 
					 | 
				
			||||||
                        name=f"Mise en commun - {'Général' if i == 0 else f'Problème {i}'}",
 | 
					 | 
				
			||||||
                        topic=f"Discussion autour des problèmes",
 | 
					 | 
				
			||||||
                        federate=False,
 | 
					 | 
				
			||||||
                        preset=RoomPreset.public_chat,
 | 
					 | 
				
			||||||
                        invite=[f"@{registration.matrix_username}:tfjm.org"
 | 
					 | 
				
			||||||
                                for registration in Registration.objects.all()],
 | 
					 | 
				
			||||||
                        power_level_override={
 | 
					 | 
				
			||||||
                            f"@{registration.matrix_username}:tfjm.org": (95 if registration.is_admin else 50)
 | 
					 | 
				
			||||||
                            for registration in VolunteerRegistration.objects.all()
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
                    await Matrix.set_room_avatar(f"#mec-{i}:tfjm.org", avatar_uri)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                for registration in Registration.objects.all():
 | 
					 | 
				
			||||||
                    await Matrix.invite(f"#mec-{i}:tfjm.org", registration.matrix_username)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                for registration in VolunteerRegistration.objects.all():
 | 
					 | 
				
			||||||
                    await Matrix.set_room_power_level(f"#mec-{i}:tfjm.org",
 | 
					 | 
				
			||||||
                                                      f"@{registration.matrix_username}:tfjm.org",
 | 
					 | 
				
			||||||
                                                      95 if registration.is_admin else 50)
 | 
					 | 
				
			||||||
            """
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        asyncio.get_event_loop().run_until_complete(main())
 | 
					 | 
				
			||||||
@@ -16,8 +16,6 @@ from django.utils.text import format_lazy
 | 
				
			|||||||
from django.utils.translation import gettext_lazy as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
from registration.models import VolunteerRegistration
 | 
					from registration.models import VolunteerRegistration
 | 
				
			||||||
from tfjm.lists import get_sympa_client
 | 
					from tfjm.lists import get_sympa_client
 | 
				
			||||||
from tfjm.matrix import Matrix, RoomPreset, RoomVisibility
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_motivation_letter_filename(instance, filename):
 | 
					def get_motivation_letter_filename(instance, filename):
 | 
				
			||||||
    return f"authorization/motivation_letters/motivation_letter_{instance.trigram}"
 | 
					    return f"authorization/motivation_letters/motivation_letter_{instance.trigram}"
 | 
				
			||||||
@@ -101,18 +99,9 @@ class Team(models.Model):
 | 
				
			|||||||
    def save(self, *args, **kwargs):
 | 
					    def save(self, *args, **kwargs):
 | 
				
			||||||
        if not self.access_code:
 | 
					        if not self.access_code:
 | 
				
			||||||
            # if the team got created, generate the access code, create the contact mailing list
 | 
					            # if the team got created, generate the access code, create the contact mailing list
 | 
				
			||||||
            # and create a dedicated Matrix room.
 | 
					 | 
				
			||||||
            self.access_code = get_random_string(6)
 | 
					            self.access_code = get_random_string(6)
 | 
				
			||||||
            self.create_mailing_list()
 | 
					            self.create_mailing_list()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Matrix.create_room(
 | 
					 | 
				
			||||||
                visibility=RoomVisibility.private,
 | 
					 | 
				
			||||||
                name=f"#équipe-{self.trigram.lower()}",
 | 
					 | 
				
			||||||
                alias=f"equipe-{self.trigram.lower()}",
 | 
					 | 
				
			||||||
                topic=f"Discussion de l'équipe {self.name}",
 | 
					 | 
				
			||||||
                preset=RoomPreset.private_chat,
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return super().save(*args, **kwargs)
 | 
					        return super().save(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_absolute_url(self):
 | 
					    def get_absolute_url(self):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,12 +19,11 @@ def create_team_participation(instance, created, raw, **_):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
def update_mailing_list(instance: Team, raw, **_):
 | 
					def update_mailing_list(instance: Team, raw, **_):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    When a team name or trigram got updated, update mailing lists and Matrix rooms
 | 
					    When a team name or trigram got updated, update mailing lists
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    if instance.pk and not raw:
 | 
					    if instance.pk and not raw:
 | 
				
			||||||
        old_team = Team.objects.get(pk=instance.pk)
 | 
					        old_team = Team.objects.get(pk=instance.pk)
 | 
				
			||||||
        if old_team.trigram != instance.trigram:
 | 
					        if old_team.trigram != instance.trigram:
 | 
				
			||||||
            # TODO Rename Matrix room
 | 
					 | 
				
			||||||
            # Delete old mailing list, create a new one
 | 
					            # Delete old mailing list, create a new one
 | 
				
			||||||
            old_team.delete_mailing_list()
 | 
					            old_team.delete_mailing_list()
 | 
				
			||||||
            instance.create_mailing_list()
 | 
					            instance.create_mailing_list()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,7 +32,6 @@ from odf.table import CoveredTableCell, Table, TableCell, TableColumn, TableRow
 | 
				
			|||||||
from odf.text import P
 | 
					from odf.text import P
 | 
				
			||||||
from registration.models import StudentRegistration, VolunteerRegistration
 | 
					from registration.models import StudentRegistration, VolunteerRegistration
 | 
				
			||||||
from tfjm.lists import get_sympa_client
 | 
					from tfjm.lists import get_sympa_client
 | 
				
			||||||
from tfjm.matrix import Matrix
 | 
					 | 
				
			||||||
from tfjm.views import AdminMixin, VolunteerMixin
 | 
					from tfjm.views import AdminMixin, VolunteerMixin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .forms import AddJuryForm, JoinTeamForm, MotivationLetterForm, NoteForm, ParticipationForm, PassageForm, \
 | 
					from .forms import AddJuryForm, JoinTeamForm, MotivationLetterForm, NoteForm, ParticipationForm, PassageForm, \
 | 
				
			||||||
@@ -68,8 +67,7 @@ class CreateTeamView(LoginRequiredMixin, CreateView):
 | 
				
			|||||||
        """
 | 
					        """
 | 
				
			||||||
        When a team is about to be created, the user automatically
 | 
					        When a team is about to be created, the user automatically
 | 
				
			||||||
        joins the team, a mailing list got created and the user is
 | 
					        joins the team, a mailing list got created and the user is
 | 
				
			||||||
        automatically subscribed to this mailing list, and finally
 | 
					        automatically subscribed to this mailing list.
 | 
				
			||||||
        a Matrix room is created and the user is invited in this room.
 | 
					 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        ret = super().form_valid(form)
 | 
					        ret = super().form_valid(form)
 | 
				
			||||||
        # The user joins the team
 | 
					        # The user joins the team
 | 
				
			||||||
@@ -82,9 +80,6 @@ class CreateTeamView(LoginRequiredMixin, CreateView):
 | 
				
			|||||||
        get_sympa_client().subscribe(user.email, f"equipe-{form.instance.trigram.lower()}", False,
 | 
					        get_sympa_client().subscribe(user.email, f"equipe-{form.instance.trigram.lower()}", False,
 | 
				
			||||||
                                     f"{user.first_name} {user.last_name}")
 | 
					                                     f"{user.first_name} {user.last_name}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Invite the user in the team Matrix room
 | 
					 | 
				
			||||||
        Matrix.invite(f"#equipe-{form.instance.trigram.lower()}:tfjm.org",
 | 
					 | 
				
			||||||
                      f"@{user.registration.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
        return ret
 | 
					        return ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -112,7 +107,7 @@ class JoinTeamView(LoginRequiredMixin, FormView):
 | 
				
			|||||||
    def form_valid(self, form):
 | 
					    def form_valid(self, form):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        When a user joins a team, the user is automatically subscribed to
 | 
					        When a user joins a team, the user is automatically subscribed to
 | 
				
			||||||
        the team mailing list,the user is invited in the team Matrix room.
 | 
					        the team mailing list.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        self.object = form.instance
 | 
					        self.object = form.instance
 | 
				
			||||||
        ret = super().form_valid(form)
 | 
					        ret = super().form_valid(form)
 | 
				
			||||||
@@ -127,9 +122,6 @@ class JoinTeamView(LoginRequiredMixin, FormView):
 | 
				
			|||||||
        get_sympa_client().subscribe(user.email, f"equipe-{form.instance.trigram.lower()}", False,
 | 
					        get_sympa_client().subscribe(user.email, f"equipe-{form.instance.trigram.lower()}", False,
 | 
				
			||||||
                                     f"{user.first_name} {user.last_name}")
 | 
					                                     f"{user.first_name} {user.last_name}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Invite the user in the team Matrix room
 | 
					 | 
				
			||||||
        Matrix.invite(f"#equipe-{form.instance.trigram.lower()}:tfjm.org",
 | 
					 | 
				
			||||||
                      f"@{user.registration.matrix_username}:tfjm.org")
 | 
					 | 
				
			||||||
        return ret
 | 
					        return ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_success_url(self):
 | 
					    def get_success_url(self):
 | 
				
			||||||
@@ -468,9 +460,6 @@ class TeamLeaveView(LoginRequiredMixin, TemplateView):
 | 
				
			|||||||
        request.user.registration.team = None
 | 
					        request.user.registration.team = None
 | 
				
			||||||
        request.user.registration.save()
 | 
					        request.user.registration.save()
 | 
				
			||||||
        get_sympa_client().unsubscribe(request.user.email, f"equipe-{team.trigram.lower()}", False)
 | 
					        get_sympa_client().unsubscribe(request.user.email, f"equipe-{team.trigram.lower()}", False)
 | 
				
			||||||
        Matrix.kick(f"#equipe-{team.trigram.lower()}:tfjm.org",
 | 
					 | 
				
			||||||
                    f"@{request.user.registration.matrix_username}:tfjm.org",
 | 
					 | 
				
			||||||
                    "Équipe quittée")
 | 
					 | 
				
			||||||
        if team.students.count() + team.coaches.count() == 0:
 | 
					        if team.students.count() + team.coaches.count() == 0:
 | 
				
			||||||
            team.delete()
 | 
					            team.delete()
 | 
				
			||||||
        return redirect(reverse_lazy("index"))
 | 
					        return redirect(reverse_lazy("index"))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,17 +0,0 @@
 | 
				
			|||||||
# Copyright (C) 2020 by Animath
 | 
					 | 
				
			||||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from cas_server.auth import DjangoAuthUser  # pragma: no cover
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class CustomAuthUser(DjangoAuthUser):  # pragma: no cover
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    Override Django Auth User model to define a custom Matrix username.
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def attributs(self):
 | 
					 | 
				
			||||||
        d = super().attributs()
 | 
					 | 
				
			||||||
        if self.user:
 | 
					 | 
				
			||||||
            d["matrix_username"] = self.user.registration.matrix_username
 | 
					 | 
				
			||||||
            d["display_name"] = str(self.user.registration)
 | 
					 | 
				
			||||||
        return d
 | 
					 | 
				
			||||||
@@ -1,26 +0,0 @@
 | 
				
			|||||||
[
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        "model": "cas_server.servicepattern",
 | 
					 | 
				
			||||||
        "pk": 1,
 | 
					 | 
				
			||||||
        "fields": {
 | 
					 | 
				
			||||||
            "pos": 100,
 | 
					 | 
				
			||||||
            "name": "Plateforme du TFJM²",
 | 
					 | 
				
			||||||
            "pattern": "^https://tfjm.org(:8448)?/.*$",
 | 
					 | 
				
			||||||
            "user_field": "matrix_username",
 | 
					 | 
				
			||||||
            "restrict_users": false,
 | 
					 | 
				
			||||||
            "proxy": true,
 | 
					 | 
				
			||||||
            "proxy_callback": true,
 | 
					 | 
				
			||||||
            "single_log_out": true,
 | 
					 | 
				
			||||||
            "single_log_out_callback": ""
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        "model": "cas_server.replaceattributname",
 | 
					 | 
				
			||||||
        "pk": 1,
 | 
					 | 
				
			||||||
        "fields": {
 | 
					 | 
				
			||||||
            "name": "display_name",
 | 
					 | 
				
			||||||
            "replace": "",
 | 
					 | 
				
			||||||
            "service_pattern": 1
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
@@ -85,10 +85,6 @@ class Registration(PolymorphicModel):
 | 
				
			|||||||
    def is_volunteer(self):
 | 
					    def is_volunteer(self):
 | 
				
			||||||
        return isinstance(self, VolunteerRegistration)
 | 
					        return isinstance(self, VolunteerRegistration)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					 | 
				
			||||||
    def matrix_username(self):
 | 
					 | 
				
			||||||
        return f"tfjm_{self.user.pk}"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_absolute_url(self):
 | 
					    def get_absolute_url(self):
 | 
				
			||||||
        return reverse_lazy("registration:user_detail", args=(self.user_id,))
 | 
					        return reverse_lazy("registration:user_detail", args=(self.user_id,))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,6 @@ channels[daphne]~=4.0.0
 | 
				
			|||||||
channels-redis~=4.0.0
 | 
					channels-redis~=4.0.0
 | 
				
			||||||
crispy-bootstrap5~=0.7
 | 
					crispy-bootstrap5~=0.7
 | 
				
			||||||
Django>=4.1,<5.0
 | 
					Django>=4.1,<5.0
 | 
				
			||||||
django-cas-server~=2.0
 | 
					 | 
				
			||||||
django-crispy-forms~=1.14
 | 
					django-crispy-forms~=1.14
 | 
				
			||||||
django-extensions~=3.2
 | 
					django-extensions~=3.2
 | 
				
			||||||
django-filter~=22.1
 | 
					django-filter~=22.1
 | 
				
			||||||
@@ -14,7 +13,6 @@ django-tables2~=2.4
 | 
				
			|||||||
djangorestframework~=3.14
 | 
					djangorestframework~=3.14
 | 
				
			||||||
django-rest-polymorphic~=0.1
 | 
					django-rest-polymorphic~=0.1
 | 
				
			||||||
gunicorn~=20.1
 | 
					gunicorn~=20.1
 | 
				
			||||||
matrix-nio~=0.20
 | 
					 | 
				
			||||||
odfpy~=1.4.1
 | 
					odfpy~=1.4.1
 | 
				
			||||||
phonenumbers~=8.12.57
 | 
					phonenumbers~=8.12.57
 | 
				
			||||||
psycopg2-binary~=2.9.5
 | 
					psycopg2-binary~=2.9.5
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,9 +10,6 @@
 | 
				
			|||||||
# Recreate sympa lists
 | 
					# Recreate sympa lists
 | 
				
			||||||
*/2     *       *       *       *       cd /code && python manage.py fix_sympa_lists &> /dev/null
 | 
					*/2     *       *       *       *       cd /code && python manage.py fix_sympa_lists &> /dev/null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Update matrix channels
 | 
					 | 
				
			||||||
03      */6     *       *       *       cd /code && python manage.py fix_matrix_channels &> /dev/null
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Check payments from Hello Asso
 | 
					# Check payments from Hello Asso
 | 
				
			||||||
*/6     *       *       *       *       cd /code && python manage.py check_hello_asso &> /dev/null
 | 
					*/6     *       *       *       *       cd /code && python manage.py check_hello_asso &> /dev/null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										432
									
								
								tfjm/matrix.py
									
									
									
									
									
								
							
							
						
						
									
										432
									
								
								tfjm/matrix.py
									
									
									
									
									
								
							@@ -1,432 +0,0 @@
 | 
				
			|||||||
# Copyright (C) 2020 by Animath
 | 
					 | 
				
			||||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from enum import Enum
 | 
					 | 
				
			||||||
import os
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Matrix:
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    Utility class to manage interaction with the Matrix homeserver.
 | 
					 | 
				
			||||||
    This log in the @tfjmbot account (must be created before).
 | 
					 | 
				
			||||||
    The access token is then stored.
 | 
					 | 
				
			||||||
    All is done with this bot account, that is a server administrator.
 | 
					 | 
				
			||||||
    Tasks are normally asynchronous, but for compatibility we make
 | 
					 | 
				
			||||||
    them synchronous.
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    _token = None
 | 
					 | 
				
			||||||
    _device_id = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    async def _get_client(cls):  # pragma: no cover
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        Retrieve the bot account.
 | 
					 | 
				
			||||||
        If not logged, log in and store access token.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        if not os.getenv("SYNAPSE_PASSWORD") and not os.getenv("SYNAPSE_TOKEN"):
 | 
					 | 
				
			||||||
            return FakeMatrixClient()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        from nio import AsyncClient
 | 
					 | 
				
			||||||
        client = AsyncClient("https://tfjm.org", "@tfjmbot:tfjm.org")
 | 
					 | 
				
			||||||
        client.user_id = "@tfjmbot:tfjm.org"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if os.getenv("SYNAPSE_TOKEN"):
 | 
					 | 
				
			||||||
            client.access_token = os.getenv("SYNAPSE_TOKEN")
 | 
					 | 
				
			||||||
            client.device_id = os.getenv("SYNAPSE_DEVICE")
 | 
					 | 
				
			||||||
            return client
 | 
					 | 
				
			||||||
        elif os.path.isfile(".matrix_token"):
 | 
					 | 
				
			||||||
            with open(".matrix_device", "r") as f:
 | 
					 | 
				
			||||||
                cls._device_id = f.read().rstrip(" \t\r\n")
 | 
					 | 
				
			||||||
                client.device_id = cls._device_id
 | 
					 | 
				
			||||||
            with open(".matrix_token", "r") as f:
 | 
					 | 
				
			||||||
                cls._token = f.read().rstrip(" \t\r\n")
 | 
					 | 
				
			||||||
                client.access_token = cls._token
 | 
					 | 
				
			||||||
                return client
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        await client.login(password=os.getenv("SYNAPSE_PASSWORD"), device_name="Plateforme")
 | 
					 | 
				
			||||||
        cls._token = client.access_token
 | 
					 | 
				
			||||||
        cls._device_id = client.device_id
 | 
					 | 
				
			||||||
        with open(".matrix_token", "w") as f:
 | 
					 | 
				
			||||||
            f.write(cls._token)
 | 
					 | 
				
			||||||
        with open(".matrix_device", "w") as f:
 | 
					 | 
				
			||||||
            f.write(cls._device_id)
 | 
					 | 
				
			||||||
        return client
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    async def set_display_name(cls, name: str):
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        Set the display name of the bot account.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        client = await cls._get_client()
 | 
					 | 
				
			||||||
        return await client.set_displayname(name)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    async def set_avatar(cls, avatar_url: str):  # pragma: no cover
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        Set the display avatar of the bot account.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        client = await cls._get_client()
 | 
					 | 
				
			||||||
        return await client.set_avatar(avatar_url)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    async def get_avatar(cls):  # pragma: no cover
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        Set the display avatar of the bot account.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        client = await cls._get_client()
 | 
					 | 
				
			||||||
        resp = await client.get_avatar()
 | 
					 | 
				
			||||||
        return resp.avatar_url if hasattr(resp, "avatar_url") else resp
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    async def upload(
 | 
					 | 
				
			||||||
            cls,
 | 
					 | 
				
			||||||
            data_provider,
 | 
					 | 
				
			||||||
            content_type: str = "application/octet-stream",
 | 
					 | 
				
			||||||
            filename: str = None,
 | 
					 | 
				
			||||||
            encrypt: bool = False,
 | 
					 | 
				
			||||||
            monitor=None,
 | 
					 | 
				
			||||||
            filesize: int = None,
 | 
					 | 
				
			||||||
    ):  # pragma: no cover
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        Upload a file to the content repository.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Returns a tuple containing:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        - Either a `UploadResponse` if the request was successful, or a
 | 
					 | 
				
			||||||
          `UploadError` if there was an error with the request
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        - A dict with file decryption info if encrypt is ``True``,
 | 
					 | 
				
			||||||
          else ``None``.
 | 
					 | 
				
			||||||
        Args:
 | 
					 | 
				
			||||||
            data_provider (Callable, SynchronousFile, AsyncFile): A function
 | 
					 | 
				
			||||||
                returning the data to upload or a file object. File objects
 | 
					 | 
				
			||||||
                must be opened in binary mode (``mode="r+b"``). Callables
 | 
					 | 
				
			||||||
                returning a path string, Path, async iterable or aiofiles
 | 
					 | 
				
			||||||
                open binary file object allow the file data to be read in an
 | 
					 | 
				
			||||||
                asynchronous and lazy way (without reading the entire file
 | 
					 | 
				
			||||||
                into memory). Returning a synchronous iterable or standard
 | 
					 | 
				
			||||||
                open binary file object will still allow the data to be read
 | 
					 | 
				
			||||||
                lazily, but not asynchronously.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                The function will be called again if the upload fails
 | 
					 | 
				
			||||||
                due to a server timeout, in which case it must restart
 | 
					 | 
				
			||||||
                from the beginning.
 | 
					 | 
				
			||||||
                Callables receive two arguments: the total number of
 | 
					 | 
				
			||||||
                429 "Too many request" errors that occured, and the total
 | 
					 | 
				
			||||||
                number of server timeout exceptions that occured, thus
 | 
					 | 
				
			||||||
                cleanup operations can be performed for retries if necessary.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            content_type (str): The content MIME type of the file,
 | 
					 | 
				
			||||||
                e.g. "image/png".
 | 
					 | 
				
			||||||
                Defaults to "application/octet-stream", corresponding to a
 | 
					 | 
				
			||||||
                generic binary file.
 | 
					 | 
				
			||||||
                Custom values are ignored if encrypt is ``True``.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            filename (str, optional): The file's original name.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            encrypt (bool): If the file's content should be encrypted,
 | 
					 | 
				
			||||||
                necessary for files that will be sent to encrypted rooms.
 | 
					 | 
				
			||||||
                Defaults to ``False``.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            monitor (TransferMonitor, optional): If a ``TransferMonitor``
 | 
					 | 
				
			||||||
                object is passed, it will be updated by this function while
 | 
					 | 
				
			||||||
                uploading.
 | 
					 | 
				
			||||||
                From this object, statistics such as currently
 | 
					 | 
				
			||||||
                transferred bytes or estimated remaining time can be gathered
 | 
					 | 
				
			||||||
                while the upload is running as a task; it also allows
 | 
					 | 
				
			||||||
                for pausing and cancelling.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            filesize (int, optional): Size in bytes for the file to transfer.
 | 
					 | 
				
			||||||
                If left as ``None``, some servers might refuse the upload.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        client = await cls._get_client()
 | 
					 | 
				
			||||||
        return await client.upload(data_provider, content_type, filename, encrypt, monitor, filesize) \
 | 
					 | 
				
			||||||
            if not isinstance(client, FakeMatrixClient) else None, None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    async def create_room(
 | 
					 | 
				
			||||||
            cls,
 | 
					 | 
				
			||||||
            visibility=None,
 | 
					 | 
				
			||||||
            alias=None,
 | 
					 | 
				
			||||||
            name=None,
 | 
					 | 
				
			||||||
            topic=None,
 | 
					 | 
				
			||||||
            room_version=None,
 | 
					 | 
				
			||||||
            federate=True,
 | 
					 | 
				
			||||||
            is_direct=False,
 | 
					 | 
				
			||||||
            preset=None,
 | 
					 | 
				
			||||||
            invite=(),
 | 
					 | 
				
			||||||
            initial_state=(),
 | 
					 | 
				
			||||||
            power_level_override=None,
 | 
					 | 
				
			||||||
    ):
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        Create a new room.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Returns either a `RoomCreateResponse` if the request was successful or
 | 
					 | 
				
			||||||
        a `RoomCreateError` if there was an error with the request.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Args:
 | 
					 | 
				
			||||||
            visibility (RoomVisibility): whether to have the room published in
 | 
					 | 
				
			||||||
                the server's room directory or not.
 | 
					 | 
				
			||||||
                Defaults to ``RoomVisibility.private``.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            alias (str, optional): The desired canonical alias local part.
 | 
					 | 
				
			||||||
                For example, if set to "foo" and the room is created on the
 | 
					 | 
				
			||||||
                "example.com" server, the room alias will be
 | 
					 | 
				
			||||||
                "#foo:example.com".
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            name (str, optional): A name to set for the room.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            topic (str, optional): A topic to set for the room.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            room_version (str, optional): The room version to set.
 | 
					 | 
				
			||||||
                If not specified, the homeserver will use its default setting.
 | 
					 | 
				
			||||||
                If a version not supported by the homeserver is specified,
 | 
					 | 
				
			||||||
                a 400 ``M_UNSUPPORTED_ROOM_VERSION`` error will be returned.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            federate (bool): Whether to allow users from other homeservers from
 | 
					 | 
				
			||||||
                joining the room. Defaults to ``True``.
 | 
					 | 
				
			||||||
                Cannot be changed later.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            is_direct (bool): If this should be considered a
 | 
					 | 
				
			||||||
                direct messaging room.
 | 
					 | 
				
			||||||
                If ``True``, the server will set the ``is_direct`` flag on
 | 
					 | 
				
			||||||
                ``m.room.member events`` sent to the users in ``invite``.
 | 
					 | 
				
			||||||
                Defaults to ``False``.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            preset (RoomPreset, optional): The selected preset will set various
 | 
					 | 
				
			||||||
                rules for the room.
 | 
					 | 
				
			||||||
                If unspecified, the server will choose a preset from the
 | 
					 | 
				
			||||||
                ``visibility``: ``RoomVisibility.public`` equates to
 | 
					 | 
				
			||||||
                ``RoomPreset.public_chat``, and
 | 
					 | 
				
			||||||
                ``RoomVisibility.private`` equates to a
 | 
					 | 
				
			||||||
                ``RoomPreset.private_chat``.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            invite (list): A list of user id to invite to the room.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            initial_state (list): A list of state event dicts to send when
 | 
					 | 
				
			||||||
                the room is created.
 | 
					 | 
				
			||||||
                For example, a room could be made encrypted immediatly by
 | 
					 | 
				
			||||||
                having a ``m.room.encryption`` event dict.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            power_level_override (dict): A ``m.room.power_levels content`` dict
 | 
					 | 
				
			||||||
                to override the default.
 | 
					 | 
				
			||||||
                The dict will be applied on top of the generated
 | 
					 | 
				
			||||||
                ``m.room.power_levels`` event before it is sent to the room.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        client = await cls._get_client()
 | 
					 | 
				
			||||||
        return await client.room_create(
 | 
					 | 
				
			||||||
            visibility, alias, name, topic, room_version, federate, is_direct, preset, invite, initial_state,
 | 
					 | 
				
			||||||
            power_level_override)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    async def resolve_room_alias(cls, room_alias: str):
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        Resolve a room alias to a room ID.
 | 
					 | 
				
			||||||
        Return None if the alias does not exist.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        client = await cls._get_client()
 | 
					 | 
				
			||||||
        resp = await client.room_resolve_alias(room_alias)
 | 
					 | 
				
			||||||
        return resp.room_id if resp and hasattr(resp, "room_id") else None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    async def invite(cls, room_id: str, user_id: str):
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        Invite a user to a room.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Returns either a `RoomInviteResponse` if the request was successful or
 | 
					 | 
				
			||||||
        a `RoomInviteError` if there was an error with the request.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Args:
 | 
					 | 
				
			||||||
            room_id (str): The room id of the room that the user will be
 | 
					 | 
				
			||||||
                invited to.
 | 
					 | 
				
			||||||
            user_id (str): The user id of the user that should be invited.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        client = await cls._get_client()
 | 
					 | 
				
			||||||
        if room_id.startswith("#"):
 | 
					 | 
				
			||||||
            room_id = await cls.resolve_room_alias(room_id)
 | 
					 | 
				
			||||||
        return await client.room_invite(room_id, user_id)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    async def send_message(cls, room_id: str, body: str, formatted_body: str = None,
 | 
					 | 
				
			||||||
                           msgtype: str = "m.text", html: bool = True):
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        Send a message to a room.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        client = await cls._get_client()
 | 
					 | 
				
			||||||
        if room_id.startswith("#"):
 | 
					 | 
				
			||||||
            room_id = await cls.resolve_room_alias(room_id)
 | 
					 | 
				
			||||||
        content = {
 | 
					 | 
				
			||||||
                "msgtype": msgtype,
 | 
					 | 
				
			||||||
                "body": body,
 | 
					 | 
				
			||||||
                "formatted_body": formatted_body or body,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if html:
 | 
					 | 
				
			||||||
            content["format"] = "org.matrix.custom.html"
 | 
					 | 
				
			||||||
        return await client.room_send(
 | 
					 | 
				
			||||||
            room_id=room_id,
 | 
					 | 
				
			||||||
            message_type="m.room.message",
 | 
					 | 
				
			||||||
            content=content,
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    async def add_integration(cls, room_id: str, widget_url: str, state_key: str,
 | 
					 | 
				
			||||||
                              widget_type: str = "customwidget", widget_name: str = "Custom widget",
 | 
					 | 
				
			||||||
                              widget_title: str = ""):
 | 
					 | 
				
			||||||
        client = await cls._get_client()
 | 
					 | 
				
			||||||
        if room_id.startswith("#"):
 | 
					 | 
				
			||||||
            room_id = await cls.resolve_room_alias(room_id)
 | 
					 | 
				
			||||||
        content = {
 | 
					 | 
				
			||||||
            "type": widget_type,
 | 
					 | 
				
			||||||
            "url": widget_url,
 | 
					 | 
				
			||||||
            "name": widget_name,
 | 
					 | 
				
			||||||
            "data": {
 | 
					 | 
				
			||||||
                "curl": widget_url,
 | 
					 | 
				
			||||||
                "title": widget_title,
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            "creatorUserId": client.user,
 | 
					 | 
				
			||||||
            "roomId": room_id,
 | 
					 | 
				
			||||||
            "id": state_key,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return await client.room_put_state(
 | 
					 | 
				
			||||||
            room_id=room_id,
 | 
					 | 
				
			||||||
            event_type="im.vector.modular.widgets",
 | 
					 | 
				
			||||||
            content=content,
 | 
					 | 
				
			||||||
            state_key=state_key,
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    async def remove_integration(cls, room_id: str, state_key: str):
 | 
					 | 
				
			||||||
        client = await cls._get_client()
 | 
					 | 
				
			||||||
        if room_id.startswith("#"):
 | 
					 | 
				
			||||||
            room_id = await cls.resolve_room_alias(room_id)
 | 
					 | 
				
			||||||
        return await client.room_put_state(
 | 
					 | 
				
			||||||
            room_id=room_id,
 | 
					 | 
				
			||||||
            event_type="im.vector.modular.widgets",
 | 
					 | 
				
			||||||
            content={},
 | 
					 | 
				
			||||||
            state_key=state_key,
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    async def kick(cls, room_id: str, user_id: str, reason: str = None):
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        Kick a user from a room, or withdraw their invitation.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Kicking a user adjusts their membership to "leave" with an optional
 | 
					 | 
				
			||||||
        reason.
 | 
					 | 
				
			||||||
²
 | 
					 | 
				
			||||||
        Returns either a `RoomKickResponse` if the request was successful or
 | 
					 | 
				
			||||||
        a `RoomKickError` if there was an error with the request.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Args:
 | 
					 | 
				
			||||||
            room_id (str): The room id of the room that the user will be
 | 
					 | 
				
			||||||
                kicked from.
 | 
					 | 
				
			||||||
            user_id (str): The user_id of the user that should be kicked.
 | 
					 | 
				
			||||||
            reason (str, optional): A reason for which the user is kicked.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        client = await cls._get_client()
 | 
					 | 
				
			||||||
        if room_id.startswith("#"):
 | 
					 | 
				
			||||||
            room_id = await cls.resolve_room_alias(room_id)
 | 
					 | 
				
			||||||
        return await client.room_kick(room_id, user_id, reason)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    async def set_room_power_level(cls, room_id: str, user_id: str, power_level: int):  # pragma: no cover
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        Put a given power level to a user in a certain room.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Returns either a `RoomPutStateResponse` if the request was successful or
 | 
					 | 
				
			||||||
        a `RoomPutStateError` if there was an error with the request.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Args:
 | 
					 | 
				
			||||||
            room_id (str): The room id of the room where the power level
 | 
					 | 
				
			||||||
                of the user should be updated.
 | 
					 | 
				
			||||||
            user_id (str): The user_id of the user which power level should
 | 
					 | 
				
			||||||
                be updated.
 | 
					 | 
				
			||||||
            power_level (int): The target power level to give.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        client = await cls._get_client()
 | 
					 | 
				
			||||||
        if isinstance(client, FakeMatrixClient):
 | 
					 | 
				
			||||||
            return None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if room_id.startswith("#"):
 | 
					 | 
				
			||||||
            room_id = await cls.resolve_room_alias(room_id)
 | 
					 | 
				
			||||||
        resp = await client.room_get_state_event(room_id, "m.room.power_levels")
 | 
					 | 
				
			||||||
        content = resp.content
 | 
					 | 
				
			||||||
        content["users"][user_id] = power_level
 | 
					 | 
				
			||||||
        return await client.room_put_state(room_id, "m.room.power_levels", content=content, state_key=resp.state_key)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    async def set_room_power_level_event(cls, room_id: str, event: str, power_level: int):  # pragma: no cover
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        Define the minimal power level to have to send a certain event type
 | 
					 | 
				
			||||||
         in a given room.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Returns either a `RoomPutStateResponse` if the request was successful or
 | 
					 | 
				
			||||||
        a `RoomPutStateError` if there was an error with the request.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Args:
 | 
					 | 
				
			||||||
            room_id (str): The room id of the room where the power level
 | 
					 | 
				
			||||||
                of the event should be updated.
 | 
					 | 
				
			||||||
            event (str): The event name which minimal power level should
 | 
					 | 
				
			||||||
                be updated.
 | 
					 | 
				
			||||||
            power_level (int): The target power level to give.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        client = await cls._get_client()
 | 
					 | 
				
			||||||
        if isinstance(client, FakeMatrixClient):
 | 
					 | 
				
			||||||
            return None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if room_id.startswith("#"):
 | 
					 | 
				
			||||||
            room_id = await cls.resolve_room_alias(room_id)
 | 
					 | 
				
			||||||
        resp = await client.room_get_state_event(room_id, "m.room.power_levels")
 | 
					 | 
				
			||||||
        content = resp.content
 | 
					 | 
				
			||||||
        if event.startswith("m."):
 | 
					 | 
				
			||||||
            content["events"][event] = power_level
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            content[event] = power_level
 | 
					 | 
				
			||||||
        return await client.room_put_state(room_id, "m.room.power_levels", content=content, state_key=resp.state_key)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    async def set_room_avatar(cls, room_id: str, avatar_uri: str):
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        Define the avatar of a room.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Returns either a `RoomPutStateResponse` if the request was successful or
 | 
					 | 
				
			||||||
        a `RoomPutStateError` if there was an error with the request.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Args:
 | 
					 | 
				
			||||||
            room_id (str): The room id of the room where the avatar
 | 
					 | 
				
			||||||
                should be changed.
 | 
					 | 
				
			||||||
            avatar_uri (str): The internal avatar URI to apply.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        client = await cls._get_client()
 | 
					 | 
				
			||||||
        if room_id.startswith("#"):
 | 
					 | 
				
			||||||
            room_id = await cls.resolve_room_alias(room_id)
 | 
					 | 
				
			||||||
        return await client.room_put_state(room_id, "m.room.avatar", content={
 | 
					 | 
				
			||||||
            "url": avatar_uri
 | 
					 | 
				
			||||||
        }, state_key="")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if os.getenv("SYNAPSE_PASSWORD"):  # pragma: no cover
 | 
					 | 
				
			||||||
    from nio import RoomVisibility, RoomPreset
 | 
					 | 
				
			||||||
    RoomVisibility = RoomVisibility
 | 
					 | 
				
			||||||
    RoomPreset = RoomPreset
 | 
					 | 
				
			||||||
else:
 | 
					 | 
				
			||||||
    # When running tests, faking matrix-nio classes to don't include the module
 | 
					 | 
				
			||||||
    class RoomVisibility(Enum):
 | 
					 | 
				
			||||||
        private = 'private'
 | 
					 | 
				
			||||||
        public = 'public'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class RoomPreset(Enum):
 | 
					 | 
				
			||||||
        private_chat = "private_chat"
 | 
					 | 
				
			||||||
        trusted_private_chat = "trusted_private_chat"
 | 
					 | 
				
			||||||
        public_chat = "public_chat"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class FakeMatrixClient:
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    Simulate a Matrix client to run tests, if no Matrix homeserver is connected.
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __getattribute__(self, item):
 | 
					 | 
				
			||||||
        async def func(*_, **_2):
 | 
					 | 
				
			||||||
            return None
 | 
					 | 
				
			||||||
        return func
 | 
					 | 
				
			||||||
@@ -74,7 +74,6 @@ INSTALLED_APPS = [
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
if "test" not in sys.argv:  # pragma: no cover
 | 
					if "test" not in sys.argv:  # pragma: no cover
 | 
				
			||||||
    INSTALLED_APPS += [
 | 
					    INSTALLED_APPS += [
 | 
				
			||||||
        'cas_server',
 | 
					 | 
				
			||||||
        'django_extensions',
 | 
					        'django_extensions',
 | 
				
			||||||
        'mailer',
 | 
					        'mailer',
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
@@ -147,8 +146,6 @@ PASSWORD_HASHERS = [
 | 
				
			|||||||
    'django.contrib.auth.hashers.BCryptPasswordHasher',
 | 
					    'django.contrib.auth.hashers.BCryptPasswordHasher',
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CAS_AUTH_CLASS = 'registration.auth.CustomAuthUser'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
REST_FRAMEWORK = {
 | 
					REST_FRAMEWORK = {
 | 
				
			||||||
    'DEFAULT_PERMISSION_CLASSES': [
 | 
					    'DEFAULT_PERMISSION_CLASSES': [
 | 
				
			||||||
        'rest_framework.permissions.IsAdminUser'
 | 
					        'rest_framework.permissions.IsAdminUser'
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user