From b1cd46bf7de7533078ba34b59072fac05950d7cc Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO <yohann.danello@gmail.com> Date: Sun, 5 Apr 2020 08:01:51 +0200 Subject: [PATCH] Invalidate registrations, fix profile creation --- apps/member/signals.py | 4 +- apps/member/views.py | 13 +++-- apps/registration/urls.py | 6 ++- apps/registration/views.py | 47 +++++++++++++--- apps/treasury/forms.py | 2 +- .../account_activation_email.html | 2 +- .../registration/future_profile_detail.html | 54 +++++++++++++++++++ templates/registration/future_user_list.html | 14 +++-- 8 files changed, 121 insertions(+), 21 deletions(-) create mode 100644 templates/registration/future_profile_detail.html diff --git a/apps/member/signals.py b/apps/member/signals.py index 2b03e3ce..fbb66c1f 100644 --- a/apps/member/signals.py +++ b/apps/member/signals.py @@ -10,7 +10,7 @@ def save_user_profile(instance, created, raw, **_kwargs): # When provisionning data, do not try to autocreate return - if created: + if created and instance.is_active: from .models import Profile Profile.objects.get_or_create(user=instance) - instance.profile.save() + instance.profile.save() diff --git a/apps/member/views.py b/apps/member/views.py index 29b16222..ed5826ef 100644 --- a/apps/member/views.py +++ b/apps/member/views.py @@ -102,11 +102,8 @@ class UserUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): return super().form_valid(form) def get_success_url(self, **kwargs): - if kwargs: - return reverse_lazy('member:user_detail', - kwargs={'pk': kwargs['id']}) - else: - return reverse_lazy('member:user_detail', args=(self.object.id,)) + url = 'member:user_detail' if self.object.profile.registration_valid else 'registration:future_user_detail' + return reverse_lazy(url, args=(self.object.id,)) class UserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): @@ -117,6 +114,12 @@ class UserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): context_object_name = "user_object" template_name = "member/profile_detail.html" + def get_queryset(self, **kwargs): + """ + We can't display information of a not registered user. + """ + return super().get_queryset().filter(profile__registration_valid=True) + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) user = context['user_object'] diff --git a/apps/registration/urls.py b/apps/registration/urls.py index ce2977dc..ae9b2fca 100644 --- a/apps/registration/urls.py +++ b/apps/registration/urls.py @@ -8,7 +8,9 @@ from . import views app_name = 'registration' urlpatterns = [ path('signup/', views.UserCreateView.as_view(), name="signup"), - path('validate_email/sent', views.UserActivationEmailSentView.as_view(), name='account_activation_sent'), - path('validate_email/<uidb64>/<token>', views.UserActivateView.as_view(), name='account_activation'), + path('validate_email/sent/', views.UserActivationEmailSentView.as_view(), name='account_activation_sent'), + path('validate_email/<uidb64>/<token>/', views.UserActivateView.as_view(), name='account_activation'), path('validate_user/', views.FutureUserListView.as_view(), name="future_user_list"), + path('validate_user/<int:pk>/', views.FutureUserDetailView.as_view(), name="future_user_detail"), + path('validate_user/<int:pk>/invalidate/', views.FutureUserInvalidateView.as_view(), name="future_user_invalidate"), ] diff --git a/apps/registration/views.py b/apps/registration/views.py index 543f2fb9..7f06f92f 100644 --- a/apps/registration/views.py +++ b/apps/registration/views.py @@ -5,15 +5,18 @@ from django.conf import settings from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.models import User from django.core.exceptions import ValidationError -from django.shortcuts import resolve_url +from django.shortcuts import resolve_url, redirect from django.urls import reverse_lazy from django.utils.decorators import method_decorator from django.utils.http import urlsafe_base64_decode from django.utils.translation import gettext_lazy as _ +from django.views import View from django.views.decorators.csrf import csrf_protect -from django.views.generic import CreateView, TemplateView +from django.views.generic import CreateView, TemplateView, DetailView from django_tables2 import SingleTableView from member.forms import ProfileForm +from member.models import Profile +from permission.backends import PermissionBackend from permission.views import ProtectQuerysetMixin from .forms import SignUpForm @@ -42,15 +45,19 @@ class UserCreateView(CreateView): If the form is valid, then the user is created with is_active set to False so that the user cannot log in until the email has been validated. """ - profile_form = ProfileForm(self.request.POST) + profile_form = ProfileForm(data=self.request.POST) if not profile_form.is_valid(): return self.form_invalid(form) user = form.save(commit=False) user.is_active = False - user.profile = profile_form.save(commit=False) + profile_form.instance.user = user + profile = profile_form.save(commit=False) + user.profile = profile user.save() - user.profile.save() + user.refresh_from_db() + profile.user = user + profile.save() user.profile.send_email_validation_link() @@ -86,7 +93,6 @@ class UserActivateView(TemplateView): return self.render_to_response(self.get_context_data()) def get_user(self, uidb64): - print(uidb64) try: # urlsafe_base64_decode() decodes to bytestring uid = urlsafe_base64_decode(uidb64).decode() @@ -131,3 +137,32 @@ class FutureUserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableVi return context + +class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): + """ + Affiche les informations sur un utilisateur, sa note, ses clubs... + """ + model = User + context_object_name = "user_object" + template_name = "registration/future_profile_detail.html" + + def get_queryset(self, **kwargs): + """ + We only display information of a not registered user. + """ + return super().get_queryset().filter(profile__registration_valid=False) + + +class FutureUserInvalidateView(ProtectQuerysetMixin, LoginRequiredMixin, View): + """ + Affiche les informations sur un utilisateur, sa note, ses clubs... + """ + + def dispatch(self, request, *args, **kwargs): + user = User.objects.filter(profile__registration_valid=False)\ + .filter(PermissionBackend.filter_queryset(request.user, User, "change", "is_valid"))\ + .get(pk=self.kwargs["pk"]) + + user.delete() + + return redirect('registration:future_user_list') diff --git a/apps/treasury/forms.py b/apps/treasury/forms.py index ad479e14..b09a46c7 100644 --- a/apps/treasury/forms.py +++ b/apps/treasury/forms.py @@ -53,7 +53,7 @@ ProductFormSet = forms.inlineformset_factory( class ProductFormSetHelper(FormHelper): """ - Specify some template informations for the product form. + Specify some template information for the product form. """ def __init__(self, form=None): diff --git a/templates/registration/account_activation_email.html b/templates/registration/account_activation_email.html index e8f2032d..252b83c7 100644 --- a/templates/registration/account_activation_email.html +++ b/templates/registration/account_activation_email.html @@ -2,7 +2,7 @@ Hi {{ user.username }}, Welcome to {{ site_name }}. Please click on the link below to confirm your registration. -{{ protocol }}://{{ domain }}{% url 'member:account_activation' uidb64=uid token=token %} +{{ protocol }}://{{ domain }}{% url 'registration:account_activation' uidb64=uid token=token %} This link is only valid for a couple of days, after that you will need to contact us to validate your email. diff --git a/templates/registration/future_profile_detail.html b/templates/registration/future_profile_detail.html new file mode 100644 index 00000000..9b7449e2 --- /dev/null +++ b/templates/registration/future_profile_detail.html @@ -0,0 +1,54 @@ +{% extends "base.html" %} +{% load static %} +{% load i18n %} +{% load render_table from django_tables2 %} +{% load pretty_money %} + +{% block content %} + +<div class="card bg-light shadow"> + <div class="card-header text-center" > + <h4> {% trans "Account #" %} {{ object.pk }}</h4> + </div> + <div class="card-body" id="profile_infos"> + <dl class="row"> + <dt class="col-xl-6">{% trans 'name'|capfirst %}, {% trans 'first name' %}</dt> + <dd class="col-xl-6">{{ object.last_name }} {{ object.first_name }}</dd> + + <dt class="col-xl-6">{% trans 'username'|capfirst %}</dt> + <dd class="col-xl-6">{{ object.username }}</dd> + + <dt class="col-xl-6">{% trans 'email'|capfirst %}</dt> + <dd class="col-xl-6"><a href="mailto:{{ object.email }}">{{ object.email }}</a></dd> + + <dt class="col-xl-6">{% trans 'password'|capfirst %}</dt> + <dd class="col-xl-6"> + <a class="small" href="{% url 'password_change' %}"> + {% trans 'Change password' %} + </a> + </dd> + + <dt class="col-xl-6">{% trans 'section'|capfirst %}</dt> + <dd class="col-xl-6">{{ object.profile.section }}</dd> + + <dt class="col-xl-6">{% trans 'address'|capfirst %}</dt> + <dd class="col-xl-6">{{ object.profile.address }}</dd> + + <dt class="col-xl-6">{% trans 'phone number'|capfirst %}</dt> + <dd class="col-xl-6">{{ object.profile.phone_number }}</dd> + + <dt class="col-xl-6">{% trans 'paid'|capfirst %}</dt> + <dd class="col-xl-6">{{ object.profile.paid|yesno }}</dd> + </dl> + + {% if object.pk == user.pk %} + <a class="small" href="{% url 'member:auth_token' %}">{% trans 'Manage auth token' %}</a> + {% endif %} + </div> + <div class="card-footer text-center"> + <a class="btn btn-primary btn-sm" href="{% url 'member:user_update_profile' object.pk %}">{% trans 'Update Profile' %}</a> + <a class="btn btn-danger btn-sm" href="{% url 'registration:future_user_invalidate' object.pk %}">{% trans 'Delete registration' %}</a> + </div> +</div> + +{% endblock %} \ No newline at end of file diff --git a/templates/registration/future_user_list.html b/templates/registration/future_user_list.html index e500ee19..490fe2ab 100644 --- a/templates/registration/future_user_list.html +++ b/templates/registration/future_user_list.html @@ -4,13 +4,19 @@ {% load i18n %} {% block content %} - <div id="user_table"> - {% render_table table %} - </div> + <a href="{% url 'registration:signup' %}"><button class="btn btn-primary btn-block">{% trans "New user" %}</button></a> <hr> - <a href="{% url 'registration:signup' %}"><button class="btn btn-primary btn-block">{% trans "New user" %}</button></a> + {% if table.data %} + <div id="user_table"> + {% render_table table %} + </div> + {% else %} + <div class="alert alert-warning"> + {% trans "There is no pending user." %} + </div> + {% endif %} {% endblock %} {% block extrajavascript %} -- GitLab