mirror of
				https://gitlab.com/animath/si/plateforme.git
				synced 2025-10-31 03:29:52 +01:00 
			
		
		
		
	Compare commits
	
		
			4 Commits
		
	
	
		
			ddaf5e82bd
			...
			35042f077f
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 35042f077f | ||
|  | 56ad352e64 | ||
|  | 97761e07a9 | ||
|  | fd587099cb | 
| @@ -143,7 +143,7 @@ class SolutionForm(forms.ModelForm): | ||||
| class PoolForm(forms.ModelForm): | ||||
|     class Meta: | ||||
|         model = Pool | ||||
|         fields = ('tournament', 'round', 'juries',) | ||||
|         fields = ('tournament', 'round', 'bbb_code', 'juries',) | ||||
|         widgets = { | ||||
|             "juries": forms.CheckboxSelectMultiple, | ||||
|         } | ||||
|   | ||||
| @@ -5,6 +5,8 @@ import os | ||||
|  | ||||
| from asgiref.sync import async_to_sync | ||||
| 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 AdminRegistration, Registration, VolunteerRegistration | ||||
| from tfjm.matrix import Matrix, RoomPreset, RoomVisibility | ||||
| @@ -12,6 +14,8 @@ from tfjm.matrix import Matrix, RoomPreset, RoomVisibility | ||||
|  | ||||
| class Command(BaseCommand): | ||||
|     def handle(self, *args, **options):  # noqa: C901 | ||||
|         activate("fr") | ||||
|  | ||||
|         Matrix.set_display_name("Bot du TFJM²") | ||||
|  | ||||
|         if not os.getenv("SYNAPSE_PASSWORD"): | ||||
| @@ -127,6 +131,7 @@ class Command(BaseCommand): | ||||
|         Matrix.set_room_avatar("#bienvenue:tfjm.org", avatar_uri) | ||||
|         Matrix.set_room_avatar("#bot:tfjm.org", avatar_uri) | ||||
|         Matrix.set_room_avatar("#cno:tfjm.org", avatar_uri) | ||||
|         Matrix.set_room_avatar("#dev-bot:tfjm.org", avatar_uri) | ||||
|         Matrix.set_room_avatar("#faq:tfjm.org", avatar_uri) | ||||
|         Matrix.set_room_avatar("#flood:tfjm.org", avatar_uri) | ||||
|         Matrix.set_room_avatar("#je-cherche-une-equipe:tfjm.org", avatar_uri) | ||||
| @@ -316,6 +321,17 @@ class Command(BaseCommand): | ||||
|                 Matrix.set_room_avatar(f"#poule-{slug}-{pool.id}:tfjm.org", avatar_uri) | ||||
|                 Matrix.set_room_avatar(f"#poule-{slug}-{pool.id}-jurys:tfjm.org", avatar_uri) | ||||
|  | ||||
|                 url_params = urlencode(dict(url=f"https://visio.animath.live/b/{pool.bbb_code}", | ||||
|                                             isAudioConf='false', displayName='$matrix_display_name', | ||||
|                                             avatarUrl='$matrix_avatar_url', userId='$matrix_user_id')) \ | ||||
|                     .replace("%24", "$") | ||||
|                 Matrix.add_integration(f"#poule-{slug}-{pool.id}:tfjm.org", | ||||
|                                        f"https://scalar.vector.im/api/widgets/bigbluebutton.html?{url_params}", | ||||
|                                        f"bbb-{slug}-{pool.id}", "bigbluebutton", "BigBlueButton", str(pool)) | ||||
|                 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 AdminRegistration.objects.all(): | ||||
|                     Matrix.invite(f"#poule-{slug}-{pool.id}:tfjm.org", f"@{admin.matrix_username}:tfjm.org") | ||||
|   | ||||
							
								
								
									
										19
									
								
								apps/participation/migrations/0012_pool_bbb_code.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								apps/participation/migrations/0012_pool_bbb_code.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| # Generated by Django 3.0.11 on 2021-01-21 16:47 | ||||
