3 files changed, 106 insertions(+), 112 deletions(-)

M README.md
M README.rst
M impersonate/__init__.py
M README.md +1 -3
@@ 3,7 3,7 @@ 
 
 Simple application to allow superusers to "impersonate" other non-superuser accounts.
 
-**Version:** 1.7
+**Version:** 1.7.1
 
 **Project Links:** [Issues][issues] - [Mailing List][pinbox] -
 [Contributing](#contributing)

          
@@ 472,8 472,6 @@ And you should see:
 We accept patches submitted via `hg email` which is the `patchbomb` extension
 included with Mercurial.
 
-Please see our [contributing document][cdoc] for more information.
-
 The mailing list where you submit your patches is
 `~petersanchez/public-inbox@lists.code.netlandish.com`. You can also view the
 archives on the web here:

          
M README.rst +104 -108
@@ 1,10 1,10 @@ 
 django-impersonate |nlshield|
 -----------------------------
 
-Simple application to allow superusers to "impersonate" other
+Simple application to allow superusers to “impersonate” other
 non-superuser accounts.
 
-**Version:** 1.6
+**Version:** 1.7.1
 
 **Project Links:**
 `Issues <https://todo.code.netlandish.com/~petersanchez/django-impersonate>`__

          
@@ 35,7 35,7 @@ Dependencies
 -  **Version 1.6** has officially removed support for the old settings
    format. Please see the `settings <#settings>`__ section for how
    settings should be configured.
--  **Version 1.5 is now only officially supporting Django's 1.11, 2.2,
+-  **Version 1.5 is now only officially supporting Django’s 1.11, 2.2,
    and 3.0**
 -  **Version 1.4 is now officially supporting Python 3.6+ and Django
    1.11+**

          
@@ 64,14 64,14 @@ PIP:
 
 ::
 
-    pip install django-impersonate
+   pip install django-impersonate
 
 Basic Manual Install:
 
 ::
 
-    $ python setup.py build
-    $ sudo python setup.py install
+   $ python setup.py build
+   $ sudo python setup.py install
 
 Alternative Install (Manually):
 

          
@@ 82,18 82,18 @@ variable to include a directory where th
 Use
 ===
 
-1. Add ``impersonate`` to your INSTALLED\_APPS
+1. Add ``impersonate`` to your INSTALLED_APPS
 2. Add ``impersonate.middleware.ImpersonateMiddleware`` to your
    ``MIDDLEWARE`` setting.
 3. Add ``impersonate.urls`` somewhere in your url structure. Example:
 
    ::
 
-       urlpatterns = patterns('',
-           url(r'^admin/', include(admin.site.urls)),
-           url(r'^impersonate/', include('impersonate.urls')),
-           ... (all your other urls here) ...
-       )
+      urlpatterns = patterns('',
+          url(r'^admin/', include(admin.site.urls)),
+          url(r'^impersonate/', include('impersonate.urls')),
+          ... (all your other urls here) ...
+      )
 
 **Note:** The ``ImpersonationMiddleware`` class should be placed AFTER
 the ``django.contrib.auth.*`` middleware classes

          
@@ 105,30 105,30 @@ Functionality
 
 ::
 
-    /impersonate/<user-id>/
+   /impersonate/<user-id>/
 
 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
+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...:
+in your templates or view, you just do something like…:
 
 ::
 
-    {% if user.is_impersonate %} .... {% endif %}
+   {% if user.is_impersonate %} .... {% endif %}
 
 The original user is available as ``request.impersonator``:
 
 ::
 
-    {{ request.user }} ({{ 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)
+   assert request.real_user == getattr(request, 'impersonator', request.user)
 
 You can reference this URL with ``reverse`` or the ``{% url %}``
 template tag as ``impersonate-start`` and expects the argument of the

          
@@ 136,14 136,14 @@ user ID. Example:
 
 ::
 
-    reverse('impersonate-start', args=[user.id])
-    reverse('impersonate-start', uid=user.id)
+   reverse('impersonate-start', args=[user.id])
+   reverse('impersonate-start', uid=user.id)
 
 **To remove the impersonation, hit the following path:**
 
 ::
 
-    /impersonate/stop/
+   /impersonate/stop/
 
 You can reference this URL with ``reverse`` or the ``{% url %}``
 template tag as ``impersonate-stop``. When you call this URL, you will

          
@@ 154,7 154,7 @@ be redirected to the page that you used 
 
 ::
 
-    /impersonate/list/
+   /impersonate/list/
 
 This will render the template ``impersonate/list_users.html`` and will
 pass the following in the context:

          
@@ 171,9 171,9 @@ template tag as ``impersonate-list``.
 
 ::
 
-    /impersonate/search/
+   /impersonate/search/
 
-This will render the template 'impersonate/search\_users.html' and will
+This will render the template ‘impersonate/search_users.html’ and will
 pass the following in the context:
 
 -  ``users`` - queryset of all users

          
@@ 249,28 249,28 @@ For example:
 
 ::
 
-    IMPERSONATE = {
-        'REDIRECT_URL': '/some-path/',
-        'PAGINATE_COUNT': 10,
-    }
+   IMPERSONATE = {
+       'REDIRECT_URL': '/some-path/',
+       'PAGINATE_COUNT': 10,
+   }
 
-Here are the options available...
+Here are the options available…
 
 ::
 
-    REDIRECT_URL
+   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.
+LOGIN_REDIRECT_URL setting and fall back to ‘/’ if neither is present.
 Value should be a string containing the redirect path.
 
 ::
 
-    READ_ONLY
+   READ_ONLY
 
 A boolean that if set to ``True`` any requests that are not either
-``GET`` or ``HEAD`` will result in a "Bad Request" response (status code
+``GET`` or ``HEAD`` will result in a “Bad Request” response (status code
 405). Use this if you want to limit your impersonating users to read
 only impersonation sessions.
 

          
@@ 278,27 278,27 @@ Value should be a boolean, defaults to `
 
 ::
 
-    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 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
+‘/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 ``REDIRECT_URL``.
 
 Value should be a boolean, defaults to ``False``
 
 ::
 
-    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.
 
 ::
 
-    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

          
@@ 315,33 315,33 @@ this setting is ignored.
 
 ::
 
-    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 REQUIRE\_SUPERUSER.
+superusers, regardless of the value of REQUIRE_SUPERUSER.
 
 Value should be a boolean and the default is ``False``.
 
 ::
 
-    URI_EXCLUSIONS
+   URI_EXCLUSIONS
 
 Set to a list/tuple of url patterns that, if matched, user 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 empty list/tuple.
 
 ::
 
-    CUSTOM_USER_QUERYSET
+   CUSTOM_USER_QUERYSET
 
 A string that represents a function (e.g.
 ``module.submodule.mod.function_name``) that allows more fine grained

          
@@ 351,17 351,17 @@ 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. ``REQUIRE_SUPERUSER`` and ``CUSTOM_ALLOW``).
+(cf. ``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()``).
+user (i.e. the default is ``User.objects.all()``).
 
 ::
 
-    CUSTOM_ALLOW
+   CUSTOM_ALLOW
 
 A string that represents a function (e.g.
 ``module.submodule.mod.function_name``) that allows more fine grained

          
@@ 375,7 375,7 @@ superuser and ``REQUIRE_SUPERUSER`` appl
 
 ::
 
-    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

          
@@ 383,62 383,62 @@ used to redirect to a custom page after 
 
 ::
 
-    # in settings.py
-    IMPERSONATE = {'REDIRECT_FIELD_NAME': 'next'}
+   # in settings.py
+   IMPERSONATE = {'REDIRECT_FIELD_NAME': 'next'}
 
-    # in your template
-    <a href="{% url 'impersonate-list' %}?next=/some/url/">switch user</a>
+   # in your template
+   <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>`
 
 Each use case is different so obviously set the next value to whatever
 your case requires.
 
 ::
 
-    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).
+``email``]. If the User model doesn’t have the ``USERNAME_FIELD``
+attribute, it falls back to ‘username’ (< Django 1.5).
 
 ::
 
-    LOOKUP_TYPE
+   LOOKUP_TYPE
 
 A string that represents SQL lookup type for searching users by query on
 fields above. It is ``icontains`` by default.
 
 ::
 
-    DISABLE_LOGGING
+   DISABLE_LOGGING
 
 A boolean that can be used to disable the logging of impersonation
 sessions. By default each impersonation ``session_begin`` signal will
 create a new ``ImpersonationLog`` object, which is closed out (duration
 calculated) at the corresponding ``session_end`` signal.
 
-It is optional, and defaults to False (i.e. logging is enabled).
+It is optional, and defaults to False (i.e. logging is enabled).
 
 ::
 
-    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 list is the size of the
-settings value. This is used by the "Filter by impersonator" filter.
+settings value. This is used by the “Filter by impersonator” filter.
 
 It is optional, and defaults to 100.
 
 ::
 
-    ADMIN_DELETE_PERMISSION
+   ADMIN_DELETE_PERMISSION
 
 A boolean to enable/disable deletion of impersonation logs in the Django
 admin.

          
@@ 447,7 447,7 @@ Default is ``False``
 
 ::
 
-    ADMIN_ADD_PERMISSION
+   ADMIN_ADD_PERMISSION
 
 A boolean to enable/disable ability to add impersonation logs in the
 Django admin.

          
@@ 456,9 456,9 @@ Default is ``False``
 
 ::
 
-    ADMIN_READ_ONLY
+   ADMIN_READ_ONLY
 
-A boolean to enable/disable "read only" mode of impersonation logs in
+A boolean to enable/disable “read only” mode of impersonation logs in
 the Django admin. Generally you want to leave this enabled otherwise
 admin users can alter logs within the Django admin area.
 

          
@@ 466,21 466,21 @@ Default is ``True``
 
 ::
 
-    MAX_DURATION
+   MAX_DURATION
 
 A number specifying the maximum allowed duration of impersonation
 sessions in **seconds**.
 
-Default is `None`
+Default is ``None``
 
 Admin
 =====
 
 As of version 1.3 django-impersonate now includes a helper admin mixin,
 located at ``impersonate.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
+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.
 

          
@@ 489,23 489,23 @@ The ``UserAdminImpersonateMixin`` has a 
 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:
+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
+   # 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
+   class NewUserAdmin(UserAdminImpersonateMixin, UserAdmin):
+       open_new_window = True
+       pass
 
-    admin.site.unregister(User)
-    admin.site.register(User, NewUserAdmin)
+   admin.site.unregister(User)
+   admin.site.register(User, NewUserAdmin)
 
 Testing
 =======

          
@@ 515,38 515,38 @@ and run:
 
 ::
 
-    $ python runtests.py
+   $ python runtests.py
 
 To get test coverage, use:
 
 ::
 
-    $ coverage run --branch runtests.py
-    $ coverage html  <- Pretty HTML files for you
-    $ coverage report -m  <- Ascii report
+   $ coverage run --branch runtests.py
+   $ coverage html  <- Pretty HTML files for you
+   $ coverage report -m  <- Ascii report
 
-If you're bored and want to test all the supported environments, you'll
+If you’re bored and want to test all the supported environments, you’ll
 need tox.:
 
 ::
 
-    $ pip install tox
-    $ tox
+   $ pip install tox
+   $ tox
 
 And you should see:
 
 ::
 
-    py36-django2.2: commands succeeded
-    py36-django3.0: commands succeeded
-    py36-django3.1: commands succeeded
-    py37-django2.2: commands succeeded
-    py37-django3.0: commands succeeded
-    py37-django3.1: commands succeeded
-    py38-django2.2: commands succeeded
-    py38-django3.0: commands succeeded
-    py38-django3.1: commands succeeded
-    congratulations :)
+   py36-django2.2: commands succeeded
+   py36-django3.0: commands succeeded
+   py36-django3.1: commands succeeded
+   py37-django2.2: commands succeeded
+   py37-django3.0: commands succeeded
+   py37-django3.1: commands succeeded
+   py38-django2.2: commands succeeded
+   py38-django3.0: commands succeeded
+   py38-django3.1: commands succeeded
+   congratulations :)
 
 Contributing
 ============

          
