diff --git a/apps/member/signals.py b/apps/member/signals.py index 2b03e3ced7fac6f67efaa9f509d978c0df8e7987..fbb66c1f6055de516653e62bef2bef2348bc6e24 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 29b1622284ac8ff37057f0049237d00e5bb67c63..ed5826ef00e6f8871688cb5df5635c849edf747d 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 ce2977dc7d0ab6d154f332ae0f7693bdb0f70d9a..ae9b2fca6c63ebb8cbc817bc35cdb9e66748f364 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 543f2fb9bdf6313f56ce80f03976b80eac14c559..7f06f92f41270ba72c456883191e398fadb77498 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 ad479e143ed33ba07275261ecf86a0c2c09fc8b9..b09a46c750badb975f455d71fa0216b5311a4fd1 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 e8f2032dc1d233aa45d5b34d3bf4cc7ceb7d201b..252b83c7ae8f7a40c5d996c5b35a2e144dcd68b2 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 0000000000000000000000000000000000000000..9b7449e231a2db6fac1e6d23cbabf782a19b2e43 --- /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 e500ee19bbb4d4ff4f9ccc915a73d83625c83e3b..490fe2abce657b41bf2612d798500020a71e62ac 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 %}