Select Git revision
exporter.py
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'