Replace organizer_edit_tabs by nav_organizer

This commit is contained in:
Raphael Michel
2017-04-27 10:00:09 +02:00
parent bbe272c35c
commit 4f015f1d96
8 changed files with 218 additions and 181 deletions

View File

@@ -47,7 +47,7 @@ Backend
------- -------
.. automodule:: pretix.control.signals .. automodule:: pretix.control.signals
:members: nav_event, html_head, quota_detail_html, nav_topbar, nav_global, organizer_edit_tabs :members: nav_event, html_head, quota_detail_html, nav_topbar, nav_global, nav_organizer
.. automodule:: pretix.base.signals .. automodule:: pretix.base.signals

View File

@@ -1,3 +1,4 @@
import warnings
from typing import Any, Callable, List, Tuple from typing import Any, Callable, List, Tuple
import django.dispatch import django.dispatch
@@ -52,6 +53,13 @@ class EventPluginSignal(django.dispatch.Signal):
return responses return responses
class DeprecatedSignal(django.dispatch.Signal):
def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
warnings.warn('This signal is deprecated and will soon be removed', stacklevel=3)
super().connect(receiver, sender=None, weak=True, dispatch_uid=None)
event_live_issues = EventPluginSignal( event_live_issues = EventPluginSignal(
providing_args=[] providing_args=[]
) )

View File

