Redirecting to proper stop URL when a session reaches MAX_DURATION. This is to ensure the signals are called properly. Closes ~petersanchez/django-impersonate#60
4 files changed, 23 insertions(+), 26 deletions(-)

M impersonate/middleware.py
M impersonate/tests.py
M impersonate/urls.py
M impersonate/views.py
M impersonate/middleware.py +4 -7
@@ 2,6 2,7 @@ 
 from datetime import datetime, timedelta
 
 from django.http import HttpResponseNotAllowed
+from django.shortcuts import redirect
 from django.utils import timezone
 from django.utils.deprecation import MiddlewareMixin
 from django.utils.functional import SimpleLazyObject

          
@@ 31,14 32,10 @@ class ImpersonateMiddleware(MiddlewareMi
                 start_time = datetime.fromtimestamp(
                     request.session['_impersonate_start'], timezone.utc
                 )
+                delta = timedelta(seconds=settings.MAX_DURATION)
 
-                if datetime.now(timezone.utc) - start_time > timedelta(
-                    seconds=settings.MAX_DURATION
-                ):
-                    del request.session['_impersonate']
-                    del request.session['_impersonate_start']
-
-                    return
+                if datetime.now(timezone.utc) - start_time > delta:
+                    return redirect('impersonate-stop')
 
             new_user_id = request.session['_impersonate']
             if isinstance(new_user_id, User):

          
M impersonate/tests.py +5 -6
@@ 170,12 170,9 @@ class TestMiddleware(TestCase):
                 datetime.now(timezone.utc) - timedelta(seconds=3601)
             ).timestamp(),
         }
-        self.middleware.process_request(request)
-
-        self.assertEqual(request.user, self.superuser)
-        self.assertFalse(request.user.is_impersonate)
-        self.assertNotIn('_impersonate', request.session)
-        self.assertNotIn('_impersonate_start', request.session)
+        response = self.middleware.process_request(request)
+        self.assertEqual(response.status_code, 302)
+        self.assertEqual(response.get('Location'), reverse('impersonate-stop'))
 
     def test_not_impersonated_request(self, use_id=True):
         """Check the real_user request attr is set correctly when **not** impersonating."""

          
@@ 264,8 261,10 @@ class TestImpersonation(TestCase):
     def test_successful_impersonation(self):
         self._impersonate_helper('user1', 'foobar', 4)
         self.assertEqual(self.client.session['_impersonate'], 4)
+        self.assertIn('_impersonate_start', self.client.session)
         self.client.get(reverse('impersonate-stop'))
         self.assertEqual(self.client.session.get('_impersonate'), None)
+        self.assertNotIn('_impersonate_start', self.client.session)
         self.client.logout()
 
     def test_successful_impersonation_signals(self):

          
M impersonate/urls.py +10 -11
@@ 3,20 3,19 @@ from django.urls import path
 
 from . import views
 
-
 urlpatterns = [
-    path('stop/',
-        views.stop_impersonate,
-        name='impersonate-stop'),
-    path('list/',
+    path('stop/', views.stop_impersonate, name='impersonate-stop'),
+    path(
+        'list/',
         views.list_users,
         {'template': 'impersonate/list_users.html'},
-        name='impersonate-list'),
-    path('search/',
+        name='impersonate-list',
+    ),
+    path(
+        'search/',
         views.search_users,
         {'template': 'impersonate/search_users.html'},
-        name='impersonate-search'),
-    path('<path:uid>/',
-        views.impersonate,
-        name='impersonate-start'),
+        name='impersonate-search',
+    ),
+    path('<path:uid>/', views.impersonate, name='impersonate-start'),
 ]

          
M impersonate/views.py +4 -2
@@ 77,11 77,12 @@ def stop_impersonate(request):
             )
             impersonating = None
 
+    use_refer = settings.USE_HTTP_REFERER
+    request.session.pop('_impersonate_start', None)
     original_path = request.session.pop('_impersonate_prev_path', None)
-    use_refer = settings.USE_HTTP_REFERER
+    request.session.modified = True
 
     if impersonating is not None:
-        request.session.modified = True
         session_end.send(
             sender=None,
             impersonator=request.impersonator,

          
@@ 94,6 95,7 @@ def stop_impersonate(request):
         if original_path and use_refer
         else get_redir_path(request)
     )
+
     return redirect(dest)