Source code for django_pam.accounts.views

# -*- coding: utf-8 -*-
#
# django_pam/accounts/views.py
#
"""
Django PAM views.py
"""
__docformat__ = "restructuredtext en"


import logging
import json

from django.core.exceptions import ImproperlyConfigured
from django.contrib.auth import REDIRECT_FIELD_NAME, login, logout
from django.utils.decorators import method_decorator
from django.utils.translation import gettext_lazy as _
from django.utils.encoding import force_str
from django.views.decorators.csrf import csrf_protect
from django.views.decorators.cache import never_cache
from django.views.generic import TemplateView
from django.views.generic.edit import FormView
from django.shortcuts import redirect, resolve_url
from django.conf import settings

from .forms import AuthenticationForm
from .view_mixins import JSONResponseMixin, AjaxableResponseMixin

log = logging.getLogger('django_pam.accounts.views')


#
# LoginView
#
[docs] class LoginView(AjaxableResponseMixin, FormView): """ A class version of django.contrib.auth.views.login. Usage: .. code-block:: php re_path(r'^login/$', LoginView.as_view( form_class=MyAuthenticationForm, success_url='/my/success/url/', redirect_field_name='my-redirect-field-name', template_name='your_template.html' ), name='login'), """ form_class = AuthenticationForm redirect_field_name = REDIRECT_FIELD_NAME template_name = 'django_pam/accounts/login.html' success_url = ''
[docs] @method_decorator(csrf_protect) @method_decorator(never_cache) def dispatch(self, request, *args, **kwargs): """ Dispatches the request to the correct HTTP handler method. :param request: The Django request object. :param args: Positional arguments. :param kwargs: Keyword arguments. :rtype: The proper handler. """ return super().dispatch(request, *args, **kwargs)
[docs] def get_form_kwargs(self): """ Incoming AJAX data structure from an HTML <form> tag: .. code-block:: php [{'name': 'username', 'value': '<username>'}, {'name': 'password', 'value': '<password>'}, {'name': 'next', 'value': '<redirect URI>'} ] :rtype: dict """ if self.is_ajax(): json_data = json.loads(self.request.body.decode('utf-8')) kwargs = {} data = {} for arg in json_data: name = arg.get('name') value = arg.get('value') if name == self.redirect_field_name: self.success_url = resolve_url(value) else: data[name] = value kwargs['data'] = data else: kwargs = super().get_form_kwargs() return kwargs
[docs] def form_valid(self, form): """ The user has provided valid credentials (this was checked in the form's is_valid() method). :param form: A Django form object. :type form: Django Form :rtype: Result of ``AjaxableResponseMixin.form_valid``. """ self.object = form.get_user() login(self.request, self.object) return super().form_valid(form)
[docs] def get_data(self, **context): """ Add to the JSON context. :param context: A json response context. :type context: dict :rtype: dict """ # Called in form_valid in AjaxableResponseMixin. context.update({'username': self.object.get_username(), 'full_name': self.object.get_full_name(), self.redirect_field_name: self.get_success_url()}) return super().get_data(**context)
[docs] def get_success_url(self): """ Returns a url used for redirection. :rtype: str """ if self.success_url: redirect_to = self.success_url else: redirect_to = self.request.GET.get(self.redirect_field_name, '') if not redirect_to: redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL) return redirect_to
[docs] def get_context_data(self, **context): """ Get any extra context for GET methods. :param context: Context for GET methods. :type context: dict :rtype: dict """ context[self.redirect_field_name] = self.get_success_url() return super().get_context_data(**context)
# # LogoutView #
[docs] class LogoutView(JSONResponseMixin, TemplateView): """ A class version of django.contrib.auth.views.logout. Usage: .. code-block:: php re_path(r'^logout/$', LogoutView.as_view( template_name='my_template.html', success_url='/my/success/url/), redirect_field_name='my-redirect-field-name' ), name='logout') """ template_name = "django_pam/accounts/logout.html" redirect_field_name = REDIRECT_FIELD_NAME success_url = settings.LOGIN_URL
[docs] def get(self, request, *args, **kwargs): """ A GET method handler. :param request: The Django request object. :param args: Positional arguments. :param kwargs: Keyword arguments. :type kwargs: dict :rtype: A response object. """ log.debug("request: %s, args: %s, kwargs: %s", request, args, kwargs) if not request.user.is_authenticated: response = redirect(self.get_success_url()) else: next_page = request.GET.get(self.redirect_field_name, '') kwargs[self.redirect_field_name] = next_page context = self.get_context_data(**kwargs) response = self.render_to_response(context) return response
[docs] def post(self, request, *args, **kwargs): """ A POST method handler. .. note:: Incoming AJAX data structure from an HTML <form> tag: .. code-block:: php [{'name': 'next', 'value': '<redirect URI>'}] :param request: The Django request object. :param args: Positional arguments. :param kwargs: Keyword arguments. :type kwargs: dict :rtype: A response object. """ log.debug("request: %s, args: %s, kwargs: %s", request, args, kwargs) next_page = request.POST.get(self.redirect_field_name, '') kwargs[self.redirect_field_name] = next_page self.success_url = next_page if request.user.is_authenticated: logout(request) if self.is_ajax(): response = self.render_to_json_response({}) else: response = redirect(self.get_success_url()) return response
[docs] def get_data(self, **context): """ Add to the JSON context. :param context: A json response context. :type context: dict :rtype: dict """ # Called in JSONResponseMixin. context = super().get_data(**context) json_data = json.loads(self.request.body.decode('utf-8')) log.debug("json_data: %s", json_data) for arg in json_data: name = arg.get('name') value = arg.get('value') if name == self.redirect_field_name: context[name] = resolve_url(value) else: context[name] = value log.debug("context: %s, success_url: %s", context, self.success_url) return context
[docs] def get_context_data(self, **kwargs): """ Add to the template context. :param kwargs: Keyword arguments. :type kwargs: dict :type kwargs: dict :rtype: dict """ context = super().get_context_data(**kwargs) log.debug("kwargs: %s, context: %s", kwargs, context) context.update({ self.redirect_field_name: kwargs.get(self.redirect_field_name), }) return context
[docs] def get_success_url(self): """ Returns the supplied success URL. :rtype: str """ if self.success_url: # Forcing possible reverse_lazy evaluation url = force_str(self.success_url) else: raise ImproperlyConfigured( _("No URL to redirect to. Provide a success_url.")) return url