Skip to content
Snippets Groups Projects
Select Git revision
  • 179c9cde23965ef307052442a553431dd3fd98b6
  • main default protected
2 results

exporter.py

Blame
  • auth.py 7.97 KiB
    import logging
    
    from django.conf import settings
    from django.contrib import messages
    from django.contrib.auth import views as auth_views
    from django.contrib.auth.mixins import LoginRequiredMixin
    from django.contrib.sites.shortcuts import get_current_site
    from django.core.mail import EmailMessage
    from django.http import JsonResponse, HttpResponseRedirect
    from django.shortcuts import redirect
    from django.template.loader import render_to_string
    from django.utils.decorators import method_decorator
    from django.views.decorators.cache import never_cache
    from django.views.decorators.debug import sensitive_post_parameters
    from django.views.generic import FormView, TemplateView, View
    from django.urls import reverse, reverse_lazy
    from django.utils.encoding import force_bytes, force_str
    from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode
    
    from core.models import PlatformUser, UserCommunicationChannel
    from core.forms import PasswordResetForm
    
    from ..forms import SignUpForm
    from ..tokens import channel_activation_token
    from .mixins import ConferenceMixin, PasswordMixin
    
    
    logger = logging.getLogger(__name__)
    
    
    class LoginView(auth_views.LoginView):
        template_name = 'backoffice/login.html'
    
        def get_success_url(self):
            return reverse('backoffice:index')
    
    
    class LogoutView(auth_views.LogoutView):
        next_page = reverse_lazy('backoffice:index')
    
    
    class SignupView(FormView):
        form_class = SignUpForm
        template_name = 'registration/signup.html'
    
        def form_valid(self, form):
            user = form.save(commit=False)
            user.is_active = False
            user.save()
    
            channel = user.communication_channels.create(
                channel=UserCommunicationChannel.Channel.MAIL,
                address=form.cleaned_data['email'],
            )
            channel.save()
    
            try:
                subject = 'Activate Your RC3 Platform Account'
                body = render_to_string('registration/account_activation_email.txt', {
                    'user': user,
                    'domain': get_current_site(self.request).domain,
                    'uid': urlsafe_base64_encode(force_bytes(user.pk)),
                    'cid': channel.id,
                    'token': channel_activation_token.make_token(channel),
                })
                message = EmailMessage(
                    to=[user.email],
                    subject=subject,
                    body=body,
                    reply_to=settings.MAIL_REPLY_TO,
                )
                result = message.send()
                logger.info('Sent account activation mail to "' + user.email + '" for ' + user.username + ' = ' + str(result))
                return redirect('backoffice:account_activation_sent')
    
            except Exception as err:
                print('MIMIMI', err)
                logger.exception('sending account activation mail failed')
                user.delete()
                messages.error(self.request, 'Could not send mail, please try again :(')
                return self.get(self.request)
    
    
    class SignupDoneView(ConferenceMixin, TemplateView):
        template_name = 'registration/signup_done.html'
    
    
    def signup_activate(request, uidb64, channel_id, token):
        user, channel = None, None  # ensure variables exists if any of the next two fail, otherwise the logger call fails
        try:
            uid = force_str(urlsafe_base64_decode(uidb64))
            user, channel = None, None  # ensure variables exists if any of the next two fail, otherwise the logger call fails
            user = PlatformUser.objects.get(pk=uid)
            channel = user.communication_channels.get(id=channel_id)
        except Exception as err:
            messages.warning(request, 'Invalid activation code.')
            logger.warning(f'Account activation failed (user={user}, uidb64={uidb64}, channel={channel_id}, token={token}): {err}')
            return redirect('backoffice:signup')
    
        if not channel_activation_token.check_token(channel, token):
            messages.warning(request, 'Invalid activation code.')
            logger.warning(f'Account activation failed (user={user}, uidb64={uidb64}, channel={channel_id}, token={token}) due to invalid token.')
            return redirect('backoffice:signup')
    
        if channel.channel != UserCommunicationChannel.Channel.MAIL or user.email is None or user.email != channel.address:
            messages.warning(request, 'Not an account registration.')
            logger.warning(f'Account activation failed for non-registration-channel (user={user}, uidb64={uidb64}, channel={channel_id}, token={token})')
            return redirect('backoffice:signup')
    
        # first time registration: user.email was still set to the mail communication channel's address
        user.is_active = True
        user.email = ''
        channel.is_verified = True
        user.save()
        channel.save()
    
        messages.success(request, 'Activation code OK')
        logger.info(f'Account activated successfully: {user.username}')
    
        return redirect('backoffice:index')
    
    
    class AuthDebugView(LoginRequiredMixin, ConferenceMixin, View):
        def get(self, *args, **kwargs):
            u = self.request.user
    
            result = {}
            result['conference'] = self.conference.slug
            result['global'] = {
                'username': u.username,
                'active': u.is_active,
                'flags': [],
                'groups': list(u.groups.values_list('name', flat=True)),
                'permissions': list(str(x) for x in u.get_all_permissions()),
            }
            if u.is_superuser:
                result['global']['flags'].append('superuser')
            if u.is_staff:
                result['global']['flags'].append('staff')
    
            if (member := self.conferencemember) is not None:
                result['member'] = {
                    'staff': member.is_staff,
                    'active_angel': member.active_angel,
                    'pages': member.static_page_groups,
                    'groups': list(member.permission_groups.values_list('name', flat=True)),
                    'permissions': list(str(x) for x in member.get_permission_groups_permissions()),
                }
    
                result['combined_permissions'] = list(str(x) for x in member.all_permissions)
    
            else:
                result['member'] = False
    
            return JsonResponse(result)
    
    
    class PasswordChangeView(PasswordMixin, auth_views.PasswordChangeView):
        template_name = 'registration/change_password.html'
        success_url = reverse_lazy('backoffice:password_change_done')
    
    
    class PasswordChangeDoneView(PasswordMixin, auth_views.PasswordChangeView):
        template_name = 'registration/change_password_done.html'
    
    
    class PasswordResetView(PasswordMixin, auth_views.PasswordResetView):
        template_name = 'registration/reset_password.html'
        subject_template_name = 'registration/reset_password_subject.txt'
    
        form_class = PasswordResetForm
        email_template_name = 'registration/reset_password_mail.txt'
        success_url = reverse_lazy('backoffice:password_reset_done')
        retry = False
    
        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            context.setdefault("retry", self.retry)
            return context
    
    
    class PasswordResetDoneView(PasswordMixin, auth_views.PasswordResetDoneView):
        template_name = 'registration/reset_password_done.html'
    
    
    class PasswordResetConfirmView(PasswordMixin, auth_views.PasswordResetConfirmView):
        template_name = 'registration/reset_password_confirm.html'
        success_url = reverse_lazy('backoffice:password_reset_complete')
        failure_url = reverse_lazy('backoffice:password_reset_retry')
    
        @method_decorator(sensitive_post_parameters())
        @method_decorator(never_cache)
        def dispatch(self, *args, **kwargs):
            resp = super().dispatch(*args, **kwargs)
            if resp.status_code == 200 and resp.context_data['form'] is None:
                return HttpResponseRedirect(self.failure_url)
            return resp
    
        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            context.update({
                'title': self.title,
                **(self.extra_context or {}),
            })
            return context
    
    
    class PasswordResetCompleteView(PasswordMixin, auth_views.PasswordResetCompleteView):
        template_name = 'registration/reset_password_complete.html'