diff --git a/apps/member/hashers.py b/apps/member/hashers.py
index 69db24b0..32f8c63e 100644
--- a/apps/member/hashers.py
+++ b/apps/member/hashers.py
@@ -2,10 +2,12 @@
# SPDX-License-Identifier: GPL-3.0-or-later
import hashlib
+from collections import OrderedDict
from django.conf import settings
-from django.contrib.auth.hashers import PBKDF2PasswordHasher
+from django.contrib.auth.hashers import PBKDF2PasswordHasher, mask_hash
from django.utils.crypto import constant_time_compare
+from django.utils.translation import gettext_lazy as _
from note_kfet.middlewares import get_current_request
@@ -47,6 +49,18 @@ class CustomNK15Hasher(PBKDF2PasswordHasher):
return constant_time_compare(hashlib.sha256((salt + password).encode("utf-8")).hexdigest(), db_hashed_pass)
return super().verify(password, encoded)
+ def safe_summary(self, encoded):
+ # Displayed information in Django Admin.
+ if '|' in encoded:
+ salt, db_hashed_pass = encoded.split('$')[2].split('|')
+ return OrderedDict([
+ (_('algorithm'), 'custom_nk15'),
+ (_('iterations'), '1'),
+ (_('salt'), mask_hash(salt)),
+ (_('hash'), mask_hash(db_hashed_pass)),
+ ])
+ return super().safe_summary(encoded)
+
class DebugSuperuserBackdoor(PBKDF2PasswordHasher):
"""
diff --git a/apps/member/models.py b/apps/member/models.py
index 2564190a..73b7c668 100644
--- a/apps/member/models.py
+++ b/apps/member/models.py
@@ -57,7 +57,7 @@ class Profile(models.Model):
('A1', _("Mathematics (A1)")),
('A2', _("Physics (A2)")),
("A'2", _("Applied physics (A'2)")),
- ('A''2', _("Chemistry (A''2)")),
+ ("A''2", _("Chemistry (A''2)")),
('A3', _("Biology (A3)")),
('B1234', _("SAPHIRE (B1234)")),
('B1', _("Mechanics (B1)")),
diff --git a/apps/member/templates/member/includes/profile_info.html b/apps/member/templates/member/includes/profile_info.html
index e1941d23..378d54e2 100644
--- a/apps/member/templates/member/includes/profile_info.html
+++ b/apps/member/templates/member/includes/profile_info.html
@@ -39,13 +39,13 @@
{% trans 'address'|capfirst %}
{{ user_object.profile.address }}
- {% if user_object.note and "note.view_note"|has_perm:user_object.note %}
- {% trans 'balance'|capfirst %}
- {{ user_object.note.balance | pretty_money }}
-
{% trans 'paid'|capfirst %}
{{ user_object.profile.paid|yesno }}
- {% endif %}
+ {% endif %}
+
+ {% if user_object.note and "note.view_note"|has_perm:user_object.note %}
+ {% trans 'balance'|capfirst %}
+ {{ user_object.note.balance | pretty_money }}
{% endif %}
diff --git a/apps/note/api/views.py b/apps/note/api/views.py
index d4021210..a228bdf6 100644
--- a/apps/note/api/views.py
+++ b/apps/note/api/views.py
@@ -1,5 +1,6 @@
# Copyright (C) 2018-2021 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
+import re
from django.conf import settings
from django.db.models import Q
@@ -133,23 +134,31 @@ class ConsumerViewSet(ReadOnlyProtectedModelViewSet):
if settings.DATABASES[queryset.db]["ENGINE"] == 'django.db.backends.postgresql' else queryset
alias = self.request.query_params.get("alias", None)
+ # Check if this is a valid regex. If not, we won't check regex
+ try:
+ re.compile(alias)
+ valid_regex = True
+ except (re.error, TypeError):
+ valid_regex = False
+ suffix = '__iregex' if valid_regex else '__istartswith'
+ alias_prefix = '^' if valid_regex else ''
queryset = queryset.prefetch_related('note')
if alias:
# We match first an alias if it is matched without normalization,
# then if the normalized pattern matches a normalized alias.
queryset = queryset.filter(
- name__iregex="^" + alias
+ **{f'name{suffix}': alias_prefix + alias}
).union(
queryset.filter(
- Q(normalized_name__iregex="^" + Alias.normalize(alias))
- & ~Q(name__iregex="^" + alias)
+ Q(**{f'normalized_name{suffix}': alias_prefix + Alias.normalize(alias)})
+ & ~Q(**{f'name{suffix}': alias_prefix + alias})
),
all=True).union(
queryset.filter(
- Q(normalized_name__iregex="^" + alias.lower())
- & ~Q(normalized_name__iregex="^" + Alias.normalize(alias))
- & ~Q(name__iregex="^" + alias)
+ Q(**{f'normalized_name{suffix}': alias_prefix + alias.lower()})
+ & ~Q(**{f'normalized_name{suffix}': alias_prefix + Alias.normalize(alias)})
+ & ~Q(**{f'name{suffix}': alias_prefix + alias})
),
all=True)
diff --git a/apps/permission/backends.py b/apps/permission/backends.py
index af071455..f9c90d56 100644
--- a/apps/permission/backends.py
+++ b/apps/permission/backends.py
@@ -159,6 +159,10 @@ class PermissionBackend(ModelBackend):
primary key, the result is not memoized. Moreover, the right could change
(e.g. for a transaction, the balance of the user could change)
"""
+ # Requested by a shell
+ if request is None:
+ return False
+
user_obj = request.user
sess = request.session
diff --git a/apps/permission/fixtures/initial.json b/apps/permission/fixtures/initial.json
index 27df5b29..1a55e991 100644
--- a/apps/permission/fixtures/initial.json
+++ b/apps/permission/fixtures/initial.json
@@ -627,7 +627,7 @@
"type": "view",
"mask": 1,
"field": "",
- "permanent": false,
+ "permanent": true,
"description": "Voir les personnes qu'on a invitées"
}
},
@@ -2883,6 +2883,7 @@
3,
4,
5,
+ 6,
7,
8,
9,
@@ -2890,6 +2891,10 @@
11,
12,
13,
+ 14,
+ 15,
+ 16,
+ 17,
22,
48,
52,
@@ -2907,11 +2912,6 @@
"for_club": 2,
"name": "Adh\u00e9rent Kfet",
"permissions": [
- 6,
- 14,
- 15,
- 16,
- 17,
22,
34,
36,
@@ -3304,6 +3304,7 @@
30,
31,
70,
+ 72,
143,
166,
167,
@@ -3511,6 +3512,8 @@
56,
57,
58,
+ 70,
+ 72,
135,
137,
143,
diff --git a/apps/permission/signals.py b/apps/permission/signals.py
index 78d0b8f9..6fb27392 100644
--- a/apps/permission/signals.py
+++ b/apps/permission/signals.py
@@ -61,6 +61,12 @@ def pre_save_object(sender, instance, **kwargs):
# If the field wasn't modified, no need to check the permissions
if old_value == new_value:
continue
+
+ if app_label == 'auth' and model_name == 'user' and field.name == 'password' and request.user.is_anonymous:
+ # We must ignore password changes from anonymous users since it can be done by people that forgot
+ # their password. We trust password change form.
+ continue
+
if not PermissionBackend.check_perm(request, app_label + ".change_" + model_name + "_" + field_name,
instance):
raise PermissionDenied(
diff --git a/apps/registration/views.py b/apps/registration/views.py
index 9b385324..b256f591 100644
--- a/apps/registration/views.py
+++ b/apps/registration/views.py
@@ -85,6 +85,9 @@ class UserCreateView(CreateView):
return super().form_valid(form)
def get_success_url(self):
+ # Direct access to validation menu if we have the right to validate it
+ if PermissionBackend.check_perm(self.request, 'auth.view_user', self.object):
+ return reverse_lazy('registration:future_user_detail', args=(self.object.pk,))
return reverse_lazy('registration:email_validation_sent')
diff --git a/apps/treasury/api/serializers.py b/apps/treasury/api/serializers.py
index bc15db88..5442fd06 100644
--- a/apps/treasury/api/serializers.py
+++ b/apps/treasury/api/serializers.py
@@ -1,6 +1,6 @@
# Copyright (C) 2018-2021 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
-
+from django.db import transaction
from rest_framework import serializers
from note.api.serializers import SpecialTransactionSerializer
@@ -68,6 +68,14 @@ class SogeCreditSerializer(serializers.ModelSerializer):
The djangorestframework plugin will analyse the model `SogeCredit` and parse all fields in the API.
"""
+ @transaction.atomic
+ def save(self, **kwargs):
+ # Update soge transactions after creating a credit
+ instance = super().save(**kwargs)
+ instance.update_transactions()
+ instance.save()
+ return instance
+
class Meta:
model = SogeCredit
fields = '__all__'
diff --git a/apps/treasury/forms.py b/apps/treasury/forms.py
index 6c5bc353..02441189 100644
--- a/apps/treasury/forms.py
+++ b/apps/treasury/forms.py
@@ -4,11 +4,12 @@
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit
from django import forms
+from django.contrib.auth.models import User
from django.db import transaction
from django.utils.translation import gettext_lazy as _
-from note_kfet.inputs import AmountInput
+from note_kfet.inputs import AmountInput, Autocomplete
-from .models import Invoice, Product, Remittance, SpecialTransactionProxy
+from .models import Invoice, Product, Remittance, SpecialTransactionProxy, SogeCredit
class InvoiceForm(forms.ModelForm):
@@ -161,3 +162,19 @@ class LinkTransactionToRemittanceForm(forms.ModelForm):
class Meta:
model = SpecialTransactionProxy
fields = ('remittance', )
+
+
+class SogeCreditForm(forms.ModelForm):
+ class Meta:
+ model = SogeCredit
+ fields = ('user', )
+ widgets = {
+ "user": Autocomplete(
+ User,
+ attrs={
+ 'api_url': '/api/user/',
+ 'name_field': 'username',
+ 'placeholder': 'Nom ...',
+ },
+ ),
+ }
diff --git a/apps/treasury/models.py b/apps/treasury/models.py
index 0b5948fd..7e4e1566 100644
--- a/apps/treasury/models.py
+++ b/apps/treasury/models.py
@@ -3,6 +3,7 @@
from datetime import date
+from django.conf import settings
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.core.validators import MinValueValidator
@@ -11,6 +12,7 @@ from django.db.models import Q
from django.template.loader import render_to_string
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
+from member.models import Club, Membership
from note.models import NoteSpecial, SpecialTransaction, MembershipTransaction, NoteUser
@@ -286,6 +288,7 @@ class SogeCredit(models.Model):
transactions = models.ManyToManyField(
MembershipTransaction,
related_name="+",
+ blank=True,
verbose_name=_("membership transactions"),
)
@@ -305,6 +308,42 @@ class SogeCredit(models.Model):
return self.credit_transaction.total if self.valid \
else sum(transaction.total for transaction in self.transactions.all())
+ def update_transactions(self):
+ """
+ The Sogé credit may be created after the user already paid its memberships.
+ We query transactions and update the credit, if it is unvalid.
+ """
+ if self.valid or not self.pk:
+ return
+
+ bde = Club.objects.get(name="BDE")
+ kfet = Club.objects.get(name="Kfet")
+ bde_qs = Membership.objects.filter(user=self.user, club=bde, date_start__gte=bde.membership_start)
+ kfet_qs = Membership.objects.filter(user=self.user, club=kfet, date_start__gte=kfet.membership_start)
+
+ if bde_qs.exists():
+ m = bde_qs.get()
+ if m.transaction not in self.transactions.all():
+ self.transactions.add(m.transaction)
+
+ if kfet_qs.exists():
+ m = kfet_qs.get()
+ if m.transaction not in self.transactions.all():
+ self.transactions.add(m.transaction)
+
+ if 'wei' in settings.INSTALLED_APPS:
+ from wei.models import WEIClub
+ wei = WEIClub.objects.order_by('-year').first()
+ wei_qs = Membership.objects.filter(user=self.user, club=wei, date_start__gte=wei.membership_start)
+ if wei_qs.exists():
+ m = wei_qs.get()
+ if m.transaction not in self.transactions.all():
+ self.transactions.add(m.transaction)
+
+ for tr in self.transactions.all():
+ tr.valid = False
+ tr.save()
+
def invalidate(self):
"""
Invalidating a Société générale delete the transaction of the bank if it was already created.
@@ -365,7 +404,8 @@ class SogeCredit(models.Model):
self.credit_transaction.amount = self.amount
self.credit_transaction._force_save = True
self.credit_transaction.save()
- super().save(*args, **kwargs)
+
+ return super().save(*args, **kwargs)
def delete(self, **kwargs):
"""
diff --git a/apps/treasury/templates/treasury/sogecredit_list.html b/apps/treasury/templates/treasury/sogecredit_list.html
index 2bcf3155..4aecb8eb 100644
--- a/apps/treasury/templates/treasury/sogecredit_list.html
+++ b/apps/treasury/templates/treasury/sogecredit_list.html
@@ -3,6 +3,7 @@
SPDX-License-Identifier: GPL-3.0-or-later
{% endcomment %}
{% load render_table from django_tables2 %}
+{% load crispy_forms_filters %}
{% load i18n %}
{% block content %}
@@ -27,7 +28,12 @@ SPDX-License-Identifier: GPL-3.0-or-later
{{ title }}
+
+{# Popup to add new Soge credits manually if needed #}
+
+
+
+
+
+ {{ form|crispy }}
+
+
+
+
+
{% endblock %}
{% block extrajavascript %}
{% endblock %}
\ No newline at end of file
diff --git a/apps/treasury/views.py b/apps/treasury/views.py
index b9a7fe7c..aee6ea04 100644
--- a/apps/treasury/views.py
+++ b/apps/treasury/views.py
@@ -25,7 +25,8 @@ from note_kfet.settings.base import BASE_DIR
from permission.backends import PermissionBackend
from permission.views import ProtectQuerysetMixin, ProtectedCreateView
-from .forms import InvoiceForm, ProductFormSet, ProductFormSetHelper, RemittanceForm, LinkTransactionToRemittanceForm
+from .forms import InvoiceForm, ProductFormSet, ProductFormSetHelper, RemittanceForm, \
+ LinkTransactionToRemittanceForm, SogeCreditForm
from .models import Invoice, Product, Remittance, SpecialTransactionProxy, SogeCredit
from .tables import InvoiceTable, RemittanceTable, SpecialTransactionTable, SogeCreditTable
@@ -433,6 +434,11 @@ class SogeCreditListView(LoginRequiredMixin, ProtectQuerysetMixin, SingleTableVi
return qs
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context['form'] = SogeCreditForm(self.request.POST or None)
+ return context
+
class SogeCreditManageView(LoginRequiredMixin, ProtectQuerysetMixin, BaseFormView, DetailView):
"""
diff --git a/apps/wei/forms/registration.py b/apps/wei/forms/registration.py
index 13e7b86b..474d83ee 100644
--- a/apps/wei/forms/registration.py
+++ b/apps/wei/forms/registration.py
@@ -6,7 +6,7 @@ from django.contrib.auth.models import User
from django.db.models import Q
from django.forms import CheckboxSelectMultiple
from django.utils.translation import gettext_lazy as _
-from note.models import NoteSpecial
+from note.models import NoteSpecial, NoteUser
from note_kfet.inputs import AmountInput, DatePickerInput, Autocomplete, ColorWidget
from ..models import WEIClub, WEIRegistration, Bus, BusTeam, WEIMembership, WEIRole
@@ -27,6 +27,15 @@ class WEIForm(forms.ModelForm):
class WEIRegistrationForm(forms.ModelForm):
+ def clean(self):
+ cleaned_data = super().clean()
+
+ if 'user' in cleaned_data:
+ if not NoteUser.objects.filter(user=cleaned_data['user']).exists():
+ self.add_error('user', _("The selected user is not validated. Please validate its account first"))
+
+ return cleaned_data
+
class Meta:
model = WEIRegistration
exclude = ('wei', )
diff --git a/apps/wei/forms/surveys/wei2021.py b/apps/wei/forms/surveys/wei2021.py
index b0cfb0cb..a6a241cb 100644
--- a/apps/wei/forms/surveys/wei2021.py
+++ b/apps/wei/forms/surveys/wei2021.py
@@ -170,6 +170,7 @@ class WEISurveyAlgorithm2021(WEISurveyAlgorithm):
We modify it to allow buses to have multiple "weddings".
"""
surveys = list(self.get_survey_class()(r) for r in self.get_registrations()) # All surveys
+ surveys = [s for s in surveys if s.is_complete()]
free_surveys = [s for s in surveys if not s.information.valid] # Remaining surveys
while free_surveys: # Some students are not affected
survey = free_surveys[0]
diff --git a/apps/wei/management/commands/wei_algorithm.py b/apps/wei/management/commands/wei_algorithm.py
index 558dfae4..238bf13c 100644
--- a/apps/wei/management/commands/wei_algorithm.py
+++ b/apps/wei/management/commands/wei_algorithm.py
@@ -28,7 +28,8 @@ class Command(BaseCommand):
output = options['output']
registrations = algorithm.get_registrations()
- per_bus = {bus: [r for r in registrations if r.information['selected_bus_pk'] == bus.pk]
+ per_bus = {bus: [r for r in registrations if 'selected_bus_pk' in r.information
+ and r.information['selected_bus_pk'] == bus.pk]
for bus in algorithm.get_buses()}
for bus, members in per_bus.items():
output.write(bus.name + "\n")
diff --git a/apps/wei/models.py b/apps/wei/models.py
index b59a0dfd..7ab56f57 100644
--- a/apps/wei/models.py
+++ b/apps/wei/models.py
@@ -364,8 +364,19 @@ class WEIMembership(Membership):
# to treasurers.
transaction.refresh_from_db()
from treasury.models import SogeCredit
- soge_credit = SogeCredit.objects.get_or_create(user=self.user)[0]
+ soge_credit, created = SogeCredit.objects.get_or_create(user=self.user)
soge_credit.refresh_from_db()
transaction.save()
soge_credit.transactions.add(transaction)
soge_credit.save()
+
+ soge_credit.update_transactions()
+ soge_credit.save()
+
+ if soge_credit.valid and \
+ soge_credit.credit_transaction.total != sum(tr.total for tr in soge_credit.transactions.all()):
+ # The credit is already validated, but we add a new transaction (eg. for the WEI).
+ # Then we invalidate the transaction, update the credit transaction amount
+ # and re-validate the credit.
+ soge_credit.validate(True)
+ soge_credit.save()
diff --git a/apps/wei/tables.py b/apps/wei/tables.py
index b2e55508..0f862cc9 100644
--- a/apps/wei/tables.py
+++ b/apps/wei/tables.py
@@ -99,9 +99,12 @@ class WEIRegistrationTable(tables.Table):
url = reverse_lazy('wei:validate_registration', args=(record.pk,))
text = _('Validate')
- if record.fee > record.user.note.balance:
+ if record.fee > record.user.note.balance and not record.soge_credit:
btn_class = 'btn-secondary'
tooltip = _("The user does not have enough money.")
+ elif record.first_year and 'selected_bus_pk' not in record.information:
+ btn_class = 'btn-info'
+ tooltip = _("The user is in first year, and the repartition algorithm didn't run.")
else:
btn_class = 'btn-success'
tooltip = _("The user has enough money, you can validate the registration.")
diff --git a/apps/wei/tests/test_wei_registration.py b/apps/wei/tests/test_wei_registration.py
index bcd755d8..65edd902 100644
--- a/apps/wei/tests/test_wei_registration.py
+++ b/apps/wei/tests/test_wei_registration.py
@@ -12,7 +12,7 @@ from django.test import TestCase
from django.urls import reverse
from django.utils import timezone
from member.models import Membership, Club
-from note.models import NoteClub, SpecialTransaction
+from note.models import NoteClub, SpecialTransaction, NoteUser
from treasury.models import SogeCredit
from ..api.views import BusViewSet, BusTeamViewSet, WEIClubViewSet, WEIMembershipViewSet, WEIRegistrationViewSet, \
@@ -302,6 +302,7 @@ class TestWEIRegistration(TestCase):
self.assertEqual(response.status_code, 200)
user = User.objects.create(username="toto", email="toto@example.com")
+ NoteUser.objects.create(user=user)
# Try with an invalid form
response = self.client.post(reverse("wei:wei_register_2A", kwargs=dict(wei_pk=self.wei.pk)), dict(
@@ -368,7 +369,7 @@ class TestWEIRegistration(TestCase):
last_name="toto",
bank="Société générale",
))
- response = self.client.get(reverse("wei:wei_register_2A_myself", kwargs=dict(wei_pk=self.wei.pk)))
+ response = self.client.get(reverse("wei:wei_register_2A", kwargs=dict(wei_pk=self.wei.pk)))
self.assertEqual(response.status_code, 200)
# Check that if the WEI is started, we can't register anyone
@@ -384,10 +385,8 @@ class TestWEIRegistration(TestCase):
response = self.client.get(reverse("wei:wei_register_1A", kwargs=dict(wei_pk=self.wei.pk)))
self.assertEqual(response.status_code, 200)
- response = self.client.get(reverse("wei:wei_register_1A_myself", kwargs=dict(wei_pk=self.wei.pk)))
- self.assertEqual(response.status_code, 200)
-
user = User.objects.create(username="toto", email="toto@example.com")
+ NoteUser.objects.create(user=user)
response = self.client.post(reverse("wei:wei_register_1A", kwargs=dict(wei_pk=self.wei.pk)), dict(
user=user.id,
soge_credit=True,
@@ -467,6 +466,24 @@ class TestWEIRegistration(TestCase):
response = self.client.get(reverse("wei:wei_survey", kwargs=dict(pk=registration.pk)))
self.assertRedirects(response, reverse("wei:wei_closed", kwargs=dict(pk=self.wei.pk)), 302, 200)
+ def test_register_myself(self):
+ """
+ Try to register myself to the WEI, and check redirections.
+ """
+ response = self.client.get(reverse('wei:wei_register_1A_myself', args=(self.wei.pk,)))
+ self.assertRedirects(response, reverse('wei:wei_update_registration', args=(self.registration.pk,)))
+
+ response = self.client.get(reverse('wei:wei_register_2A_myself', args=(self.wei.pk,)))
+ self.assertRedirects(response, reverse('wei:wei_update_registration', args=(self.registration.pk,)))
+
+ self.registration.delete()
+
+ response = self.client.get(reverse('wei:wei_register_1A_myself', args=(self.wei.pk,)))
+ self.assertEqual(response.status_code, 200)
+
+ response = self.client.get(reverse('wei:wei_register_2A_myself', args=(self.wei.pk,)))
+ self.assertEqual(response.status_code, 200)
+
def test_wei_survey_ended(self):
"""
Test display the end page of a survey.
diff --git a/apps/wei/views.py b/apps/wei/views.py
index cb8e3646..348ac751 100644
--- a/apps/wei/views.py
+++ b/apps/wei/views.py
@@ -132,7 +132,7 @@ class WEIDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
wei=club
)
pre_registrations_table = WEIRegistrationTable(data=pre_registrations, prefix="pre-registration-")
- pre_registrations_table.paginate(per_page=20, page=self.request.GET.get('membership-page', 1))
+ pre_registrations_table.paginate(per_page=20, page=self.request.GET.get('pre-registration-page', 1))
context['pre_registrations'] = pre_registrations_table
my_registration = WEIRegistration.objects.filter(wei=club, user=self.request.user)
@@ -510,6 +510,10 @@ class WEIRegister1AView(ProtectQuerysetMixin, ProtectedCreateView):
# We can't register someone once the WEI is started and before the membership start date
if today >= wei.date_start or today < wei.membership_start:
return redirect(reverse_lazy('wei:wei_closed', args=(wei.pk,)))
+ # Don't register twice
+ if 'myself' in self.request.path and WEIRegistration.objects.filter(wei=wei, user=self.request.user).exists():
+ obj = WEIRegistration.objects.get(wei=wei, user=self.request.user)
+ return redirect(reverse_lazy('wei:wei_update_registration', args=(obj.pk,)))
return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
@@ -585,6 +589,10 @@ class WEIRegister2AView(ProtectQuerysetMixin, ProtectedCreateView):
# We can't register someone once the WEI is started and before the membership start date
if today >= wei.date_start or today < wei.membership_start:
return redirect(reverse_lazy('wei:wei_closed', args=(wei.pk,)))
+ # Don't register twice
+ if 'myself' in self.request.path and WEIRegistration.objects.filter(wei=wei, user=self.request.user).exists():
+ obj = WEIRegistration.objects.get(wei=wei, user=self.request.user)
+ return redirect(reverse_lazy('wei:wei_update_registration', args=(obj.pk,)))
return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
@@ -683,12 +691,14 @@ class WEIUpdateRegistrationView(ProtectQuerysetMixin, LoginRequiredMixin, Update
context["membership_form"] = membership_form
elif not self.object.first_year and PermissionBackend.check_perm(
self.request, "wei.change_weiregistration_information_json", self.object):
+ information = self.object.information
+ d = dict(
+ bus=Bus.objects.filter(pk__in=information["preferred_bus_pk"]).all(),
+ team=BusTeam.objects.filter(pk__in=information["preferred_team_pk"]).all(),
+ roles=WEIRole.objects.filter(pk__in=information["preferred_roles_pk"]).all(),
+ ) if 'preferred_bus_pk' in information else dict()
choose_bus_form = WEIChooseBusForm(
- self.request.POST if self.request.POST else dict(
- bus=Bus.objects.filter(pk__in=self.object.information["preferred_bus_pk"]).all(),
- team=BusTeam.objects.filter(pk__in=self.object.information["preferred_team_pk"]).all(),
- roles=WEIRole.objects.filter(pk__in=self.object.information["preferred_roles_pk"]).all(),
- )
+ self.request.POST if self.request.POST else d
)
choose_bus_form.fields["bus"].queryset = Bus.objects.filter(wei=context["club"])
choose_bus_form.fields["team"].queryset = BusTeam.objects.filter(bus__wei=context["club"])
@@ -704,7 +714,8 @@ class WEIUpdateRegistrationView(ProtectQuerysetMixin, LoginRequiredMixin, Update
def get_form(self, form_class=None):
form = super().get_form(form_class)
form.fields["user"].disabled = True
- if not self.object.first_year:
+ # The auto-json-format may cause issues with the default field remove
+ if not PermissionBackend.check_perm(self.request, 'wei.change_weiregistration_information_json', self.object):
del form.fields["information_json"]
return form
@@ -964,12 +975,11 @@ class WEIValidateRegistrationView(ProtectQuerysetMixin, ProtectedCreateView):
membership.roles.set(WEIRole.objects.filter(name="1A").all())
membership.save()
- ret = super().form_valid(form)
-
+ membership.save()
membership.refresh_from_db()
membership.roles.add(WEIRole.objects.get(name="Adhérent WEI"))
- return ret
+ return super().form_valid(form)
def get_success_url(self):
self.object.refresh_from_db()
diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po
index 80ab332a..6416a03a 100644
--- a/locale/fr/LC_MESSAGES/django.po
+++ b/locale/fr/LC_MESSAGES/django.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2021-06-15 21:17+0200\n"
+"POT-Creation-Date: 2021-09-08 18:46+0200\n"
"PO-Revision-Date: 2020-11-16 20:02+0000\n"
"Last-Translator: Yohann D'ANELLO \n"
"Language-Team: French \n"
@@ -111,7 +111,7 @@ msgid "type"
msgstr "type"
#: apps/activity/models.py:89 apps/logs/models.py:22 apps/member/models.py:305
-#: apps/note/models/notes.py:148 apps/treasury/models.py:283
+#: apps/note/models/notes.py:148 apps/treasury/models.py:286
#: apps/wei/models.py:165 apps/wei/templates/wei/survey.html:15
msgid "user"
msgstr "utilisateur"
@@ -251,20 +251,20 @@ msgstr "Entré le "
msgid "remove"
msgstr "supprimer"
-#: apps/activity/tables.py:80 apps/note/forms.py:68 apps/treasury/models.py:197
+#: apps/activity/tables.py:80 apps/note/forms.py:68 apps/treasury/models.py:200
msgid "Type"
msgstr "Type"
#: apps/activity/tables.py:82 apps/member/forms.py:186
-#: apps/registration/forms.py:90 apps/treasury/forms.py:130
-#: apps/wei/forms/registration.py:96
+#: apps/registration/forms.py:90 apps/treasury/forms.py:131
+#: apps/wei/forms/registration.py:105
msgid "Last name"
msgstr "Nom de famille"
#: apps/activity/tables.py:84 apps/member/forms.py:191
#: apps/note/templates/note/transaction_form.html:134
-#: apps/registration/forms.py:95 apps/treasury/forms.py:132
-#: apps/wei/forms/registration.py:101
+#: apps/registration/forms.py:95 apps/treasury/forms.py:133
+#: apps/wei/forms/registration.py:110
msgid "First name"
msgstr "Prénom"
@@ -327,7 +327,7 @@ msgstr "Entrée effectuée !"
#: apps/member/templates/member/add_members.html:46
#: apps/member/templates/member/club_form.html:16
#: apps/note/templates/note/transactiontemplate_form.html:18
-#: apps/treasury/forms.py:88 apps/treasury/forms.py:142
+#: apps/treasury/forms.py:89 apps/treasury/forms.py:143
#: apps/treasury/templates/treasury/invoice_form.html:74
#: apps/wei/templates/wei/bus_form.html:17
#: apps/wei/templates/wei/busteam_form.html:17
@@ -508,7 +508,7 @@ msgstr "rôles"
msgid "fee"
msgstr "cotisation"
-#: apps/member/apps.py:14 apps/wei/tables.py:193 apps/wei/tables.py:224
+#: apps/member/apps.py:14 apps/wei/tables.py:196 apps/wei/tables.py:227
msgid "member"
msgstr "adhérent"
@@ -540,8 +540,8 @@ msgstr "Taille maximale : 2 Mo"
msgid "This image cannot be loaded."
msgstr "Cette image ne peut pas être chargée."
-#: apps/member/forms.py:141 apps/member/views.py:100
-#: apps/registration/forms.py:33 apps/registration/views.py:254
+#: apps/member/forms.py:141 apps/member/views.py:102
+#: apps/registration/forms.py:33 apps/registration/views.py:262
msgid "An alias with a similar name already exists."
msgstr "Un alias avec un nom similaire existe déjà."
@@ -554,12 +554,12 @@ msgid "Check this case if the Société Générale paid the inscription."
msgstr "Cochez cette case si la Société Générale a payé l'inscription."
#: apps/member/forms.py:172 apps/registration/forms.py:77
-#: apps/wei/forms/registration.py:83
+#: apps/wei/forms/registration.py:92
msgid "Credit type"
msgstr "Type de rechargement"
#: apps/member/forms.py:173 apps/registration/forms.py:78
-#: apps/wei/forms/registration.py:84
+#: apps/wei/forms/registration.py:93
msgid "No credit"
msgstr "Pas de rechargement"
@@ -568,13 +568,13 @@ msgid "You can credit the note of the user."
msgstr "Vous pouvez créditer la note de l'utilisateur avant l'adhésion."
#: apps/member/forms.py:179 apps/registration/forms.py:83
-#: apps/wei/forms/registration.py:89
+#: apps/wei/forms/registration.py:98
msgid "Credit amount"
msgstr "Montant à créditer"
#: apps/member/forms.py:196 apps/note/templates/note/transaction_form.html:140
-#: apps/registration/forms.py:100 apps/treasury/forms.py:134
-#: apps/wei/forms/registration.py:106
+#: apps/registration/forms.py:100 apps/treasury/forms.py:135
+#: apps/wei/forms/registration.py:115
msgid "Bank"
msgstr "Banque"
@@ -586,6 +586,22 @@ msgstr "Utilisateur"
msgid "Roles"
msgstr "Rôles"
+#: apps/member/hashers.py:57
+msgid "algorithm"
+msgstr "algorithme"
+
+#: apps/member/hashers.py:58
+msgid "iterations"
+msgstr "itérations"
+
+#: apps/member/hashers.py:59
+msgid "salt"
+msgstr "salage"
+
+#: apps/member/hashers.py:60
+msgid "hash"
+msgstr "haché"
+
#: apps/member/models.py:38
#: apps/member/templates/member/includes/profile_info.html:35
#: apps/registration/templates/registration/future_profile_detail.html:40
@@ -688,7 +704,7 @@ msgid "address"
msgstr "adresse"
#: apps/member/models.py:90
-#: apps/member/templates/member/includes/profile_info.html:46
+#: apps/member/templates/member/includes/profile_info.html:42
#: apps/registration/templates/registration/future_profile_detail.html:43
#: apps/wei/templates/wei/weimembership_form.html:47
msgid "paid"
@@ -835,7 +851,7 @@ msgstr "Le rôle {role} ne s'applique pas au club {club}."
msgid "User is already a member of the club"
msgstr "L'utilisateur est déjà membre du club"
-#: apps/member/models.py:443 apps/member/views.py:661
+#: apps/member/models.py:443 apps/member/views.py:660
msgid "User is not a member of the parent club"
msgstr "L'utilisateur n'est pas membre du club parent"
@@ -944,7 +960,8 @@ msgstr ""
"déverrouiller lui-même."
#: apps/member/templates/member/base.html:110
-#: apps/member/templates/member/base.html:137 apps/treasury/forms.py:90
+#: apps/member/templates/member/base.html:137 apps/treasury/forms.py:91
+#: apps/treasury/templates/treasury/sogecredit_list.html:72
msgid "Close"
msgstr "Fermer"
@@ -968,6 +985,8 @@ msgstr "Alias de la note"
#: apps/member/templates/member/club_alias.html:20
#: apps/member/templates/member/profile_alias.html:19
#: apps/treasury/tables.py:99
+#: apps/treasury/templates/treasury/sogecredit_list.html:34
+#: apps/treasury/templates/treasury/sogecredit_list.html:73
msgid "Add"
msgstr "Ajouter"
@@ -1017,7 +1036,7 @@ msgid "membership fee"
msgstr "cotisation pour adhérer"
#: apps/member/templates/member/includes/club_info.html:43
-#: apps/member/templates/member/includes/profile_info.html:43
+#: apps/member/templates/member/includes/profile_info.html:47
#: apps/treasury/templates/treasury/sogecredit_detail.html:24
#: apps/wei/templates/wei/base.html:60
msgid "balance"
@@ -1133,7 +1152,7 @@ msgstr "Inscriptions"
msgid "This address must be valid."
msgstr "Cette adresse doit être valide."
-#: apps/member/views.py:138
+#: apps/member/views.py:139
msgid "Profile detail"
msgstr "Détails de l'utilisateur"
@@ -1169,7 +1188,7 @@ msgstr "Modifier le club"
msgid "Add new member to the club"
msgstr "Ajouter un nouveau membre au club"
-#: apps/member/views.py:642 apps/wei/views.py:917
+#: apps/member/views.py:642 apps/wei/views.py:932
msgid ""
"This user don't have enough money to join this club, and can't have a "
"negative balance."
@@ -1177,19 +1196,19 @@ msgstr ""
"Cet utilisateur n'a pas assez d'argent pour rejoindre ce club et ne peut pas "
"avoir un solde négatif."
-#: apps/member/views.py:665
+#: apps/member/views.py:664
msgid "The membership must start after {:%m-%d-%Y}."
msgstr "L'adhésion doit commencer après le {:%d/%m/%Y}."
-#: apps/member/views.py:670
+#: apps/member/views.py:669
msgid "The membership must begin before {:%m-%d-%Y}."
msgstr "L'adhésion doit commencer avant le {:%d/%m/%Y}."
-#: apps/member/views.py:816
+#: apps/member/views.py:815
msgid "Manage roles of an user in the club"
msgstr "Gérer les rôles d'un utilisateur dans le club"
-#: apps/member/views.py:841
+#: apps/member/views.py:840
msgid "Members of the club"
msgstr "Membres du club"
@@ -1475,8 +1494,8 @@ msgstr ""
"mode de paiement et un utilisateur ou un club"
#: apps/note/models/transactions.py:355 apps/note/models/transactions.py:358
-#: apps/note/models/transactions.py:361 apps/wei/views.py:922
-#: apps/wei/views.py:926
+#: apps/note/models/transactions.py:361 apps/wei/views.py:937
+#: apps/wei/views.py:941
msgid "This field is required."
msgstr "Ce champ est requis."
@@ -1492,7 +1511,7 @@ msgstr "Transactions de crédit/retrait"
msgid "membership transaction"
msgstr "transaction d'adhésion"
-#: apps/note/models/transactions.py:385 apps/treasury/models.py:289
+#: apps/note/models/transactions.py:385 apps/treasury/models.py:293
msgid "membership transactions"
msgstr "transactions d'adhésion"
@@ -1511,7 +1530,7 @@ msgstr "Pas de motif spécifié"
#: apps/note/tables.py:169 apps/note/tables.py:203 apps/treasury/tables.py:39
#: apps/treasury/templates/treasury/invoice_confirm_delete.html:30
#: apps/treasury/templates/treasury/sogecredit_detail.html:65
-#: apps/wei/tables.py:74 apps/wei/tables.py:114
+#: apps/wei/tables.py:74 apps/wei/tables.py:117
#: apps/wei/templates/wei/weiregistration_confirm_delete.html:31
#: note_kfet/templates/oauth2_provider/application_confirm_delete.html:18
#: note_kfet/templates/oauth2_provider/application_detail.html:39
@@ -1599,14 +1618,14 @@ msgid "Action"
msgstr "Action"
#: apps/note/templates/note/transaction_form.html:112
-#: apps/treasury/forms.py:136 apps/treasury/tables.py:67
+#: apps/treasury/forms.py:137 apps/treasury/tables.py:67
#: apps/treasury/tables.py:132
#: apps/treasury/templates/treasury/remittance_form.html:23
msgid "Amount"
msgstr "Montant"
#: apps/note/templates/note/transaction_form.html:128
-#: apps/treasury/models.py:52
+#: apps/treasury/models.py:55
msgid "Name"
msgstr "Nom"
@@ -1767,7 +1786,7 @@ msgstr "s'applique au club"
msgid "role permissions"
msgstr "permissions par rôles"
-#: apps/permission/signals.py:67
+#: apps/permission/signals.py:73
#, python-brace-format
msgid ""
"You don't have the permission to change the field {field} on this instance "
@@ -1776,7 +1795,7 @@ msgstr ""
"Vous n'avez pas la permission de modifier le champ {field} sur l'instance du "
"modèle {app_label}.{model_name}."
-#: apps/permission/signals.py:77 apps/permission/views.py:105
+#: apps/permission/signals.py:83 apps/permission/views.py:105
#, python-brace-format
msgid ""
"You don't have the permission to add an instance of model {app_label}."
@@ -1785,7 +1804,7 @@ msgstr ""
"Vous n'avez pas la permission d'ajouter une instance du modèle {app_label}."
"{model_name}."
-#: apps/permission/signals.py:106
+#: apps/permission/signals.py:112
#, python-brace-format
msgid ""
"You don't have the permission to delete this instance of model {app_label}."
@@ -2032,50 +2051,50 @@ msgstr "L'équipe de la Note Kfet."
msgid "Register new user"
msgstr "Enregistrer un nouvel utilisateur"
-#: apps/registration/views.py:95
+#: apps/registration/views.py:98
msgid "Email validation"
msgstr "Validation de l'adresse mail"
-#: apps/registration/views.py:97
+#: apps/registration/views.py:100
msgid "Validate email"
msgstr "Valider l'adresse e-mail"
-#: apps/registration/views.py:141
+#: apps/registration/views.py:144
msgid "Email validation unsuccessful"
msgstr "La validation de l'adresse mail a échoué"
-#: apps/registration/views.py:152
+#: apps/registration/views.py:155
msgid "Email validation email sent"
msgstr "L'email de vérification de l'adresse email a bien été envoyé"
-#: apps/registration/views.py:160
+#: apps/registration/views.py:163
msgid "Resend email validation link"
msgstr "Renvoyer le lien de validation"
-#: apps/registration/views.py:178
+#: apps/registration/views.py:181
msgid "Pre-registered users list"
msgstr "Liste des utilisateurs en attente d'inscription"
-#: apps/registration/views.py:202
+#: apps/registration/views.py:205
msgid "Unregistered users"
msgstr "Utilisateurs en attente d'inscription"
-#: apps/registration/views.py:215
+#: apps/registration/views.py:218
msgid "Registration detail"
msgstr "Détails de l'inscription"
-#: apps/registration/views.py:278
+#: apps/registration/views.py:282
msgid "You must join the BDE."
msgstr "Vous devez adhérer au BDE."
-#: apps/registration/views.py:302
+#: apps/registration/views.py:306
msgid ""
"The entered amount is not enough for the memberships, should be at least {}"
msgstr ""
"Le montant crédité est trop faible pour adhérer, il doit être au minimum de "
"{}"
-#: apps/registration/views.py:383
+#: apps/registration/views.py:387
msgid "Invalidate pre-registration"
msgstr "Invalider l'inscription"
@@ -2083,145 +2102,145 @@ msgstr "Invalider l'inscription"
msgid "Treasury"
msgstr "Trésorerie"
-#: apps/treasury/forms.py:25 apps/treasury/models.py:91
+#: apps/treasury/forms.py:26 apps/treasury/models.py:94
#: apps/treasury/templates/treasury/invoice_form.html:22
msgid "This invoice is locked and can no longer be edited."
msgstr "Cette facture est verrouillée et ne peut plus être éditée."
-#: apps/treasury/forms.py:99
+#: apps/treasury/forms.py:100
msgid "Remittance is already closed."
msgstr "La remise est déjà fermée."
-#: apps/treasury/forms.py:104
+#: apps/treasury/forms.py:105
msgid "You can't change the type of the remittance."
msgstr "Vous ne pouvez pas changer le type de la remise."
-#: apps/treasury/forms.py:124 apps/treasury/models.py:265
+#: apps/treasury/forms.py:125 apps/treasury/models.py:268
#: apps/treasury/tables.py:97 apps/treasury/tables.py:105
#: apps/treasury/templates/treasury/invoice_list.html:16
#: apps/treasury/templates/treasury/remittance_list.html:16
-#: apps/treasury/templates/treasury/sogecredit_list.html:16
+#: apps/treasury/templates/treasury/sogecredit_list.html:17
msgid "Remittance"
msgstr "Remise"
-#: apps/treasury/forms.py:125
+#: apps/treasury/forms.py:126
msgid "No attached remittance"
msgstr "Pas de remise associée"
-#: apps/treasury/models.py:24
+#: apps/treasury/models.py:27
msgid "Invoice identifier"
msgstr "Numéro de facture"
-#: apps/treasury/models.py:38
+#: apps/treasury/models.py:41
msgid "BDE"
msgstr "BDE"
-#: apps/treasury/models.py:43
+#: apps/treasury/models.py:46
msgid "Object"
msgstr "Objet"
-#: apps/treasury/models.py:47
+#: apps/treasury/models.py:50
msgid "Description"
msgstr "Description"
-#: apps/treasury/models.py:56
+#: apps/treasury/models.py:59
msgid "Address"
msgstr "Adresse"
-#: apps/treasury/models.py:61 apps/treasury/models.py:191
+#: apps/treasury/models.py:64 apps/treasury/models.py:194
msgid "Date"
msgstr "Date"
-#: apps/treasury/models.py:65
+#: apps/treasury/models.py:68
msgid "Acquitted"
msgstr "Acquittée"
-#: apps/treasury/models.py:70
+#: apps/treasury/models.py:73
msgid "Locked"
msgstr "Verrouillée"
-#: apps/treasury/models.py:71
+#: apps/treasury/models.py:74
msgid "An invoice can't be edited when it is locked."
msgstr "Une facture ne peut plus être modifiée si elle est verrouillée."
-#: apps/treasury/models.py:77
+#: apps/treasury/models.py:80
msgid "tex source"
msgstr "fichier TeX source"
-#: apps/treasury/models.py:111 apps/treasury/models.py:127
+#: apps/treasury/models.py:114 apps/treasury/models.py:130
msgid "invoice"
msgstr "facture"
-#: apps/treasury/models.py:112
+#: apps/treasury/models.py:115
msgid "invoices"
msgstr "factures"
-#: apps/treasury/models.py:115
+#: apps/treasury/models.py:118
#, python-brace-format
msgid "Invoice #{id}"
msgstr "Facture n°{id}"
-#: apps/treasury/models.py:132
+#: apps/treasury/models.py:135
msgid "Designation"
msgstr "Désignation"
-#: apps/treasury/models.py:138
+#: apps/treasury/models.py:141
msgid "Quantity"
msgstr "Quantité"
-#: apps/treasury/models.py:143
+#: apps/treasury/models.py:146
msgid "Unit price"
msgstr "Prix unitaire"
-#: apps/treasury/models.py:159
+#: apps/treasury/models.py:162
msgid "product"
msgstr "produit"
-#: apps/treasury/models.py:160
+#: apps/treasury/models.py:163
msgid "products"
msgstr "produits"
-#: apps/treasury/models.py:180
+#: apps/treasury/models.py:183
msgid "remittance type"
msgstr "type de remise"
-#: apps/treasury/models.py:181
+#: apps/treasury/models.py:184
msgid "remittance types"
msgstr "types de remises"
-#: apps/treasury/models.py:202
+#: apps/treasury/models.py:205
msgid "Comment"
msgstr "Commentaire"
-#: apps/treasury/models.py:207
+#: apps/treasury/models.py:210
msgid "Closed"
msgstr "Fermée"
-#: apps/treasury/models.py:211
+#: apps/treasury/models.py:214
msgid "remittance"
msgstr "remise"
-#: apps/treasury/models.py:212
+#: apps/treasury/models.py:215
msgid "remittances"
msgstr "remises"
-#: apps/treasury/models.py:245
+#: apps/treasury/models.py:248
msgid "Remittance #{:d}: {}"
msgstr "Remise n°{:d} : {}"
-#: apps/treasury/models.py:269
+#: apps/treasury/models.py:272
msgid "special transaction proxy"
msgstr "proxy de transaction spéciale"
-#: apps/treasury/models.py:270
+#: apps/treasury/models.py:273
msgid "special transaction proxies"
msgstr "proxys de transactions spéciales"
-#: apps/treasury/models.py:295
+#: apps/treasury/models.py:299
msgid "credit transaction"
msgstr "transaction de crédit"
-#: apps/treasury/models.py:379
+#: apps/treasury/models.py:418
msgid ""
"This user doesn't have enough money to pay the memberships with its note. "
"Please ask her/him to credit the note before invalidating this credit."
@@ -2229,16 +2248,16 @@ msgstr ""
"Cet utilisateur n'a pas assez d'argent pour payer les adhésions avec sa "
"note. Merci de lui demander de recharger sa note avant d'invalider ce crédit."
-#: apps/treasury/models.py:399
+#: apps/treasury/models.py:438
#: apps/treasury/templates/treasury/sogecredit_detail.html:10
msgid "Credit from the Société générale"
msgstr "Crédit de la Société générale"
-#: apps/treasury/models.py:400
+#: apps/treasury/models.py:439
msgid "Credits from the Société générale"
msgstr "Crédits de la Société générale"
-#: apps/treasury/models.py:403
+#: apps/treasury/models.py:442
#, python-brace-format
msgid "Soge credit for {user}"
msgstr "Crédit de la société générale pour l'utilisateur {user}"
@@ -2250,7 +2269,7 @@ msgstr "Facture n°{:d}"
#: apps/treasury/tables.py:25
#: apps/treasury/templates/treasury/invoice_list.html:13
#: apps/treasury/templates/treasury/remittance_list.html:13
-#: apps/treasury/templates/treasury/sogecredit_list.html:13
+#: apps/treasury/templates/treasury/sogecredit_list.html:14
msgid "Invoice"
msgstr "Facture"
@@ -2267,12 +2286,12 @@ msgid "Yes"
msgstr "Oui"
#: apps/treasury/templates/treasury/invoice_confirm_delete.html:10
-#: apps/treasury/views.py:179
+#: apps/treasury/views.py:180
msgid "Delete invoice"
msgstr "Supprimer la facture"
#: apps/treasury/templates/treasury/invoice_confirm_delete.html:15
-#: apps/treasury/views.py:183
+#: apps/treasury/views.py:184
msgid "This invoice is locked and can't be deleted."
msgstr "Cette facture est verrouillée et ne peut pas être supprimée."
@@ -2306,7 +2325,7 @@ msgstr "Retirer produit"
#: apps/treasury/templates/treasury/invoice_list.html:19
#: apps/treasury/templates/treasury/remittance_list.html:19
-#: apps/treasury/templates/treasury/sogecredit_list.html:19
+#: apps/treasury/templates/treasury/sogecredit_list.html:20
msgid "Société générale credits"
msgstr "Crédits de la Société générale"
@@ -2426,54 +2445,62 @@ msgstr "Valider"
msgid "Return to credit list"
msgstr "Retour à la liste des crédits"
-#: apps/treasury/templates/treasury/sogecredit_list.html:34
+#: apps/treasury/templates/treasury/sogecredit_list.html:40
msgid "Filter with unvalidated credits only"
msgstr "Filtrer avec uniquement les crédits non valides"
-#: apps/treasury/templates/treasury/sogecredit_list.html:44
+#: apps/treasury/templates/treasury/sogecredit_list.html:50
msgid "There is no matched user that have asked for a Société générale credit."
msgstr ""
"Il n'y a pas d'utilisateur trouvé ayant demandé un crédit de la Société "
"générale."
-#: apps/treasury/views.py:39
+#: apps/treasury/templates/treasury/sogecredit_list.html:63
+msgid "Add credit from the Société générale"
+msgstr "Ajouter un crédit de la Société générale"
+
+#: apps/treasury/templates/treasury/sogecredit_list.html:109
+msgid "Credit successfully registered"
+msgstr "Le crédit a bien été enregistré"
+
+#: apps/treasury/views.py:40
msgid "Create new invoice"
msgstr "Créer une nouvelle facture"
-#: apps/treasury/views.py:96
+#: apps/treasury/views.py:97
msgid "Invoices list"
msgstr "Liste des factures"
-#: apps/treasury/views.py:111 apps/treasury/views.py:285
-#: apps/treasury/views.py:411
+#: apps/treasury/views.py:112 apps/treasury/views.py:286
+#: apps/treasury/views.py:412
msgid "You are not able to see the treasury interface."
msgstr "Vous n'êtes pas autorisé à voir l'interface de trésorerie."
-#: apps/treasury/views.py:121
+#: apps/treasury/views.py:122
msgid "Update an invoice"
msgstr "Modifier la facture"
-#: apps/treasury/views.py:246
+#: apps/treasury/views.py:247
msgid "Create a new remittance"
msgstr "Créer une nouvelle remise"
-#: apps/treasury/views.py:273
+#: apps/treasury/views.py:274
msgid "Remittances list"
msgstr "Liste des remises"
-#: apps/treasury/views.py:336
+#: apps/treasury/views.py:337
msgid "Update a remittance"
msgstr "Modifier la remise"
-#: apps/treasury/views.py:359
+#: apps/treasury/views.py:360
msgid "Attach a transaction to a remittance"
msgstr "Joindre une transaction à une remise"
-#: apps/treasury/views.py:403
+#: apps/treasury/views.py:404
msgid "List of credits from the Société générale"
msgstr "Liste des crédits de la Société générale"
-#: apps/treasury/views.py:443
+#: apps/treasury/views.py:449
msgid "Manage credits from the Société générale"
msgstr "Gérer les crédits de la Société générale"
@@ -2483,12 +2510,18 @@ msgstr "Gérer les crédits de la Société générale"
msgid "WEI"
msgstr "WEI"
-#: apps/wei/forms/registration.py:51 apps/wei/models.py:118
+#: apps/wei/forms/registration.py:35
+msgid "The selected user is not validated. Please validate its account first"
+msgstr ""
+"L'utilisateur sélectionné n'est pas validé. Merci de d'abord valider son "
+"compte."
+
+#: apps/wei/forms/registration.py:60 apps/wei/models.py:118
#: apps/wei/models.py:315
msgid "bus"
msgstr "bus"
-#: apps/wei/forms/registration.py:52
+#: apps/wei/forms/registration.py:61
msgid ""
"This choice is not definitive. The WEI organizers are free to attribute for "
"you a bus and a team, in particular if you are a free eletron."
@@ -2497,11 +2530,11 @@ msgstr ""
"attribuer un bus et une équipe, en particulier si vous êtes un électron "
"libre."
-#: apps/wei/forms/registration.py:59
+#: apps/wei/forms/registration.py:68
msgid "Team"
msgstr "Équipe"
-#: apps/wei/forms/registration.py:61
+#: apps/wei/forms/registration.py:70
msgid ""
"Leave this field empty if you won't be in a team (staff, bus chief, free "
"electron)"
@@ -2509,16 +2542,16 @@ msgstr ""
"Laissez ce champ vide si vous ne serez pas dans une équipe (staff, chef de "
"bus ou électron libre)"
-#: apps/wei/forms/registration.py:67 apps/wei/forms/registration.py:77
+#: apps/wei/forms/registration.py:76 apps/wei/forms/registration.py:86
#: apps/wei/models.py:153
msgid "WEI Roles"
msgstr "Rôles au WEI"
-#: apps/wei/forms/registration.py:68
+#: apps/wei/forms/registration.py:77
msgid "Select the roles that you are interested in."
msgstr "Sélectionnez les rôles qui vous intéressent."
-#: apps/wei/forms/registration.py:113
+#: apps/wei/forms/registration.py:122
msgid "This team doesn't belong to the given bus."
msgstr "Cette équipe n'appartient pas à ce bus."
@@ -2677,23 +2710,29 @@ msgid "The user does not have enough money."
msgstr "L'utilisateur n'a pas assez d'argent."
#: apps/wei/tables.py:107
+msgid "The user is in first year, and the repartition algorithm didn't run."
+msgstr ""
+"L'utilisateur est en première année, et l'algorithme de répartition n'a pas "
+"tourné."
+
+#: apps/wei/tables.py:110
msgid "The user has enough money, you can validate the registration."
msgstr "L'utilisateur a assez d'argent, l'inscription est possible."
-#: apps/wei/tables.py:139
+#: apps/wei/tables.py:142
msgid "Year"
msgstr "Année"
-#: apps/wei/tables.py:177 apps/wei/templates/wei/bus_detail.html:32
+#: apps/wei/tables.py:180 apps/wei/templates/wei/bus_detail.html:32
#: apps/wei/templates/wei/busteam_detail.html:50
msgid "Teams"
msgstr "Équipes"
-#: apps/wei/tables.py:186 apps/wei/tables.py:227
+#: apps/wei/tables.py:189 apps/wei/tables.py:230
msgid "Members count"
msgstr "Nombre de membres"
-#: apps/wei/tables.py:193 apps/wei/tables.py:224
+#: apps/wei/tables.py:196 apps/wei/tables.py:227
msgid "members"
msgstr "adhérents"
@@ -2713,11 +2752,11 @@ msgstr "Prix du WEI (étudiants)"
msgid "WEI list"
msgstr "Liste des WEI"
-#: apps/wei/templates/wei/base.html:81 apps/wei/views.py:510
+#: apps/wei/templates/wei/base.html:81 apps/wei/views.py:517
msgid "Register 1A"
msgstr "Inscrire un 1A"
-#: apps/wei/templates/wei/base.html:85 apps/wei/views.py:578
+#: apps/wei/templates/wei/base.html:85 apps/wei/views.py:592
msgid "Register 2A+"
msgstr "Inscrire un 2A+"
@@ -2746,8 +2785,8 @@ msgstr "Télécharger au format PDF"
#: apps/wei/templates/wei/survey.html:11
#: apps/wei/templates/wei/survey_closed.html:11
-#: apps/wei/templates/wei/survey_end.html:11 apps/wei/views.py:973
-#: apps/wei/views.py:1028 apps/wei/views.py:1038
+#: apps/wei/templates/wei/survey_end.html:11 apps/wei/views.py:988
+#: apps/wei/views.py:1043 apps/wei/views.py:1053
msgid "Survey WEI"
msgstr "Questionnaire WEI"
@@ -2985,11 +3024,11 @@ msgstr "Gérer l'équipe WEI"
msgid "Register first year student to the WEI"
msgstr "Inscrire un 1A au WEI"
-#: apps/wei/views.py:532 apps/wei/views.py:613
+#: apps/wei/views.py:539 apps/wei/views.py:627
msgid "This user is already registered to this WEI."
msgstr "Cette personne est déjà inscrite au WEI."
-#: apps/wei/views.py:537
+#: apps/wei/views.py:544
msgid ""
"This user can't be in her/his first year since he/she has already "
"participated to a WEI."
@@ -2997,27 +3036,27 @@ msgstr ""
"Cet utilisateur ne peut pas être en première année puisqu'il a déjà "
"participé à un WEI."
-#: apps/wei/views.py:554
+#: apps/wei/views.py:561
msgid "Register old student to the WEI"
msgstr "Inscrire un 2A+ au WEI"
-#: apps/wei/views.py:597 apps/wei/views.py:686
+#: apps/wei/views.py:611 apps/wei/views.py:700
msgid "You already opened an account in the Société générale."
msgstr "Vous avez déjà ouvert un compte auprès de la société générale."
-#: apps/wei/views.py:643
+#: apps/wei/views.py:657
msgid "Update WEI Registration"
msgstr "Modifier l'inscription WEI"
-#: apps/wei/views.py:746
+#: apps/wei/views.py:761
msgid "Delete WEI registration"
msgstr "Supprimer l'inscription WEI"
-#: apps/wei/views.py:757
+#: apps/wei/views.py:772
msgid "You don't have the right to delete this WEI registration."
msgstr "Vous n'avez pas la permission de supprimer cette inscription au WEI."
-#: apps/wei/views.py:776
+#: apps/wei/views.py:791
msgid "Validate WEI registration"
msgstr "Valider l'inscription WEI"
@@ -3141,13 +3180,7 @@ msgstr ""
"Vous n'êtes plus adhérent BDE. Merci de réadhérer si vous voulez profiter de "
"la note."
-#: note_kfet/templates/base.html:164
-msgid "You are not a Kfet member, so you can't use your note account."
-msgstr ""
-"Vous n'êtes pas adhérent Kfet, vous ne pouvez par conséquent pas utiliser "
-"votre compte note."
-
-#: note_kfet/templates/base.html:170
+#: note_kfet/templates/base.html:166
msgid ""
"Your e-mail address is not validated. Please check your mail inbox and click "
"on the validation link."
@@ -3155,7 +3188,7 @@ msgstr ""
"Votre adresse e-mail n'est pas validée. Merci de vérifier votre boîte mail "
"et de cliquer sur le lien de validation."
-#: note_kfet/templates/base.html:176
+#: note_kfet/templates/base.html:172
msgid ""
"You declared that you opened a bank account in the Société générale. The "
"bank did not validate the creation of the account to the BDE, so the "
@@ -3170,7 +3203,7 @@ msgstr ""
"durer quelques jours. Merci de vous assurer de bien aller au bout de vos "
"démarches."
-#: note_kfet/templates/base.html:199
+#: note_kfet/templates/base.html:195
msgid "Contact us"
msgstr "Nous contacter"
@@ -3218,9 +3251,10 @@ msgid ""
"link templates and convert permissions to scope numbers with the permissions "
"that you want to grant for your application."
msgstr ""
-"Vous pouvez aller ici pour générer des modèles "
-"de liens d'autorisation et convertir des permissions en identifiants de "
-"scopes avec les permissions que vous souhaitez attribuer à votre application."
+"Vous pouvez aller ici pour générer des "
+"modèles de liens d'autorisation et convertir des permissions en identifiants "
+"de scopes avec les permissions que vous souhaitez attribuer à votre "
+"application."
#: note_kfet/templates/oauth2_provider/application_detail.html:37
#: note_kfet/templates/oauth2_provider/application_form.html:23
@@ -3400,3 +3434,8 @@ msgstr ""
"vous connecter. Vous devez vous rendre à la Kfet et payer les frais "
"d'adhésion. Vous devez également valider votre adresse email en suivant le "
"lien que vous avez reçu."
+
+#~ msgid "You are not a Kfet member, so you can't use your note account."
+#~ msgstr ""
+#~ "Vous n'êtes pas adhérent Kfet, vous ne pouvez par conséquent pas utiliser "
+#~ "votre compte note."
diff --git a/note_kfet/middlewares.py b/note_kfet/middlewares.py
index e763a571..ed6d6acf 100644
--- a/note_kfet/middlewares.py
+++ b/note_kfet/middlewares.py
@@ -75,7 +75,7 @@ class LoginByIPMiddleware(object):
else:
ip = request.META.get('REMOTE_ADDR')
- qs = User.objects.filter(password=f"ipbased${ip}")
+ qs = User.objects.filter(password__iregex=f"ipbased\\$.*\\^{ip}\\$.*")
if qs.exists():
login(request, qs.get())
session = request.session