c400cc81c4f6 — Jordi Gutiérrez Hermoso 8 months ago
Record the impersonator on the user object.

Sometimes you need to inspect the user well below the level of the
Django view. In our particular case, we wanted to overwrite Django's
email backend to always send all email to the current user in the
request. The email backend is far removed from the context of the
Django view, and the original request is now lost further up the call
stack.

While it is currently possible to guess who the impersonating user
might be by inspecting `impersonated_by` logs and taking the latest
log entry, this is a little brittle. It is easier to have the
impersonator on the impersonated user object.
4 files changed, 12 insertions(+), 5 deletions(-)

M README.md
M README.rst
M impersonate/middleware.py
M impersonate/tests.py
M README.md +4 -2
@@ 102,12 102,14 @@ Replace <user-id> with the user id
 impersonate.
 
 While in impersonation "mode" the `request.user` object will have an
-`is_impersonate` attribute set to `True`. So if you wanted to check in
+`is_impersonate` attribute set to `True` as well as `impersonator` (and also
+`request.impersonator`) set to the original user. So if you wanted to check in
 your templates or view, you just do something like...:
 
     {% if user.is_impersonate %} .... {% endif %}
 
-The original user is available as `request.impersonator`:
+The original user is available as `user.impersonator` or
+`request.impersonator`:
 
     {{ request.user }} ({{ request.impersonator }})
 

          
M README.rst +6 -3
@@ 110,14 110,17 @@ Functionality
 Replace <user-id> with the user id of the user you want to impersonate.
 
 While in impersonation "mode" the ``request.user`` object will have an
-``is_impersonate`` attribute set to ``True``. So if you wanted to check
-in your templates or view, you just do something like...:
+``is_impersonate`` attribute set to ``True`` as well as ``impersonator``
+(and also ``request.impersonator``) set to the original user. So if you
+wanted to check in your templates or view, you just do something
+like...:
 
 ::
 
    {% if user.is_impersonate %} .... {% endif %}
 
-The original user is available as ``request.impersonator``:
+The original user is available as ``user.impersonator`` or
+``request.impersonator``:
 
 ::
 

          
M impersonate/middleware.py +1 -0
@@ 56,5 56,6 @@ class ImpersonateMiddleware(MiddlewareMi
                 request.impersonator = request.user
                 request.user = new_user
                 request.user.is_impersonate = True
+                request.user.impersonator = request.impersonator
 
         request.real_user = request.impersonator or request.user

          
M impersonate/tests.py +1 -0
@@ 124,6 124,7 @@ class TestMiddleware(TestCase):
         # Check request.user and request.user.real_user
         self.assertEqual(request.user, self.user)
         self.assertEqual(request.impersonator, self.superuser)
+        self.assertEqual(request.user.impersonator, self.superuser)
         self.assertEqual(request.real_user, self.superuser)
         self.assertTrue(request.user.is_impersonate)