@@ 554,10 554,6 @@ Contributing
 We accept patches submitted via ``hg email`` which is the ``patchbomb``
 extension included with Mercurial.
 
-Please see our `contributing
-document <https://man.code.netlandish.com/contributing.md>`__ for more
-information.
-
 The mailing list where you submit your patches is
 ``~petersanchez/public-inbox@lists.code.netlandish.com``. You can also
 view the archives on the web here:

          
@@ 569,14 565,14 @@ mailing list just edit your ``.hg/hgrc``
 
 ::
 
-    [email]
-    to = ~petersanchez/public-inbox@lists.code.netlandish.com
+   [email]
+   to = ~petersanchez/public-inbox@lists.code.netlandish.com
 
-    [patchbomb]
-    flagtemplate = "django-impersonate"
+   [patchbomb]
+   flagtemplate = "django-impersonate"
 
-    [diff]
-    git = 1
+   [diff]
+   git = 1
 
 We have more information on the topic here:
 

          
@@ 598,7 594,7 @@ Commercial Support
 ------------------
 
 This software, and lots of other software like it, has been built in
-support of many of Netlandish's own projects, and the projects of our
+support of many of Netlandish’s own projects, and the projects of our
 clients. We would love to help you on your next project so get in touch
 by dropping us a note at hello@netlandish.com.
 

          
M impersonate/__init__.py +1 -1
@@ 1,5 1,5 @@ 
 # -*- coding: utf-8 -*-
-VERSION = (1, 7, 0, 'final', 0)
+VERSION = (1, 7, 1, 'final', 0)
 
 
 # taken from django-registration