diff --git a/src/pretix/base/models/organizer.py b/src/pretix/base/models/organizer.py index c77988187c..eb0b09d88a 100644 --- a/src/pretix/base/models/organizer.py +++ b/src/pretix/base/models/organizer.py @@ -4,6 +4,7 @@ from datetime import date, datetime, time from django.core.validators import MinLengthValidator, RegexValidator from django.db import models from django.db.models import Exists, OuterRef, Q +from django.urls import reverse from django.utils.crypto import get_random_string from django.utils.functional import cached_property from django.utils.timezone import get_current_timezone, make_aware, now @@ -88,6 +89,15 @@ class Organizer(LoggedModel): return ObjectRelatedCache(self) + @cached_property + def all_logentries_link(self): + return reverse( + 'control:organizer.log', + kwargs={ + 'organizer': self.slug, + } + ) + @property def has_gift_cards(self): return self.cache.get_or_set( diff --git a/src/pretix/control/logdisplay.py b/src/pretix/control/logdisplay.py index 3609a7b860..c7f42486d6 100644 --- a/src/pretix/control/logdisplay.py +++ b/src/pretix/control/logdisplay.py @@ -273,8 +273,15 @@ def _display_checkin(event, logentry): def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs): plains = { 'pretix.object.cloned': _('This object has been created by cloning.'), + 'pretix.organizer.changed': _('The organizer has been changed.'), + 'pretix.organizer.settings': _('The organizer settings have been changed.'), + 'pretix.giftcards.acceptance.added': _('Gift card acceptance for another organizer has been added.'), + 'pretix.giftcards.acceptance.removed': _('Gift card acceptance for another organizer has been removed.'), + 'pretix.webhook.created': _('The webhook has been created.'), + 'pretix.webhook.changed': _('The webhook has been changed.'), 'pretix.event.comment': _('The event\'s internal comment has been updated.'), 'pretix.event.canceled': _('The event has been canceled.'), + 'pretix.event.deleted': _('An event has been deleted.'), 'pretix.event.order.modified': _('The order details have been changed.'), 'pretix.event.order.unpaid': _('The order has been marked as unpaid.'), 'pretix.event.order.secret.changed': _('The order\'s secret has been changed.'), diff --git a/src/pretix/control/templates/pretixcontrol/organizers/edit.html b/src/pretix/control/templates/pretixcontrol/organizers/edit.html index 363e86c5d4..1d33e9dc93 100644 --- a/src/pretix/control/templates/pretixcontrol/organizers/edit.html +++ b/src/pretix/control/templates/pretixcontrol/organizers/edit.html @@ -22,54 +22,68 @@ {% csrf_token %} {% bootstrap_form_errors sform %} {% bootstrap_form_errors form %} -
-
- {% trans "General" %} - {% bootstrap_field form.name layout="control" %} - {% bootstrap_field form.slug layout="control" %} - {% if form.domain %} - {% bootstrap_field form.domain layout="control" %} - {% endif %} - {% bootstrap_field sform.imprint_url layout="control" %} - {% bootstrap_field sform.contact_mail layout="control" %} - {% bootstrap_field sform.organizer_info_text layout="control" %} - {% bootstrap_field sform.event_team_provisioning layout="control" %} -
-
- {% trans "Organizer page" %} - {% bootstrap_field sform.organizer_logo_image layout="control" %} - {% bootstrap_field sform.organizer_logo_image_large layout="control" %} - {% bootstrap_field sform.organizer_homepage_text layout="control" %} - {% bootstrap_field sform.event_list_type layout="control" %} - {% bootstrap_field sform.event_list_availability layout="control" %} - {% bootstrap_field sform.organizer_link_back layout="control" %} -
-
- {% trans "Localization" %} - {% bootstrap_field sform.locales layout="control" %} - {% bootstrap_field sform.region layout="control" %} -
-
- {% trans "Shop design" %} -

- {% blocktrans trimmed %} - These settings will be used for the organizer page as well as for the default settings - for all events in this account that do not have their own design settings. - {% endblocktrans %} -

- {% bootstrap_field sform.primary_color layout="control" %} - {% bootstrap_field sform.theme_color_success layout="control" %} - {% bootstrap_field sform.theme_color_danger layout="control" %} - {% bootstrap_field sform.theme_color_background layout="control" %} - {% bootstrap_field sform.theme_round_borders layout="control" %} - {% bootstrap_field sform.primary_font layout="control" %} - {% bootstrap_field sform.favicon layout="control" %} -
-
- {% trans "Gift cards" %} - {% bootstrap_field sform.giftcard_expiry_years layout="control" %} - {% bootstrap_field sform.giftcard_length layout="control" %} -
+
+
+
+
+ {% trans "General" %} + {% bootstrap_field form.name layout="control" %} + {% bootstrap_field form.slug layout="control" %} + {% if form.domain %} + {% bootstrap_field form.domain layout="control" %} + {% endif %} + {% bootstrap_field sform.imprint_url layout="control" %} + {% bootstrap_field sform.contact_mail layout="control" %} + {% bootstrap_field sform.organizer_info_text layout="control" %} + {% bootstrap_field sform.event_team_provisioning layout="control" %} +
+
+ {% trans "Organizer page" %} + {% bootstrap_field sform.organizer_logo_image layout="control" %} + {% bootstrap_field sform.organizer_logo_image_large layout="control" %} + {% bootstrap_field sform.organizer_homepage_text layout="control" %} + {% bootstrap_field sform.event_list_type layout="control" %} + {% bootstrap_field sform.event_list_availability layout="control" %} + {% bootstrap_field sform.organizer_link_back layout="control" %} +
+
+ {% trans "Localization" %} + {% bootstrap_field sform.locales layout="control" %} + {% bootstrap_field sform.region layout="control" %} +
+
+ {% trans "Shop design" %} +

+ {% blocktrans trimmed %} + These settings will be used for the organizer page as well as for the default settings + for all events in this account that do not have their own design settings. + {% endblocktrans %} +

+ {% bootstrap_field sform.primary_color layout="control" %} + {% bootstrap_field sform.theme_color_success layout="control" %} + {% bootstrap_field sform.theme_color_danger layout="control" %} + {% bootstrap_field sform.theme_color_background layout="control" %} + {% bootstrap_field sform.theme_round_borders layout="control" %} + {% bootstrap_field sform.primary_font layout="control" %} + {% bootstrap_field sform.favicon layout="control" %} +
+
+ {% trans "Gift cards" %} + {% bootstrap_field sform.giftcard_expiry_years layout="control" %} + {% bootstrap_field sform.giftcard_length layout="control" %} +
+
+
+
+
+
+

+ {% trans "Change history" %} +

+
+ {% include "pretixcontrol/includes/logs.html" with obj=organizer %} +
+
+

+ + + {% include "pretixcontrol/pagination.html" %} +{% endblock %} diff --git a/src/pretix/control/urls.py b/src/pretix/control/urls.py index cae129e67e..2ebd95149f 100644 --- a/src/pretix/control/urls.py +++ b/src/pretix/control/urls.py @@ -122,6 +122,7 @@ urlpatterns = [ url(r'^organizer/(?P[^/]+)/team/(?P[^/]+)/delete$', organizer.TeamDeleteView.as_view(), name='organizer.team.delete'), url(r'^organizer/(?P[^/]+)/slugrng', main.SlugRNG.as_view(), name='events.add.slugrng'), + url(r'^organizer/(?P[^/]+)/logs', organizer.LogView.as_view(), name='organizer.log'), url(r'^organizer/(?P[^/]+)/export/$', organizer.ExportView.as_view(), name='organizer.export'), url(r'^organizer/(?P[^/]+)/export/do$', organizer.ExportDoView.as_view(), name='organizer.export.do'), url(r'^nav/typeahead/$', typeahead.nav_context_list, name='nav.typeahead'), diff --git a/src/pretix/control/views/organizer.py b/src/pretix/control/views/organizer.py index dd224f8f05..b572502a46 100644 --- a/src/pretix/control/views/organizer.py +++ b/src/pretix/control/views/organizer.py @@ -51,6 +51,7 @@ from pretix.control.forms.organizer import ( GiftCardUpdateForm, OrganizerDeleteForm, OrganizerForm, OrganizerSettingsForm, OrganizerUpdateForm, TeamForm, WebHookForm, ) +from pretix.control.logdisplay import OVERVIEW_BANLIST from pretix.control.permissions import ( AdministratorPermissionRequiredMixin, OrganizerPermissionRequiredMixin, ) @@ -1434,3 +1435,24 @@ class EventMetaPropertyDeleteView(OrganizerDetailViewMixin, OrganizerPermissionR self.object.delete() messages.success(request, _('The selected property has been deleted.')) return redirect(success_url) + + +class LogView(OrganizerPermissionRequiredMixin, ListView): + template_name = 'pretixcontrol/organizers/logs.html' + permission = 'can_change_organizer_settings' + model = LogEntry + context_object_name = 'logs' + paginate_by = 20 + + def get_queryset(self): + qs = self.request.organizer.all_logentries().select_related( + 'user', 'content_type', 'api_token', 'oauth_application', 'device' + ).order_by('-datetime') + qs = qs.exclude(action_type__in=OVERVIEW_BANLIST) + if self.request.GET.get('user'): + qs = qs.filter(user_id=self.request.GET.get('user')) + return qs + + def get_context_data(self, **kwargs): + ctx = super().get_context_data() + return ctx