diff --git a/src/backoffice/forms.py b/src/backoffice/forms.py index e211c295b2811608523cb20bbac3b89daf2ea2de..1ddb05345dd80e3d5d4153fdd30e7b7466e5d150 100644 --- a/src/backoffice/forms.py +++ b/src/backoffice/forms.py @@ -126,6 +126,11 @@ class AssemblyEditForm(forms.ModelForm): # call original .clean() which e.g. removes 'slug' from cleaned_data if that isn't a slug super().clean() + # ensure assembly is either a channel or an assembly + if self.cleaned_data.get('state_assembly') == Assembly.State.NONE and self.cleaned_data.get('state_channel') == Assembly.State.NONE: + self.add_error('state_assembly', _('Assembly__states_must_not_be_none')) + self.add_error('state_channel', _('Assembly__states_must_not_be_none')) + # slug must not already exist in the conference slug = self.cleaned_data.get('slug') if slug is not None and Assembly.objects.filter(conference=self.instance.conference, slug=slug).exclude(pk=self.instance.pk).exists(): diff --git a/src/backoffice/locale/de/LC_MESSAGES/django.po b/src/backoffice/locale/de/LC_MESSAGES/django.po index 3b8348d13a5a80e3e3f97b08054bb15938b83841..ed050947c6b1200740614f04665a14ced2e75c39 100644 --- a/src/backoffice/locale/de/LC_MESSAGES/django.po +++ b/src/backoffice/locale/de/LC_MESSAGES/django.po @@ -545,6 +545,9 @@ msgstr "Übersicht" msgid "nav_assemblies" msgstr "Assembly-Team" +msgid "nav_channels" +msgstr "Channels-Team" + msgid "nav_users" msgstr "Teilnehmer" @@ -901,6 +904,21 @@ msgstr "" msgid "UserCommunicationChannel__address" msgstr "" +msgid "nav_channels_all" +msgstr "alle" + +msgid "nav_channels_accepted" +msgstr "akzeptiert" + +msgid "nav_channels_pending" +msgstr "wartend" + +msgid "nav_channels_planned" +msgstr "geplant" + +msgid "nav_channels_rejected" +msgstr "abgelehnt" + msgid "backoffice:assembly-organisational-data" msgstr "Organisatorisches" diff --git a/src/backoffice/locale/en/LC_MESSAGES/django.po b/src/backoffice/locale/en/LC_MESSAGES/django.po index 2586b84e04eabc5b857b4aefacbc0c1ca894788a..198043ad86366eb491bbf6a8a14ee5aa70ede5b2 100644 --- a/src/backoffice/locale/en/LC_MESSAGES/django.po +++ b/src/backoffice/locale/en/LC_MESSAGES/django.po @@ -546,6 +546,9 @@ msgstr "Home" msgid "nav_assemblies" msgstr "assemblies team" +msgid "nav_channels" +msgstr "channels team" + msgid "nav_users" msgstr "users" @@ -901,6 +904,21 @@ msgstr "" msgid "UserCommunicationChannel__address" msgstr "" +msgid "nav_channels_all" +msgstr "all" + +msgid "nav_channels_accepted" +msgstr "accepted" + +msgid "nav_channels_pending" +msgstr "pending" + +msgid "nav_channels_planned" +msgstr "planned" + +msgid "nav_channels_rejected" +msgstr "rejected" + msgid "backoffice:assembly-organisational-data" msgstr "Organisational Data" diff --git a/src/backoffice/static/backoffice.css b/src/backoffice/static/backoffice.css index 53fff09e9e385113f43a3f4c1866470141239d28..2d06111ba1a3b0246cd896f39b116ed12f1785c3 100644 --- a/src/backoffice/static/backoffice.css +++ b/src/backoffice/static/backoffice.css @@ -2,6 +2,7 @@ display: flex; width: 100%; align-items: stretch; + min-height: calc(100vh - 56px); } .legal-footer { @@ -21,7 +22,7 @@ } #sidebar .list-group-item, -#sidebar .list-group-item > a { +#sidebar .list-group-item > a { align-items: center; background: #7386D5; border: none; @@ -29,13 +30,13 @@ display: flex; } -#sidebar .list-group-item.active, +#sidebar .list-group-item.active, #sidebar .list-group-item.active a { color: #ff0; font-weight: bold; } -#sidebar .list-group-item.child, +#sidebar .list-group-item.child, #sidebar .list-group-item.child a { background: #6d7fcc; } diff --git a/src/backoffice/templates/backoffice/assembly_auth.html b/src/backoffice/templates/backoffice/assembly_auth.html index d836514b443d81664107afd9c8b397309dbbcf78..f9315bf8498ae420f0098642704169a17e91217b 100644 --- a/src/backoffice/templates/backoffice/assembly_auth.html +++ b/src/backoffice/templates/backoffice/assembly_auth.html @@ -31,7 +31,7 @@ </div> </div> -<div class="row mt-3"> +<div class="row mt-3 pb-10rem"> <div class="col-md-12"> <div class="card border-primary"> <div class="card-header bg-primary text-white"> @@ -72,4 +72,4 @@ </form> </div> </div> -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/src/backoffice/templates/backoffice/assembly_edit.html b/src/backoffice/templates/backoffice/assembly_edit.html index 6196f384aaab18ff9f87f189447cd23eb7eb9db7..32810db10719d125de3892d7768fa677ec836bef 100644 --- a/src/backoffice/templates/backoffice/assembly_edit.html +++ b/src/backoffice/templates/backoffice/assembly_edit.html @@ -35,7 +35,7 @@ {% if not field.disabled %} {% render_field field class+="form-control" %} {% else %} - <input type="hidden" name="{{ field.name }}" value="{{ field.value }}">{{ field.value }} + <input type="hidden" name="{{ field.name }}" value="{{ field.value }}">{% render_field field class+="form-control" disabled="disabled" %} {% endif %} {% if field.help_text %} <small class="form-text text-muted">{{ field.help_text }}</small> diff --git a/src/backoffice/templates/backoffice/assembly_editlinks.html b/src/backoffice/templates/backoffice/assembly_editlinks.html index debb0553780072833fb7b90253584f6ae26a411e..79111c38111c971d7ffa1b07d48c2f5d955df1e7 100644 --- a/src/backoffice/templates/backoffice/assembly_editlinks.html +++ b/src/backoffice/templates/backoffice/assembly_editlinks.html @@ -37,7 +37,7 @@ </div> </div> -<div class="row"> +<div class="row pb-10rem"> <div class="col-md-12"> <div class="card mb-3"> <div class="card-header"> @@ -65,4 +65,4 @@ </div> {% endwith %} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/src/backoffice/templates/backoffice/assembly_members.html b/src/backoffice/templates/backoffice/assembly_members.html index cabe71263e0aecece3fb46b7105276a58a46e1ed..34b6ebe7030cc60ee3446da9076b82685ba34a9f 100644 --- a/src/backoffice/templates/backoffice/assembly_members.html +++ b/src/backoffice/templates/backoffice/assembly_members.html @@ -9,7 +9,7 @@ {% block content %} {% include "backoffice/assembly_edit_header.html" %} -<div class="row pb-5"> +<div class="row pb-10rem"> <div class="col-md-12"> <div class="card border-default"> <div class="card-header bg-default"> @@ -51,10 +51,10 @@ <td>{% if member.show_public %}S{% else %}-{% endif %}</td> {% if can_manage %}<td> <a class="btn btn-secondary btn-sm" href="{% url 'backoffice:assembly-members-edit' pk=assembly.id uname=member.member.username %}">{% trans 'Assembly__members__edit' %}</a> - <input - type="submit" - class="btn btn-default btn-sm" - name="{% if member.show_public %}hide{% else %}show{% endif %}-{{ member.member.id }}" + <input + type="submit" + class="btn btn-default btn-sm" + name="{% if member.show_public %}hide{% else %}show{% endif %}-{{ member.member.id }}" value="{% if member.show_public %}{% trans 'Assembly__members__hide' %}{% else %}{% trans 'Assembly__members__show' %}{% endif %}"> <input type="submit" class="btn btn-default btn-sm" name="delete-{{ member.member.id }}" value="{% trans 'Assembly__members__delete' %}"> </td>{% endif %} diff --git a/src/backoffice/templates/backoffice/base.html b/src/backoffice/templates/backoffice/base.html index c626c6184ea2b90f1432e704c106aecfc44fb280..a7d32af6d6c0d8a8f9b3c645ddc8768b6dac973b 100644 --- a/src/backoffice/templates/backoffice/base.html +++ b/src/backoffice/templates/backoffice/base.html @@ -29,6 +29,11 @@ <a class="nav-link" href="{% url 'backoffice:assemblies' %}">{% trans "nav_assemblies" %}{% if active_page == 'assemblies' %} <span class="sr-only">{{ activetab_srmarker }}</span>{% endif %}</a> </li> {% endif %} + {% if has_channel %} + <li class="nav-item{% if active_page == 'channels' %} active{% endif %}"> + <a class="nav-link" href="{% url 'backoffice:channels' %}">{% trans "nav_channels" %}{% if active_page == 'channels' %} <span class="sr-only">{{ activetab_srmarker }}</span>{% endif %}</a> + </li> + {% endif %} {% if has_users %} <li class="nav-item{% if active_page == 'users' %} active{% endif %}"> <a class="nav-link" href="{% url 'backoffice:users' %}">{% trans "nav_users" %}{% if active_page == 'users' %} <span class="sr-only">{{ activetab_srmarker }}</span>{% endif %}</a> diff --git a/src/backoffice/urls.py b/src/backoffice/urls.py index 6420101d079918df378d657d781482c072fdac78..03a4aa2f64895c522881fbbab047a313881134c1 100644 --- a/src/backoffice/urls.py +++ b/src/backoffice/urls.py @@ -4,6 +4,7 @@ from .views import \ assemblies, \ assemblyteam, \ auth, \ + channelteam, \ events, \ misc, \ pages, \ @@ -45,6 +46,8 @@ urlpatterns = [ path('assemblies', assemblyteam.AssembliesView.as_view(), name='assemblies'), path('assemblies/list/<str:variant>', assemblyteam.AssembliesListsView.as_view(), name='assemblieslist'), + path('channels', channelteam.ChannelsView.as_view(), name='channels'), + path('channels/list/<str:variant>', channelteam.ChannelsListView.as_view(), name='channelslist'), path('assembly/create', assemblies.CreateAssemblyView.as_view(), name='assembly-create'), path('assembly/<uuid:pk>', assemblies.AssemblyView.as_view(), name='assembly'), diff --git a/src/backoffice/views/assemblies.py b/src/backoffice/views/assemblies.py index e83022d22057323ff050dabbe539da79f4823943..96409a3c4f6d56c921367cd8d8189920ad18235c 100644 --- a/src/backoffice/views/assemblies.py +++ b/src/backoffice/views/assemblies.py @@ -90,12 +90,20 @@ class EditAssemblyView(AssemblyMixin, UpdateView): form['is_virtual'].disabled = True if not self.staff_access: - form['state_assembly'].disabled = True - form['state_channel'].disabled = True for x in AssemblyEditForm.Meta.staff_fields: if x in form.fields: del(form.fields[x]) + # disable assembly-related field editing for everyone except assembly team + if not self.assembly_staff_access: + form['state_assembly'].disabled = True + # but allow setting 'is_official' if only the channel team has access + form['is_official'].disabled = not (self.assembly.state_assembly == Assembly.State.NONE and self.channel_staff_access) + + # disable channel state editing for everyone except channel team + if not self.channel_staff_access: + form['state_channel'].disabled = True + return form def form_valid(self, form): @@ -128,6 +136,8 @@ class EditAssemblyView(AssemblyMixin, UpdateView): assembly.add_tag(tag, autocreate=True) if assembly.state_assembly == Assembly.State.PLANNED: assembly.state_assembly = Assembly.State.REGISTERED + if assembly.state_channel == Assembly.State.PLANNED: + assembly.state_channel = Assembly.State.REGISTERED if assembly.hierarchy == Assembly.Hierarchy.REGULAR: parent_id = form.cleaned_data.get('parent_id', '') if self.conference.support_clusters else None diff --git a/src/backoffice/views/assemblyteam.py b/src/backoffice/views/assemblyteam.py index 8258b870642375974c90c5872a4535a045daaab4..f6a56c552c02f2f5636588c6e515b982ecd4b6aa 100644 --- a/src/backoffice/views/assemblyteam.py +++ b/src/backoffice/views/assemblyteam.py @@ -23,6 +23,10 @@ logger = logging.getLogger(__name__) class AssemblyTeamMixin(ConferenceMixin): require_conference = True permission_required = ['core.assembly_team'] + active_page = 'assemblies' + base_view_name = 'backoffice:assemblies' + list_view_name = 'backoffice:assemblieslist' + sidebar_caption = _("nav_assemblies") MODES = { 'all': (Q(), _('nav_assemblies_all')), @@ -34,13 +38,14 @@ class AssemblyTeamMixin(ConferenceMixin): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context['active_page'] = 'assemblies' + context['active_page'] = self.active_page + self.request.session['assembly_back'] = {'link': self.request.get_full_path(), 'title': str(self.sidebar_caption)} assemblies = [] lists = [] context['sidebar'] = { - 'title': _('nav_assemblies'), - # 'title_link': reverse('backoffice:assemblies'), + 'title': self.sidebar_caption, + # 'title_link': reverse(self.base_view_name), 'items': [ { 'caption': _('Assemblys'), @@ -57,24 +62,28 @@ class AssemblyTeamMixin(ConferenceMixin): for m, (q, t) in self.MODES.items(): assemblies.append({ + 'mode': m, 'caption': t, 'count': self.conference.assemblies.filter(q).count(), - 'link': reverse('backoffice:assemblies') + '?mode=' + m, + 'link': reverse(self.base_view_name) + '?mode=' + m, }) lists.append({ 'caption': format_lazy('{accepted}: slug+name', accepted=_('nav_assemblies_accepted')), - 'link': reverse('backoffice:assemblieslist', kwargs={'variant': 'slugname'}) + '?mode=accepted', + 'link': reverse(self.list_view_name, kwargs={'variant': 'slugname'}) + '?mode=accepted', + 'variant': 'slugname', }) lists.append({ 'caption': format_lazy('{accepted}: contacts', accepted=_('nav_assemblies_accepted')), - 'link': reverse('backoffice:assemblieslist', kwargs={'variant': 'assemblycontacts'}) + '?mode=accepted', + 'link': reverse(self.list_view_name, kwargs={'variant': 'assemblycontacts'}) + '?mode=accepted', + 'variant': 'assemblycontacts', }) lists.append({ 'caption': format_lazy('{accepted}: contact mails', accepted=_('nav_assemblies_accepted')), - 'link': reverse('backoffice:assemblieslist', kwargs={'variant': 'contactsmail'}) + '?mode=accepted', + 'link': reverse(self.list_view_name, kwargs={'variant': 'contactsmail'}) + '?mode=accepted', + 'variant': 'contactsmail', }) return context @@ -86,6 +95,13 @@ class AssembliesListMixin(AssemblyTeamMixin): def get_queryset(self, **kwargs): # not using .accessible_by_user() here as we're the Assembly Team anyway qs = Assembly.objects.filter(conference=self.conference) + if self.active_page == 'assemblies': + qs = qs.exclude(state_assembly=Assembly.State.NONE) + elif self.active_page == 'channels': + qs = qs.exclude(state_channel=Assembly.State.NONE) + else: + logging.warning('AssembliesListMixin: unexpected active_page="%s"', self.active_page) + qs = Assembly.objects.none() # mode selection mode = (self.request.POST if self.request.method == 'POST' else self.request.GET).get('mode', self.default_assemblies_mode) @@ -111,6 +127,12 @@ class AssembliesView(AssembliesListMixin, ListView): context['mode'] = self.assemblies_mode context['mode_display'] = self.MODES[self.assemblies_mode][1] + # activate current sidebar item + for sidebar_item in context['sidebar']['items'][0]['children']: + if sidebar_item['mode'] == self.assemblies_mode: + sidebar_item['active'] = True + break + for obj in context['object_list']: obj.user_can_edit = property(lambda x: x.user_can_manage(self.request.user, staff_can_manage=True)) @@ -211,6 +233,12 @@ class AssembliesListsView(AssembliesListMixin, View): ctx['fields'] = variant_fields ctx['data'] = data + # activate current sidebar item + for sidebar_item in ctx['sidebar']['items'][1]['children']: + if sidebar_item['variant'] == variant: + sidebar_item['active'] = True + break + ctx['download_available'] = len(data) > 0 ctx['download_default_delimiter'] = self.DEFAULT_DELIMITER_CHAR ctx['download_default_quotechar'] = self.DEFAULT_QUOTE_CHAR diff --git a/src/backoffice/views/channelteam.py b/src/backoffice/views/channelteam.py new file mode 100644 index 0000000000000000000000000000000000000000..e996f98db465b707ef74e50d7ba617d9b2e836d9 --- /dev/null +++ b/src/backoffice/views/channelteam.py @@ -0,0 +1,30 @@ +from django.utils.translation import gettext_lazy as _ +from django.db.models import Q + +from core.models.assemblies import Assembly + +from .assemblyteam import AssembliesView, AssembliesListsView + + +class ChannelsMixin: + """ sets options that configure the Assemblies views to work in Channels mode """ + MODES = { + 'all': (Q(), _('nav_channels_all')), + 'accepted': (Q(state_channel__in=Assembly.PUBLIC_STATES), _('nav_channels_accepted')), + 'pending': (Q(state_channel__in=[Assembly.State.REGISTERED]), _('nav_channels_pending')), + 'planned': (Q(state_channel__in=[Assembly.State.PLANNED]), _('nav_channels_planned')), + 'rejected': (Q(state_channel__in=[Assembly.State.REJECTED, Assembly.State.HIDDEN]), _('nav_channels_rejected')), + } + permission_required = ['core.channel_team'] + active_page = 'channels' + base_view_name = 'backoffice:channels' + list_view_name = 'backoffice:channelslist' + sidebar_caption = _("nav_channels") + + +class ChannelsView(ChannelsMixin, AssembliesView): + pass + + +class ChannelsListView(ChannelsMixin, AssembliesListsView): + pass diff --git a/src/backoffice/views/misc.py b/src/backoffice/views/misc.py index c5f350e8e3af640f6abe93318dfd9307c258b994..e995f2f290320ba05fef2fd8c0d77476c225b366 100644 --- a/src/backoffice/views/misc.py +++ b/src/backoffice/views/misc.py @@ -43,6 +43,9 @@ class IndexView(ConferenceMixin, View): def get(self, *args, **kwargs): if self.request.user.is_authenticated: myassemblies = list(Assembly.objects.associated_to_user(conference=self.conference, user=self.request.user)) + + # remove stored backlink for assembly pages from the session if it is set, so the backlink will go to the overview, which is the default + self.request.session.pop('assembly_back', None) else: myassemblies = None diff --git a/src/backoffice/views/mixins.py b/src/backoffice/views/mixins.py index eea0265eaffe894bf0c43a6b429de8bd53e2857e..a152c06b213f81fd2c8bfd491829fa4894b1c644 100644 --- a/src/backoffice/views/mixins.py +++ b/src/backoffice/views/mixins.py @@ -63,6 +63,10 @@ class ConferenceMixin(PermissionRequiredMixin): def is_assembly_team(self): return self.request.user.has_conference_staffpermission(self.conference, 'core.assembly_team') + @property + def is_channel_team(self): + return self.request.user.has_conference_staffpermission(self.conference, 'core.channel_team') + def dispatch(self, request, *args, **kwargs): if self.require_conference and self.conference is None: return redirect('conference_selection') @@ -91,6 +95,7 @@ class ConferenceMixin(PermissionRequiredMixin): if self.request.user.is_authenticated: context.update({ 'has_assemblies': self.is_assembly_team, + 'has_channel': self.is_channel_team, 'has_pages': self.request.user.has_conference_staffpermission(self.conference, 'core.static_pages'), 'has_users': self.request.user.has_conference_staffpermission(self.conference, 'core.platformusers'), 'has_schedules': self.request.user.has_conference_staffpermission(self.conference, 'core.scheduleadmin'), @@ -99,6 +104,7 @@ class ConferenceMixin(PermissionRequiredMixin): else: context.update({ 'has_assemblies': False, + 'has_channel': False, 'has_pages': False, 'has_users': False, 'has_schedules': False, @@ -126,9 +132,19 @@ class AssemblyMixin(LoginRequiredMixin, ConferenceMixin, SingleObjectMixin): super().__init__(*args, **kwargs) + # if _can_manage is set, user can edit assembly. This is a cache variable for the can_manage property self._can_manage = None + # if _staff_access is set, extra staff fields can be modified (internal comment, is_official) self._staff_access = False - self._staff_mode = None + # if _assembly_staff_access is set, the field state_assembly can be modified + self._assembly_staff_access = False + # if _channels_staff_access is set, the field state_channel can be modified + self._channels_staff_access = False + + # configures the staff warning + self._staff_mode = False + + # ensure self.object is present if not hasattr(self, 'object'): self.object = property(self._get_assembly) @@ -140,12 +156,19 @@ class AssemblyMixin(LoginRequiredMixin, ConferenceMixin, SingleObjectMixin): # check if it's the assembly team if self.request.user.has_conference_staffpermission(self.conference, 'assembly_team'): - self._staff_access = True + self._assembly_staff_access = True + self._staff_access = self._staff_access or assembly.state_assembly != Assembly.State.NONE + self._staff_mode = True + + # check if it's the channel team + if self.request.user.has_conference_staffpermission(self.conference, 'channel_team'): + self._channels_staff_access = True + self._staff_access = self._staff_access or assembly.state_channel != Assembly.State.NONE self._staff_mode = True # check if the current user is associated as a contact if assembly.has_user(self.request.user): - self._staff_mode = False + # don't set self._staff_mode = False here as this would prevent assembly team members to edit their own assemblies if not self._staff_access and \ assembly.state_assembly in [Assembly.State.NONE, Assembly.State.HIDDEN] and \ @@ -153,7 +176,7 @@ class AssemblyMixin(LoginRequiredMixin, ConferenceMixin, SingleObjectMixin): raise Assembly.DoesNotExist() # neither owner/manager nor assembly team? go away - elif not self._staff_access: + elif not self._assembly_staff_access and not self._channels_staff_access: raise PermissionDenied() self._assembly = assembly @@ -179,6 +202,14 @@ class AssemblyMixin(LoginRequiredMixin, ConferenceMixin, SingleObjectMixin): def staff_access(self): return self._staff_access + @property + def assembly_staff_access(self): + return self._assembly_staff_access + + @property + def channel_staff_access(self): + return self._channels_staff_access + @property def staff_mode(self): return self._staff_mode @@ -206,8 +237,12 @@ class AssemblyMixin(LoginRequiredMixin, ConferenceMixin, SingleObjectMixin): 'items': sidebar, } - if self.staff_mode: - context['sidebar']['back_link'] = {'link': reverse('backoffice:assemblies'), 'caption': _('nav_assemblies')} + # load backlink from the session if it set. Set by Assemblyteam / Channelsteam pages as there are a bunch of + # pages that will link to assembly views + if 'assembly_back' in self.request.session: + assembly_back = self.request.session['assembly_back'] + if 'link' in assembly_back and 'title' in assembly_back: + context['sidebar']['back_link'] = {'link': assembly_back['link'], 'caption': assembly_back['title']} organisation = [] sidebar.append({'caption': _('backoffice:assembly-organisational-data'), 'children': organisation}) diff --git a/src/core/locale/de/LC_MESSAGES/django.po b/src/core/locale/de/LC_MESSAGES/django.po index 3dd97efba4264f33b02e344a0ca15d7ad5bf5e0a..7dad9e681166152bcb9e6862b7bb53cd76c48b52 100644 --- a/src/core/locale/de/LC_MESSAGES/django.po +++ b/src/core/locale/de/LC_MESSAGES/django.po @@ -255,6 +255,9 @@ msgstr "Die Assembly muss einen Typ haben (zumindest eins von physisch/virtuell/ msgid "Assembly__technical_user__must_be_assembly" msgstr "Der technische Benutzer muss vom Typ 'Assembly' sein." +msgid "Assembly__states_must_not_be_none" +msgstr "Assemblystate oder Channelstate muss gesetzt sein!" + msgid "Assembly__slug__is_forbidden" msgstr "Dieser Kurzname ist verboten!" @@ -381,6 +384,9 @@ msgstr "Art/Verwendung" msgid "ConferenceMember__permission-assembly_team" msgstr "Assembly-Team: alle Assemblies verwaltbar, auch noch nicht fertig angelegte und abgelehnte sind sichtbar" +msgid "ConferenceMember__permission-channel_team" +msgstr "Channel-Team: alle Assemblies verwaltbar, auch noch nicht fertig angelegte und abgelehnte sind sichtbar" + msgid "ConferenceMember__permission-static_pages" msgstr "Statische Seiten: Verwaltung von Info-Seiten" diff --git a/src/core/locale/en/LC_MESSAGES/django.po b/src/core/locale/en/LC_MESSAGES/django.po index b4a7655850a23dc0739330483e6856636b7832a9..62b73f72e1abfe58c9d8f43659f22b751b977d9f 100644 --- a/src/core/locale/en/LC_MESSAGES/django.po +++ b/src/core/locale/en/LC_MESSAGES/django.po @@ -255,6 +255,9 @@ msgstr "The assembly requires a type (at least one of physical/virtual/remote)." msgid "Assembly__technical_user__must_be_assembly" msgstr "The technical user must be of type 'assembly'." +msgid "Assembly__states_must_not_be_none" +msgstr "assembly state or channel state must be set!" + msgid "Assembly__slug__is_forbidden" msgstr "this short name is forbidden" @@ -379,7 +382,10 @@ msgid "BadgeToken__badge_class" msgstr "class" msgid "ConferenceMember__permission-assembly_team" -msgstr "assembly team: manage all assemblies, see also incomplete and rejected registrations" +msgstr "assemblies team: manage all assemblies, see also incomplete and rejected registrations" + +msgid "ConferenceMember__permission-channel_team" +msgstr "channel team: manage all assemblies, see also incomplete and rejected registrations" msgid "ConferenceMember__permission-static_pages" msgstr "static pages: manage information pages" diff --git a/src/core/migrations/0074_channel_team_permission.py b/src/core/migrations/0074_channel_team_permission.py new file mode 100644 index 0000000000000000000000000000000000000000..681c61803987ff4d6fc016d31e2400df43d333a1 --- /dev/null +++ b/src/core/migrations/0074_channel_team_permission.py @@ -0,0 +1,17 @@ +# Generated by Django 3.2.10 on 2021-12-16 23:06 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0073_alter_room_assembly'), + ] + + operations = [ + migrations.AlterModelOptions( + name='conferencemember', + options={'permissions': [('assembly_team', 'ConferenceMember__permission-assembly_team'), ('channel_team', 'ConferenceMember__permission-channel_team'), ('static_pages', 'ConferenceMember__permission-static_pages'), ('platformusers', 'Orga: Users List'), ('rename_platformuser', 'Orga: Rename User'), ('block_platformuser', 'ConferenceMember__permission-block_platformuser'), ('change_conferencemember__active_angel', 'ConferenceMember__permission-change_conferencemember__active_angel'), ('view_platformuser__guardian', 'ConferenceMember__permission-view_platformuser__guardian'), ('scheduleadmin', 'ConferenceMember__permission-scheduleadmin'), ('workadventure_admin', 'ConferenceMember__permission-workadventure_admin')]}, + ), + ] diff --git a/src/core/models/assemblies.py b/src/core/models/assemblies.py index c530ffa3f14d456dc7e665459c32b511b9f7a321..6756f2d2eb9bb86a10dac58d8a3a99450a25511d 100644 --- a/src/core/models/assemblies.py +++ b/src/core/models/assemblies.py @@ -374,7 +374,7 @@ class Assembly(TaggedItemMixin, models.Model): if not user.is_authenticated: return False - if staff_can_manage and user.has_conference_staffpermission(self.conference, 'assembly_team'): + if staff_can_manage and user.has_conference_staffpermission(self.conference, 'assembly_team', 'channel_team'): return True return self.members.filter(member=user, can_manage_assembly=True).exists() diff --git a/src/core/models/conference.py b/src/core/models/conference.py index 7766e1841b0fedb188075430c4913f0c118a0b51..f22452d8c9addd5da476104a42c2e0dc11b524f7 100644 --- a/src/core/models/conference.py +++ b/src/core/models/conference.py @@ -34,6 +34,9 @@ class ConferenceMember(models.Model): ('assembly_team', _('ConferenceMember__permission-assembly_team')), # See all assemblies, not only the accepted ones. + ('channel_team', _("ConferenceMember__permission-channel_team")), + # Channelteam, Assemblyteam for Channel-Type Assemblies (Assemblies that provide their own content) + ('static_pages', _('ConferenceMember__permission-static_pages')), # Access to static pages, can be further limited by configuring static_page_groups.