Skip to content
Snippets Groups Projects
views.py 5.6 KiB
Newer Older
from django.conf import settings
from django.contrib import messages
from django.contrib.auth import get_user_model, login, update_session_auth_hash
from django.contrib.auth.decorators import login_required
from django.contrib.auth.forms import AdminPasswordChangeForm
Dan Braghis's avatar
Dan Braghis committed
from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.contrib.auth.views import SuccessURLAllowedHostsMixin
from django.http import HttpResponseRedirect
from django.shortcuts import redirect, render, resolve_url
from django.template.response import TemplateResponse
Dan Braghis's avatar
Dan Braghis committed
from django.urls import reverse_lazy
from django.utils.decorators import method_decorator
Dan Braghis's avatar
Dan Braghis committed
from django.utils.encoding import force_text
from django.utils.http import is_safe_url, urlsafe_base64_decode
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_protect
from django.views.decorators.debug import sensitive_post_parameters
from django.views.generic import UpdateView
Dan Braghis's avatar
Dan Braghis committed
from django.views.generic.base import TemplateView
Todd Dembrey's avatar
Todd Dembrey committed
from hijack.views import login_with_id
from two_factor.views import LoginView as TwoFactorLoginView
from wagtail.admin.views.account import password_management_enabled
from .decorators import require_oauth_whitelist
from .forms import BecomeUserForm, ProfileForm
Todd Dembrey's avatar
Todd Dembrey committed
User = get_user_model()

class LoginView(SuccessURLAllowedHostsMixin, TwoFactorLoginView):
    redirect_authenticated_user = False

    @method_decorator(sensitive_post_parameters())
    @method_decorator(csrf_protect)
    @method_decorator(never_cache)
    def dispatch(self, request, *args, **kwargs):
        if self.redirect_authenticated_user and self.request.user.is_authenticated:
            redirect_to = self.get_success_url()
            if redirect_to == self.request.path:
                raise ValueError(
                    "Redirection loop for authenticated user detected. Check that "
                    "your LOGIN_REDIRECT_URL doesn't point to a login page."
                )
            return HttpResponseRedirect(redirect_to)
        return super().dispatch(request, *args, **kwargs)

    def get_success_url(self):
        url = self.get_redirect_url()
        return url or resolve_url(settings.LOGIN_REDIRECT_URL)

    def get_redirect_url(self):
        """Return the user-originating redirect URL if it's safe."""
        redirect_to = self.request.POST.get(
            self.redirect_field_name,
            self.request.GET.get(self.redirect_field_name, '')
        )
        url_is_safe = is_safe_url(
            url=redirect_to,
            allowed_hosts=self.get_success_url_allowed_hosts(),
            require_https=self.request.is_secure(),
        )
        return redirect_to if url_is_safe else ''


@method_decorator(login_required, name='dispatch')
class AccountView(UpdateView):
    form_class = ProfileForm
    template_name = 'users/account.html'

    def get_object(self):
        return self.request.user

    def get_success_url(self,):
        return reverse_lazy('users:account')

    def get_context_data(self, **kwargs):
        if self.request.user.is_superuser:
            swappable_form = BecomeUserForm()
        else:
            swappable_form = None

        show_change_password = password_management_enabled() and self.request.user.has_usable_password(),

        return super().get_context_data(
            swappable_form=swappable_form,
            show_change_password=show_change_password,
            **kwargs,
        )
Todd Dembrey's avatar
Todd Dembrey committed
def become(request):
    id = request.POST['user']
    if request.POST and id:
Todd Dembrey's avatar
Todd Dembrey committed
        return login_with_id(request, id)
    return redirect('users:account')


@require_oauth_whitelist
def oauth(request):
Dan Braghis's avatar
Dan Braghis committed
    """Generic, empty view for the OAuth associations."""

    return TemplateResponse(request, 'users/oauth.html', {})


class ActivationView(TemplateView):
    def get(self, request, *args, **kwargs):
Dan Braghis's avatar
Dan Braghis committed
        user = self.get_user(kwargs.get('uidb64'))

        if self.valid(user, kwargs.get('token')):
Dan Braghis's avatar
Dan Braghis committed
            user.backend = 'django.contrib.auth.backends.ModelBackend'
            login(request, user)
            return redirect('users:activate_password')
Dan Braghis's avatar
Dan Braghis committed

        return render(request, 'users/activation/invalid.html')

Dan Braghis's avatar
Dan Braghis committed
    def valid(self, user, token):
Dan Braghis's avatar
Dan Braghis committed
        """
Dan Braghis's avatar
Dan Braghis committed
        Verify that the activation token is valid and within the
        permitted activation time window.
Dan Braghis's avatar
Dan Braghis committed
        """

        token_generator = PasswordResetTokenGenerator()
Dan Braghis's avatar
Dan Braghis committed
        return user is not None and token_generator.check_token(user, token)
Dan Braghis's avatar
Dan Braghis committed
    def get_user(self, uidb64):
Dan Braghis's avatar
Dan Braghis committed
        """
        Given the verified uid, look up and return the
        corresponding user account if it exists, or ``None`` if it
        doesn't.
        """
        try:
            user = User.objects.get(**{
                'pk': force_text(urlsafe_base64_decode(uidb64))
Dan Braghis's avatar
Dan Braghis committed
            })
            return user
        except (TypeError, ValueError, OverflowError, User.DoesNotExist):
            return None


def create_password(request):
    """
    A custom view for the admin password change form used for account activation.
    """

    if request.method == 'POST':
        form = AdminPasswordChangeForm(request.user, request.POST)
        if form.is_valid():
            user = form.save()
            update_session_auth_hash(request, user)  # Important!
            messages.success(request, 'Your password was successfully updated!')
            return redirect('users:account')
        else:
            messages.error(request, 'Please correct the errors below.')
    else:
        form = AdminPasswordChangeForm(request.user)
    return render(request, 'users/change_password.html', {
        'form': form
    })