forked from CGM_Public/pretix_original
Allow to inspect organizer-level logs
This commit is contained in:
@@ -4,6 +4,7 @@ from datetime import date, datetime, time
|
|||||||
from django.core.validators import MinLengthValidator, RegexValidator
|
from django.core.validators import MinLengthValidator, RegexValidator
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Exists, OuterRef, Q
|
from django.db.models import Exists, OuterRef, Q
|
||||||
|
from django.urls import reverse
|
||||||
from django.utils.crypto import get_random_string
|
from django.utils.crypto import get_random_string
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.timezone import get_current_timezone, make_aware, now
|
from django.utils.timezone import get_current_timezone, make_aware, now
|
||||||
@@ -88,6 +89,15 @@ class Organizer(LoggedModel):
|
|||||||
|
|
||||||
return ObjectRelatedCache(self)
|
return ObjectRelatedCache(self)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def all_logentries_link(self):
|
||||||
|
return reverse(
|
||||||
|
'control:organizer.log',
|
||||||
|
kwargs={
|
||||||
|
'organizer': self.slug,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def has_gift_cards(self):
|
def has_gift_cards(self):
|
||||||
return self.cache.get_or_set(
|
return self.cache.get_or_set(
|
||||||
|
|||||||
@@ -273,8 +273,15 @@ def _display_checkin(event, logentry):
|
|||||||
def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs):
|
def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs):
|
||||||
plains = {
|
plains = {
|
||||||
'pretix.object.cloned': _('This object has been created by cloning.'),
|
'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.comment': _('The event\'s internal comment has been updated.'),
|
||||||
'pretix.event.canceled': _('The event has been canceled.'),
|
'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.modified': _('The order details have been changed.'),
|
||||||
'pretix.event.order.unpaid': _('The order has been marked as unpaid.'),
|
'pretix.event.order.unpaid': _('The order has been marked as unpaid.'),
|
||||||
'pretix.event.order.secret.changed': _('The order\'s secret has been changed.'),
|
'pretix.event.order.secret.changed': _('The order\'s secret has been changed.'),
|
||||||
|
|||||||
@@ -22,54 +22,68 @@
|
|||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% bootstrap_form_errors sform %}
|
{% bootstrap_form_errors sform %}
|
||||||
{% bootstrap_form_errors form %}
|
{% bootstrap_form_errors form %}
|
||||||
<div class="tabbed-form">
|
<div class="row">
|
||||||
<fieldset>
|
<div class="col-xs-12 col-lg-10">
|
||||||
<legend>{% trans "General" %}</legend>
|
<div class="tabbed-form">
|
||||||
{% bootstrap_field form.name layout="control" %}
|
<fieldset>
|
||||||
{% bootstrap_field form.slug layout="control" %}
|
<legend>{% trans "General" %}</legend>
|
||||||
{% if form.domain %}
|
{% bootstrap_field form.name layout="control" %}
|
||||||
{% bootstrap_field form.domain layout="control" %}
|
{% bootstrap_field form.slug layout="control" %}
|
||||||
{% endif %}
|
{% if form.domain %}
|
||||||
{% bootstrap_field sform.imprint_url layout="control" %}
|
{% bootstrap_field form.domain layout="control" %}
|
||||||
{% bootstrap_field sform.contact_mail layout="control" %}
|
{% endif %}
|
||||||
{% bootstrap_field sform.organizer_info_text layout="control" %}
|
{% bootstrap_field sform.imprint_url layout="control" %}
|
||||||
{% bootstrap_field sform.event_team_provisioning layout="control" %}
|
{% bootstrap_field sform.contact_mail layout="control" %}
|
||||||
</fieldset>
|
{% bootstrap_field sform.organizer_info_text layout="control" %}
|
||||||
<fieldset>
|
{% bootstrap_field sform.event_team_provisioning layout="control" %}
|
||||||
<legend>{% trans "Organizer page" %}</legend>
|
</fieldset>
|
||||||
{% bootstrap_field sform.organizer_logo_image layout="control" %}
|
<fieldset>
|
||||||
{% bootstrap_field sform.organizer_logo_image_large layout="control" %}
|
<legend>{% trans "Organizer page" %}</legend>
|
||||||
{% bootstrap_field sform.organizer_homepage_text layout="control" %}
|
{% bootstrap_field sform.organizer_logo_image layout="control" %}
|
||||||
{% bootstrap_field sform.event_list_type layout="control" %}
|
{% bootstrap_field sform.organizer_logo_image_large layout="control" %}
|
||||||
{% bootstrap_field sform.event_list_availability layout="control" %}
|
{% bootstrap_field sform.organizer_homepage_text layout="control" %}
|
||||||
{% bootstrap_field sform.organizer_link_back layout="control" %}
|
{% bootstrap_field sform.event_list_type layout="control" %}
|
||||||
</fieldset>
|
{% bootstrap_field sform.event_list_availability layout="control" %}
|
||||||
<fieldset>
|
{% bootstrap_field sform.organizer_link_back layout="control" %}
|
||||||
<legend>{% trans "Localization" %}</legend>
|
</fieldset>
|
||||||
{% bootstrap_field sform.locales layout="control" %}
|
<fieldset>
|
||||||
{% bootstrap_field sform.region layout="control" %}
|
<legend>{% trans "Localization" %}</legend>
|
||||||
</fieldset>
|
{% bootstrap_field sform.locales layout="control" %}
|
||||||
<fieldset>
|
{% bootstrap_field sform.region layout="control" %}
|
||||||
<legend>{% trans "Shop design" %}</legend>
|
</fieldset>
|
||||||
<p class="help-block">
|
<fieldset>
|
||||||
{% blocktrans trimmed %}
|
<legend>{% trans "Shop design" %}</legend>
|
||||||
These settings will be used for the organizer page as well as for the default settings
|
<p class="help-block">
|
||||||
for all events in this account that do not have their own design settings.
|
{% blocktrans trimmed %}
|
||||||
{% endblocktrans %}
|
These settings will be used for the organizer page as well as for the default settings
|
||||||
</p>
|
for all events in this account that do not have their own design settings.
|
||||||
{% bootstrap_field sform.primary_color layout="control" %}
|
{% endblocktrans %}
|
||||||
{% bootstrap_field sform.theme_color_success layout="control" %}
|
</p>
|
||||||
{% bootstrap_field sform.theme_color_danger layout="control" %}
|
{% bootstrap_field sform.primary_color layout="control" %}
|
||||||
{% bootstrap_field sform.theme_color_background layout="control" %}
|
{% bootstrap_field sform.theme_color_success layout="control" %}
|
||||||
{% bootstrap_field sform.theme_round_borders layout="control" %}
|
{% bootstrap_field sform.theme_color_danger layout="control" %}
|
||||||
{% bootstrap_field sform.primary_font layout="control" %}
|
{% bootstrap_field sform.theme_color_background layout="control" %}
|
||||||
{% bootstrap_field sform.favicon layout="control" %}
|
{% bootstrap_field sform.theme_round_borders layout="control" %}
|
||||||
</fieldset>
|
{% bootstrap_field sform.primary_font layout="control" %}
|
||||||
<fieldset>
|
{% bootstrap_field sform.favicon layout="control" %}
|
||||||
<legend>{% trans "Gift cards" %}</legend>
|
</fieldset>
|
||||||
{% bootstrap_field sform.giftcard_expiry_years layout="control" %}
|
<fieldset>
|
||||||
{% bootstrap_field sform.giftcard_length layout="control" %}
|
<legend>{% trans "Gift cards" %}</legend>
|
||||||
</fieldset>
|
{% bootstrap_field sform.giftcard_expiry_years layout="control" %}
|
||||||
|
{% bootstrap_field sform.giftcard_length layout="control" %}
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-12 col-lg-2">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h3 class="panel-title">
|
||||||
|
{% trans "Change history" %}
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
{% include "pretixcontrol/includes/logs.html" with obj=organizer %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group submit-group">
|
<div class="form-group submit-group">
|
||||||
<button type="submit" class="btn btn-primary btn-save">
|
<button type="submit" class="btn btn-primary btn-save">
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
{% extends "pretixcontrol/items/base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load static %}
|
||||||
|
{% block title %}{% trans "Organizer logs" %}{% endblock %}
|
||||||
|
{% block inside %}
|
||||||
|
<h1>{% trans "Organizer logs" %}</h1>
|
||||||
|
<form class="form-inline helper-display-inline" action="" method="get">
|
||||||
|
<input type="hidden" name="content_type" value="{{ request.GET.content_type }}">
|
||||||
|
<input type="hidden" name="object" value="{{ request.GET.object }}">
|
||||||
|
<p>
|
||||||
|
<select name="user" class="form-control">
|
||||||
|
<option value="">{% trans "All actions" %}</option>
|
||||||
|
{% for up in userlist %}
|
||||||
|
{% if up.user__id %}
|
||||||
|
<option value="{{ up.user__id }}"
|
||||||
|
{% if request.GET.user == up.user__id %}selected="selected"{% endif %}>
|
||||||
|
{{ up.user__email }}
|
||||||
|
</option>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
<button class="btn btn-primary" type="submit">{% trans "Filter" %}</button>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
<ul class="list-group">
|
||||||
|
{% for log in logs %}
|
||||||
|
<li class="list-group-item logentry">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-2 col-sm-6 col-xs-12">
|
||||||
|
<span class="fa fa-clock-o"></span>
|
||||||
|
{{ log.datetime|date:"SHORT_DATETIME_FORMAT" }}
|
||||||
|
{% if log.shredded %}
|
||||||
|
<span class="fa fa-eraser fa-danger fa-fw"
|
||||||
|
data-toggle="tooltip"
|
||||||
|
title="{% trans "Personal data was cleared from this log entry." %}">
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-2 col-sm-6 col-xs-12">
|
||||||
|
{% if log.user %}
|
||||||
|
{% if log.user.is_staff %}
|
||||||
|
<span class="fa fa-id-card fa-danger fa-fw"
|
||||||
|
data-toggle="tooltip"
|
||||||
|
title="{% trans "This change was performed by a pretix administrator." %}">
|
||||||
|
</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="fa fa-user fa-fw"></span>
|
||||||
|
{% endif %}
|
||||||
|
{{ log.user.get_full_name }}
|
||||||
|
{% if log.oauth_application %}
|
||||||
|
<br><span class="fa fa-plug fa-fw"></span>
|
||||||
|
{{ log.oauth_application.name }}
|
||||||
|
{% endif %}
|
||||||
|
{% elif log.device %}
|
||||||
|
<span class="fa fa-mobile fa-fw"></span>
|
||||||
|
{{ log.device.name }}
|
||||||
|
{% elif log.api_token %}
|
||||||
|
<span class="fa fa-key fa-fw"></span>
|
||||||
|
{{ log.api_token.name }}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-2 col-sm-12 col-xs-12">
|
||||||
|
{% if log.display_object %}
|
||||||
|
<span class="fa fa-flag"></span> {{ log.display_object|safe }}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-6 col-sm-12 col-xs-12">
|
||||||
|
{{ log.display }}
|
||||||
|
{% if staff_session %}
|
||||||
|
<a href="" class="btn btn-default btn-xs" data-expandlogs data-id="{{ log.pk }}">
|
||||||
|
<span class="fa-eye fa fa-fw"></span>
|
||||||
|
{% trans "Inspect" %}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{% empty %}
|
||||||
|
<div class="list-group-item">
|
||||||
|
<em>{% trans "No results" %}</em>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% include "pretixcontrol/pagination.html" %}
|
||||||
|
{% endblock %}
|
||||||
@@ -122,6 +122,7 @@ urlpatterns = [
|
|||||||
url(r'^organizer/(?P<organizer>[^/]+)/team/(?P<team>[^/]+)/delete$', organizer.TeamDeleteView.as_view(),
|
url(r'^organizer/(?P<organizer>[^/]+)/team/(?P<team>[^/]+)/delete$', organizer.TeamDeleteView.as_view(),
|
||||||
name='organizer.team.delete'),
|
name='organizer.team.delete'),
|
||||||
url(r'^organizer/(?P<organizer>[^/]+)/slugrng', main.SlugRNG.as_view(), name='events.add.slugrng'),
|
url(r'^organizer/(?P<organizer>[^/]+)/slugrng', main.SlugRNG.as_view(), name='events.add.slugrng'),
|
||||||
|
url(r'^organizer/(?P<organizer>[^/]+)/logs', organizer.LogView.as_view(), name='organizer.log'),
|
||||||
url(r'^organizer/(?P<organizer>[^/]+)/export/$', organizer.ExportView.as_view(), name='organizer.export'),
|
url(r'^organizer/(?P<organizer>[^/]+)/export/$', organizer.ExportView.as_view(), name='organizer.export'),
|
||||||
url(r'^organizer/(?P<organizer>[^/]+)/export/do$', organizer.ExportDoView.as_view(), name='organizer.export.do'),
|
url(r'^organizer/(?P<organizer>[^/]+)/export/do$', organizer.ExportDoView.as_view(), name='organizer.export.do'),
|
||||||
url(r'^nav/typeahead/$', typeahead.nav_context_list, name='nav.typeahead'),
|
url(r'^nav/typeahead/$', typeahead.nav_context_list, name='nav.typeahead'),
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ from pretix.control.forms.organizer import (
|
|||||||
GiftCardUpdateForm, OrganizerDeleteForm, OrganizerForm,
|
GiftCardUpdateForm, OrganizerDeleteForm, OrganizerForm,
|
||||||
OrganizerSettingsForm, OrganizerUpdateForm, TeamForm, WebHookForm,
|
OrganizerSettingsForm, OrganizerUpdateForm, TeamForm, WebHookForm,
|
||||||
)
|
)
|
||||||
|
from pretix.control.logdisplay import OVERVIEW_BANLIST
|
||||||
from pretix.control.permissions import (
|
from pretix.control.permissions import (
|
||||||
AdministratorPermissionRequiredMixin, OrganizerPermissionRequiredMixin,
|
AdministratorPermissionRequiredMixin, OrganizerPermissionRequiredMixin,
|
||||||
)
|
)
|
||||||
@@ -1434,3 +1435,24 @@ class EventMetaPropertyDeleteView(OrganizerDetailViewMixin, OrganizerPermissionR
|
|||||||
self.object.delete()
|
self.object.delete()
|
||||||
messages.success(request, _('The selected property has been deleted.'))
|
messages.success(request, _('The selected property has been deleted.'))
|
||||||
return redirect(success_url)
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user