prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Wagtail doesn't gracefully support session invalidation on password change
  According to [Django's documentation](https://docs.djangoproject.com/en/1.7/topics/auth/default/#session-invalidation-on-password-change), SessionAuthenticationMiddleware is new in Django 1.7, enabled by default, and will be mandatory in Django 2.0.
  
  Currently, when the middleware is loaded and the user changes their password, they are immediately kicked out to the sign in screen. The user's session is most likely invalidated. This is very obtrusive and the user is not informed if their password was successfully updated. I believe the offending code is in
  [account.py](https://github.com/torchbox/wagtail/blob/master/wagtail/wagtailadmin/views/account.py#L26) and attempted to modify the code from the example to make it work, but the outcome was the same:
  
  ``` python
  # ...
  from django.contrib.auth import update_session_auth_hash # new code
  # ...
  def change_password(request):
      can_change_password = request.user.has_usable_password()
  
      if can_change_password:
          if request.POST:
              form = SetPasswordForm(request.user, request.POST)
  
              if form.is_valid():
                  form.save()
                  update_session_auth_hash(request, form.user) # new code
  
                  messages.success(request, _("Your password has been changed successfully!"))
                  return redirect('wagtailadmin_account')
          else:
              form = SetPasswordForm(request.user)
      else:
          form = None
  
      return render(request, 'wagtailadmin/account/change_password.html', {
          'form': form,
          'can_change_password': can_change_password,
      })
  ```
  
  I am, currently, a Django novice, so that's as far as I was able to get. Hope this is an easy fix!
  
  
  </issue>
  <code>
  [start of wagtail/wagtailadmin/views/account.py]
  1 from django.conf import settings
  2 from django.shortcuts import render, redirect
  3 from django.contrib import messages
  4 from django.contrib.auth.forms import SetPasswordForm
  5 from django.contrib.auth.views import logout as auth_logout, login as auth_login
  6 from django.utils.translation import ugettext as _ 
  7 from django.views.decorators.debug import sensitive_post_parameters
  8 from django.views.decorators.cache import never_cache
  9 
  10 from wagtail.wagtailadmin import forms
  11 from wagtail.wagtailusers.forms import NotificationPreferencesForm
  12 from wagtail.wagtailusers.models import UserProfile
  13 from wagtail.wagtailcore.models import UserPagePermissionsProxy
  14 
  15 
  16 def account(request):
  17     user_perms = UserPagePermissionsProxy(request.user)
  18     show_notification_preferences = user_perms.can_edit_pages() or user_perms.can_publish_pages()
  19 
  20     return render(request, 'wagtailadmin/account/account.html', {
  21         'show_change_password': getattr(settings, 'WAGTAIL_PASSWORD_MANAGEMENT_ENABLED', True) and request.user.has_usable_password(),
  22         'show_notification_preferences': show_notification_preferences
  23     })
  24 
  25 
  26 def change_password(request):
  27     can_change_password = request.user.has_usable_password()
  28 
  29     if can_change_password:
  30         if request.POST:
  31             form = SetPasswordForm(request.user, request.POST)
  32 
  33             if form.is_valid():
  34                 form.save()
  35 
  36                 messages.success(request, _("Your password has been changed successfully!"))
  37                 return redirect('wagtailadmin_account')
  38         else:
  39             form = SetPasswordForm(request.user)
  40     else:
  41         form = None
  42 
  43     return render(request, 'wagtailadmin/account/change_password.html', {
  44         'form': form,
  45         'can_change_password': can_change_password,
  46     })
  47 
  48 
  49 def notification_preferences(request):
  50 
  51     if request.POST:
  52         form = NotificationPreferencesForm(request.POST, instance=UserProfile.get_for_user(request.user))
  53 
  54         if form.is_valid():
  55             form.save()
  56             messages.success(request, _("Your preferences have been updated successfully!"))
  57             return redirect('wagtailadmin_account')
  58     else:
  59         form = NotificationPreferencesForm(instance=UserProfile.get_for_user(request.user))
  60 
  61     # quick-and-dirty catch-all in case the form has been rendered with no
  62     # fields, as the user has no customisable permissions
  63     if not form.fields:
  64         return redirect('wagtailadmin_account')
  65 
  66     return render(request, 'wagtailadmin/account/notification_preferences.html', {
  67         'form': form,
  68     })
  69 
  70 
  71 @sensitive_post_parameters()
  72 @never_cache
  73 def login(request):
  74     if request.user.is_authenticated() and request.user.has_perm('wagtailadmin.access_admin'):
  75         return redirect('wagtailadmin_home')
  76     else:
  77         from django.contrib.auth import get_user_model
  78         return auth_login(request,
  79             template_name='wagtailadmin/login.html',
  80             authentication_form=forms.LoginForm,
  81             extra_context={
  82                 'show_password_reset': getattr(settings, 'WAGTAIL_PASSWORD_MANAGEMENT_ENABLED', True),
  83                 'username_field': get_user_model().USERNAME_FIELD,
  84             },
  85         )
  86 
  87 
  88 def logout(request):
  89     response = auth_logout(request, next_page='wagtailadmin_login')
  90 
  91     # By default, logging out will generate a fresh sessionid cookie. We want to use the
  92     # absence of sessionid as an indication that front-end pages are being viewed by a
  93     # non-logged-in user and are therefore cacheable, so we forcibly delete the cookie here.
  94     response.delete_cookie(settings.SESSION_COOKIE_NAME,
  95         domain=settings.SESSION_COOKIE_DOMAIN,
  96         path=settings.SESSION_COOKIE_PATH)
  97 
  98     # HACK: pretend that the session hasn't been modified, so that SessionMiddleware
  99     # won't override the above and write a new cookie.
  100     request.session.modified = False
  101 
  102     return response
  103
  [end of wagtail/wagtailadmin/views/account.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/wagtail/wagtailadmin/views/account.py b/wagtail/wagtailadmin/views/account.py
  --- a/wagtail/wagtailadmin/views/account.py
  +++ b/wagtail/wagtailadmin/views/account.py
  @@ -3,6 +3,7 @@
   from django.contrib import messages
   from django.contrib.auth.forms import SetPasswordForm
   from django.contrib.auth.views import logout as auth_logout, login as auth_login
  +from django.contrib.auth import update_session_auth_hash
   from django.utils.translation import ugettext as _ 
   from django.views.decorators.debug import sensitive_post_parameters
   from django.views.decorators.cache import never_cache
  @@ -32,6 +33,7 @@
   
               if form.is_valid():
                   form.save()
  +                update_session_auth_hash(request, form.user)
   
                   messages.success(request, _("Your password has been changed successfully!"))
                   return redirect('wagtailadmin_account')
  
verification_info: {"golden_diff": "diff --git a/wagtail/wagtailadmin/views/account.py b/wagtail/wagtailadmin/views/account.py\n--- a/wagtail/wagtailadmin/views/account.py\n+++ b/wagtail/wagtailadmin/views/account.py\n@@ -3,6 +3,7 @@\n from django.contrib import messages\n from django.contrib.auth.forms import SetPasswordForm\n from django.contrib.auth.views import logout as auth_logout, login as auth_login\n+from django.contrib.auth import update_session_auth_hash\n from django.utils.translation import ugettext as _ \n from django.views.decorators.debug import sensitive_post_parameters\n from django.views.decorators.cache import never_cache\n@@ -32,6 +33,7 @@\n \n             if form.is_valid():\n                 form.save()\n+                update_session_auth_hash(request, form.user)\n \n                 messages.success(request, _(\"Your password has been changed successfully!\"))\n                 return redirect('wagtailadmin_account')\n", "issue": "Wagtail doesn't gracefully support session invalidation on password change\nAccording to [Django's documentation](https://docs.djangoproject.com/en/1.7/topics/auth/default/#session-invalidation-on-password-change), SessionAuthenticationMiddleware is new in Django 1.7, enabled by default, and will be mandatory in Django 2.0.\n\nCurrently, when the middleware is loaded and the user changes their password, they are immediately kicked out to the sign in screen. The user's session is most likely invalidated. This is very obtrusive and the user is not informed if their password was successfully updated. I believe the offending code is in\n[account.py](https://github.com/torchbox/wagtail/blob/master/wagtail/wagtailadmin/views/account.py#L26) and attempted to modify the code from the example to make it work, but the outcome was the same:\n\n``` python\n# ...\nfrom django.contrib.auth import update_session_auth_hash # new code\n# ...\ndef change_password(request):\n    can_change_password = request.user.has_usable_password()\n\n    if can_change_password:\n        if request.POST:\n            form = SetPasswordForm(request.user, request.POST)\n\n            if form.is_valid():\n                form.save()\n                update_session_auth_hash(request, form.user) # new code\n\n                messages.success(request, _(\"Your password has been changed successfully!\"))\n                return redirect('wagtailadmin_account')\n        else:\n            form = SetPasswordForm(request.user)\n    else:\n        form = None\n\n    return render(request, 'wagtailadmin/account/change_password.html', {\n        'form': form,\n        'can_change_password': can_change_password,\n    })\n```\n\nI am, currently, a Django novice, so that's as far as I was able to get. Hope this is an easy fix!\n\n", "before_files": [{"content": "from django.conf import settings\nfrom django.shortcuts import render, redirect\nfrom django.contrib import messages\nfrom django.contrib.auth.forms import SetPasswordForm\nfrom django.contrib.auth.views import logout as auth_logout, login as auth_login\nfrom django.utils.translation import ugettext as _ \nfrom django.views.decorators.debug import sensitive_post_parameters\nfrom django.views.decorators.cache import never_cache\n\nfrom wagtail.wagtailadmin import forms\nfrom wagtail.wagtailusers.forms import NotificationPreferencesForm\nfrom wagtail.wagtailusers.models import UserProfile\nfrom wagtail.wagtailcore.models import UserPagePermissionsProxy\n\n\ndef account(request):\n    user_perms = UserPagePermissionsProxy(request.user)\n    show_notification_preferences = user_perms.can_edit_pages() or user_perms.can_publish_pages()\n\n    return render(request, 'wagtailadmin/account/account.html', {\n        'show_change_password': getattr(settings, 'WAGTAIL_PASSWORD_MANAGEMENT_ENABLED', True) and request.user.has_usable_password(),\n        'show_notification_preferences': show_notification_preferences\n    })\n\n\ndef change_password(request):\n    can_change_password = request.user.has_usable_password()\n\n    if can_change_password:\n        if request.POST:\n            form = SetPasswordForm(request.user, request.POST)\n\n            if form.is_valid():\n                form.save()\n\n                messages.success(request, _(\"Your password has been changed successfully!\"))\n                return redirect('wagtailadmin_account')\n        else:\n            form = SetPasswordForm(request.user)\n    else:\n        form = None\n\n    return render(request, 'wagtailadmin/account/change_password.html', {\n        'form': form,\n        'can_change_password': can_change_password,\n    })\n\n\ndef notification_preferences(request):\n\n    if request.POST:\n        form = NotificationPreferencesForm(request.POST, instance=UserProfile.get_for_user(request.user))\n\n        if form.is_valid():\n            form.save()\n            messages.success(request, _(\"Your preferences have been updated successfully!\"))\n            return redirect('wagtailadmin_account')\n    else:\n        form = NotificationPreferencesForm(instance=UserProfile.get_for_user(request.user))\n\n    # quick-and-dirty catch-all in case the form has been rendered with no\n    # fields, as the user has no customisable permissions\n    if not form.fields:\n        return redirect('wagtailadmin_account')\n\n    return render(request, 'wagtailadmin/account/notification_preferences.html', {\n        'form': form,\n    })\n\n\n@sensitive_post_parameters()\n@never_cache\ndef login(request):\n    if request.user.is_authenticated() and request.user.has_perm('wagtailadmin.access_admin'):\n        return redirect('wagtailadmin_home')\n    else:\n        from django.contrib.auth import get_user_model\n        return auth_login(request,\n            template_name='wagtailadmin/login.html',\n            authentication_form=forms.LoginForm,\n            extra_context={\n                'show_password_reset': getattr(settings, 'WAGTAIL_PASSWORD_MANAGEMENT_ENABLED', True),\n                'username_field': get_user_model().USERNAME_FIELD,\n            },\n        )\n\n\ndef logout(request):\n    response = auth_logout(request, next_page='wagtailadmin_login')\n\n    # By default, logging out will generate a fresh sessionid cookie. We want to use the\n    # absence of sessionid as an indication that front-end pages are being viewed by a\n    # non-logged-in user and are therefore cacheable, so we forcibly delete the cookie here.\n    response.delete_cookie(settings.SESSION_COOKIE_NAME,\n        domain=settings.SESSION_COOKIE_DOMAIN,\n        path=settings.SESSION_COOKIE_PATH)\n\n    # HACK: pretend that the session hasn't been modified, so that SessionMiddleware\n    # won't override the above and write a new cookie.\n    request.session.modified = False\n\n    return response\n", "path": "wagtail/wagtailadmin/views/account.py"}]}