1
0
mirror of https://gitlab.crans.org/bde/nk20 synced 2024-12-23 07:52:23 +00:00

Merge branch 'wei' into 'beta'

Corrections de bugs

See merge request bde/nk20!176
This commit is contained in:
ynerant 2021-09-09 11:43:34 +00:00
commit cea3138daf
22 changed files with 440 additions and 196 deletions

View File

@ -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):
"""

View File

@ -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)")),

View File

@ -39,13 +39,13 @@
<dt class="col-xl-6">{% trans 'address'|capfirst %}</dt>
<dd class="col-xl-6">{{ user_object.profile.address }}</dd>
{% if user_object.note and "note.view_note"|has_perm:user_object.note %}
<dt class="col-xl-6">{% trans 'balance'|capfirst %}</dt>
<dd class="col-xl-6">{{ user_object.note.balance | pretty_money }}</dd>
<dt class="col-xl-6">{% trans 'paid'|capfirst %}</dt>
<dd class="col-xl-6">{{ user_object.profile.paid|yesno }}</dd>
{% endif %}
{% endif %}
{% if user_object.note and "note.view_note"|has_perm:user_object.note %}
<dt class="col-xl-6">{% trans 'balance'|capfirst %}</dt>
<dd class="col-xl-6">{{ user_object.note.balance | pretty_money }}</dd>
{% endif %}
</dl>

View File

@ -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)

View File

@ -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

View File

@ -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,

View File

@ -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(

View File

@ -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')

View File

@ -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__'

View File

@ -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 ...',
},
),
}

View File

@ -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):
"""

View File

@ -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 }}
</h3>
<div class="card-body">
<input id="searchbar" type="text" class="form-control" placeholder="Nom/prénom/note ...">
<div class="input-group">
<input id="searchbar" type="text" class="form-control" placeholder="Nom/prénom/note ...">
<div class="input-group-append">
<button id="add_sogecredit" class="btn btn-success" data-toggle="modal" data-target="#add-sogecredit-modal">{% trans "Add" %}</button>
</div>
</div>
<div class="form-check">
<label for="invalid_only" class="form-check-label">
<input id="invalid_only" name="invalid_only" type="checkbox" class="checkboxinput form-check-input" checked>
@ -47,28 +53,65 @@ SPDX-License-Identifier: GPL-3.0-or-later
{% endif %}
</div>
</div>
{# Popup to add new Soge credits manually if needed #}
<div class="modal fade" id="add-sogecredit-modal" tabindex="-1" role="dialog" aria-labelledby="addSogeCredit"
aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="lockNote">{% trans "Add credit from the Société générale" %}</h5>
<button type="button" class="close btn-modal" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
{{ form|crispy }}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary btn-modal" data-dismiss="modal">{% trans "Close" %}</button>
<button type="button" class="btn btn-success btn-modal" data-dismiss="modal" onclick="addSogeCredit()">{% trans "Add" %}</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extrajavascript %}
<script type="text/javascript">
$(document).ready(function () {
let old_pattern = null;
let searchbar_obj = $("#searchbar");
let invalid_only_obj = $("#invalid_only");
let old_pattern = null;
let searchbar_obj = $("#searchbar");
let invalid_only_obj = $("#invalid_only");
function reloadTable() {
let pattern = searchbar_obj.val();
function reloadTable() {
let pattern = searchbar_obj.val();
$("#credits_table").load(location.pathname + "?search=" + pattern.replace(" ", "%20") + (
invalid_only_obj.is(':checked') ? "" : "&valid=1") + " #credits_table");
$("#credits_table").load(location.pathname + "?search=" + pattern.replace(" ", "%20") + (
invalid_only_obj.is(':checked') ? "" : "&valid=1") + " #credits_table");
$(".table-row").click(function () {
window.document.location = $(this).data("href");
});
}
$(".table-row").click(function () {
window.document.location = $(this).data("href");
});
}
searchbar_obj.keyup(reloadTable);
invalid_only_obj.change(reloadTable);
});
searchbar_obj.keyup(reloadTable);
invalid_only_obj.change(reloadTable);
function addSogeCredit() {
let user_pk = $('#id_user_pk').val()
if (!user_pk)
return
$.post('/api/treasury/soge_credit/?format=json', {
csrfmiddlewaretoken: CSRF_TOKEN,
user: user_pk,
}).done(function() {
addMsg("{% trans "Credit successfully registered" %}", 'success', 10000)
reloadTable()
}).fail(function (xhr) {
errMsg(xhr.responseJSON, 30000)
reloadTable()
})
}
</script>
{% endblock %}

View File

@ -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):
"""

View File

@ -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', )

View File

@ -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]

View File

@ -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")

View File

@ -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()

View File

@ -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.")

View File

@ -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.

View File

@ -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()

View File

@ -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 <ynerant@crans.org>\n"
"Language-Team: French <http://translate.ynerant.fr/projects/nk20/nk20/fr/>\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 <a href=\"%(scopes_url)s\">ici</a> 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 <a href=\"%(scopes_url)s\">ici</a> 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."

View File

@ -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