From 14da25bd9ed51265e11cc03168360344462853e8 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Mon, 29 Jan 2018 11:15:32 +0100 Subject: [PATCH] Allow administrators to impersonate other users --- .../control/templates/pretixcontrol/base.html | 14 +++++++++++ .../templates/pretixcontrol/users/form.html | 4 ++++ src/pretix/control/urls.py | 2 ++ src/pretix/control/views/users.py | 23 +++++++++++++++++++ src/pretix/settings.py | 4 +++- .../static/pretixcontrol/scss/main.scss | 16 +++++++++++++ src/requirements/production.txt | 1 + src/setup.py | 1 + 8 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/pretix/control/templates/pretixcontrol/base.html b/src/pretix/control/templates/pretixcontrol/base.html index 446da9d997..dcd47d7eaf 100644 --- a/src/pretix/control/templates/pretixcontrol/base.html +++ b/src/pretix/control/templates/pretixcontrol/base.html @@ -1,6 +1,7 @@ {% load compress %} {% load staticfiles %} {% load i18n %} +{% load hijack_tags %} {% load statici18n %} {% load eventurl %} @@ -258,6 +259,19 @@ + {% if request|is_hijacked %} +
+ + {% blocktrans with user=request.user%}You are currently working on behalf of {{ user }}.{% endblocktrans %} + +
+ {% csrf_token %} + +
+
+ {% endif %}
{% if messages %} diff --git a/src/pretix/control/templates/pretixcontrol/users/form.html b/src/pretix/control/templates/pretixcontrol/users/form.html index 484a29e6d9..ad1c9c7582 100644 --- a/src/pretix/control/templates/pretixcontrol/users/form.html +++ b/src/pretix/control/templates/pretixcontrol/users/form.html @@ -9,6 +9,10 @@ {% csrf_token %} +
+ {% csrf_token %} + +

diff --git a/src/pretix/control/urls.py b/src/pretix/control/urls.py index fad11adecf..d099abe209 100644 --- a/src/pretix/control/urls.py +++ b/src/pretix/control/urls.py @@ -21,8 +21,10 @@ urlpatterns = [ url(r'^users/$', users.UserListView.as_view(), name='users'), url(r'^users/select2$', typeahead.users_select2, name='users.select2'), url(r'^users/add$', users.UserCreateView.as_view(), name='users.add'), + url(r'^users/impersonate/stop', users.UserImpersonateStopView.as_view(), name='users.impersonate.stop'), url(r'^users/(?P\d+)/$', users.UserEditView.as_view(), name='users.edit'), url(r'^users/(?P\d+)/reset$', users.UserResetView.as_view(), name='users.reset'), + url(r'^users/(?P\d+)/impersonate', users.UserImpersonateView.as_view(), name='users.impersonate'), url(r'^settings/?$', user.UserSettings.as_view(), name='user.settings'), url(r'^settings/history/$', user.UserHistoryView.as_view(), name='user.settings.history'), url(r'^settings/notifications/$', user.UserNotificationsEditView.as_view(), name='user.settings.notifications'), diff --git a/src/pretix/control/views/users.py b/src/pretix/control/views/users.py index 9cca4cc127..a790a850f7 100644 --- a/src/pretix/control/views/users.py +++ b/src/pretix/control/views/users.py @@ -1,11 +1,13 @@ from django.conf import settings from django.contrib import messages +from django.contrib.auth.mixins import LoginRequiredMixin from django.shortcuts import get_object_or_404, redirect from django.urls import reverse from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ from django.views import View from django.views.generic import ListView +from hijack.helpers import login_user, release_hijack from pretix.base.models import User from pretix.base.services.mail import SendMailException @@ -76,6 +78,9 @@ class UserEditView(AdministratorPermissionRequiredMixin, RecentAuthenticationReq class UserResetView(AdministratorPermissionRequiredMixin, RecentAuthenticationRequiredMixin, View): + def get(self, request, *args, **kwargs): + return redirect(reverse('control:users.edit', kwargs=self.kwargs)) + def post(self, request, *args, **kwargs): self.object = get_object_or_404(User, pk=self.kwargs.get("id")) try: @@ -93,6 +98,24 @@ class UserResetView(AdministratorPermissionRequiredMixin, RecentAuthenticationRe return reverse('control:users.edit', kwargs=self.kwargs) +class UserImpersonateView(AdministratorPermissionRequiredMixin, RecentAuthenticationRequiredMixin, View): + + def get(self, request, *args, **kwargs): + return redirect(reverse('control:users.edit', kwargs=self.kwargs)) + + def post(self, request, *args, **kwargs): + self.object = get_object_or_404(User, pk=self.kwargs.get("id")) + login_user(request, self.object) + return redirect(reverse('control:index')) + + +class UserImpersonateStopView(LoginRequiredMixin, View): + + def post(self, request, *args, **kwargs): + release_hijack(request) + return redirect(reverse('control:index')) + + class UserCreateView(AdministratorPermissionRequiredMixin, RecentAuthenticationRequiredMixin, CreateView): template_name = 'pretixcontrol/users/create.html' context_object_name = 'user' diff --git a/src/pretix/settings.py b/src/pretix/settings.py index 13321ac81a..d731ab0ecf 100644 --- a/src/pretix/settings.py +++ b/src/pretix/settings.py @@ -226,7 +226,9 @@ INSTALLED_APPS = [ 'django_otp.plugins.otp_totp', 'django_otp.plugins.otp_static', 'statici18n', - 'django_countries' + 'django_countries', + 'hijack', + 'compat', ] try: diff --git a/src/pretix/static/pretixcontrol/scss/main.scss b/src/pretix/static/pretixcontrol/scss/main.scss index cc43c0041b..489e2b2a19 100644 --- a/src/pretix/static/pretixcontrol/scss/main.scss +++ b/src/pretix/static/pretixcontrol/scss/main.scss @@ -419,6 +419,22 @@ body.loading #wrapper { width: 30%; } +.impersonate-warning { + background-color: #ffe761; + background-image: -webkit-linear-gradient(-45deg, rgba(0, 0, 0, .04) 25%, transparent 25%, transparent 50%, rgba(0, 0, 0, .04) 50%, rgba(0, 0, 0, .04) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(0, 0, 0, .04) 25%, transparent 25%, transparent 50%, rgba(0, 0, 0, .04) 50%, rgba(0, 0, 0, .04) 75%, transparent 75%, transparent); + background-image: linear-gradient(135deg, rgba(0, 0, 0, .04) 25%, transparent 25%, transparent 50%, rgba(0, 0, 0, .04) 50%, rgba(0, 0, 0, .04) 75%, transparent 75%, transparent); + padding: 15px; +} + +@media(min-width:768px) { + .impersonate-warning { + position: inherit; + margin: 0 0 0 250px; + padding: 15px 30px; + } +} + .quotabox { display: inline-block; vertical-align: top; diff --git a/src/requirements/production.txt b/src/requirements/production.txt index 1078a1e275..82f1b339ad 100644 --- a/src/requirements/production.txt +++ b/src/requirements/production.txt @@ -31,6 +31,7 @@ markdown bleach==2.* raven django-i18nfield>=1.2.1 +django-hijack==2.1.* # Stripe stripe==1.62.* # PayPal diff --git a/src/setup.py b/src/setup.py index 83444c54c3..9816426a96 100644 --- a/src/setup.py +++ b/src/setup.py @@ -109,6 +109,7 @@ setup( 'pyuca', 'defusedcsv', 'vat_moss==0.11.0', + 'django-hijack==2.1.*' ], extras_require={ 'dev': [