1
0
mirror of https://gitlab.crans.org/bde/nk20 synced 2025-06-21 01:48:21 +02:00

Merge branch 'beta' into traduction

This commit is contained in:
elkmaennchen
2020-09-13 12:17:25 +02:00
139 changed files with 5891 additions and 4687 deletions

View File

@ -16,4 +16,8 @@ Font-Awesome attribution is already done inside SVG files
#login-form select {
-moz-appearance: none;
cursor: pointer;
}
}
#login-form .asteriskField {
display: none;
}

View File

@ -5,14 +5,29 @@ SPDX-License-Identifier: GPL-3.0-or-later
{% load i18n %}
{% block content %}
{% if validlink %}
{% trans "Your email have successfully been validated." %}
<div class="card bg-light">
<h3 class="card-header text-center">
{{ title }}
</h3>
<div class="card-body">
{% if validlink %}
<p>
{% trans "Your email have successfully been validated." %}
</p>
{% if user_object.profile.registration_valid %}
<p>
{% blocktrans %}You can now <a href="{{ login_url }}">log in</a>.{% endblocktrans %}
</p>
{% else %}
<p>
{% trans "You must pay now your membership in the Kfet to complete your registration." %}
</p>
{% endif %}
{% else %}
{% trans "The link was invalid. The token may have expired. Please send us an email to activate your account." %}
{% endif %}
{% else %}
<p>
{% trans "The link was invalid. The token may have expired. Please send us an email to activate your account." %}
</p>
{% endif %}
</div>
</div>
{% endblock %}

View File

@ -5,13 +5,17 @@ SPDX-License-Identifier: GPL-3.0-or-later
{% load i18n %}
{% block content %}
<h2>{% trans "Account activation" %}</h2>
<p>
{% trans "An email has been sent. Please click on the link to activate your account." %}
</p>
<p>
{% trans "You must also go to the Kfet to pay your membership. The WEI registration includes the BDE membership." %}
</p>
{% endblock %}
<div class="card bg-light">
<h3 class="card-header text-center">
{% trans "Account activation" %}
</h3>
<div class="card-body">
<p>
{% trans "An email has been sent. Please click on the link to activate your account." %}
</p>
<p>
{% trans "You must also go to the Kfet to pay your membership." %}
</p>
</div>
</div>
{% endblock %}

View File

@ -27,7 +27,7 @@
</p>
<p>
{% trans "After that, you'll have to wait that someone validates your account before you can log in. You will need to pay your membership in the Kfet. Note that the WEI registration includes the Kfet membership." %}
{% trans "After that, you'll have to wait that someone validates your account before you can log in. You will need to pay your membership in the Kfet." %}
</p>
<p>
@ -38,4 +38,4 @@
<p>
{% trans "The Note Kfet team." %}<br>
{% trans "Mail generated by the Note Kfet on the" %} {% now "j F Y à H:i:s" %}
</p>
</p>

View File

@ -8,9 +8,9 @@ https://{{ domain }}{% url 'registration:email_validation' uidb64=uid token=toke
{% trans "This link is only valid for a couple of days, after that you will need to contact us to validate your email." %}
{% trans "After that, you'll have to wait that someone validates your account before you can log in. You will need to pay your membership in the Kfet. Note that the WEI registration includes the Kfet membership." %}
{% trans "After that, you'll have to wait that someone validates your account before you can log in. You will need to pay your membership in the Kfet." %}
{% trans "Thanks" %},
{% trans "The Note Kfet team." %}
{% trans "Mail generated by the Note Kfet on the" %} {% now "j F Y à H:i:s" %}
{% trans "Mail generated by the Note Kfet on the" %} {% now "j F Y à H:i:s" %}

View File

View File