|  | ||||
| import django.core.validators | ||||
| from django.db import migrations, models | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|  | ||||
|     dependencies = [ | ||||
|         ('participation', '0011_note'), | ||||
|     ] | ||||
|  | ||||
|     operations = [ | ||||
|         migrations.AddField( | ||||
|             model_name='pool', | ||||
|             name='bbb_code', | ||||
|             field=models.CharField(blank=True, default='', help_text='The code of the form xxx-xxx-xxx at the end of the BBB link.', max_length=11, validators=[django.core.validators.RegexValidator('[a-z]{3}-[a-z]{3}-[a-z]{3}')], verbose_name='BigBlueButton code'), | ||||
|         ), | ||||
|     ] | ||||
| @@ -344,6 +344,15 @@ class Pool(models.Model): | ||||
|         verbose_name=_("juries"), | ||||
|     ) | ||||
|  | ||||
|     bbb_code = models.CharField( | ||||
|         max_length=11, | ||||
|         blank=True, | ||||
|         default="", | ||||
|         verbose_name=_("BigBlueButton code"), | ||||
|         help_text=_("The code of the form xxx-xxx-xxx at the end of the BBB link."), | ||||
|         validators=[RegexValidator("[a-z]{3}-[a-z]{3}-[a-z]{3}")], | ||||
|     ) | ||||
|  | ||||
|     @property | ||||
|     def solutions(self): | ||||
|         return Solution.objects.filter(participation__in=self.participations, final_solution=self.tournament.final) | ||||
|   | ||||
| @@ -7,7 +7,7 @@ msgid "" | ||||
| msgstr "" | ||||
| "Project-Id-Version: TFJM\n" | ||||
| "Report-Msgid-Bugs-To: \n" | ||||
| "POT-Creation-Date: 2021-01-19 00:29+0100\n" | ||||
| "POT-Creation-Date: 2021-01-21 17:46+0100\n" | ||||
| "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | ||||
| "Last-Translator: Yohann D'ANELLO <yohann.danello@animath.fr>\n" | ||||
| "Language-Team: LANGUAGE <LL@li.org>\n" | ||||
| @@ -120,26 +120,32 @@ msgstr "Je m'engage à participer à l'intégralité du TFJM²." | ||||
| msgid "Message to address to the team:" | ||||
| msgstr "Message à adresser à l'équipe :" | ||||
|  | ||||
| #: apps/participation/forms.py:123 | ||||
| #: apps/participation/forms.py:124 | ||||
| msgid "The uploaded file size must be under 5 Mo." | ||||
| msgstr "Le fichier envoyé doit peser moins de 5 Mo." | ||||
|  | ||||
| #: apps/participation/forms.py:125 | ||||
| #: apps/participation/forms.py:126 apps/participation/forms.py:189 | ||||
| msgid "The uploaded file must be a PDF file." | ||||
| msgstr "Le fichier envoyé doit être au format PDF." | ||||
|  | ||||
| #: apps/participation/forms.py:129 | ||||
| #: apps/participation/forms.py:130 | ||||
| msgid "The PDF file must not have more than 30 pages." | ||||
| msgstr "Le fichier PDF ne doit pas avoir plus de 30 pages." | ||||
|  | ||||
| #: apps/participation/forms.py:169 | ||||
| #: apps/participation/forms.py:170 | ||||
| msgid "The defender, the opponent and the reporter must be different." | ||||
| msgstr "Le défenseur, l'opposant et le rapporteur doivent être différents." | ||||
|  | ||||
| #: apps/participation/forms.py:173 | ||||
| #: apps/participation/forms.py:174 | ||||
| msgid "This defender did not work on this problem." | ||||
| msgstr "Ce défenseur ne travaille pas sur ce problème." | ||||
|  | ||||
| #: apps/participation/forms.py:187 apps/registration/forms.py:116 | ||||
| #: apps/registration/forms.py:138 apps/registration/forms.py:160 | ||||
| #: apps/registration/forms.py:214 | ||||
| msgid "The uploaded file size must be under 2 Mo." | ||||
| msgstr "Le fichier envoyé doit peser moins de 2 Mo." | ||||
|  | ||||
| #: apps/participation/models.py:30 apps/participation/models.py:121 | ||||
| #: apps/participation/tables.py:17 apps/participation/tables.py:34 | ||||
| msgid "name" | ||||
| @@ -179,7 +185,7 @@ msgstr "début" | ||||
| msgid "end" | ||||
| msgstr "fin" | ||||
|  | ||||
| #: apps/participation/models.py:136 apps/participation/models.py:377 | ||||
| #: apps/participation/models.py:136 apps/participation/models.py:386 | ||||
| #: apps/participation/templates/participation/tournament_detail.html:18 | ||||
| msgid "place" | ||||
| msgstr "lieu" | ||||
| @@ -257,8 +263,8 @@ msgstr "L'équipe est sélectionnée pour la finale." | ||||
| msgid "Participation of the team {name} ({trigram})" | ||||
| msgstr "Participation de l'équipe {name} ({trigram})" | ||||
|  | ||||
| #: apps/participation/models.py:315 apps/participation/models.py:499 | ||||
| #: apps/participation/models.py:537 | ||||
| #: apps/participation/models.py:315 apps/participation/models.py:508 | ||||
| #: apps/participation/models.py:546 | ||||
| msgid "participation" | ||||
| msgstr "participation" | ||||
|  | ||||
| @@ -279,140 +285,148 @@ msgstr "Tour {round}" | ||||
| msgid "juries" | ||||
| msgstr "jurys" | ||||
|  | ||||
| #: apps/participation/models.py:358 | ||||
| #: apps/participation/models.py:352 | ||||
| msgid "BigBlueButton code" | ||||
| msgstr "Code BigBlueButton" | ||||
|  | ||||
| #: apps/participation/models.py:353 | ||||
| msgid "The code of the form xxx-xxx-xxx at the end of the BBB link." | ||||
| msgstr "Le code de la forme xxx-xxx-xxx à la fin du lien BBB." | ||||
|  | ||||
| #: apps/participation/models.py:367 | ||||
| #, python-brace-format | ||||
| msgid "Pool {round} for tournament {tournament} with teams {teams}" | ||||
| msgstr "Poule {round} du tournoi {tournament} avec les équipes {teams}" | ||||
|  | ||||
| #: apps/participation/models.py:364 apps/participation/models.py:372 | ||||
| #: apps/participation/models.py:373 apps/participation/models.py:381 | ||||
| msgid "pool" | ||||
| msgstr "poule" | ||||
|  | ||||
| #: apps/participation/models.py:365 | ||||
| #: apps/participation/models.py:374 | ||||
| msgid "pools" | ||||
| msgstr "poules" | ||||
|  | ||||
| #: apps/participation/models.py:379 | ||||
| #: apps/participation/models.py:388 | ||||
| msgid "Where the solution is presented?" | ||||
| msgstr "Où est-ce que les solutions sont défendues ?" | ||||
|  | ||||
| #: apps/participation/models.py:384 | ||||
| #: apps/participation/models.py:393 | ||||
| msgid "defended solution" | ||||
| msgstr "solution défendue" | ||||
|  | ||||
| #: apps/participation/models.py:386 apps/participation/models.py:506 | ||||
| #: apps/participation/models.py:395 apps/participation/models.py:515 | ||||
| #, python-brace-format | ||||
| msgid "Problem #{problem}" | ||||
| msgstr "Problème n°{problem}" | ||||
|  | ||||
| #: apps/participation/models.py:393 apps/participation/tables.py:105 | ||||
| #: apps/participation/models.py:402 apps/participation/tables.py:105 | ||||
| msgid "defender" | ||||
| msgstr "défenseur" | ||||
|  | ||||
| #: apps/participation/models.py:400 apps/participation/models.py:549 | ||||
| #: apps/participation/models.py:409 apps/participation/models.py:558 | ||||
| msgid "opponent" | ||||
| msgstr "opposant" | ||||
|  | ||||
| #: apps/participation/models.py:407 apps/participation/models.py:550 | ||||
| #: apps/participation/models.py:416 apps/participation/models.py:559 | ||||
| msgid "reporter" | ||||
| msgstr "rapporteur" | ||||
|  | ||||
| #: apps/participation/models.py:467 apps/participation/models.py:470 | ||||
| #: apps/participation/models.py:473 | ||||
| #: apps/participation/models.py:476 apps/participation/models.py:479 | ||||
| #: apps/participation/models.py:482 | ||||
| #, python-brace-format | ||||
| msgid "Team {trigram} is not registered in the pool." | ||||
| msgstr "L'équipe {trigram} n'est pas inscrite dans la poule." | ||||
|  | ||||
| #: apps/participation/models.py:478 | ||||
| #: apps/participation/models.py:487 | ||||
| #, python-brace-format | ||||
| msgid "Passage of {defender} for problem {problem}" | ||||
| msgstr "Passage de {defender} pour le problème {problem}" | ||||
|  | ||||
| #: apps/participation/models.py:482 apps/participation/models.py:544 | ||||
| #: apps/participation/models.py:582 | ||||
| #: apps/participation/models.py:491 apps/participation/models.py:553 | ||||
| #: apps/participation/models.py:591 | ||||
| msgid "passage" | ||||
| msgstr "passage" | ||||
|  | ||||
| #: apps/participation/models.py:483 | ||||
| #: apps/participation/models.py:492 | ||||
| msgid "passages" | ||||
| msgstr "passages" | ||||
|  | ||||
| #: apps/participation/models.py:504 | ||||
| #: apps/participation/models.py:513 | ||||
| msgid "problem" | ||||
| msgstr "numéro de problème" | ||||
|  | ||||
| #: apps/participation/models.py:511 | ||||
| #: apps/participation/models.py:520 | ||||
| msgid "solution for the final tournament" | ||||
| msgstr "solution pour la finale" | ||||
|  | ||||
| #: apps/participation/models.py:516 apps/participation/models.py:555 | ||||
| #: apps/participation/models.py:525 apps/participation/models.py:564 | ||||
| msgid "file" | ||||
| msgstr "fichier" | ||||
|  | ||||
| #: apps/participation/models.py:524 | ||||
| #: apps/participation/models.py:533 | ||||
| #, python-brace-format | ||||
| msgid "Solution of team {team} for problem {problem}" | ||||
| msgstr "Solution de l'équipe {team} pour le problème {problem}" | ||||
|  | ||||
| #: apps/participation/models.py:528 | ||||
| #: apps/participation/models.py:537 | ||||
| msgid "solution" | ||||
| msgstr "solution" | ||||
|  | ||||
| #: apps/participation/models.py:529 | ||||
| #: apps/participation/models.py:538 | ||||
| msgid "solutions" | ||||
| msgstr "solutions" | ||||
|  | ||||
| #: apps/participation/models.py:563 | ||||
| #: apps/participation/models.py:572 | ||||
| #, python-brace-format | ||||
| msgid "Synthesis for the {type} of the {passage}" | ||||
| msgstr "Synthèse pour {type} du {passage}" | ||||
|  | ||||
| #: apps/participation/models.py:566 | ||||
| #: apps/participation/models.py:575 | ||||
| msgid "synthesis" | ||||
| msgstr "note de synthèse" | ||||
|  | ||||
| #: apps/participation/models.py:567 | ||||
| #: apps/participation/models.py:576 | ||||
| msgid "syntheses" | ||||
| msgstr "notes de synthèse" | ||||
|  | ||||
| #: apps/participation/models.py:575 | ||||
| #: apps/participation/models.py:584 | ||||
| msgid "jury" | ||||
| msgstr "jury" | ||||
|  | ||||
| #: apps/participation/models.py:587 | ||||
| #: apps/participation/models.py:596 | ||||
| msgid "defender writing note" | ||||
| msgstr "note d'écrit du défenseur" | ||||
|  | ||||
| #: apps/participation/models.py:593 | ||||
| #: apps/participation/models.py:602 | ||||
| msgid "defender oral note" | ||||
| msgstr "note d'oral du défenseur" | ||||
|  | ||||
| #: apps/participation/models.py:599 | ||||
| #: apps/participation/models.py:608 | ||||
| msgid "opponent writing note" | ||||
| msgstr "note d'écrit de l'opposant" | ||||
|  | ||||
| #: apps/participation/models.py:605 | ||||
| #: apps/participation/models.py:614 | ||||
| msgid "opponent oral note" | ||||
| msgstr "note d'oral de l'opposant" | ||||
|  | ||||
| #: apps/participation/models.py:611 | ||||
| #: apps/participation/models.py:620 | ||||
| msgid "reporter writing note" | ||||
| msgstr "not d'écrit du rapporteur" | ||||
|  | ||||
| #: apps/participation/models.py:617 | ||||
| #: apps/participation/models.py:626 | ||||
| msgid "reporter oral note" | ||||
| msgstr "note d'oral du rapporteur" | ||||
|  | ||||
| #: apps/participation/models.py:626 | ||||
| #: apps/participation/models.py:635 | ||||
| #, python-brace-format | ||||
| msgid "Notes of {jury} for {passage}" | ||||
| msgstr "Notes de {jury} pour le {passage}" | ||||
|  | ||||
| #: apps/participation/models.py:633 | ||||
| #: apps/participation/models.py:642 | ||||
| msgid "note" | ||||
| msgstr "note" | ||||
|  | ||||
| #: apps/participation/models.py:634 | ||||
| #: apps/participation/models.py:643 | ||||
| msgid "notes" | ||||
| msgstr "notes" | ||||
|  | ||||
| @@ -1017,11 +1031,6 @@ msgstr "bénévole" | ||||
| msgid "admin" | ||||
| msgstr "admin" | ||||
|  | ||||
| #: apps/registration/forms.py:116 apps/registration/forms.py:138 | ||||
| #: apps/registration/forms.py:160 apps/registration/forms.py:214 | ||||
| msgid "The uploaded file size must be under 2 Mo." | ||||
| msgstr "Le fichier envoyé doit peser moins de 2 Mo." | ||||
|  | ||||
| #: apps/registration/forms.py:118 apps/registration/forms.py:140 | ||||
| #: apps/registration/forms.py:162 apps/registration/forms.py:216 | ||||
| msgid "The uploaded file must be a PDF, PNG of JPEG file." | ||||
|   | ||||
| @@ -263,6 +263,46 @@ class Matrix: | ||||
|             content=content, | ||||
|         ) | ||||
|  | ||||
|     @classmethod | ||||
|     @async_to_sync | ||||
|     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_to_sync | ||||
|     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_to_sync | ||||
|     async def kick(cls, room_id: str, user_id: str, reason: str = None): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user