diff --git a/src/backoffice/forms.py b/src/backoffice/forms.py index 610e321d045dc8589faf9f05b2318f1d728e44aa..e4f3d7c6355c56d56a4f0778bdde827fa989ebd3 100644 --- a/src/backoffice/forms.py +++ b/src/backoffice/forms.py @@ -6,7 +6,7 @@ from django.core.exceptions import ValidationError from django.contrib.auth.forms import UserCreationForm from django.utils.translation import gettext_lazy as _ -from core.integrations import BigBlueButton, IntegrationError, WorkAdventure +from core.integrations import BigBlueButton, Hangar, IntegrationError, WorkAdventure from core.models import Application, Assembly, AssemblyMember, Event, PlatformUser, Room, RoomLink @@ -224,6 +224,38 @@ class AssemblyCreateRoomBigBlueButtonForm(AssemblyCreateRoomForm): return room +class AssemblyCreateRoomHangarForm(AssemblyCreateRoomForm): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields['name'].initial = self.assembly.slug + self.fields['name'].disabled = True + + def clean(self, *args, **kwargs): + cleaned_data = super().clean(*args, **kwargs) + + if not Hangar.can_create_for_assembly(self.assembly): + raise ValidationError(_('Room-new-hangar__unavailable')) + + return cleaned_data + + def create_room(self, request): + room = self.assembly.rooms.create( + conference=self.assembly.conference, + room_type=Room.RoomType.HANGAR, + backend_status=Room.BackendStatus.NEW, + **self.cleaned_data, + ) + room.save() + self.room_id = room.id + + if not self.create_room_on_backend(request, Hangar, room): + room.delete() + room = None + self.room_id = None + + return room + + class CreateAssemblyEventForm(forms.ModelForm): class Meta: model = Event @@ -262,6 +294,8 @@ class EditAssemblyRoomForm(forms.ModelForm): self.fields['backend_status'] = forms.CharField(initial=self.instance.get_backend_status_display(), disabled=True) if self.instance.room_type in Room.TYPES_WITH_CAPACITY: self.fields['capacity'] = forms.IntegerField(initial=self.instance.capacity) + if self.instance.room_type in [Room.RoomType.HANGAR]: + self.fields['name'].disabled = True def save(self, commit=False): obj = super().save(commit) diff --git a/src/backoffice/locale/de/LC_MESSAGES/django.po b/src/backoffice/locale/de/LC_MESSAGES/django.po index 4fbfdd9c61340ab2a09f4797c78d4d9b2016ecba..888f387e9d1a970cbf0a3f4a99c497412615a55b 100644 --- a/src/backoffice/locale/de/LC_MESSAGES/django.po +++ b/src/backoffice/locale/de/LC_MESSAGES/django.po @@ -39,6 +39,9 @@ msgstr "Pfad zu einem Git-Repository mit den Kartendaten. Die angegebene URL mus msgid "Room-single_workadventure_only" msgstr "Es ist derzeit nur ein WorkAdventure-Raum möglich." +msgid "Room-new-hangar__unavailable" +msgstr "nur eine Ablage pro Assembly" + msgid "Event__schedule_start__placeholder" msgstr "'dd.mm.YYYY HH:MM' oder 'YYYY-mm-dd HH:MM'" @@ -336,12 +339,15 @@ msgstr "Schöner Raum und auch so hübsch dekoriert. Wirklich in Schutt und Asch msgid "Project__remove__confirm" msgstr "Nettes Projekt. Alle Spuren davon (zumindest auf dieser Konferenz) verwischen?" -msgid "Room__remove__notpossible" -msgstr "Hier könnte der Raum gelöscht werden, jedoch sind noch Veranstaltungen vorhanden. Lösche zuerst auch diese Veranstaltungen oder entferne die Zuordnung zu diesem Raum." - msgid "Project__remove__notpossible" msgstr "Hier solltest du das Projekt löschen können aber scheinbar hat das Management etwas dagegen - unklar weswegen. Bitte wende dich an den Support." +msgid "Hangar__remove__notpossible" +msgstr "Hangar entfernen benötigt manuelle Interaktion, bitte kontaktiere den Support." + +msgid "Room__remove__notpossible" +msgstr "Hier könnte der Raum gelöscht werden, jedoch sind noch Veranstaltungen vorhanden. Lösche zuerst auch diese Veranstaltungen oder entferne die Zuordnung zu diesem Raum." + msgid "nav_activetab_srmarker" msgstr "(ausgewählt)" @@ -441,6 +447,15 @@ msgstr "Anlegen" msgid "Room-new-bbb__unavailable" msgstr "BBB nicht verfügbar." +msgid "Room-new-hangar" +msgstr "Hangar beziehen" + +msgid "Room-new-hangar__help" +msgstr "Dateiablage für Assembly-Inhalte erstellen." + +msgid "Room-new-hangar__create" +msgstr "Anlegen" + msgid "Room-new-lecturehall" msgstr "Vorlesungsraum" @@ -606,6 +621,9 @@ msgstr "Bezug zur Assembly '{linked_name}' wurde vermerkt." msgid "assemblyedit_removedlink" msgstr "Bezug zur Assembly '{linked_name}' wurde entfernt." +msgid "Room-new-hangar__legal_hint" +msgstr "Du bestätigst, dass ihr ausschließlich nur solche Inhalte ablegt/veröffentlicht, für die ihr auch die nötigen Lizenzen/Rechte habt. Zuwiderhandlungen können ggf. straf- bzw. zivilrechtliche Folgen haben!" + msgid "updated" msgstr "Eintrag aktualisiert" @@ -642,6 +660,9 @@ msgstr "404 Benutzer nicht gefunden: " msgid "removed" msgstr "entfernt" +msgid "internal_error_please_retry" +msgstr "Mist. Irgendwas ist schief gelaufen, der Techniker ist informiert! Bitte probiere die Aktion erneut - wenn das Problem bestehen bleibt melde dich bei uns." + msgid "RoomLink__created" msgstr "Link hinzugefügt: {name}" diff --git a/src/backoffice/locale/en/LC_MESSAGES/django.po b/src/backoffice/locale/en/LC_MESSAGES/django.po index 411510ee5821850398b735ae2769310515bc365a..8ab10ac7f18dfa5e02fcbe0169d839cdcbce4502 100644 --- a/src/backoffice/locale/en/LC_MESSAGES/django.po +++ b/src/backoffice/locale/en/LC_MESSAGES/django.po @@ -39,6 +39,9 @@ msgstr "Link to a Git repository containing the map configuration. The given URL msgid "Room-single_workadventure_only" msgstr "Only a single WorkAdventure room is currently supported." +msgid "Room-new-hangar__unavailable" +msgstr "only one per assembly" + msgid "Event__schedule_start__placeholder" msgstr "YYYY-mm-dd HH:MM" @@ -337,12 +340,15 @@ msgstr "Nice room. So much wow. Do you really want to burn it down?" msgid "Project__remove__confirm" msgstr "You are about to leave no public traces of this project (at least on this conference). Sure?" -msgid "Room__remove__notpossible" -msgstr "Here you could remove the room if it hadn't at least one event assigned to it. Please delete all events associated with this room first (or remove the association)." - msgid "Project__remove__notpossible" msgstr "Here you should be able to remove the project but management says 'no'. We don't know why either, please contact support." +msgid "Hangar__remove__notpossible" +msgstr "Hangar removal needs manual interaction, please contact support." + +msgid "Room__remove__notpossible" +msgstr "Here you could remove the room if it hadn't at least one event assigned to it. Please delete all events associated with this room first (or remove the association)." + msgid "nav_activetab_srmarker" msgstr "(current)" @@ -442,6 +448,15 @@ msgstr "create" msgid "Room-new-bbb__unavailable" msgstr "BBB not available" +msgid "Room-new-hangar" +msgstr "Hangar" + +msgid "Room-new-hangar__help" +msgstr "Configure a file storage for your assembly." + +msgid "Room-new-hangar__create" +msgstr "create" + msgid "Room-new-lecturehall" msgstr "lecture hall" @@ -565,7 +580,6 @@ msgstr "Reset password" msgid "registration_reset_password_done" msgstr "Passwor reset initiated." - msgid "registration_reset_password_mailsent" msgstr "An email with a password reset link has been sent to the given e-mail address. Please check your inbox and open the link sent to you in order to reset your password." @@ -608,6 +622,9 @@ msgstr "Association with assembly '{linked_name}' has been saved." msgid "assemblyedit_removedlink" msgstr "Association with assembly '{linked_name}' has been deleted." +msgid "Room-new-hangar__legal_hint" +msgstr "You acknowledge that you will only store/publish content to which you own the necessary rights/licenses. Any violation might be liable to prosecution!" + msgid "updated" msgstr "Entry has been updated." @@ -644,6 +661,9 @@ msgstr "404 User Not Found: " msgid "removed" msgstr "removed" +msgid "internal_error_please_retry" +msgstr "D'oh. Something's gone wrong, the issue has been logged. Please retry your action and if the issue persists contact us." + msgid "RoomLink__created" msgstr "added link: {name}" diff --git a/src/backoffice/templates/backoffice/assembly_room.html b/src/backoffice/templates/backoffice/assembly_room.html index 2760fbdff08ddf2cacdd3a48c9d7b1693d27aed6..be33b0e7a7037b7f09406737341ab9c0c7415b55 100644 --- a/src/backoffice/templates/backoffice/assembly_room.html +++ b/src/backoffice/templates/backoffice/assembly_room.html @@ -25,6 +25,8 @@ {% if room.name %}{% if room.room_type != 'project' %}{{ room.get_room_type_display }} {% trans 'Room' %}{% else %}{% trans 'Project' %}{% endif %} "{{ room.name }}"{% else %}<span class="badge badge-secondary">{% trans 'Room-new' %}</span>{% endif %} </div> <div class="card-body"> + {% if legal_warning %}<div class="alert alert-warning">{{ legal_warning }}</div>{% endif %} + {% bootstrap_form form %} </div> {% if can_manage %} @@ -101,7 +103,7 @@ <button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('{% if room.room_type != 'project' %}{% trans 'Room__remove__confirm' %}{% else %}{% trans 'Project__remove__confirm' %}{% endif %}')">{% if room.room_type != 'project' %}{% trans 'Room__remove' %}{% else %}{% trans 'Project__remove' %}{% endif %}: {{ room.name }}</button> </form> {% else %} - <p>{% if room.room_type != 'project' %}{% trans 'Room__remove__notpossible' %}{% else %}{% trans 'Project__remove__notpossible' %}{% endif %}</p> + <p>{% if room.room_type == 'project' %}{% trans 'Project__remove__notpossible' %}{% elif room.room_type == 'hangar' %}{% trans 'Hangar__remove__notpossible' %}{% else %}{% trans 'Room__remove__notpossible' %}{% endif %}</p> {% endif %} </div> </div> diff --git a/src/backoffice/templates/backoffice/room-new.html b/src/backoffice/templates/backoffice/room-new.html index 760ce74263e20f2b58f85635b4afdda9c05d986b..73585ddf0e2846a8720cbec5c20d1b43539100f4 100644 --- a/src/backoffice/templates/backoffice/room-new.html +++ b/src/backoffice/templates/backoffice/room-new.html @@ -52,6 +52,20 @@ room++ | {{ assembly.name }} | {{ conference.name }} </div> </div> + {# Hangar #} + <div class="card"> + <div class="card-body {% if rooms_available.hangar %}border-primary{% else %}border-default{% endif %}"> + <h5 class="card-title {% if rooms_available.hangar %}text-primary{% else %}text-default{% endif %}">{% trans 'Room-new-hangar' %}</h5> + <p class="card-text">{% trans 'Room-new-hangar__help' %}</p> + </div> + <div class="card-footer"> + {% if rooms_available.hangar %} + <a class="btn btn-sm btn-primary" href="{% url 'backoffice:assembly-create-room' assembly=assembly.id %}?type=hangar">{% trans 'Room-new-hangar__create' %}</a> + {% else %} + <span class="text-muted" style="font-size: 90%;">{% trans 'Room-new-hangar__unavailable' %} + {% endif %} + </div> + </div> </div>{# /card-deck, open a new row #} <div class="card-deck mt-4"> @@ -114,6 +128,7 @@ room++ | {{ assembly.name }} | {{ conference.name }} <div class="card-body"> <form action="{% url 'backoffice:assembly-create-room' assembly=assembly.id %}" method="POST">{% csrf_token %} <input type="hidden" name="type" value="{{ room_type }}"> + {% if legal_warning %}<div class="alert alert-warning">{{ legal_warning }}</div>{% endif %} {% bootstrap_form form %} diff --git a/src/backoffice/views/assemblies.py b/src/backoffice/views/assemblies.py index 3f071346ab769cd8d432b2de31f56472eb5a414c..278026ce64f13298cf48002c8aa5394a500be24f 100644 --- a/src/backoffice/views/assemblies.py +++ b/src/backoffice/views/assemblies.py @@ -21,11 +21,11 @@ from core.models.rooms import Room, RoomLink from core.models.sso import Application from core.models.tags import ConferenceTag from core.models.users import PlatformUser -from core.integrations import BigBlueButton, IntegrationError, WorkAdventure +from core.integrations import BigBlueButton, Hangar, IntegrationError, WorkAdventure from ..forms import \ AssemblyAddApplicationForm, AssemblyAddMemberForm, \ - AssemblyCreateForm, AssemblyCreateRoomGenericForm, AssemblyCreateRoomBigBlueButtonForm, AssemblyCreateRoomWorkAdventureForm, \ + AssemblyCreateForm, AssemblyCreateRoomGenericForm, AssemblyCreateRoomBigBlueButtonForm, AssemblyCreateRoomWorkAdventureForm, AssemblyCreateRoomHangarForm, \ AssemblyEditForm, \ CreateAssemblyRoomLinkForm, \ EditAssemblyRoomForm, EditAssemblyRoomWorkAdventureForm, \ @@ -295,6 +295,11 @@ class AssemblyRoomView(AssemblyMixin, UpdateView): ctx['createform'] = self.create_roomlink_form or CreateAssemblyRoomLinkForm() ctx['supports_links'] = self.object.room_type in Room.TYPES_WITH_LINKS ctx['can_delete'] = not Event.objects.filter(conference=self.conference, room=self.object).exists() + + if self.object.room_type == Room.RoomType.HANGAR: + ctx['legal_warning'] = _('Room-new-hangar__legal_hint') + ctx['can_delete'] = False + return ctx def get_object(self, *args, **kwargs): @@ -604,6 +609,10 @@ class BadgeView(AssemblyMixin, UpdateView): return reverse('backoffice:assembly-badges', kwargs={'assembly': self.assembly.id}) +class RoomNotAvailableError(Exception): + pass + + class CreateRoomView(AssemblyMixin, FormView): assembly_url_param = 'assembly' template_name = 'backoffice/room-new.html' @@ -611,28 +620,43 @@ class CreateRoomView(AssemblyMixin, FormView): def dispatch(self, *args, **kwargs): self.room_type = (self.request.POST if self.request.method != 'GET' else self.request.GET).get('type', None) - return super().dispatch(*args, **kwargs) + try: + return super().dispatch(*args, **kwargs) + except RoomNotAvailableError: + return redirect('backoffice:assembly-create-room', assembly=self.assembly.id) def get_form(self, *args, **kwargs): + if self.room_type is None: + return None + if self.room_type == Room.RoomType.BIGBLUEBUTTON: if BigBlueButton is None or not BigBlueButton.can_create_for_assembly(self.assembly): messages.error(self.request, 'BBB not available') - return redirect('backoffice:assembly-create-room', assembly=self.assembly.id) + raise RoomNotAvailableError() return AssemblyCreateRoomBigBlueButtonForm(self.request.POST, assembly=self.assembly) if self.room_type == Room.RoomType.WORKADVENTURE: if WorkAdventure is None or not WorkAdventure.can_create_for_assembly(self.assembly): messages.error(self.request, 'WA not available') - return redirect('backoffice:assembly-create-room', assembly=self.assembly.id) + raise RoomNotAvailableError() return AssemblyCreateRoomWorkAdventureForm(self.request.POST, assembly=self.assembly) - if self.room_type: + if self.room_type == Room.RoomType.HANGAR: + if Hangar is None or not Hangar.can_create_for_assembly(self.assembly): + messages.error(self.request, 'Hangar not available') + raise RoomNotAvailableError() + + return AssemblyCreateRoomHangarForm(self.request.POST, assembly=self.assembly) + + if self.room_type in Room.RoomType.values: return AssemblyCreateRoomGenericForm(self.request.POST, assembly=self.assembly, initial={'room_type': self.room_type}) else: - return None + logger.warning('Unexpected room_type "%s" upon creating new room for %s.', self.room_type, self.assembly) + messages.warning(self.request, _('internal_error_please_retry')) + raise RoomNotAvailableError() def get_context_data(self, *args, **kwargs): ctx = super().get_context_data(*args, **kwargs) @@ -643,8 +667,12 @@ class CreateRoomView(AssemblyMixin, FormView): rooms_available.update({ 'workadventure': WorkAdventure is not None and WorkAdventure.can_create_for_assembly(self.assembly), 'bbb': BigBlueButton is not None and BigBlueButton.can_create_for_assembly(self.assembly), + 'hangar': Hangar is not None and Hangar.can_create_for_assembly(self.assembly), }) + elif self.room_type == Room.RoomType.HANGAR: + ctx['legal_warning'] = _('Room-new-hangar__legal_hint') + return ctx def form_valid(self, form): diff --git a/src/core/integrations/__init__.py b/src/core/integrations/__init__.py index 20f1b1bac6a82eae26ba929b152399557b14be9f..8ded4750e683cc544adbdef7582db2ef484f20e8 100644 --- a/src/core/integrations/__init__.py +++ b/src/core/integrations/__init__.py @@ -1,5 +1,6 @@ from django.conf import settings from .bigbluebutton import BigBlueButtonIntegration +from .rc3hangar import HangarIntegration from .error import IntegrationError from .workadventure import WorkAdventureIntegration @@ -7,11 +8,18 @@ if settings.BIGBLUEBUTTON_API_URL is not None: BigBlueButton = BigBlueButtonIntegration(settings.BIGBLUEBUTTON_API_URL, settings.BIGBLUEBUTTON_API_TOKEN, settings.BIGBLUEBUTTON_END_MEETING_CALLBACK) else: BigBlueButton = None # type: BigBlueButtonIntegration + +if settings.HANGAR_URL is not None: + Hangar = HangarIntegration(settings.HANGAR_URL) +else: + Hangar = None + WorkAdventure = WorkAdventureIntegration() __all__ = [ 'BigBlueButton', + 'Hangar', 'IntegrationError', 'WorkAdventure', ] diff --git a/src/core/integrations/rc3hangar.py b/src/core/integrations/rc3hangar.py new file mode 100644 index 0000000000000000000000000000000000000000..655103297df7462109a55c4c959ab15b3724d37c --- /dev/null +++ b/src/core/integrations/rc3hangar.py @@ -0,0 +1,46 @@ +from core.models.assemblies import Assembly +from core.models.rooms import Room +from core.models.users import PlatformUser + + +class HangarIntegration: + def __init__(self, url): + self._url = url + + def is_available(self): + return self._url is not None + + def can_create_for_assembly(self, assembly: Assembly): + assert assembly is not None + + # limit to one instance per assembly + existing = assembly.rooms.filter(room_type=Room.RoomType.HANGAR).exists() + return not existing + + def create_room(self, room: Room): + assert room is not None and room.room_type == Room.RoomType.HANGAR and room.backend_status == Room.BackendStatus.NEW + + # status is managed externally + pass + + def remove_room(self, room: Room): + assert room is not None and room.room_type == Room.RoomType.HANGAR + + # cannot be done here, trigger "contact technician" message + return False + + def room_status(self, room: Room): + assert room is not None and room.room_type == Room.RoomType.HANGAR + + return room.backend_status + + def join_room(self, room: Room, user: PlatformUser): + assert room is not None and room.room_type == Room.RoomType.HANGAR + assert user is not None + + url = self._url.format( + assembly_slug=room.assembly_slug, + room_id=room.id, + username=user.username, + ) + return url diff --git a/src/core/locale/de/LC_MESSAGES/django.po b/src/core/locale/de/LC_MESSAGES/django.po index 8db02a507ba653bc69d7e0a4c11aa9f770d9a67e..2ba3b3a1edabb4f68915231c26f8c4d831f7e54e 100644 --- a/src/core/locale/de/LC_MESSAGES/django.po +++ b/src/core/locale/de/LC_MESSAGES/django.po @@ -771,6 +771,9 @@ msgstr "BigBlueButton" msgid "Room__type-workadventure" msgstr "WorkAdventure" +msgid "Room__type-hangar" +msgstr "Hangar" + msgid "Room__type-other" msgstr "andere" diff --git a/src/core/locale/en/LC_MESSAGES/django.po b/src/core/locale/en/LC_MESSAGES/django.po index da07eb5f8d825d3163343d08b83ff8e3bc5c4c14..d415042cbe8c753fec3705d942da123539d03f66 100644 --- a/src/core/locale/en/LC_MESSAGES/django.po +++ b/src/core/locale/en/LC_MESSAGES/django.po @@ -771,6 +771,9 @@ msgstr "BigBlueButton" msgid "Room__type-workadventure" msgstr "WorkAdventure" +msgid "Room__type-hangar" +msgstr "hangar" + msgid "Room__type-other" msgstr "other" diff --git a/src/core/management/commands/hangar_creation.py b/src/core/management/commands/hangar_creation.py new file mode 100644 index 0000000000000000000000000000000000000000..cf5256c107ce85af2acc4ee7f2615a37dfeeaaae --- /dev/null +++ b/src/core/management/commands/hangar_creation.py @@ -0,0 +1,63 @@ +import logging +import subprocess + +from django.conf import settings +from django.core.management.base import BaseCommand, CommandError +from django.utils import timezone + +from core.models.rooms import Room + + +def create_hangar(room: Room): + username = room.assembly.slug + cmd = ['ssh', settings.HANGAR_HOST, settings.HANGAR_CMD, username] + + result = subprocess.run(cmd, capture_output=True, timeout=42, encoding='utf-8', stderr=subprocess.STDOUT) + if result.returncode == 0: + password = result.stdout + room.backend_link = settings.BACKEND_URL.format(username=username, password=password) + room.backend_status = Room.BackendStatus.ACTIVE + + all_contacts = room.assembly.get_all_managing_contacts() + room.backend_data = { + 'timestamp': timezone.now(), + 'contacts': all_contacts, + } + room.save() + + else: + room.backend_data = { + 'timestamp': timezone.now(), + '_error': result.stdout, + } + room.backend_status = Room.BackendStatus.ERROR + room.save() + + raise Exception('Backend creation failed.') + + +class Command(BaseCommand): + def handle(self, *args, **options): + for x in ['URL', 'BACKEND_URL', 'HOST', 'CMD']: + if not hasattr(settings, 'HANGAR_' + x) or getattr(settings, 'HANGAR_' + x) in [None, '']: + raise CommandError(f'No HANGAR_{x} configured.') + + if settings.HANGAR_BACKEND_URL is None or settings.HANGAR_BACKEND_URL == '': + raise CommandError('No HANGAR_BACKEND_URL configured.') + + rooms = Room.objects.filter(room_type=Room.RoomType.HANGAR, backend_status=Room.BackendStatus.NEW) + for room in rooms: + room.backend_status = Room.BackendStatus.SETUP + room.save() + + try: + create_hangar(room) + + except Exception as err: + logging.error('Got error on creating hangar for %s: %s', room, err) + room.backend_status = Room.BackendStatus.ERROR + room.backend_data = { + 'timestamp': timezone.now(), + '_exception': str(err), + } + room.save() diff --git a/src/core/migrations/0001_initial.py b/src/core/migrations/0001_initial.py index a07fd132c390383d4348ce4a9f06c3ca0b6ef7d3..fa4518b36821816d522e10439d4ea7e6c924068d 100644 --- a/src/core/migrations/0001_initial.py +++ b/src/core/migrations/0001_initial.py @@ -119,7 +119,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ('name', models.CharField(max_length=200)), - ('room_type', models.CharField(choices=[('lecturehall', 'Room__type-lecturehall'), ('stage', 'Room__type-stage'), ('workshop', 'Room__type-workshop'), ('outside', 'Room__type-outside'), ('online', 'Room__type-online'), ('project', 'Room__type-project'), ('bbb', 'Room__type-bbb'), ('workadventure', 'Room__type-workadventure'), ('other', 'Room__type-other')], help_text='Room__type__help', max_length=20, verbose_name='Room__type')), + ('room_type', models.CharField(choices=[('lecturehall', 'Room__type-lecturehall'), ('stage', 'Room__type-stage'), ('workshop', 'Room__type-workshop'), ('outside', 'Room__type-outside'), ('online', 'Room__type-online'), ('project', 'Room__type-project'), ('bbb', 'Room__type-bbb'), ('workadventure', 'Room__type-workadventure'), ('hangar', 'Room__type-hangar'), ('other', 'Room__type-other')], help_text='Room__type__help', max_length=20, verbose_name='Room__type')), ('capacity', models.PositiveIntegerField(blank=True, help_text='Room__capacity__help', null=True, verbose_name='Room__capacity')), ('conference', core.fields.ConferenceReference(help_text='Conference__reference_help', on_delete=django.db.models.deletion.CASCADE, related_name='rooms', to='core.conference', verbose_name='Conference__reference')), ], diff --git a/src/core/models/assemblies.py b/src/core/models/assemblies.py index 69cadfbd62940390a4d396c928f2d02c9b51394e..fcbf599818e3f3ba1c7902f88884e55c3effa898 100644 --- a/src/core/models/assemblies.py +++ b/src/core/models/assemblies.py @@ -297,6 +297,12 @@ class Assembly(TaggedItemMixin, models.Model): def sorted_tags(self): return sorted(t['slug'] for t in self.tags) + def get_all_managing_contacts(self): + result = {} + for member in self.members.filter(role__in=AssemblyMember.MANAGEMENT_ROLES): + result[member.member.username] = member.member.get_verified_contacts() + return result + def create_technical_user_if_necessary(self): if self.technical_user is not None: return self.technical_user diff --git a/src/core/models/rooms.py b/src/core/models/rooms.py index 4e5d5c3fd9a9ad258e7747f5c17e703ac07e8445..3df44acb4eabc05867bd5c9b0086418b080b3dc1 100644 --- a/src/core/models/rooms.py +++ b/src/core/models/rooms.py @@ -57,9 +57,10 @@ class Room(models.Model): PROJECT = 'project', _('Room__type-project') BIGBLUEBUTTON = 'bbb', _('Room__type-bbb') WORKADVENTURE = 'workadventure', _('Room__type-workadventure') + HANGAR = 'hangar', _('Room__type-hangar') OTHER = 'other', _('Room__type-other') - BACKEND_ROOMTYPES = [RoomType.BIGBLUEBUTTON, RoomType.WORKADVENTURE] + BACKEND_ROOMTYPES = [RoomType.BIGBLUEBUTTON, RoomType.WORKADVENTURE, RoomType.HANGAR] TYPES_WITH_CAPACITY = [RoomType.LECTURE_HALL, RoomType.STAGE, RoomType.WORKSHOP] TYPES_WITH_LINKS = [RoomType.PROJECT, RoomType.LECTURE_HALL, RoomType.STAGE, RoomType.WORKSHOP, RoomType.OUTSIDE, RoomType.ONLINE, RoomType.OTHER] diff --git a/src/rc3platform/settings/base.py b/src/rc3platform/settings/base.py index 4711ef80478f7526688f64860bfee35eee8cc18e..4ef40a5bd8ac6d4c3c6a8be1a05980e8c602bfcf 100644 --- a/src/rc3platform/settings/base.py +++ b/src/rc3platform/settings/base.py @@ -217,5 +217,8 @@ BIGBLUEBUTTON_API_TOKEN = None BIGBLUEBUTTON_END_MEETING_CALLBACK = None # url bbb will call to notify us of ending meetings # BIGBLUEBUTTON_END_MEETING_CALLBACK = 'https://rc3.world/api/bbb_meeting_end' +# Hangar +HANGAR_URL = None + # Workadventure WORKADVENTURE_URL_SCHEME = 'http://play.{assembly_slug}.localhost:8080/?u={username}'