@ -0,0 +1,386 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from django.contrib.auth.models import User
from django.db.models import Q
from django.test import TestCase
from django.urls import reverse
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode
from member.models import Club, Membership
from note.models import NoteUser, NoteSpecial, Transaction
from registration.tokens import email_validation_token
from treasury.models import SogeCredit
"""
Check that pre-registrations and validations are working as well.
"""
class TestSignup(TestCase):
"""
Assume we are a new user.
Check that it can pre-register without any problem.
"""
fixtures = ("initial", )
def test_signup(self):
"""
A first year member signs up and validates its email address.
"""
response = self.client.get(reverse("registration:signup"))
self.assertEqual(response.status_code, 200)
# Signup
response = self.client.post(reverse("registration:signup"), dict(
first_name="Toto",
last_name="TOTO",
username="toto",
email="toto@example.com",
password1="toto1234",
password2="toto1234",
phone_number="+33123456789",
department="EXT",
promotion=Club.objects.get(name="BDE").membership_start.year,
address="Earth",
paid=False,
ml_events_registration="en",
ml_sport_registration=True,
ml_art_registration=True,
))
self.assertRedirects(response, reverse("registration:email_validation_sent"), 302, 200)
self.assertTrue(User.objects.filter(username="toto").exists())
user = User.objects.get(username="toto")
# A preregistred user has no note
self.assertFalse(NoteUser.objects.filter(user=user).exists())
self.assertFalse(user.profile.registration_valid)
self.assertFalse(user.profile.email_confirmed)
self.assertFalse(user.is_active)
response = self.client.get(reverse("registration:email_validation_sent"))
self.assertEqual(response.status_code, 200)
# Check that the email validation link is valid
token = email_validation_token.make_token(user)
uid = urlsafe_base64_encode(force_bytes(user.pk))
response = self.client.get(reverse("registration:email_validation", kwargs=dict(uidb64=uid, token=token)))
self.assertEqual(response.status_code, 200)
user.profile.refresh_from_db()
self.assertTrue(user.profile.email_confirmed)
# Token has expired
response = self.client.get(reverse("registration:email_validation", kwargs=dict(uidb64=uid, token=token)))
self.assertEqual(response.status_code, 400)
# Uid does not exist
response = self.client.get(reverse("registration:email_validation", kwargs=dict(uidb64=0, token="toto")))
self.assertEqual(response.status_code, 400)
def test_invalid_signup(self):
"""
Send wrong data and check that it is not valid
"""
User.objects.create_superuser(
first_name="Toto",
last_name="TOTO",
username="toto",
email="toto@example.com",
password="toto1234",
)
# The email is already used
response = self.client.post(reverse("registration:signup"), dict(
first_name="Toto",
last_name="TOTO",
username="tôtö",
email="toto@example.com",
password1="toto1234",
password2="toto1234",
phone_number="+33123456789",
department="EXT",
promotion=Club.objects.get(name="BDE").membership_start.year,
address="Earth",
paid=False,
ml_events_registration="en",
ml_sport_registration=True,
ml_art_registration=True,
))
self.assertTrue(response.status_code, 200)
# The username is similar to a known alias
response = self.client.post(reverse("registration:signup"), dict(
first_name="Toto",
last_name="TOTO",
username="tôtö",
email="othertoto@example.com",
password1="toto1234",
password2="toto1234",
phone_number="+33123456789",
department="EXT",
promotion=Club.objects.get(name="BDE").membership_start.year,
address="Earth",
paid=False,
ml_events_registration="en",
ml_sport_registration=True,
ml_art_registration=True,
))
self.assertTrue(response.status_code, 200)
# The phone number is invalid
response = self.client.post(reverse("registration:signup"), dict(
first_name="Toto",
last_name="TOTO",
username="Ihaveanotherusername",
email="othertoto@example.com",
password1="toto1234",
password2="toto1234",
phone_number="invalid phone number",
department="EXT",
promotion=Club.objects.get(name="BDE").membership_start.year,
address="Earth",
paid=False,
ml_events_registration="en",
ml_sport_registration=True,
ml_art_registration=True,
))
self.assertTrue(response.status_code, 200)
class TestValidateRegistration(TestCase):
"""
Test the admin interface to validate users
"""
fixtures = ('initial',)
def setUp(self) -> None:
self.superuser = User.objects.create_superuser(
username="admintoto",
password="toto1234",
email="admin.toto@example.com",
)
self.client.force_login(self.superuser)
self.user = User.objects.create(
username="toto",
first_name="Toto",
last_name="TOTO",
email="toto@example.com",
)
sess = self.client.session
sess["permission_mask"] = 42
sess.save()
def test_future_user_list(self):
"""
Display the list of pre-registered users
"""
response = self.client.get(reverse("registration:future_user_list"))
self.assertEqual(response.status_code, 200)
response = self.client.get(reverse("registration:future_user_list") + "?search=toto")
self.assertEqual(response.status_code, 200)
def test_invalid_registrations(self):
"""
Send wrong data and check that errors are detected
"""
# BDE Membership is mandatory
response = self.client.post(reverse("registration:future_user_detail", args=(self.user.pk,)), data=dict(
soge=False,
credit_type=NoteSpecial.objects.get(special_type="Chèque").id,
credit_amount=4200,
last_name="TOTO",
first_name="Toto",
bank="Société générale",
join_BDE=False,
join_Kfet=False,
))
self.assertEqual(response.status_code, 200)
self.assertTrue(response.context["form"].errors)
# Same
response = self.client.post(reverse("registration:future_user_detail", args=(self.user.pk,)), data=dict(
soge=False,
credit_type="",
credit_amount=0,
last_name="TOTO",
first_name="Toto",
bank="Société générale",
join_BDE=False,
join_Kfet=True,
))
self.assertEqual(response.status_code, 200)
self.assertTrue(response.context["form"].errors)
# The BDE membership is not free
response = self.client.post(reverse("registration:future_user_detail", args=(self.user.pk,)), data=dict(
soge=False,
credit_type=NoteSpecial.objects.get(special_type="Espèces").id,
credit_amount=0,
last_name="TOTO",
first_name="Toto",
bank="J'ai pas d'argent",
join_BDE=True,
join_Kfet=True,
))
self.assertEqual(response.status_code, 200)
self.assertTrue(response.context["form"].errors)
# Last and first names are required for a credit
response = self.client.post(reverse("registration:future_user_detail", args=(self.user.pk,)), data=dict(
soge=False,
credit_type=NoteSpecial.objects.get(special_type="Chèque").id,
credit_amount=4000,
last_name="",
first_name="",
bank="",
join_BDE=True,
join_Kfet=True,
))
self.assertEqual(response.status_code, 200)
self.assertTrue(response.context["form"].errors)
# The username admïntoto is too similar with the alias admintoto.
# Since the form is valid, the user must update its username.
self.user.username = "admïntoto"
self.user.save()
response = self.client.post(reverse("registration:future_user_detail", args=(self.user.pk,)), data=dict(
soge=False,
credit_type=NoteSpecial.objects.get(special_type="Chèque").id,
credit_amount=500,
last_name="TOTO",
first_name="Toto",
bank="Société générale",
join_BDE=True,
join_Kfet=False,
))
self.assertEqual(response.status_code, 200)
self.assertTrue(response.context["form"].errors)
def test_validate_bde_registration(self):
"""
The user wants only to join the BDE. We validate the registration.
"""
response = self.client.get(reverse("registration:future_user_detail", args=(self.user.pk,)))
self.assertEqual(response.status_code, 200)
response = self.client.get(self.user.profile.get_absolute_url())
self.assertEqual(response.status_code, 404)
self.user.profile.email_confirmed = True
self.user.profile.save()
response = self.client.post(reverse("registration:future_user_detail", args=(self.user.pk,)), data=dict(
soge=False,
credit_type=NoteSpecial.objects.get(special_type="Chèque").id,
credit_amount=500,
last_name="TOTO",
first_name="Toto",
bank="Société générale",
join_BDE=True,
join_Kfet=False,
))
self.assertRedirects(response, self.user.profile.get_absolute_url(), 302, 200)
self.user.profile.refresh_from_db()
self.assertTrue(self.user.profile.registration_valid)
self.assertTrue(NoteUser.objects.filter(user=self.user).exists())
self.assertTrue(Membership.objects.filter(club__name="BDE", user=self.user).exists())
self.assertFalse(Membership.objects.filter(club__name="Kfet", user=self.user).exists())
self.assertFalse(SogeCredit.objects.filter(user=self.user).exists())
self.assertEqual(Transaction.objects.filter(
Q(source=self.user.note) | Q(destination=self.user.note)).count(), 2)
response = self.client.get(self.user.profile.get_absolute_url())
self.assertEqual(response.status_code, 200)
def test_validate_kfet_registration(self):
"""
The user joins the BDE and the Kfet.
"""
response = self.client.get(reverse("registration:future_user_detail", args=(self.user.pk,)))
self.assertEqual(response.status_code, 200)
response = self.client.get(self.user.profile.get_absolute_url())
self.assertEqual(response.status_code, 404)
self.user.profile.email_confirmed = True
self.user.profile.save()
response = self.client.post(reverse("registration:future_user_detail", args=(self.user.pk,)), data=dict(
soge=False,
credit_type=NoteSpecial.objects.get(special_type="Espèces").id,
credit_amount=4000,
last_name="TOTO",
first_name="Toto",
bank="Société générale",
join_BDE=True,
join_Kfet=True,
))
self.assertRedirects(response, self.user.profile.get_absolute_url(), 302, 200)
self.user.profile.refresh_from_db()
self.assertTrue(self.user.profile.registration_valid)
self.assertTrue(NoteUser.objects.filter(user=self.user).exists())
self.assertTrue(Membership.objects.filter(club__name="BDE", user=self.user).exists())
self.assertTrue(Membership.objects.filter(club__name="Kfet", user=self.user).exists())
self.assertFalse(SogeCredit.objects.filter(user=self.user).exists())
self.assertEqual(Transaction.objects.filter(
Q(source=self.user.note) | Q(destination=self.user.note)).count(), 3)
response = self.client.get(self.user.profile.get_absolute_url())
self.assertEqual(response.status_code, 200)
def test_validate_kfet_registration_with_soge(self):
"""
The user joins the BDE and the Kfet, but the membership is paid by the Société générale.
"""
response = self.client.get(reverse("registration:future_user_detail", args=(self.user.pk,)))
self.assertEqual(response.status_code, 200)
response = self.client.get(self.user.profile.get_absolute_url())
self.assertEqual(response.status_code, 404)
self.user.profile.email_confirmed = True
self.user.profile.save()
response = self.client.post(reverse("registration:future_user_detail", args=(self.user.pk,)), data=dict(
soge=True,
credit_type=NoteSpecial.objects.get(special_type="Espèces").id,
credit_amount=4000,
last_name="TOTO",
first_name="Toto",
bank="Société générale",
join_BDE=True,
join_Kfet=True,
))
self.assertRedirects(response, self.user.profile.get_absolute_url(), 302, 200)
self.user.profile.refresh_from_db()
self.assertTrue(self.user.profile.registration_valid)
self.assertTrue(NoteUser.objects.filter(user=self.user).exists())
self.assertTrue(Membership.objects.filter(club__name="BDE", user=self.user).exists())
self.assertTrue(Membership.objects.filter(club__name="Kfet", user=self.user).exists())
self.assertTrue(SogeCredit.objects.filter(user=self.user).exists())
self.assertEqual(Transaction.objects.filter(
Q(source=self.user.note) | Q(destination=self.user.note)).count(), 3)
self.assertFalse(Transaction.objects.filter(valid=True).exists())
response = self.client.get(self.user.profile.get_absolute_url())
self.assertEqual(response.status_code, 200)
def test_invalidate_registration(self):
"""
Try to invalidate (= delete) pre-registration.
"""
response = self.client.get(reverse("registration:future_user_invalidate", args=(self.user.pk,)))
self.assertRedirects(response, reverse("registration:future_user_list"), 302, 200)
self.assertFalse(User.objects.filter(pk=self.user.pk).exists())
def test_resend_email_validation_link(self):
"""
Resend email validation linK.
"""
response = self.client.get(reverse("registration:email_validation_resend", args=(self.user.pk,)))
self.assertRedirects(response, reverse("registration:future_user_detail", args=(self.user.pk,)), 302, 200)

