Skip to content
Snippets Groups Projects
views.py 5.75 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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.models import BaseUserManager
    
    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.csrf import csrf_protect
    
    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(csrf_protect)
        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')):
                user.is_active = True
    
                # Set a temp password so users who skip setting one can use the password reset function.
                temp_pass = BaseUserManager().make_random_password(length=32)
                user.set_password(temp_pass)
    
    Dan Braghis's avatar
    Dan Braghis committed
                user.save()
    
    
    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(**{
    
    Dan Braghis's avatar
    Dan Braghis committed
                    'pk': force_text(urlsafe_base64_decode(uidb64)),
    
    Dan Braghis's avatar
    Dan Braghis committed
                    'is_active': False
                })
                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
        })