From ea6acbe079115015fa260fe3e5957eaf4932baa3 Mon Sep 17 00:00:00 2001 From: Lucas Brandstaetter <lucas@brandstaetter.tech> Date: Sun, 27 Oct 2024 12:43:58 +0100 Subject: [PATCH] Add ConferencePublicationView view Wit this view a conference_admin can edit the conference settings, without the need to go to the admin interface or superuser privileges. Fixes #584 --- .../locale/de/LC_MESSAGES/django.po | 69 +++++++++- .../locale/en/LC_MESSAGES/django.po | 74 +++++++++-- src/backoffice/templates/backoffice/base.html | 5 + .../conferences/publication_edit.html | 120 ++++++++++++++++++ src/backoffice/urls.py | 6 +- src/backoffice/views/conferences.py | 119 ++++++++++++++++- src/backoffice/views/mixins.py | 2 + src/core/fixtures/bootstrap_auth_groups.json | 5 + src/core/forms.py | 44 ++++++- src/core/locale/de/LC_MESSAGES/django.po | 6 + src/core/locale/en/LC_MESSAGES/django.po | 6 + .../0152_alter_conferencemember_options.py | 35 +++++ src/core/models/conference.py | 2 + 13 files changed, 477 insertions(+), 16 deletions(-) create mode 100644 src/backoffice/templates/backoffice/conferences/publication_edit.html create mode 100644 src/core/migrations/0152_alter_conferencemember_options.py diff --git a/src/backoffice/locale/de/LC_MESSAGES/django.po b/src/backoffice/locale/de/LC_MESSAGES/django.po index 3624aaca3..cbe5fdbb3 100644 --- a/src/backoffice/locale/de/LC_MESSAGES/django.po +++ b/src/backoffice/locale/de/LC_MESSAGES/django.po @@ -819,6 +819,9 @@ msgstr "Karte" msgid "nav_moderation" msgstr "Moderation" +msgid "nav_conference_admin" +msgstr "Konferenz" + msgid "nav_wiki" msgstr "Wiki" @@ -852,6 +855,45 @@ msgstr "alle" msgid "backoffice__not_a_conference_member" msgstr "Das Nutzerkonto, mit dem du gerade angemeldet bist, ist zur Zeit nicht mit einem Veranstaltungsticket verknüpft. Wenn Du gerade beim Aufbau hilfst, ist das kein Problem. Denk aber bitte daran, rechtzeitig ein Ticket zu kaufen und dies kurz vor Veranstaltungsbeginn mit deinem Nutzerkonto zu verknüpfen. Ansonsten kannst Du mit diesem Nutzerkonto nicht an der Veranstaltung teilnehmen." +msgid "create" +msgstr "Erstellen" + +msgid "Conference__recall__warning__header" +msgstr "Konferenz wirklich zurücknehmen?" + +msgid "Conference__recall__warning__text" +msgstr "Mit dieser Aktion wird die Konferenz zurückgenommen und ist ab diesem Zeitpunkt nicht mehr öffentlich sichtbar!" + +msgid "Conference__recall__submit" +msgstr "Konferenz zurücknehmen" + +msgid "Conference__publish__warning__header" +msgstr "Konferenz wirklich veröffentlichen?" + +msgid "Conference__publish__warning__text" +msgstr "Bitte stelle sicher, dass alle Informationen der Konferenz korrekt sind. Mit dieser Aktion wird die Konferenz für die Öffentlichkeit sichtbar!" + +msgid "Conference__publish__submit" +msgstr "Konferenz veröffentlichen" + +msgid "create conference" +msgstr "Konferenz erstellen" + +msgid "edit conference" +msgstr "Konferenz bearbeiten" + +msgid "Conference__recall__introduction" +msgstr "Die Konferenz ist aktuell sichtbar und du kannst es mittels des Öffentlichen Links besuchen. Zusätzlich kannst du die Veranstaltung auch wieder zurücknehmen." + +msgid "Conference__publish__introduction" +msgstr "Die Konferenz ist aktuell noch nicht öffentlich! Mit der Veröffentlichung wird diese Konferenz für alle sichtbar. Bitte kontrolliere vorher alle Daten!" + +msgid "Conference__edit-metadata" +msgstr "Konferenz-Daten" + +msgid "Conference__submit" +msgstr "Konferenz speichern" + msgid "Conferences__selection__header" msgstr "Konferenz auswählen" @@ -1177,9 +1219,6 @@ msgstr "Self-organized Projekte" msgid "Project__So__create" msgstr "Self-organized Projekt erstellen" -msgid "create" -msgstr "Erstellen" - msgid "Project__recall__warning__header" msgstr "Projekt wirklich zurücknehmen?" @@ -1829,6 +1868,30 @@ msgstr "abgelehnt" msgid "nav_channels_hidden" msgstr "versteckt" +msgid "nav_conference" +msgstr "Konferenz" + +msgid "Conference__Publication" +msgstr "Veröffentlichung" + +msgid "Conference__publish__success" +msgstr "Die Konferenz wurde erfolgreich veröffentlicht! Viel Spaß!" + +msgid "Conference__recall__success" +msgstr "Die Konferenz wurde erfolgreich zurückgenommen." + +msgid "Conference__create__success" +msgstr "Die Konferenz wurde erfolgreich angelegt!" + +msgid "Conference__update__success" +msgstr "Die Veröffentlichungsinformationen der Konferenz wurden angepasst." + +msgid "Conference__publish__failed" +msgstr "Beim veröffentlichen der Konferenz ist ein Fehler aufgetreten" + +msgid "Conference__form__invalid" +msgstr "Die angegebenen Daten zur Konferenz sind fehlerhaft!" + #, python-format msgid "Event__publish__failed %(event_type)s" msgstr "Fehler beim veröffentlichen der %(event_type)s!" diff --git a/src/backoffice/locale/en/LC_MESSAGES/django.po b/src/backoffice/locale/en/LC_MESSAGES/django.po index 1ce5dc96d..9b36b74b2 100644 --- a/src/backoffice/locale/en/LC_MESSAGES/django.po +++ b/src/backoffice/locale/en/LC_MESSAGES/django.po @@ -818,6 +818,9 @@ msgstr "map" msgid "nav_moderation" msgstr "moderation" +msgid "nav_conference_admin" +msgstr "Conference" + msgid "nav_wiki" msgstr "Wiki" @@ -851,6 +854,45 @@ msgstr "all" msgid "backoffice__not_a_conference_member" msgstr "The user account you are currently logged in with is not linked to an valid event ticket. If you are helping with the set-up, this is not a problem. But please remember to buy a ticket in time and link it to your user account. Otherwise you will not be able to participate in the event with this user account. Linking the ticket to the user account will be available directly before the event." +msgid "create" +msgstr "" + +msgid "Conference__recall__warning__header" +msgstr "Do you really want to recall the conference?" + +msgid "Conference__recall__warning__text" +msgstr "With this action, the conference is recalled and is no longer publicly visible from this point on!" + +msgid "Conference__recall__submit" +msgstr "Recall conference" + +msgid "Conference__publish__warning__header" +msgstr "Really publish conference?" + +msgid "Conference__publish__warning__text" +msgstr "Please make sure that all conference information is correct. This action will make the conference visible to the public!" + +msgid "Conference__publish__submit" +msgstr "Publish conference" + +msgid "create conference" +msgstr "Create Conference" + +msgid "edit conference" +msgstr "Edit Conference" + +msgid "Conference__recall__introduction" +msgstr "The conference is currently visible and you can visit it using the public link. You can also cancel the conference again." + +msgid "Conference__publish__introduction" +msgstr "The conference is currently not yet public! With the publication this conference will be visible for everyone. Please check all data beforehand!" + +msgid "Conference__edit-metadata" +msgstr "conference data" + +msgid "Conference__submit" +msgstr "Recall conference" + msgid "Conferences__selection__header" msgstr "Select Conference" @@ -1184,9 +1226,6 @@ msgstr "Self-organized project" msgid "Project__So__create" msgstr "Create self-organized project" -msgid "create" -msgstr "" - msgid "Project__recall__warning__header" msgstr "Do you really recall the event?" @@ -1836,6 +1875,30 @@ msgstr "rejected" msgid "nav_channels_hidden" msgstr "hidden" +msgid "nav_conference" +msgstr "Conference" + +msgid "Conference__Publication" +msgstr "Publication Settings" + +msgid "Conference__publish__success" +msgstr "Conference was successfully published! Have fun!" + +msgid "Conference__recall__success" +msgstr "Conference was successfully recalled." + +msgid "Conference__create__success" +msgstr "Conference was successfully crewated." + +msgid "Conference__update__success" +msgstr "Conference was successfully updated." + +msgid "Conference__publish__failed" +msgstr "Failed to publish the conference!" + +msgid "Conference__form__invalid" +msgstr "Conference data you entered is invalid!" + #, python-format msgid "Event__publish__failed %(event_type)s" msgstr "Error while publishing the %(event_type)s" @@ -1968,8 +2031,3 @@ msgstr "sessions" msgid "wa_textures" msgstr "textures" - -#, fuzzy -#~| msgid "Conference" -#~ msgid "nav_conference" -#~ msgstr "Conference" diff --git a/src/backoffice/templates/backoffice/base.html b/src/backoffice/templates/backoffice/base.html index 71b80a48e..922d681b9 100644 --- a/src/backoffice/templates/backoffice/base.html +++ b/src/backoffice/templates/backoffice/base.html @@ -54,6 +54,11 @@ <a class="nav-link{% if active_page == 'moderation' %} active{% endif %}" href="{% url 'backoffice:moderation' %}">{% trans "nav_moderation" %}{% if active_page == 'moderation' %} <span class="visually-hidden">{{ activetab_srmarker }}</span>{% endif %}</a> </li> {% endif %} + {% if has_conference_admin %} + <li class="nav-item"> + <a class="nav-link{% if active_page == 'conference_admin' %} active{% endif %}" href="{% url 'backoffice:conference-publication' conference.id %}">{% trans "nav_conference_admin" %}{% if active_page == 'conference_admin' %} <span class="visually-hidden">{{ activetab_srmarker }}</span>{% endif %}</a> + </li> + {% endif %} {% if has_pages %} <li class="nav-item"> <a class="nav-link{% if active_page == 'wiki' %} active{% endif %}" href="{% url 'backoffice:wiki' %}">{% trans "nav_wiki" %}{% if active_page == 'wiki' %} <span class="visually-hidden">{{ activetab_srmarker }}</span>{% endif %}</a> diff --git a/src/backoffice/templates/backoffice/conferences/publication_edit.html b/src/backoffice/templates/backoffice/conferences/publication_edit.html new file mode 100644 index 000000000..760369f34 --- /dev/null +++ b/src/backoffice/templates/backoffice/conferences/publication_edit.html @@ -0,0 +1,120 @@ +{% extends 'backoffice/base.html' %} +{% load django_bootstrap5 %} +{% load i18n %} +{% load static %} +{% block title %} + {% if form.create %} + {% trans 'create' %} + {% else %} + {{ form.instance.name }} + {% endif %} +{% endblock title %} +{% block scripts %} + <script src="{% static "backoffice/modal.js" %}"></script> + <script> + $(document).ready(() => { + showModal = registerModal() + publishConference = document.getElementById('publishConference'); + if(publishConference){ + document.getElementById('publishConference').addEventListener('click', (e) => { + e.preventDefault(); + if (document.getElementById('id_is_public').value === "True"){ + showModal( + () => { + form = document.getElementById('ConferenceForm'); + form.action = publishConference.formAction + form.submit() + }, + 'warning', + '{% trans "Conference__recall__warning__header" %}', + '{% trans "Conference__recall__warning__text" %}', + '{% trans "Conference__recall__submit" %}') + } else { + showModal( + () => { + form = document.getElementById('ConferenceForm'); + form.action = publishConference.formAction + form.submit() + }, + 'warning', + '{% trans "Conference__publish__warning__header" %}', + '{% trans "Conference__publish__warning__text" %}', + '{% trans "Conference__publish__submit" %}') + } + }) + }; + }); + </script> +{% endblock scripts %} +{% block content %} + {% url 'backoffice:conference-publication' pk=form.instance.id assembly=form.instance.assembly.id as edit_url %} + <form method="POST" enctype="multipart/form-data" id="ConferenceForm"> + {% csrf_token %} + <div class="card border-default"> + <div class="card-header bg-default"> + {% if form.create %} + {% blocktrans %}create conference{% endblocktrans %} + {% else %} + {% blocktrans %}edit conference{% endblocktrans %} + {% endif %} + </div> + <div class="card-body"> + {% if has_form_perms and form.instance.is_public and not form.create %} + <div class="alert alert-success d-flex"> + <div class="flex-grow-0 pe-3"> + <i class="bi bi-megaphone fs-1"></i> + </div> + <div class="flex-grow-1 px-3">{% blocktrans %}Conference__recall__introduction{% endblocktrans %}</div> + <div class="d-inline-flex gap-2 align-items-start"> + <a class="float-end btn btn-info me-2" + href="{% url 'plainui:index' %}">{% trans 'public_link' %}</a> + <button class="btn btn-warning float-end" + id="publishConference" + formaction="{{ edit_url }}?recall=true">{% trans "Conference__recall__submit" %}</button> + </div> + </div> + {% elif has_form_perms and not form.create %} + <div class="alert alert-warning d-flex"> + <div class="flex-grow-0 pe-3"> + <i class="bi bi-eye-slash fs-1"></i> + </div> + <div class="flex-grow-1 px-3">{% blocktrans %}Conference__publish__introduction{% endblocktrans %}</div> + <div class="d-inline-flex gap-2 align-items-start"> + <button class="btn btn-primary float-end" + id="publishConference" + formaction="{{ edit_url }}?publish=true" + {% if publication_errors %}disabled{% endif %}>{% trans "Conference__publish__submit" %}</button> + </div> + </div> + {% endif %} + {% if form.errors %}<div class="alert alert-danger">{{ form.errors }}</div>{% endif %} + + <input id="id_is_public" + type="hidden" + name="{{ form.is_public.name }}" + value="{{ form.is_public.value }}"> + + <p class="fw-bold border-bottom mb-3">{% trans "Conference__edit-metadata" %}</p> + <div class="row mb-3"> + <div class="col-md-4">{% bootstrap_field form.name %}</div> + <div class="col-md-4">{% bootstrap_field form.slug %}</div> + <div class="col-md-4">{% bootstrap_field form.timezone %}</div> + </div> + <div class="row mb-3"> + <div class="col-md-4">{% bootstrap_field form.start %}</div> + <div class="col-md-4">{% bootstrap_field form.end %}</div> + <div class="col-md-4">{% bootstrap_field form.publication_date %}</div> + </div> + <div class="row mb-3"> + <div class="col-md-12">{% bootstrap_field form.global_notification %}</div> + </div> + </div> + {% if has_form_perms %} + {% trans 'Conference__submit' as button_text %} + <div class="card-footer"> + {% bootstrap_button button_text button_type="submit" button_class="btn-primary float-end" %} + </div> + {% endif %} + </div> + </form> +{% endblock content %} diff --git a/src/backoffice/urls.py b/src/backoffice/urls.py index 748dfa12c..02d825e11 100644 --- a/src/backoffice/urls.py +++ b/src/backoffice/urls.py @@ -1,7 +1,10 @@ from django.urls import path, re_path from django.views.generic import RedirectView -from backoffice.views.conferences import ConferenceSelectionView +from backoffice.views.conferences import ( + ConferencePublicationView, + ConferenceSelectionView, +) from backoffice.views.map import ( FloorCreateView, FloorListView, @@ -49,6 +52,7 @@ urlpatterns = [ path('logout', auth.LogoutView.as_view(), name='logout'), path('auth_debug', auth.AuthDebugView.as_view()), path('conferences', ConferenceSelectionView.as_view(), name='conferences'), + path('conference/<uuid:pk>', ConferencePublicationView.as_view(), name='conference-publication'), path('wiki', wiki.WikiOverviewView.as_view(), name='wiki'), path('wiki/namespaces', wiki.NamespaceListView.as_view(), name='wiki-namespaces'), path('wiki/locks', wiki.LockListView.as_view(), name='wiki-locks'), diff --git a/src/backoffice/views/conferences.py b/src/backoffice/views/conferences.py index facd80268..8a1c7c2ff 100644 --- a/src/backoffice/views/conferences.py +++ b/src/backoffice/views/conferences.py @@ -1,10 +1,22 @@ +import logging +from typing import Any + +from django.contrib import messages +from django.core.exceptions import PermissionDenied +from django.forms.forms import BaseForm +from django.http import HttpRequest, HttpResponse, HttpResponseRedirect from django.shortcuts import redirect -from django.views.generic.edit import FormView +from django.urls import reverse +from django.utils.translation import gettext_lazy as _ +from django.views.generic.edit import FormView, UpdateView -from core.models import Conference +from core.forms import ConferencePublicationForm +from core.models import Conference, ConferenceMember from backoffice.forms import ConferenceSelectionForm -from backoffice.views.mixins import LoginRequiredMixin +from backoffice.views.mixins import ConferenceRequiredMixin, LoginRequiredMixin + +logger = logging.getLogger(__name__) class ConferenceSelectionView(LoginRequiredMixin, FormView): @@ -48,3 +60,104 @@ class ConferenceSelectionView(LoginRequiredMixin, FormView): 'conferences': Conference.objects.accessible_by_user(self.request.user), 'active_page': self.active_page, } + + +class ConferenceFormMixin(ConferenceRequiredMixin, FormView): + object: Conference | None + model = Conference + context_object_name = 'conference' + permission_required = ['core.conference_admin', 'core.assembly_registration_admin'] + require_all_permissions = False + require_staff = True + form_permissions_required = [] + sidebar_caption = _('nav_conference') + active_page: str + + def get_context_data(self, *args, **kwargs): + return { + **super().get_context_data(*args, **kwargs), + 'has_form_perms': self.request.user.has_conference_staff_permission(self.conference, *self.form_permissions_required), + 'active_page': self.active_page, + 'sidebar': { + 'title': self.sidebar_caption, + 'items': [ + { + 'caption': _('Conference__Publication'), + 'link': reverse( + 'backoffice:conference-publication', + kwargs={'pk': self.conference.pk}, + ), + }, + ], + }, + } + + def get_form(self, form_class: type | None = None) -> ConferencePublicationForm | BaseForm: + form = super().get_form(form_class) + member = ConferenceMember.objects.filter(user=self.request.user, conference=self.object).first() + if member and member.has_perms(*self.form_permissions_required, require_staff=self.require_staff): + return form + for field in form.fields: + form.fields[field].disabled = True + return form + + def post(self, request: HttpRequest, *args: str, **kwargs: Any) -> HttpResponse: + if not self.request.user.has_conference_staff_permission(self.conference, *self.form_permissions_required): + raise PermissionDenied + return super().post(request, *args, **kwargs) + + +class ConferencePublicationView(ConferenceFormMixin, UpdateView): + """ + An UpdateView to change the publication settings of the current :model:`core.conference`. + """ + + form_class = ConferencePublicationForm + template_name = 'backoffice/conferences/publication_edit.html' + active_page = 'conference' + form_permissions_required = ['core.conference_admin'] + + def get_form_kwargs(self, *args, **kwargs) -> dict[str, Any]: + publish = False + if self.object: + publish = (not self.object.is_public and self.request.GET.get('publish') == 'true') or ( + self.object.is_public and self.request.GET.get('recall') == 'true' + ) + return { + **super().get_form_kwargs(*args, **kwargs), + 'publish': publish, + } + + def form_valid(self, form: ConferencePublicationForm): + # Try to safe the form before creating logs and messages + self.object = form.save() + logger.info( + 'changed publication info of "%(conference)s" by %(user)s', + { + 'conference': form.instance, + 'user': self.request.user, + }, + ) + + if form.publish and self.object.is_public: + messages.success(self.request, _('Conference__publish__success')) + elif form.publish and not self.object.is_public: + messages.success(self.request, _('Conference__recall__success')) + elif form.create: + messages.success(self.request, _('Conference__create__success')) + else: + messages.success(self.request, _('Conference__update__success')) + + return HttpResponseRedirect(self.get_success_url()) + + def form_invalid(self, form: ConferencePublicationForm): + if form.publish: + form.instance.is_public = False + messages.error(self.request, _('Conference__publish__failed')) + else: + messages.error(self.request, _('Conference__form__invalid')) + + return super().form_invalid(form) + + def get_success_url(self): + return reverse('backoffice:conference-publication', kwargs={'pk': self.object.pk}) diff --git a/src/backoffice/views/mixins.py b/src/backoffice/views/mixins.py index a56853bd8..c7adadf12 100644 --- a/src/backoffice/views/mixins.py +++ b/src/backoffice/views/mixins.py @@ -111,6 +111,7 @@ class ConferenceRequiredMixin(PermissionRequiredMixin): 'has_channel': self.is_channel_team, 'has_pages': self.conferencemember.has_perms('core.static_pages', require_staff=True), 'has_map': self.conferencemember.has_perms('core.map_edit', require_staff=True), + 'has_conference_admin': self.conferencemember.has_perms('core.conference_admin', require_staff=True), 'has_moderation': self.conferencemember.has_perms('core.moderation', require_staff=True), 'has_schedules': self.conferencemember.has_perms('core.scheduleadmin', require_staff=True), 'has_workadventure': settings.INTEGRATIONS_WORKADVENTURE @@ -124,6 +125,7 @@ class ConferenceRequiredMixin(PermissionRequiredMixin): 'has_channel': False, 'has_pages': False, 'has_map': False, + 'has_conference_admin': False, 'has_moderation': False, 'has_schedules': False, 'has_workadventure': False, diff --git a/src/core/fixtures/bootstrap_auth_groups.json b/src/core/fixtures/bootstrap_auth_groups.json index 364f79683..2b7b8cf1f 100644 --- a/src/core/fixtures/bootstrap_auth_groups.json +++ b/src/core/fixtures/bootstrap_auth_groups.json @@ -92,6 +92,11 @@ "static_pages", "core", "conferencemember" + ], + [ + "conference_admin", + "core", + "conferencemember" ] ] } diff --git a/src/core/forms.py b/src/core/forms.py index 86a57d08f..c4cb99550 100644 --- a/src/core/forms.py +++ b/src/core/forms.py @@ -13,7 +13,7 @@ from django.contrib.sites.shortcuts import get_current_site from django.core.exceptions import ValidationError from django.core.mail import EmailMultiAlternatives from django.db.models import Q -from django.forms import BaseModelFormSet, CharField, ChoiceField, EmailField, EmailInput, ModelForm +from django.forms import BaseModelFormSet, CharField, ChoiceField, DateTimeInput, EmailField, EmailInput, ModelForm from django.template import loader from django.utils.encoding import force_bytes from django.utils.http import urlsafe_base64_encode @@ -21,6 +21,7 @@ from django.utils.translation import gettext_lazy as _ from core.base_forms import TranslatedFieldsForm from core.models import Assembly, ConferenceMember, Link, PlatformUser, Project, UserCommunicationChannel +from core.models.conference import Conference from core.models.tags import clean_tags from core.tokens import channel_activation_token @@ -243,6 +244,47 @@ class LinkFormSet(BaseModelFormSet): form.set_linked_object(linked_object) +class ConferencePublicationForm(TranslatedFieldsForm): + class Meta: + model = Conference + fields = [ + 'name', + 'slug', + 'start', + 'end', + 'publication_date', + 'timezone', + 'global_notification', + 'is_public', + ] + + widgets = { + 'start': DateTimeInput(attrs={'type': 'datetime-local'}, format='%Y-%m-%dT%H:%M:%S%z'), + 'end': DateTimeInput(attrs={'type': 'datetime-local'}, format='%Y-%m-%dT%H:%M:%S%z'), + 'publication_date': DateTimeInput(attrs={'type': 'datetime-local'}, format='%Y-%m-%dT%H:%M:%S%z'), + } + + def __init__( + self, + *args, + instance: Conference | None = None, + publish: bool = False, + **kwargs, + ): + self.publish = publish + self.create = instance is None + super().__init__(*args, instance=instance, **kwargs) + if not self.create: + self.fields['name'].disabled = True + self.fields['slug'].disabled = True + + def clean(self) -> dict[str, Any]: + if self.instance.is_public != self.cleaned_data['is_public']: + raise ValidationError(_('Conference__is_public__unchangeable')) + self.cleaned_data['is_public'] = not self.instance.is_public if self.publish else self.instance.is_public + return super().clean() + + class ProjectForm(TranslatedFieldsForm): class Meta: model = Project diff --git a/src/core/locale/de/LC_MESSAGES/django.po b/src/core/locale/de/LC_MESSAGES/django.po index f8d30d14d..c74d549de 100644 --- a/src/core/locale/de/LC_MESSAGES/django.po +++ b/src/core/locale/de/LC_MESSAGES/django.po @@ -137,6 +137,9 @@ msgstr "Zu viele Request (Rate-Limited), bitte einen Moment warten!" msgid "Registration__username__nounderscore" msgstr "Der Benutzername darf nicht mit einem Unterstrich beginnen." +msgid "Conference__is_public__unchangeable" +msgstr "Der Konferenz Veröffentlichungsstatus kann nur mittels des Veröffentlichen Buttons durchgeführt werden." + msgid "Tags" msgstr "" @@ -628,6 +631,9 @@ msgstr "Wenn du eine neue Badge akzeptierst wird sie standardmäßig mit dieser msgid "ConferenceMember__default_badge_visibility" msgstr "Sichtbarkeit neuer Badges" +msgid "ConferenceMember__permission-confernece_admin" +msgstr "Konferenz-Admin: Kann die Veröffentlichungszeitpunkte der Konferenz verwalten" + msgid "ConferenceMember__permission-assembly_team" msgstr "Assembly-Team: alle Assemblies verwaltbar, auch noch nicht fertig angelegte und abgelehnte sind sichtbar" diff --git a/src/core/locale/en/LC_MESSAGES/django.po b/src/core/locale/en/LC_MESSAGES/django.po index dc6c5f67a..b12d86106 100644 --- a/src/core/locale/en/LC_MESSAGES/django.po +++ b/src/core/locale/en/LC_MESSAGES/django.po @@ -137,6 +137,9 @@ msgstr "Too many requests (Rate-Limited), please wait a moment!" msgid "Registration__username__nounderscore" msgstr "The username must not begin with an underscore." +msgid "Conference__is_public__unchangeable" +msgstr "The conference publication status can only be changed using the publish button." + msgid "Tags" msgstr "" @@ -628,6 +631,9 @@ msgstr " When you accept a new badge, it will be displayed with this visibility msgid "ConferenceMember__default_badge_visibility" msgstr "visibility of new badges" +msgid "ConferenceMember__permission-confernece_admin" +msgstr "Conference admin: can manage the conference's publication times" + msgid "ConferenceMember__permission-assembly_team" msgstr "assemblies team: manage all assemblies, see also incomplete and rejected registrations" diff --git a/src/core/migrations/0152_alter_conferencemember_options.py b/src/core/migrations/0152_alter_conferencemember_options.py new file mode 100644 index 000000000..e61627205 --- /dev/null +++ b/src/core/migrations/0152_alter_conferencemember_options.py @@ -0,0 +1,35 @@ +# Generated by Django 5.1.2 on 2024-10-27 00:54 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("core", "0151_conference_publication_date"), + ] + + operations = [ + migrations.AlterModelOptions( + name="conferencemember", + options={ + "permissions": [ + ( + "conference_admin", + "ConferenceMember__permission-confernece_admin", + ), + ("assembly_team", "ConferenceMember__permission-assembly_team"), + ("channel_team", "ConferenceMember__permission-channel_team"), + ("static_pages", "ConferenceMember__permission-static_pages"), + ("map_edit", "ConferenceMember__permission-map_edit"), + ("moderation", "Orga: Moderation"), + ("voucher_admin", "ConferenceMember__permission-voucher_admin"), + ("scheduleadmin", "ConferenceMember__permission-scheduleadmin"), + ( + "workadventure_admin", + "ConferenceMember__permission-workadventure_admin", + ), + ] + }, + ), + ] diff --git a/src/core/models/conference.py b/src/core/models/conference.py index e06c906f0..cb2a9a810 100644 --- a/src/core/models/conference.py +++ b/src/core/models/conference.py @@ -78,6 +78,8 @@ class ConferenceMember(models.Model): class Meta: permissions = [ + ('conference_admin', _('ConferenceMember__permission-confernece_admin')), + # Change conference settings (e.g., dates, ), update venue json. ('assembly_team', _('ConferenceMember__permission-assembly_team')), # See all assemblies, not only the accepted ones. ('channel_team', _('ConferenceMember__permission-channel_team')), -- GitLab