Commit 529cdf7e authored by Enrico Zini's avatar Enrico Zini
Browse files

Moved Impersonate view to its own app, activate by POST instead of GET, made...

Moved Impersonate view to its own app, activate by POST instead of GET, made view work with any user model. refs: #12
parent 3e7c587b
...@@ -39,9 +39,9 @@ class VisitorMixin(NM2LayoutMixin): ...@@ -39,9 +39,9 @@ class VisitorMixin(NM2LayoutMixin):
# Implement impersonation if requested in session # Implement impersonation if requested in session
if self.visitor.is_admin: if self.visitor.is_admin:
key = self.request.session.get("impersonate", None) pk = self.request.session.get("impersonate", None)
if key is not None: if pk is not None:
p = bmodels.Person.lookup(key) p = bmodels.Person.objects.get(pk=pk)
if p is not None: if p is not None:
self.impersonator = self.visitor self.impersonator = self.visitor
self.visitor = p self.visitor = p
...@@ -121,11 +121,6 @@ class VisitPersonMixin(VisitorMixin): ...@@ -121,11 +121,6 @@ class VisitPersonMixin(VisitorMixin):
if "am_candidate" in self.person.perms: if "am_candidate" in self.person.perms:
res.append(NavLink( res.append(NavLink(
reverse("admin:backend_am_add") + f"?person={self.person.id}", _("Make AM"))) reverse("admin:backend_am_add") + f"?person={self.person.id}", _("Make AM")))
if self.visitor != self.person:
res.append(NavLink(
reverse("impersonate", kwargs={
"key": self.person.lookup_key}) + f"?url={self.request.build_absolute_uri()}",
_("Impersonate"), "random"))
if self.person.is_dd: if self.person.is_dd:
res.append(NavLink( res.append(NavLink(
reverse("mia_wat_ping", kwargs={"key": self.person.lookup_key}), _("WAT ping"), "heartbeat")) reverse("mia_wat_ping", kwargs={"key": self.person.lookup_key}), _("WAT ping"), "heartbeat"))
......
from django.contrib import admin
# Register your models here.
from django.apps import AppConfig
class ImpersonateConfig(AppConfig):
name = 'impersonate'
from django.db import models
# Create your models here.
from django.test import TestCase
# Create your tests here.
from __future__ import annotations
from django.urls import path
from . import views
urlpatterns = [
# Impersonate a user
path('impersonate/', views.Impersonate.as_view(), name="impersonate"),
]
from __future__ import annotations
from django.utils.translation import ugettext as _
from django.views.generic import View
from django.shortcuts import redirect
from django.core.exceptions import PermissionDenied
from django.contrib import messages
from django.contrib.auth import get_user_model
class Impersonate(View):
def post(self, request, *args, **kw):
User = get_user_model()
effective_user = getattr(request, "impersonator", None)
if effective_user is None:
effective_user = request.user
if not effective_user.is_authenticated or not effective_user.is_admin:
raise PermissionDenied
pk = request.POST.get("pk")
if pk is None:
del request.session["impersonate"]
messages.add_message(request, messages.INFO, _("Impersonation canceled"))
user = effective_user
else:
user = User.objects.get(pk=pk)
request.session["impersonate"] = user.pk
messages.info(request, _("Impersonating {}").format(user))
url = request.POST.get("next", None)
if url is None:
return redirect(user.get_absolute_url())
else:
return redirect(url)
...@@ -74,6 +74,7 @@ INSTALLED_APPS = [ ...@@ -74,6 +74,7 @@ INSTALLED_APPS = [
'sitechecks', 'sitechecks',
'deploy', 'deploy',
'signon', 'signon',
'impersonate',
] ]
MIDDLEWARE = [ MIDDLEWARE = [
......
...@@ -44,10 +44,9 @@ urlpatterns = [ ...@@ -44,10 +44,9 @@ urlpatterns = [
path('minechangelogs/', include("minechangelogs.urls")), path('minechangelogs/', include("minechangelogs.urls")),
path('sitechecks/', include("sitechecks.urls")), path('sitechecks/', include("sitechecks.urls")),
path('deploy/', include("deploy.urls")), path('deploy/', include("deploy.urls")),
path('rest/api/', include(router.urls)), path('rest/api/', include(router.urls)),
path('signon/', include("signon.urls")), path('signon/', include("signon.urls")),
path('impersonate/', include("impersonate.urls")),
# Uncomment the admin/doc line below to enable admin documentation: # Uncomment the admin/doc line below to enable admin documentation:
path('admin/doc/', include('django.contrib.admindocs.urls')), path('admin/doc/', include('django.contrib.admindocs.urls')),
......
...@@ -37,6 +37,13 @@ window.nm2.url_api_people = "{% url 'api_people' %}"; ...@@ -37,6 +37,13 @@ window.nm2.url_api_people = "{% url 'api_people' %}";
{% for link in navbar.person %} {% for link in navbar.person %}
<a class="dropdown-item" href="{{link.url}}">{% if link.icon %}<span class="fa fa-{{link.icon}}"></span> {% endif %}{{link.label}}</a> <a class="dropdown-item" href="{{link.url}}">{% if link.icon %}<span class="fa fa-{{link.icon}}"></span> {% endif %}{{link.label}}</a>
{% endfor %} {% endfor %}
{% if visitor != person %}
<form class="form-inline" method="POST" action="{% url 'impersonate' %}">{% csrf_token %}
<input type="hidden" name="pk" value="{{person.pk}}">
<input type="hidden" name="next" value="{{request.build_absolute_uri}}">
<button class="dropdown-item btn btn-link" type="submit"><span class="fa fa-random"></span> {% trans "Impersonate" %}</button>
</form>
{% endif %}
</div> </div>
</li> </li>
{% endif %} {% endif %}
...@@ -72,7 +79,10 @@ window.nm2.url_api_people = "{% url 'api_people' %}"; ...@@ -72,7 +79,10 @@ window.nm2.url_api_people = "{% url 'api_people' %}";
<div class="dropdown-menu dropdown-menu-right" role="menu" aria-labelledby="navbarDropdown"> <div class="dropdown-menu dropdown-menu-right" role="menu" aria-labelledby="navbarDropdown">
{% block visitor_menu %} {% block visitor_menu %}
{% if impersonator %} {% if impersonator %}
<a class="dropdown-item" href="{% url 'impersonate' %}?url={{request.build_absolute_uri}}"><span class="fa fa-random"></span> (really {{impersonator.lookup_key}})</a> <form class="form-inline" method="POST" action="{% url 'impersonate' %}">{% csrf_token %}
<input type="hidden" name="next" value="{{request.build_absolute_uri}}">
<button class="dropdown-item btn btn-link" type="submit"><span class="fa fa-random"></span> (really {{impersonator.lookup_key}})</button>
</form>
{% endif %} {% endif %}
{% if user.is_anonymous %} {% if user.is_anonymous %}
<a class="dropdown-item" href="{% url 'dm_claim' %}">{% trans "claim account" %}</a> <a class="dropdown-item" href="{% url 'dm_claim' %}">{% trans "claim account" %}</a>
...@@ -112,8 +122,10 @@ window.nm2.url_api_people = "{% url 'api_people' %}"; ...@@ -112,8 +122,10 @@ window.nm2.url_api_people = "{% url 'api_people' %}";
{% if impersonator %} {% if impersonator %}
<div id="impersonation" class="container-fluid bg-warning"> <div id="impersonation" class="container-fluid bg-warning">
<span class="badge badge-pill badge-light"><span class="fa fa-random"></span> {{impersonator.a_link}} as {{visitor.a_link}}</span> <span class="badge badge-pill badge-light"><span class="fa fa-random"></span> {{impersonator.a_link}} as {{visitor.a_link}}</span>
<a class="badge badge-pill badge-primary" href="{% url 'impersonate' %}?url={{request.build_absolute_uri}}">{% trans "Cancel" %}</a> <form class="form-inline" method="POST" action="{% url 'impersonate' %}">{% csrf_token %}
<br> <input type="hidden" name="next" value="{{request.build_absolute_uri}}">
<button class="badge badge-pill badge-primary" type="submit">{% trans "Cancel" %}</button>
</form>
{% for perm in visit_perms %}<span class="badge badge-pill badge-info mr-1">{{perm}}</span>{% endfor %} {% for perm in visit_perms %}<span class="badge badge-pill badge-info mr-1">{{perm}}</span>{% endfor %}
</div> </div>
{% endif %} {% endif %}
......
...@@ -2,8 +2,6 @@ from django.urls import path ...@@ -2,8 +2,6 @@ from django.urls import path
from . import views from . import views
urlpatterns = [ urlpatterns = [
# Impersonate a user
path('impersonate/<key>/', views.Impersonate.as_view(), name="impersonate"),
# Export database # Export database
path('db-export/', views.DBExport.as_view(), name="restricted_db_export"), path('db-export/', views.DBExport.as_view(), name="restricted_db_export"),
# Mailbox stats # Mailbox stats
......
...@@ -2,11 +2,8 @@ from __future__ import annotations ...@@ -2,11 +2,8 @@ from __future__ import annotations
from django import http from django import http
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.conf import settings from django.conf import settings
from django.shortcuts import redirect
from django.utils.translation import ugettext as _
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.views.generic import View from django.views.generic import View
from django.contrib import messages
from django.contrib.sites.shortcuts import get_current_site from django.contrib.sites.shortcuts import get_current_site
import backend.models as bmodels import backend.models as bmodels
import backend.const as const import backend.const as const
...@@ -114,26 +111,6 @@ class SalsaExport(VisitorMixin, View): ...@@ -114,26 +111,6 @@ class SalsaExport(VisitorMixin, View):
return res return res
class Impersonate(View):
def get(self, request, key=None, *args, **kw):
visitor = request.user
if not visitor.is_authenticated or not visitor.is_admin:
raise PermissionDenied
if key is None:
del request.session["impersonate"]
messages.add_message(request, messages.INFO, _("Impersonation canceled"))
else:
person = bmodels.Person.lookup_or_404(key)
request.session["impersonate"] = person.lookup_key
messages.info(request, _("Impersonating {}").format(person.lookup_key))
url = request.GET.get("url", None)
if url is None:
return redirect('home')
else:
return redirect(url)
class MailboxStats(VisitorTemplateView): class MailboxStats(VisitorTemplateView):
template_name = "restricted/mailbox-stats.html" template_name = "restricted/mailbox-stats.html"
require_visitor = "admin" require_visitor = "admin"
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment