[Python-modules-commits] [django-impersonate] 01/04: Imported Upstream version 1.3

Scott Kitterman kitterman at moszumanska.debian.org
Mon Jan 8 19:47:31 UTC 2018


This is an automated email from the git hooks/post-receive script.

kitterman pushed a commit to branch debian/master
in repository django-impersonate.

commit 709d553a0f8787c2438c492f52dfe573f3fff37a
Author: Scott Kitterman <scott at kitterman.com>
Date:   Mon Jan 8 14:23:39 2018 -0500

    Imported Upstream version 1.3
---
 CHANGELOG                              |  12 ++-
 PKG-INFO                               | 186 +++++++++++++++++++++++----------
 README.rst                             | 181 +++++++++++++++++++++++---------
 impersonate/__init__.py                |   2 +-
 impersonate/admin.py                   |  37 ++++++-
 impersonate/decorators.py              |   4 +-
 impersonate/helpers.py                 |  76 +++++++-------
 impersonate/middleware.py              |   8 +-
 impersonate/migrations/0001_initial.py |   5 +-
 impersonate/models.py                  |   2 +
 impersonate/settings.py                |  51 +++++++++
 impersonate/signals.py                 |   7 +-
 impersonate/tests.py                   | 137 ++++++++++++++----------
 impersonate/views.py                   |  16 ++-
 setup.py                               |   3 +-
 15 files changed, 500 insertions(+), 227 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 0c76063..2deee3c 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,9 +1,18 @@
 Changes
 -------
 
-1.2 (Dev)
+1.3 (2017-12-14)
+
+- Django 2.0 compatable (Issue #46)
+- Consolidate settings into a single IMPERSIONATE dictionary (Issue #20)
+- Add admin Mixin to offer quick shortcut to user impersonation via Django admin. (Issue #19)
+
+1.2.1 (2017-11-13)
 
 - TODO Issue #19
+- Make search results distinct. (Pull Request #31)
+- Add request.real_user for convenience. (Pull Request #32)
+- Ensure default user queries are ordered to ensure consistency. (Pull Request #33)
 
 1.1 (2017-01-26)
 
@@ -14,6 +23,7 @@ Changes
 - Updated middleware documentation. (Issue #33)
 
 1.0.1 (2016-04-10)
+
 - Fix migration issues with custom User models. (Issue #31, Pull Request #26)
 
 1.0 (2016-02-14)
diff --git a/PKG-INFO b/PKG-INFO
index 7820205..3f05090 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,34 +1,42 @@
 Metadata-Version: 1.1
 Name: django-impersonate
-Version: 1.1
+Version: 1.3
 Summary: Django app to allow superusers to impersonate other users.
 Home-page: http://bitbucket.org/petersanchez/django-impersonate/
 Author: Peter Sanchez
 Author-email: petersanchez at gmail.com
 License: BSD License
-Description: .. |nlshield| image:: https://img.shields.io/badge/100%-Netlandish-blue.svg?style=square-flat
+Description: .. |nlshield| image:: https://img.shields.io/badge/100%25-Netlandish-blue.svg?style=square-flat
                       :target: http://www.netlandish.com
         
         ==============================
         django-impersonate |nlshield|
         ==============================
         :Info: Simple application to allow superusers to "impersonate" other non-superuser accounts.
-        :Version: 1.1
+        :Version: 1.3.0
         :Author: Peter Sanchez (http://www.petersanchez.com)
         
+        Python / Django Support
+        =======================
+        
+        * Python 2.7+ for Django versions 1.8 - 1.11
+        * Python 3.4+ for Django versions 1.9 - 2.0
+        * Python 3.3 for Django version 1.8
+        
+        **Note:** In release 1.4 we plan to only support Python 3.4+ and Django 2.0+ moving forward. Bug fixes will be ported to older versions but new feature development will be focusing on modern releases of Python and Django.
+        
         Dependencies
         ============
         
-        * It was written for Python 2.7+ and Django 1.8+
-        * Python 3.3+ is supported but Python 3.4+ is required for Django 1.9+
-        * It depends on your project using the django.contrib.session framework.
+        * Depends on your project using the django.contrib.session framework.
         
         **NOTE:**
         
-        * **Version 1.0 adds new functionality by default.** Please see the IMPERSONATE_DISABLE_LOGGING setting section.
+        * **Version 1.3 adds a settings format change.** Please see the Settings section for details.
+        * **Version 1.0 adds new functionality by default.** Please see the DISABLE_LOGGING settings option.
         * If you need to use this with Django older than 1.8, please use version django-impersonate == 1.0.1
         * If you need to use this with Django older than 1.7, please use version django-impersonate == 0.9.2
-        * **Version 0.9.2 partially reverts work completed in version 0.9.1.** This is because work done to address a request in `Issue #17 <https://bitbucket.org/petersanchez/django-impersonate/issues/17/remember-where-to-return-to-after>`_ broke default behavior for all previous versions. `Issue #24 <https://bitbucket.org/petersanchez/django-impersonate/issues/24/impersonate_redirect_url-no-longer-works>`_ was opened and the fix was released in 0.9.2 to address it. Please see the new I [...]
+        * **Version 0.9.2 partially reverts work completed in version 0.9.1.** This is because work done to address a request in `Issue #17 <https://bitbucket.org/petersanchez/django-impersonate/issues/17/remember-where-to-return-to-after>`_ broke default behavior for all previous versions. `Issue #24 <https://bitbucket.org/petersanchez/django-impersonate/issues/24/impersonate_redirect_url-no-longer-works>`_ was opened and the fix was released in 0.9.2 to address it. Please see the new U [...]
         * If you need to use this with Django older than 1.4, please use version django-impersonate == 0.5.3
         
         
@@ -64,7 +72,7 @@ Description: .. |nlshield| image:: https://img.shields.io/badge/100%-Netlandish-
                 ... (all your other urls here) ...
             )
         
-        **Note:** The ImpersonationMiddleware class should be placed AFTER the `django.contrib.auth` middleware classes
+        **Note:** The ImpersonationMiddleware class should be placed AFTER the ``django.contrib.auth`` middleware classes
         
         Functionality
         =============
@@ -77,16 +85,24 @@ Description: .. |nlshield| image:: https://img.shields.io/badge/100%-Netlandish-
         
         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...
+        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 ``request.impersonator``::
         
             {{ request.user }} ({{ request.impersonator }})
         
+        The real user is available as ``request.real_user`` - this is equivalent
+        to calling ``getattr(request, 'impersonator', request.user)``::
+        
+            assert request.real_user == getattr(request, 'impersonator', request.user)
+        
         You can reference this URL with reverse() or the {% url %} template tag
-        as 'impersonate-start'
+        as 'impersonate-start' and expects the argument of the user ID. Example::
+        
+            reverse('impersonate-start', args=[user.id])
+            reverse('impersonate-start', uid=user.id)
         
         
         **To remove the impersonation, hit the following path:**
@@ -96,7 +112,7 @@ Description: .. |nlshield| image:: https://img.shields.io/badge/100%-Netlandish-
         You can reference this URL with reverse() or the {% url %} template tag
         as 'impersonate-stop'. When you call this URL, you will be redirected to
         the page that you used to start impersonating a user (eg, some search results
-        or the user list.)
+        or the user list).
         
         
         **To list all users you can go to:**
@@ -112,7 +128,7 @@ Description: .. |nlshield| image:: https://img.shields.io/badge/100%-Netlandish-
         * page_number - Current page number, defaults to 1
         
         You can reference this URL with reverse() or the {% url %} template tag
-        as 'impersonate-list'
+        as 'impersonate-list'.
         
         
         **To search all users you can go to:**
@@ -135,25 +151,26 @@ Description: .. |nlshield| image:: https://img.shields.io/badge/100%-Netlandish-
         User.username, User.first_name, User.last_name, User.email
         
         You can reference this URL with reverse() or the {% url %} template tag
-        as 'impersonate-search'
+        as 'impersonate-search'.
         
         
         **To allow some users to impersonate other users**
         
-        You can optionally allow only some non-superuser and non-staff users to impersonate by adding a **IMPERSONATE_CUSTOM_ALLOW** setting. Create a function that takes a request object, and based on your rules, returns True if the user is allowed to impersonate or not.
+        You can optionally allow only some non-superuser and non-staff users to impersonate by adding a **CUSTOM_ALLOW** setting option. Create a function that takes a request object, and based on your rules, returns True if the user is allowed to impersonate or not.
         
         **To limit what users a user can impersonate**
         
-        By, optionally, setting the **IMPERSONATE_CUSTOM_USER_QUERYSET** you can control what users can be impersonated. It takes a request object of the user, and returns a QuerySet of users. This is used when searching for users to impersonate, when listing what users to impersonate, and when trying to start impersonation.
+        By, optionally, setting the **CUSTOM_USER_QUERYSET** option you can control what users can be impersonated. It takes a request object of the user, and returns a QuerySet of users. This is used when searching for users to impersonate, when listing what users to impersonate, and when trying to start impersonation.
         
-        **Signals**
+        Signals
+        =======
         
         If you wish to hook into the impersonation session (for instance, in order to
         audit access), there are two signals that are fired by django-impersonate, at
         the beginning and end of a session:
         
-        * session_begin - sent when calling the `impersonate` view
-        * session_end - sent when calling the `stop_impersonate` view
+        * session_begin - sent when calling the ``impersonate`` view
+        * session_end - sent when calling the ``stop_impersonate`` view
         
         Both of these signals send the same arguments:
         
@@ -165,7 +182,7 @@ Description: .. |nlshield| image:: https://img.shields.io/badge/100%-Netlandish-
         The request object is included as it contains pertinent information that you may wish
         to audit - such as client IP address, user-agent string, etc.
         
-        For an example of how to hook up the signals, see the relevant test - `test_successful_impersonation_signals`.
+        For an example of how to hook up the signals, see the relevant test - ``test_successful_impersonation_signals``.
         
         NB The session_end signal will only be fired if the impersonator explicitly ends
         the session.
@@ -173,36 +190,47 @@ Description: .. |nlshield| image:: https://img.shields.io/badge/100%-Netlandish-
         Settings
         ========
         
-        The following settings are available for django-impersonate:
+        The following settings are available for django-impersonate. All settings should be 
+        set as variables in a dictionary assigned to the attribute named ``IMPERSONATE``.
         
+        For example::
         
-            IMPERSONATE_REDIRECT_URL
+            IMPERSONATE = {
+                'REDIRECT_URL': '/some-path/',
+                'PAGINATE_COUNT': 10,
+            }
         
-        This is the URL you want to be redirected to _after_ you have chosen to
+        **Note:** This is a new format. The old format is now deprecated and support for the old format will be removed in a future release.
+        
+        Here are the options available...
+        
+            REDIRECT_URL
+        
+        This is the URL you want to be redirected to *after* you have chosen to
         impersonate another user. If this is not present it will check for
         the LOGIN_REDIRECT_URL setting and fall back to '/' if neither is
         present. Value should be a string containing the redirect path.
         
         
-            IMPERSONATE_USE_HTTP_REFERER
+            USE_HTTP_REFERER
         
         If this is set to True, then the app will attempt to be redirect you to
-        the URL you were at when the impersonation began once you have _stopped_
+        the URL you were at when the impersonation began once you have *stopped*
         the impersonation. For example, if you were at the url '/foo/bar/' when
         you began impersonating a user, once you end the impersonation, you will
         be redirected back to '/foo/bar/' instead of the value in
-        IMPERSONATE_REDIRECT_URL.
+        REDIRECT_URL.
         
         Value should be a boolean (True/False), defaults to False
         
         
-            IMPERSONATE_PAGINATE_COUNT
+            PAGINATE_COUNT
         
         This is the number of users to paginate by when using the list or
         search views. This defaults to 20. Value should be an integer.
         
         
-            IMPERSONATE_REQUIRE_SUPERUSER
+            REQUIRE_SUPERUSER
         
         If this is set to True, then only users who have 'is_superuser' set
         to True will be allowed to impersonate other users. Default is False.
@@ -214,32 +242,32 @@ Description: .. |nlshield| image:: https://img.shields.io/badge/100%-Netlandish-
         
         Value should be a boolean (True/False)
         
-        If the IMPERSONATE_CUSTOM_ALLOW is set, then that custom function is used, and
+        If the CUSTOM_ALLOW is set, then that custom function is used, and
         this setting is ignored.
         
         
-            IMPERSONATE_ALLOW_SUPERUSER
+            ALLOW_SUPERUSER
         
         By default, superusers cannot be impersonated; this setting allows for that.
         
         **Note:** Even when this is true, only superusers can impersonate other superusers,
-        regardless of the value of IMPERSONATE_REQUIRE_SUPERUSER.
+        regardless of the value of REQUIRE_SUPERUSER.
         
         Value should be a boolean (True/False), and the default is False.
         
         
-            IMPERSONATE_URI_EXCLUSIONS
+            URI_EXCLUSIONS
         
         Set to a list/tuple of url patterns that, if matched, user
-        impersonation is not completed. It defaults to:
+        impersonation is not completed. It defaults to::
         
-        (r'^admin/',)
+            (r'^admin/',)
         
         If you do not want to use even the default exclusions then set
         the setting to an emply list/tuple.
         
         
-            IMPERSONATE_CUSTOM_USER_QUERYSET
+            CUSTOM_USER_QUERYSET
         
         A string that represents a function (e.g. 'module.submodule.mod.function_name')
         that allows more fine grained control over what users a user can impersonate.
@@ -248,57 +276,57 @@ Description: .. |nlshield| image:: https://img.shields.io/badge/100%-Netlandish-
         
         This function will not be called when the request has an unauthorised users,
         and will only be called when the user is allowed to impersonate (cf.
-        IMPERSONATE_REQUIRE_SUPERUSER and IMPERSONATE_CUSTOM_ALLOW )
+        REQUIRE_SUPERUSER and CUSTOM_ALLOW ).
         
         Regardless of what this function returns, a user cannot impersonate a
         superuser, even if there are superusers in the returned QuerySet.
         
         It is optional, and if it is not present, the user can impersonate any user
-        (i.e. the default is User.objects.all())
+        (i.e. the default is User.objects.all()).
         
         
-            IMPERSONATE_CUSTOM_ALLOW
+            CUSTOM_ALLOW
         
         A string that represents a function (e.g. 'module.submodule.mod.function_name')
         that allows more fine grained control over who can use the impersonation. It
         takes one argument, the request object, and should return True to allow
         impesonation. Regardless of this setting, the user must be logged in to
-        impersonate. If this setting is used, IMPERSONATE_REQUIRE_SUPERUSER is ignored.
+        impersonate. If this setting is used, REQUIRE_SUPERUSER is ignored.
         
         It is optional, and if it is not present, the previous rules about superuser
-        and IMPERSONATE_REQUIRE_SUPERUSER apply.
+        and REQUIRE_SUPERUSER apply.
         
         
-            IMPERSONATE_REDIRECT_FIELD_NAME
+            REDIRECT_FIELD_NAME
         
         A string that represents the name of a request (GET) parameter which contains
         the URL to redirect to after impersonating a user. This can be used to redirect
-        to a custom page after impersonating a user. Example:
+        to a custom page after impersonating a user. Example::
         
             # in settings.py
-            IMPERSONATE_REDIRECT_FIELD_NAME = 'next'
+            IMPERSONATE = {'REDIRECT_FIELD_NAME': 'next'}
         
             # in your view
             <a href="{% url 'impersonate-list' %}?next=/some/url/">switch user</a>
         
         To return always to the current page after impersonating a user, use request.path:
         
-            <a href="{% url 'impersonate-list' %}?next={{request.path}}">switch user</a>
+            ``<a href="{% url 'impersonate-list' %}?next={{request.path}}">switch user</a>``
         
         
-            IMPERSONATE_SEARCH_FIELDS
+            SEARCH_FIELDS
         
         Array of user model fields used for building searching query. Default value is
         [User.USERNAME_FIELD, 'first_name', 'last_name', 'email']. If the User model doesn't have
         the USERNAME_FIELD attribute, it falls back to 'username' (< Django 1.5).
         
         
-            IMPERSONATE_LOOKUP_TYPE
+            LOOKUP_TYPE
         
         A string that represents SQL lookup type for searching users by query on
         fields above. It is 'icontains' by default.
         
-            IMPERSONATE_DISABLE_LOGGING
+            DISABLE_LOGGING
         
         A bool that can be used to disable the logging of impersonation sessions. By
         default each impersonation ``session_begin`` signal will create a new
@@ -307,7 +335,7 @@ Description: .. |nlshield| image:: https://img.shields.io/badge/100%-Netlandish-
         
         It is optional, and defaults to False (i.e. logging is enabled).
         
-            IMPERSONATE_MAX_FILTER_SIZE
+            MAX_FILTER_SIZE
         
         The max number of items acceptable in the admin list filters. If the number of
         items exceeds this, then the filter is removed (just shows all). This is used
@@ -315,22 +343,65 @@ Description: .. |nlshield| image:: https://img.shields.io/badge/100%-Netlandish-
         
         It is optional, and defaults to 100.
         
+        SETTINGS PRIOR TO VERSION 1.3
+        =============================
+        
+        Prior to version 1.3, settings were not stored in a dictionary. They were each an individual setting. For the time being, you can still use individual settings for each option. If present, they will supersede any setting within the ``IMPERSONATE`` dictionary and will also issue a warning that the settings format has changed and you should convert your projects settings to use the new dictionary format.
+        
+        All dictionary options can be used as individual settings by simply prepending ``IMPERSONATE_`` to the name. For example, the following is the dictionary sample from above and it's old style settings equivalent.
+        
+        New format::
+        
+            IMPERSONATE = {
+                'REDIRECT_URL': '/some-path/',
+                'PAGINATE_COUNT': 10,
+            }
+        
+        
+        Deprecated (old) format::
+        
+            IMPERSONATE_REDIRECT_URL = '/some-path'
+            IMPERSONATE_PAGE_COUNT = 10
+        
+        Admin
+        =====
+        
+        As of version 1.3 django-impersonate now includes a helper admin mixin, located at ``imepersonate.admin.UserAdminImpersonateMixin``, to include in your User model's ModelAdmin. This provides a direct link to impersonate users from your user model's Django admin list view. Using it is very simple, however if you're using the default ``django.contrib.auth.models.User`` model you will need to unregister the old ModelAdmin before registering your own.
+        
+        The ``UserAdminImpersonateMixin`` has a attribute named ``open_new_window`` that **defaults to False**. If this is set to True a new window will be opened to start the new impersonation session when clicking the impersonate link directly in the admin.
+        
+        Here's an example::
+        
+            # yourapp/admin.py
+            from django.contrib import admin
+            from django.contrib.auth.models import User
+            from django.contrib.auth.admin import UserAdmin
+            from impersonate.admin import UserAdminImpersonateMixin
+        
+        
+            class NewUserAdmin(UserAdminImpersonateMixin, UserAdmin):
+                open_new_window = True
+                pass
+        
+            admin.site.unregister(User)
+            admin.site.register(User, NewUserAdmin)
+        
         Testing
         =======
         
-        You need factory_boy installed for tests to run. To install, use:
+        You need factory_boy installed for tests to run. To install, use::
         
             $ pip install factory_boy
         
-        **Note:** This currently not required for Python 3.3+. For more info on factory_boy, see: https://github.com/dnerdy/factory_boy
+        **Note:** This is currently not required for Python 3.3+. For more info on factory_boy, see: https://github.com/dnerdy/factory_boy
         
-        From the repo checkout, ensure you have Django in your PYTHONPATH and  run:
+        From the repo checkout, ensure you have Django in your PYTHONPATH and  run::
         
             $ python runtests.py
         
         To get test coverage, use::
         
-            $ coverate run --branch runtests.py
+            $ coverage run --branch runtests.py
             $ coverage html  <- Pretty HTML files for you
             $ coverage report -m  <- Ascii report
         
@@ -341,18 +412,24 @@ Description: .. |nlshield| image:: https://img.shields.io/badge/100%-Netlandish-
         
         And you should see::
         
+            py3.6-django2.0: commands succeeded
+            py3.6-django1.11: commands succeeded
+            py3.5-django1.11: commands succeeded
             py3.5-django1.10: commands succeeded
             py3.5-django1.9: commands succeeded
             py3.5-django1.8: commands succeeded
+            py3.4-django1.11: commands succeeded
             py3.4-django1.10: commands succeeded
             py3.4-django1.9: commands succeeded
             py3.4-django1.8: commands succeeded
             py3.3-django1.8: commands succeeded
+            py2.7-django1.11: commands succeeded
             py2.7-django1.10: commands succeeded
             py2.7-django1.9: commands succeeded
             py2.7-django1.8: commands succeeded
             congratulations :)
         
+        
         Copyright & Warranty
         ====================
         All documentation, libraries, and sample code are
@@ -376,8 +453,9 @@ Classifier: License :: OSI Approved :: BSD License
 Classifier: Natural Language :: English
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2.6
 Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3.3
 Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
 Classifier: Environment :: Web Environment
diff --git a/README.rst b/README.rst
index 57bb651..bb570f3 100644
--- a/README.rst
+++ b/README.rst
@@ -1,26 +1,34 @@
-.. |nlshield| image:: https://img.shields.io/badge/100%-Netlandish-blue.svg?style=square-flat
+.. |nlshield| image:: https://img.shields.io/badge/100%25-Netlandish-blue.svg?style=square-flat
               :target: http://www.netlandish.com
 
 ==============================
 django-impersonate |nlshield|
 ==============================
 :Info: Simple application to allow superusers to "impersonate" other non-superuser accounts.
-:Version: 1.1
+:Version: 1.3.0
 :Author: Peter Sanchez (http://www.petersanchez.com)
 
+Python / Django Support
+=======================
+
+* Python 2.7+ for Django versions 1.8 - 1.11
+* Python 3.4+ for Django versions 1.9 - 2.0
+* Python 3.3 for Django version 1.8
+
+**Note:** In release 1.4 we plan to only support Python 3.4+ and Django 2.0+ moving forward. Bug fixes will be ported to older versions but new feature development will be focusing on modern releases of Python and Django.
+
 Dependencies
 ============
 
-* It was written for Python 2.7+ and Django 1.8+
-* Python 3.3+ is supported but Python 3.4+ is required for Django 1.9+
-* It depends on your project using the django.contrib.session framework.
+* Depends on your project using the django.contrib.session framework.
 
 **NOTE:**
 
-* **Version 1.0 adds new functionality by default.** Please see the IMPERSONATE_DISABLE_LOGGING setting section.
+* **Version 1.3 adds a settings format change.** Please see the Settings section for details.
+* **Version 1.0 adds new functionality by default.** Please see the DISABLE_LOGGING settings option.
 * If you need to use this with Django older than 1.8, please use version django-impersonate == 1.0.1
 * If you need to use this with Django older than 1.7, please use version django-impersonate == 0.9.2
-* **Version 0.9.2 partially reverts work completed in version 0.9.1.** This is because work done to address a request in `Issue #17 <https://bitbucket.org/petersanchez/django-impersonate/issues/17/remember-where-to-return-to-after>`_ broke default behavior for all previous versions. `Issue #24 <https://bitbucket.org/petersanchez/django-impersonate/issues/24/impersonate_redirect_url-no-longer-works>`_ was opened and the fix was released in 0.9.2 to address it. Please see the new IMPERSONA [...]
+* **Version 0.9.2 partially reverts work completed in version 0.9.1.** This is because work done to address a request in `Issue #17 <https://bitbucket.org/petersanchez/django-impersonate/issues/17/remember-where-to-return-to-after>`_ broke default behavior for all previous versions. `Issue #24 <https://bitbucket.org/petersanchez/django-impersonate/issues/24/impersonate_redirect_url-no-longer-works>`_ was opened and the fix was released in 0.9.2 to address it. Please see the new USE_HTTP_ [...]
 * If you need to use this with Django older than 1.4, please use version django-impersonate == 0.5.3
 
 
@@ -56,7 +64,7 @@ Use
         ... (all your other urls here) ...
     )
 
-**Note:** The ImpersonationMiddleware class should be placed AFTER the `django.contrib.auth` middleware classes
+**Note:** The ImpersonationMiddleware class should be placed AFTER the ``django.contrib.auth`` middleware classes
 
 Functionality
 =============
@@ -69,16 +77,24 @@ 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...
+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 ``request.impersonator``::
 
     {{ request.user }} ({{ request.impersonator }})
 
+The real user is available as ``request.real_user`` - this is equivalent
+to calling ``getattr(request, 'impersonator', request.user)``::
+
+    assert request.real_user == getattr(request, 'impersonator', request.user)
+
 You can reference this URL with reverse() or the {% url %} template tag
-as 'impersonate-start'
+as 'impersonate-start' and expects the argument of the user ID. Example::
+
+    reverse('impersonate-start', args=[user.id])
+    reverse('impersonate-start', uid=user.id)
 
 
 **To remove the impersonation, hit the following path:**
@@ -88,7 +104,7 @@ as 'impersonate-start'
 You can reference this URL with reverse() or the {% url %} template tag
 as 'impersonate-stop'. When you call this URL, you will be redirected to
 the page that you used to start impersonating a user (eg, some search results
-or the user list.)
+or the user list).
 
 
 **To list all users you can go to:**
@@ -104,7 +120,7 @@ the following in the context:
 * page_number - Current page number, defaults to 1
 
 You can reference this URL with reverse() or the {% url %} template tag
-as 'impersonate-list'
+as 'impersonate-list'.
 
 
 **To search all users you can go to:**
@@ -127,25 +143,26 @@ fields searched are:
 User.username, User.first_name, User.last_name, User.email
 
 You can reference this URL with reverse() or the {% url %} template tag
-as 'impersonate-search'
+as 'impersonate-search'.
 
 
 **To allow some users to impersonate other users**
 
-You can optionally allow only some non-superuser and non-staff users to impersonate by adding a **IMPERSONATE_CUSTOM_ALLOW** setting. Create a function that takes a request object, and based on your rules, returns True if the user is allowed to impersonate or not.
+You can optionally allow only some non-superuser and non-staff users to impersonate by adding a **CUSTOM_ALLOW** setting option. Create a function that takes a request object, and based on your rules, returns True if the user is allowed to impersonate or not.
 
 **To limit what users a user can impersonate**
 
-By, optionally, setting the **IMPERSONATE_CUSTOM_USER_QUERYSET** you can control what users can be impersonated. It takes a request object of the user, and returns a QuerySet of users. This is used when searching for users to impersonate, when listing what users to impersonate, and when trying to start impersonation.
+By, optionally, setting the **CUSTOM_USER_QUERYSET** option you can control what users can be impersonated. It takes a request object of the user, and returns a QuerySet of users. This is used when searching for users to impersonate, when listing what users to impersonate, and when trying to start impersonation.
 
-**Signals**
+Signals
+=======
 
 If you wish to hook into the impersonation session (for instance, in order to
 audit access), there are two signals that are fired by django-impersonate, at
 the beginning and end of a session:
 
-* session_begin - sent when calling the `impersonate` view
-* session_end - sent when calling the `stop_impersonate` view
+* session_begin - sent when calling the ``impersonate`` view
+* session_end - sent when calling the ``stop_impersonate`` view
 
 Both of these signals send the same arguments:
 
@@ -157,7 +174,7 @@ Both of these signals send the same arguments:
 The request object is included as it contains pertinent information that you may wish
 to audit - such as client IP address, user-agent string, etc.
 
-For an example of how to hook up the signals, see the relevant test - `test_successful_impersonation_signals`.
+For an example of how to hook up the signals, see the relevant test - ``test_successful_impersonation_signals``.
 
 NB The session_end signal will only be fired if the impersonator explicitly ends
 the session.
@@ -165,36 +182,47 @@ the session.
 Settings
 ========
 
-The following settings are available for django-impersonate:
+The following settings are available for django-impersonate. All settings should be 
+set as variables in a dictionary assigned to the attribute named ``IMPERSONATE``.
 
+For example::
 
-    IMPERSONATE_REDIRECT_URL
+    IMPERSONATE = {
+        'REDIRECT_URL': '/some-path/',
+        'PAGINATE_COUNT': 10,
+    }
 
-This is the URL you want to be redirected to _after_ you have chosen to
+**Note:** This is a new format. The old format is now deprecated and support for the old format will be removed in a future release.
+
+Here are the options available...
+
+    REDIRECT_URL
+
+This is the URL you want to be redirected to *after* you have chosen to
 impersonate another user. If this is not present it will check for
 the LOGIN_REDIRECT_URL setting and fall back to '/' if neither is
 present. Value should be a string containing the redirect path.
 
 
-    IMPERSONATE_USE_HTTP_REFERER
+    USE_HTTP_REFERER
 
 If this is set to True, then the app will attempt to be redirect you to
-the URL you were at when the impersonation began once you have _stopped_
+the URL you were at when the impersonation began once you have *stopped*
 the impersonation. For example, if you were at the url '/foo/bar/' when
 you began impersonating a user, once you end the impersonation, you will
 be redirected back to '/foo/bar/' instead of the value in
-IMPERSONATE_REDIRECT_URL.
+REDIRECT_URL.
 
 Value should be a boolean (True/False), defaults to False
 
 
-    IMPERSONATE_PAGINATE_COUNT
+    PAGINATE_COUNT
 
 This is the number of users to paginate by when using the list or
 search views. This defaults to 20. Value should be an integer.
 
 
-    IMPERSONATE_REQUIRE_SUPERUSER
+    REQUIRE_SUPERUSER
 
 If this is set to True, then only users who have 'is_superuser' set
 to True will be allowed to impersonate other users. Default is False.
@@ -206,32 +234,32 @@ allowed to impersonate a 'is_superuser' user.
 
 Value should be a boolean (True/False)
 
-If the IMPERSONATE_CUSTOM_ALLOW is set, then that custom function is used, and
+If the CUSTOM_ALLOW is set, then that custom function is used, and
 this setting is ignored.
 
 
-    IMPERSONATE_ALLOW_SUPERUSER
+    ALLOW_SUPERUSER
 
 By default, superusers cannot be impersonated; this setting allows for that.
 
 **Note:** Even when this is true, only superusers can impersonate other superusers,
-regardless of the value of IMPERSONATE_REQUIRE_SUPERUSER.
+regardless of the value of REQUIRE_SUPERUSER.
 
 Value should be a boolean (True/False), and the default is False.
 
 
-    IMPERSONATE_URI_EXCLUSIONS
+    URI_EXCLUSIONS
 
 Set to a list/tuple of url patterns that, if matched, user
-impersonation is not completed. It defaults to:
+impersonation is not completed. It defaults to::
 
-(r'^admin/',)
+    (r'^admin/',)
 
 If you do not want to use even the default exclusions then set
 the setting to an emply list/tuple.
 
 
-    IMPERSONATE_CUSTOM_USER_QUERYSET
+    CUSTOM_USER_QUERYSET
 
 A string that represents a function (e.g. 'module.submodule.mod.function_name')
 that allows more fine grained control over what users a user can impersonate.
@@ -240,57 +268,57 @@ the users in this queryset can be impersonated.
 
 This function will not be called when the request has an unauthorised users,
 and will only be called when the user is allowed to impersonate (cf.
-IMPERSONATE_REQUIRE_SUPERUSER and IMPERSONATE_CUSTOM_ALLOW )
+REQUIRE_SUPERUSER and CUSTOM_ALLOW ).
 
 Regardless of what this function returns, a user cannot impersonate a
 superuser, even if there are superusers in the returned QuerySet.
 
 It is optional, and if it is not present, the user can impersonate any user
-(i.e. the default is User.objects.all())
+(i.e. the default is User.objects.all()).
 
 
-    IMPERSONATE_CUSTOM_ALLOW
+    CUSTOM_ALLOW
 
 A string that represents a function (e.g. 'module.submodule.mod.function_name')
 that allows more fine grained control over who can use the impersonation. It
 takes one argument, the request object, and should return True to allow
 impesonation. Regardless of this setting, the user must be logged in to
-impersonate. If this setting is used, IMPERSONATE_REQUIRE_SUPERUSER is ignored.
+impersonate. If this setting is used, REQUIRE_SUPERUSER is ignored.
 
 It is optional, and if it is not present, the previous rules about superuser
-and IMPERSONATE_REQUIRE_SUPERUSER apply.
+and REQUIRE_SUPERUSER apply.
 
 
-    IMPERSONATE_REDIRECT_FIELD_NAME
+    REDIRECT_FIELD_NAME
 
 A string that represents the name of a request (GET) parameter which contains
 the URL to redirect to after impersonating a user. This can be used to redirect
-to a custom page after impersonating a user. Example:
+to a custom page after impersonating a user. Example::
 
     # in settings.py
-    IMPERSONATE_REDIRECT_FIELD_NAME = 'next'
+    IMPERSONATE = {'REDIRECT_FIELD_NAME': 'next'}
 
     # in your view
     <a href="{% url 'impersonate-list' %}?next=/some/url/">switch user</a>
 
 To return always to the current page after impersonating a user, use request.path:
 
-    <a href="{% url 'impersonate-list' %}?next={{request.path}}">switch user</a>
+    ``<a href="{% url 'impersonate-list' %}?next={{request.path}}">switch user</a>``
 
 
-    IMPERSONATE_SEARCH_FIELDS
+    SEARCH_FIELDS
 
 Array of user model fields used for building searching query. Default value is
 [User.USERNAME_FIELD, 'first_name', 'last_name', 'email']. If the User model doesn't have
 the USERNAME_FIELD attribute, it falls back to 'username' (< Django 1.5).
 
 
-    IMPERSONATE_LOOKUP_TYPE
+    LOOKUP_TYPE
 
 A string that represents SQL lookup type for searching users by query on
 fields above. It is 'icontains' by default.
 
-    IMPERSONATE_DISABLE_LOGGING
+    DISABLE_LOGGING
 
 A bool that can be used to disable the logging of impersonation sessions. By
 default each impersonation ``session_begin`` signal will create a new
@@ -299,7 +327,7 @@ the corresponding ``session_end`` signal.
 
 It is optional, and defaults to False (i.e. logging is enabled).
 
-    IMPERSONATE_MAX_FILTER_SIZE
+    MAX_FILTER_SIZE
 
 The max number of items acceptable in the admin list filters. If the number of
 items exceeds this, then the filter is removed (just shows all). This is used
@@ -307,22 +335,65 @@ by the "Filter by impersonator" filter.
 
 It is optional, and defaults to 100.
 
+SETTINGS PRIOR TO VERSION 1.3
+=============================
+
+Prior to version 1.3, settings were not stored in a dictionary. They were each an individual setting. For the time being, you can still use individual settings for each option. If present, they will supersede any setting within the ``IMPERSONATE`` dictionary and will also issue a warning that the settings format has changed and you should convert your projects settings to use the new dictionary format.
+
+All dictionary options can be used as individual settings by simply prepending ``IMPERSONATE_`` to the name. For example, the following is the dictionary sample from above and it's old style settings equivalent.
+
+New format::
+
+    IMPERSONATE = {
+        'REDIRECT_URL': '/some-path/',
+        'PAGINATE_COUNT': 10,
+    }
+
+
+Deprecated (old) format::
+
+    IMPERSONATE_REDIRECT_URL = '/some-path'
+    IMPERSONATE_PAGE_COUNT = 10
+
+Admin
+=====
+
+As of version 1.3 django-impersonate now includes a helper admin mixin, located at ``imepersonate.admin.UserAdminImpersonateMixin``, to include in your User model's ModelAdmin. This provides a direct link to impersonate users from your user model's Django admin list view. Using it is very simple, however if you're using the default ``django.contrib.auth.models.User`` model you will need to unregister the old ModelAdmin before registering your own.
+
+The ``UserAdminImpersonateMixin`` has a attribute named ``open_new_window`` that **defaults to False**. If this is set to True a new window will be opened to start the new impersonation session when clicking the impersonate link directly in the admin.
+
+Here's an example::
+
+    # yourapp/admin.py
+    from django.contrib import admin
+    from django.contrib.auth.models import User
+    from django.contrib.auth.admin import UserAdmin
+    from impersonate.admin import UserAdminImpersonateMixin
+
+
+    class NewUserAdmin(UserAdminImpersonateMixin, UserAdmin):
+        open_new_window = True
+        pass
+
+    admin.site.unregister(User)
+    admin.site.register(User, NewUserAdmin)
+
 Testing
 =======
 
-You need factory_boy installed for tests to run. To install, use:
+You need factory_boy installed for tests to run. To install, use::
 
     $ pip install factory_boy
 
-**Note:** This currently not required for Python 3.3+. For more info on factory_boy, see: https://github.com/dnerdy/factory_boy
+**Note:** This is currently not required for Python 3.3+. For more info on factory_boy, see: https://github.com/dnerdy/factory_boy
 
-From the repo checkout, ensure you have Django in your PYTHONPATH and  run:
+From the repo checkout, ensure you have Django in your PYTHONPATH and  run::
 
     $ python runtests.py
 
 To get test coverage, use::
 
-    $ coverate run --branch runtests.py
+    $ coverage run --branch runtests.py
     $ coverage html  <- Pretty HTML files for you
     $ coverage report -m  <- Ascii report
 
@@ -333,18 +404,24 @@ If you're bored and want to test all the supported environments, you'll need tox
 
 And you should see::
 
+    py3.6-django2.0: commands succeeded
+    py3.6-django1.11: commands succeeded
+    py3.5-django1.11: commands succeeded
     py3.5-django1.10: commands succeeded
     py3.5-django1.9: commands succeeded
     py3.5-django1.8: commands succeeded
+    py3.4-django1.11: commands succeeded
     py3.4-django1.10: commands succeeded
     py3.4-django1.9: commands succeeded
     py3.4-django1.8: commands succeeded
     py3.3-django1.8: commands succeeded
+    py2.7-django1.11: commands succeeded
     py2.7-django1.10: commands succeeded
     py2.7-django1.9: commands succeeded
     py2.7-django1.8: commands succeeded
     congratulations :)
 
+
 Copyright & Warranty
 ====================
 All documentation, libraries, and sample code are
diff --git a/impersonate/__init__.py b/impersonate/__init__.py
index 7e8b31c..49c51a3 100644
--- a/impersonate/__init__.py
+++ b/impersonate/__init__.py
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-VERSION = (1, 1, 0, 'final', 0)
+VERSION = (1, 3, 0, 'final', 0)
 
 
 # taken from django-registration
diff --git a/impersonate/admin.py b/impersonate/admin.py
index 9c66154..7ad8713 100644
--- a/impersonate/admin.py
+++ b/impersonate/admin.py
@@ -1,10 +1,16 @@
 #  -*- coding: utf-8 -*-
 import logging
-from django.conf import settings
 from django.contrib import admin
+from django.utils.html import format_html
 
-from .helpers import User
+from .settings import settings
 from .models import ImpersonationLog
+from .helpers import User, check_allow_impersonate
+
+try:
+    from django.urls import reverse
+except ImportError:
+    from django.core.urlresolvers import reverse
 
 logger = logging.getLogger(__name__)
 
@@ -62,7 +68,7 @@ class ImpersonatorFilter(admin.SimpleListFilter):
         ''' Return list of unique users who have been an impersonator.
         '''
         # the queryset containing the ImpersonationLog objects
-        MAX_FILTER_SIZE = getattr(settings, 'IMPERSONATE_MAX_FILTER_SIZE', 100)
+        MAX_FILTER_SIZE = settings.MAX_FILTER_SIZE
         try:
             # Evaluate here to raise exception if needed
             ids = list(
@@ -100,6 +106,31 @@ class ImpersonatorFilter(admin.SimpleListFilter):
             return queryset.filter(impersonator_id=self.value())
 
 
+class UserAdminImpersonateMixin(object):
+    ''' Mixin to easily add user impersonation support via the Django
+        admin change list page.
+    '''
+    open_new_window = False
+
+    def get_list_display(self, request):
+        if not check_allow_impersonate(request):
+            return self.list_display
+        list_display = list(self.list_display)
+        list_display.append('impersonate_user')
+        return list_display
+
+    def impersonate_user(self, obj):
+        target = ''
+        if self.open_new_window:
+            target = ' target="_blank"'
+        return format_html(
+            '<a href="{}"{}>Impersonate</a>',
+            reverse('impersonate-start', args=[obj.id]),
+            target,
+        )
+    impersonate_user.short_description = 'Impersonate User'
+
+
 class ImpersonationLogAdmin(admin.ModelAdmin):
     list_display = (
         '_impersonator',
diff --git a/impersonate/decorators.py b/impersonate/decorators.py
index 468a9f8..a2b04ba 100644
--- a/impersonate/decorators.py
+++ b/impersonate/decorators.py
@@ -6,7 +6,7 @@ from django.utils.encoding import force_str
 from django.shortcuts import redirect, resolve_url
 from django.contrib.auth import REDIRECT_FIELD_NAME
 
-from .helpers import get_redir_path, check_allow_impersonate
+from .helpers import get_redir_path, check_allow_impersonate, is_authenticated
 
 
 def get_login_url():
@@ -15,7 +15,7 @@ def get_login_url():
 
 def allowed_user_required(view_func):
     def _checkuser(request, *args, **kwargs):
-        if not request.user.is_authenticated():
+        if not is_authenticated(request.user):
             return redirect(u'{0}?{1}={2}'.format(
                 get_login_url(),
                 REDIRECT_FIELD_NAME,
diff --git a/impersonate/helpers.py b/impersonate/helpers.py
index 2d805d5..3822cec 100644
... 724 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/django-impersonate.git



More information about the Python-modules-commits mailing list