@@ -1,6 +1,6 @@
from django.dispatch import Signal from django.dispatch import Signal
from pretix.base.signals import EventPluginSignal from pretix.base.signals import DeprecatedSignal, EventPluginSignal
restriction_formset = EventPluginSignal( restriction_formset = EventPluginSignal(
providing_args=["item"] providing_args=["item"]
@@ -143,14 +143,29 @@ quota as argument in the ``quota`` keyword argument.
As with all plugin signals, the ``sender`` keyword argument will contain the event. As with all plugin signals, the ``sender`` keyword argument will contain the event.
""" """
organizer_edit_tabs = Signal( organizer_edit_tabs = DeprecatedSignal(
providing_args=['organizer', 'request'] providing_args=['organizer', 'request']
) )
""" """
This signal is sent out to include tabs on the detail page of an organizer. Receivers Deprecated signal, no longer works. We just keep the definition so old plugins don't
should return a tuple with the first item being the tab title and the second item break the installation.
being the content as HTML. The receivers get the ``organizer`` and the ``request`` as """
keyword arguments.
This is a regular django signal (no pretix event signal). nav_organizer = Signal(
providing_args=['organizer', 'request']
)
"""
This signal is sent out to include tab links on the detail page of an organizer.
Receivers are expected to return a list of dictionaries. The dictionaries
should contain at least the keys ``label`` and ``url``. You should also return
an ``active`` key with a boolean set to ``True``, when this item should be marked
as active.
If your linked view should stay in the tab-like context of this page, we recommend
that you use ``pretix.control.views.organizer.OrganizerDetailViewMixin`` for your view
and your tempalte inherits from ``pretixcontrol/organizers/base.html``.
This is a regular django signal (no pretix event signal). Receivers will be passed
the keyword arguments ``organizer`` and ``request``.
""" """

View File

@@ -0,0 +1,39 @@
{% extends "pretixcontrol/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% block title %}{% trans "Organizer" %}{% endblock %}
{% block content %}
<h1>
{% blocktrans with name=organizer.name %}Organizer: {{ name }}{% endblocktrans %}
<a href="{% url "control:organizer.edit" organizer=organizer.slug %}"
class="btn btn-default">
<span class="fa fa-edit"></span>
{% trans "Edit" %}
</a>
</h1>
<ul class="nav nav-pills">
<li {% if "organizer" == url_name %}class="active"{% endif %}>
<a href="{% url "control:organizer" organizer=organizer.slug %}">
{% trans "Events" %}
</a>
</li>
{% if request.orgaperm.can_change_permissions %}
<li {% if "organizer.teams" == url_name %}class="active"{% endif %}>
<a href="{% url "control:organizer.teams" organizer=organizer.slug %}">
{% trans "Permissions" %}
</a>
</li>
{% endif %}
{% for nav in nav_organizer %}
<li {% if nav.active %}class="active"{% endif %}>
<a href="{{ nav.url }}">
{{ nav.label }}
</a>
</li>
{% endfor %}
</ul>
{% block inner %}
{% endblock %}
{% endblock %}

View File

@@ -1,159 +1,34 @@
{% extends "pretixcontrol/base.html" %} {% extends "pretixcontrol/organizers/base.html" %}
{% load i18n %} {% load i18n %}
{% load bootstrap3 %} {% load bootstrap3 %}
{% block title %}{% trans "Organizer" %}{% endblock %} {% block inner %}
{% block content %} {% if events|length == 0 %}
<h1> <p>
{% blocktrans with name=organizer.name %}Organizer: {{ name }}{% endblocktrans %} <em>{% trans "You currently do not have access to any events." %}</em>
<a href="{% url "control:organizer.edit" organizer=organizer.slug %}" </p>
class="btn btn-default"> {% else %}
<span class="fa fa-edit"></span> <table class="table table-condensed table-hover">
{% trans "Edit" %} <thead>
</a> <tr>
</h1> <th>{% trans "Event name" %}</th>
<ul class="nav nav-tabs"> <th>{% trans "Start date" %}</th>
<li class="active"> </tr>
<a href="#tab-events" data-toggle="tab">{% trans "Events" %}</a> </thead>
</li> <tbody>
{% if request.orgaperm.can_change_permissions %} {% for e in events %}
<li> <tr>
<a href="#tab-permissions" data-toggle="tab">{% trans "Team" %}</a> <td>
</li> <strong><a
{% endif %} href="{% url "control:event.index" organizer=e.organizer.slug event=e.slug %}">{{ e.name }}</a></strong>
{% for title, content in tabs %} </td>
<li> <td>{{ e.get_date_from_display }}</td>
<a href="#tab-{{ forloop.counter }}" data-toggle="tab"> </tr>
{{ title }} {% endfor %}
</a> </tbody>
</li> </table>
{% endfor %} {% endif %}
</ul> <a href="{% url "control:events.add" %}" class="btn btn-default">
<span class="fa fa-plus"></span>
<div class="tab-content organizer-tabs"> {% trans "Create a new event" %}
<div class="tab-pane active" id="tab-events"> </a>
<div class="tab-inner">
{% if events|length == 0 %}
<p>
<em>{% trans "You currently do not have access to any events." %}</em>
</p>
{% else %}
<table class="table table-condensed table-hover">
<thead>
<tr>
<th>{% trans "Event name" %}</th>
<th>{% trans "Start date" %}</th>
</tr>
</thead>
<tbody>
{% for e in events %}
<tr>
<td>
<strong><a
href="{% url "control:event.index" organizer=e.organizer.slug event=e.slug %}">{{ e.name }}</a></strong>
</td>
<td>{{ e.get_date_from_display }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
<a href="{% url "control:events.add" %}" class="btn btn-default">
<span class="fa fa-plus"></span>
{% trans "Create a new event" %}
</a>
</div>
</div>
{% if request.orgaperm.can_change_permissions %}
<div class="tab-pane" id="tab-permissions">
<div class="tab-inner">
<form action="" method="post" class="form-horizontal form-permissions">
{% csrf_token %}
<p>
{% blocktrans trimmed %}
You can use the following list to control who can create new events in the name of
this organizer and who can add more people to this list. This does <strong>not</strong>
control who has access to a particular event. You can control the access to an
event in the "Permissions" section of the event's settings. A user does not need to
be on the list here to get access to an event.
{% endblocktrans %}
</p>
<p>
{% trans "Everyone on this list can control the organizer settings on this page." %}
</p>
{% bootstrap_formset_errors formset %}
{{ formset.management_form }}
<div class="table-responsive">
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>{% trans "User" %}</th>
<th>{% trans "Create events" %}</th>
<th>{% trans "Change permissions" %}</th>
<th>{% trans "Delete" %}</th>
</tr>
</thead>
<tbody>
{% for form in formset %}
<tr>
<td>
{{ form.id }}
{% if form.instance.user %}
{{ form.instance.user }}
{% else %}
{{ form.instance.invite_email }}
<span class="fa fa-envelope-o" data-toggle="tooltip"
title="{% trans "invited, pending response" %}"></span>
{% endif %}
</td>
<td>{{ form.can_create_events }}</td>
<td>{{ form.can_change_permissions }}</td>
<td>{{ form.DELETE }}</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td colspan="9">
<strong>{% trans "Adding a new user" %}</strong><br>
{% blocktrans trimmed %}
To add a new user, you can enter their email address here. If they
already have a pretix account, they will immediately be added to the team.
Otherwise, they will be sent an email with an invitation.
{% endblocktrans %}
</td>
</tr>
<tr>
<td>
<div class="row-fluid">
<div class="col-sm-12">
{% bootstrap_field add_form.user layout='inline' %}
</div>
</div>
</td>
<td>{{ add_form.can_create_events }}</td>
<td>{{ add_form.can_change_permissions }}</td>
</tr>
</tfoot>
</table>
</div>
<div class="form-group submit-group">
<button type="submit" class="btn btn-primary btn-save">
{% trans "Save" %}
</button>
</div>
</form>
</div>
</div>
{% endif %}
{% for title, content in tabs %}
<div class="tab-pane" id="tab-{{ forloop.counter }}">
<div class="tab-inner">
{{ content }}
</div>
</div>
{% endfor %}
</div>
{% endblock %} {% endblock %}

View File

@@ -0,0 +1,84 @@
{% extends "pretixcontrol/organizers/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% block inner %}
<form action="" method="post" class="form-horizontal form-permissions">
{% csrf_token %}
<p>
{% blocktrans trimmed %}
You can use the following list to control who can create new events in the name of
this organizer and who can add more people to this list. This does <strong>not</strong>
control who has access to a particular event. You can control the access to an
event in the "Permissions" section of the event's settings. A user does not need to
be on the list here to get access to an event.
{% endblocktrans %}
</p>
<p>
{% trans "Everyone on this list can control the organizer settings on this page." %}
</p>
{% bootstrap_formset_errors formset %}
{{ formset.management_form }}
<div class="table-responsive">
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>{% trans "User" %}</th>
<th>{% trans "Create events" %}</th>
<th>{% trans "Change permissions" %}</th>
<th>{% trans "Delete" %}</th>
</tr>
</thead>
<tbody>
{% for form in formset %}
<tr>
<td>
{{ form.id }}
{% if form.instance.user %}
{{ form.instance.user }}
{% else %}
{{ form.instance.invite_email }}
<span class="fa fa-envelope-o" data-toggle="tooltip"
title="{% trans "invited, pending response" %}"></span>
{% endif %}
</td>
<td>{{ form.can_create_events }}</td>
<td>{{ form.can_change_permissions }}</td>
<td>{{ form.DELETE }}</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td colspan="9">
<strong>{% trans "Adding a new user" %}</strong><br>
{% blocktrans trimmed %}
To add a new user, you can enter their email address here. If they
already have a pretix account, they will immediately be added to the team.
Otherwise, they will be sent an email with an invitation.
{% endblocktrans %}
</td>
</tr>
<tr>
<td>
<div class="row-fluid">
<div class="col-sm-12">
{% bootstrap_field add_form.user layout='inline' %}
</div>
</div>
</td>
<td>{{ add_form.can_create_events }}</td>
<td>{{ add_form.can_change_permissions }}</td>
</tr>
</tfoot>
</table>
</div>
<div class="form-group submit-group">
<button type="submit" class="btn btn-primary btn-save">
{% trans "Save" %}
</button>
</div>
</form>
{% endblock %}

View File

@@ -35,6 +35,7 @@ urlpatterns = [
url(r'^organizers/add$', organizer.OrganizerCreate.as_view(), name='organizers.add'), url(r'^organizers/add$', organizer.OrganizerCreate.as_view(), name='organizers.add'),
url(r'^organizer/(?P<organizer>[^/]+)/$', organizer.OrganizerDetail.as_view(), name='organizer'), url(r'^organizer/(?P<organizer>[^/]+)/$', organizer.OrganizerDetail.as_view(), name='organizer'),
url(r'^organizer/(?P<organizer>[^/]+)/edit$', organizer.OrganizerUpdate.as_view(), name='organizer.edit'), url(r'^organizer/(?P<organizer>[^/]+)/edit$', organizer.OrganizerUpdate.as_view(), name='organizer.edit'),
url(r'^organizer/(?P<organizer>[^/]+)/teams$', organizer.OrganizerTeamView.as_view(), name='organizer.teams'),
url(r'^events/$', main.EventList.as_view(), name='events'), url(r'^events/$', main.EventList.as_view(), name='events'),
url(r'^events/add$', main.EventWizard.as_view(), name='events.add'), url(r'^events/add$', main.EventWizard.as_view(), name='events.add'),
url(r'^event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/', include([ url(r'^event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/', include([

View File

@@ -14,7 +14,7 @@ from pretix.base.models import Organizer, OrganizerPermission, User
from pretix.base.services.mail import SendMailException, mail from pretix.base.services.mail import SendMailException, mail
from pretix.control.forms.organizer import OrganizerForm, OrganizerUpdateForm from pretix.control.forms.organizer import OrganizerForm, OrganizerUpdateForm
from pretix.control.permissions import OrganizerPermissionRequiredMixin from pretix.control.permissions import OrganizerPermissionRequiredMixin
from pretix.control.signals import organizer_edit_tabs from pretix.control.signals import nav_organizer
from pretix.helpers.urls import build_absolute_uri from pretix.helpers.urls import build_absolute_uri
@@ -45,7 +45,23 @@ class OrganizerPermissionCreateForm(OrganizerPermissionForm):
user = forms.EmailField(required=False, label=_('User')) user = forms.EmailField(required=False, label=_('User'))
class OrganizerDetail(OrganizerPermissionRequiredMixin, DetailView): class OrganizerDetailViewMixin:
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['nav_organizer'] = []
ctx['organizer'] = self.request.organizer
for recv, retv in nav_organizer.send(sender=self.request.organizer, request=self.request,
organizer=self.request.organizer):
ctx['nav_organizer'] += retv
return ctx
def get_object(self, queryset=None) -> Organizer:
return self.request.organizer
class OrganizerDetail(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, DetailView):
model = Organizer model = Organizer
template_name = 'pretixcontrol/organizers/detail.html' template_name = 'pretixcontrol/organizers/detail.html'
permission = None permission = None
@@ -54,6 +70,18 @@ class OrganizerDetail(OrganizerPermissionRequiredMixin, DetailView):
def get_object(self, queryset=None) -> Organizer: def get_object(self, queryset=None) -> Organizer:
return self.request.organizer return self.request.organizer
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['events'] = self.request.organizer.events.all()
return ctx
class OrganizerTeamView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, DetailView):
model = Organizer
template_name = 'pretixcontrol/organizers/teams.html'
permission = 'can_change_permissions'
context_object_name = 'organizer'
@cached_property @cached_property
def formset(self): def formset(self):
fs = modelformset_factory( fs = modelformset_factory(
@@ -86,13 +114,6 @@ class OrganizerDetail(OrganizerPermissionRequiredMixin, DetailView):
ctx = super().get_context_data(**kwargs) ctx = super().get_context_data(**kwargs)
ctx['formset'] = self.formset ctx['formset'] = self.formset
ctx['add_form'] = self.add_form ctx['add_form'] = self.add_form
ctx['events'] = self.request.organizer.events.all()
ctx['tabs'] = []
for recv, retv in organizer_edit_tabs.send(sender=self.request.organizer, request=self.request,
organizer=self.request.organizer):
ctx['tabs'].append(retv)
return ctx return ctx
def _send_invite(self, instance): def _send_invite(self, instance):
@@ -116,12 +137,6 @@ class OrganizerDetail(OrganizerPermissionRequiredMixin, DetailView):
@transaction.atomic @transaction.atomic
def post(self, *args, **kwargs): def post(self, *args, **kwargs):
if not self.request.orgaperm.can_change_permissions:
raise PermissionDenied(_("You have no permission to do this."))
if 'formset-TOTAL_FORMS' not in self.request.POST:
return self.get(*args, **kwargs)
if self.formset.is_valid() and self.add_form.is_valid(): if self.formset.is_valid() and self.add_form.is_valid():
if self.add_form.has_changed(): if self.add_form.has_changed():
logdata = { logdata = {
@@ -186,7 +201,7 @@ class OrganizerDetail(OrganizerPermissionRequiredMixin, DetailView):
return self.get(*args, **kwargs) return self.get(*args, **kwargs)
def get_success_url(self) -> str: def get_success_url(self) -> str:
return reverse('control:organizer', kwargs={ return reverse('control:organizer.teams', kwargs={
'organizer': self.request.organizer.slug, 'organizer': self.request.organizer.slug,
}) })