View File

@ -16,11 +16,12 @@ from django.views.generic.edit import FormMixin
from django_tables2 import SingleTableView
from member.forms import ProfileForm
from member.models import Membership, Club
from note.models import SpecialTransaction
from note.models import SpecialTransaction, Alias
from note.templatetags.pretty_money import pretty_money
from permission.backends import PermissionBackend
from permission.models import Role
from permission.views import ProtectQuerysetMixin
from treasury.models import SogeCredit
from .forms import SignUpForm, ValidationForm
from .tables import FutureUserTable
@ -101,7 +102,7 @@ class UserValidateView(TemplateView):
user.profile.email_confirmed = True
user.save()
user.profile.save()
return self.render_to_response(self.get_context_data())
return self.render_to_response(self.get_context_data(), status=200 if self.validlink else 400)
def get_user(self, uidb64):
"""
@ -169,12 +170,9 @@ class FutureUserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableVi
:return:
"""
qs = super().get_queryset().distinct().filter(profile__registration_valid=False)
if "search" in self.request.GET:
if "search" in self.request.GET and self.request.GET["search"]:
pattern = self.request.GET["search"]
if not pattern:
return qs.none()
qs = qs.filter(
Q(first_name__iregex=pattern)
| Q(last_name__iregex=pattern)
@ -205,10 +203,7 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin,
def post(self, request, *args, **kwargs):
form = self.get_form()
self.object = self.get_object()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
return self.form_valid(form) if form.is_valid() else self.form_invalid(form)
def get_queryset(self, **kwargs):
"""
@ -225,6 +220,9 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin,
fee += bde.membership_fee_paid if user.profile.paid else bde.membership_fee_unpaid
kfet = Club.objects.get(name="Kfet")
fee += kfet.membership_fee_paid if user.profile.paid else kfet.membership_fee_unpaid
# In 2020, for COVID-19 reasons, the BDE offered 80 € to each new member that opens a Sogé account,
# since there is no WEI.
fee += 8000
ctx["total_fee"] = "{:.02f}".format(fee / 100, )
return ctx
@ -239,6 +237,10 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin,
def form_valid(self, form):
user = self.get_object()
if Alias.objects.filter(normalized_name=Alias.normalize(user.username)).exists():
form.add_error(None, _("An alias with a similar name already exists."))
return self.form_invalid(form)
# Get form data
soge = form.cleaned_data["soge"]
credit_type = form.cleaned_data["credit_type"]
@ -276,9 +278,6 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin,
if credit_type is None:
credit_amount = 0
if join_Kfet and not join_BDE:
form.add_error('join_Kfet', _("You must join BDE club before joining Kfet club."))
if fee > credit_amount and not soge:
# Check if the user credits enough money
form.add_error('credit_type',
@ -347,6 +346,11 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin,
membership.roles.add(Role.objects.get(name="Adhérent Kfet"))
membership.save()
if soge:
soge_credit = SogeCredit.objects.get(user=user)
# Update the credit transaction amount
soge_credit.save()
return ret
def get_success_url(self):