forked from CGM_Public/pretix_original
Allow administrators to impersonate other users
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
{% load compress %}
|
{% load compress %}
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
{% load hijack_tags %}
|
||||||
{% load statici18n %}
|
{% load statici18n %}
|
||||||
{% load eventurl %}
|
{% load eventurl %}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
@@ -258,6 +259,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
{% if request|is_hijacked %}
|
||||||
|
<div class="impersonate-warning">
|
||||||
|
<span class="fa fa-user-secret"></span>
|
||||||
|
{% blocktrans with user=request.user%}You are currently working on behalf of {{ user }}.{% endblocktrans %}
|
||||||
|
|
||||||
|
<form action="{% url 'control:users.impersonate.stop' %}" method="post" class="helper-display-inline">
|
||||||
|
{% csrf_token %}
|
||||||
|
<button class="btn btn-default btn-sm">
|
||||||
|
{% trans "Stop impersonating" %}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<div id="page-wrapper">
|
<div id="page-wrapper">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
{% if messages %}
|
{% if messages %}
|
||||||
|
|||||||
@@ -9,6 +9,10 @@
|
|||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<button class="btn btn-default">{% trans "Send password reset email" %}</button>
|
<button class="btn btn-default">{% trans "Send password reset email" %}</button>
|
||||||
</form>
|
</form>
|
||||||
|
<form action="{% url "control:users.impersonate" id=user.pk %}" method="post" class="form-inline helper-display-inline">
|
||||||
|
{% csrf_token %}
|
||||||
|
<button class="btn btn-default">{% trans "Impersonate user" %}</button>
|
||||||
|
</form>
|
||||||
</p>
|
</p>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-10 col-xs-12">
|
<div class="col-md-10 col-xs-12">
|
||||||
|
|||||||
@@ -21,8 +21,10 @@ urlpatterns = [
|
|||||||
url(r'^users/$', users.UserListView.as_view(), name='users'),
|
url(r'^users/$', users.UserListView.as_view(), name='users'),
|
||||||
url(r'^users/select2$', typeahead.users_select2, name='users.select2'),
|
url(r'^users/select2$', typeahead.users_select2, name='users.select2'),
|
||||||
url(r'^users/add$', users.UserCreateView.as_view(), name='users.add'),
|
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<id>\d+)/$', users.UserEditView.as_view(), name='users.edit'),
|
url(r'^users/(?P<id>\d+)/$', users.UserEditView.as_view(), name='users.edit'),
|
||||||
url(r'^users/(?P<id>\d+)/reset$', users.UserResetView.as_view(), name='users.reset'),
|
url(r'^users/(?P<id>\d+)/reset$', users.UserResetView.as_view(), name='users.reset'),
|
||||||
|
url(r'^users/(?P<id>\d+)/impersonate', users.UserImpersonateView.as_view(), name='users.impersonate'),
|
||||||
url(r'^settings/?$', user.UserSettings.as_view(), name='user.settings'),
|
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/history/$', user.UserHistoryView.as_view(), name='user.settings.history'),
|
||||||
url(r'^settings/notifications/$', user.UserNotificationsEditView.as_view(), name='user.settings.notifications'),
|
url(r'^settings/notifications/$', user.UserNotificationsEditView.as_view(), name='user.settings.notifications'),
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.shortcuts import get_object_or_404, redirect
|
from django.shortcuts import get_object_or_404, redirect
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.views import View
|
from django.views import View
|
||||||
from django.views.generic import ListView
|
from django.views.generic import ListView
|
||||||
|
from hijack.helpers import login_user, release_hijack
|
||||||
|
|
||||||
from pretix.base.models import User
|
from pretix.base.models import User
|
||||||
from pretix.base.services.mail import SendMailException
|
from pretix.base.services.mail import SendMailException
|
||||||
@@ -76,6 +78,9 @@ class UserEditView(AdministratorPermissionRequiredMixin, RecentAuthenticationReq
|
|||||||
|
|
||||||
class UserResetView(AdministratorPermissionRequiredMixin, RecentAuthenticationRequiredMixin, View):
|
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):
|
def post(self, request, *args, **kwargs):
|
||||||
self.object = get_object_or_404(User, pk=self.kwargs.get("id"))
|
self.object = get_object_or_404(User, pk=self.kwargs.get("id"))
|
||||||
try:
|
try:
|
||||||
@@ -93,6 +98,24 @@ class UserResetView(AdministratorPermissionRequiredMixin, RecentAuthenticationRe
|
|||||||
return reverse('control:users.edit', kwargs=self.kwargs)
|
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):
|
class UserCreateView(AdministratorPermissionRequiredMixin, RecentAuthenticationRequiredMixin, CreateView):
|
||||||
template_name = 'pretixcontrol/users/create.html'
|
template_name = 'pretixcontrol/users/create.html'
|
||||||
context_object_name = 'user'
|
context_object_name = 'user'
|
||||||
|
|||||||
@@ -226,7 +226,9 @@ INSTALLED_APPS = [
|
|||||||
'django_otp.plugins.otp_totp',
|
'django_otp.plugins.otp_totp',
|
||||||
'django_otp.plugins.otp_static',
|
'django_otp.plugins.otp_static',
|
||||||
'statici18n',
|
'statici18n',
|
||||||
'django_countries'
|
'django_countries',
|
||||||
|
'hijack',
|
||||||
|
'compat',
|
||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -419,6 +419,22 @@ body.loading #wrapper {
|
|||||||
width: 30%;
|
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 {
|
.quotabox {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ markdown
|
|||||||
bleach==2.*
|
bleach==2.*
|
||||||
raven
|
raven
|
||||||
django-i18nfield>=1.2.1
|
django-i18nfield>=1.2.1
|
||||||
|
django-hijack==2.1.*
|
||||||
# Stripe
|
# Stripe
|
||||||
stripe==1.62.*
|
stripe==1.62.*
|
||||||
# PayPal
|
# PayPal
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ setup(
|
|||||||
'pyuca',
|
'pyuca',
|
||||||
'defusedcsv',
|
'defusedcsv',
|
||||||
'vat_moss==0.11.0',
|
'vat_moss==0.11.0',
|
||||||
|
'django-hijack==2.1.*'
|
||||||
],
|
],
|
||||||
extras_require={
|
extras_require={
|
||||||
'dev': [
|
'dev': [
|
||||||
|
|||||||
Reference in New Issue
Block a user