Improve login form

This commit is contained in:
Skia 2016-08-31 02:43:49 +02:00
parent fcfbfb3a0b
commit f66b999f24
6 changed files with 111 additions and 90 deletions

View File

@ -3,16 +3,16 @@ from django.shortcuts import render
from django.http import HttpResponseForbidden, HttpResponseNotFound from django.http import HttpResponseForbidden, HttpResponseNotFound
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist from django.core.exceptions import PermissionDenied, ObjectDoesNotExist
from django.views.generic.base import View from django.views.generic.base import View
from django.contrib.auth.forms import AuthenticationForm
from core.models import Group from core.models import Group
from core.views.forms import LoginForm
def forbidden(request): def forbidden(request):
try: try:
return HttpResponseForbidden(render(request, "core/403.jinja", context={'next': request.path, 'form': return HttpResponseForbidden(render(request, "core/403.jinja", context={'next': request.path, 'form':
AuthenticationForm(), 'popup': request.resolver_match.kwargs['popup'] or ""})) LoginForm(), 'popup': request.resolver_match.kwargs['popup'] or ""}))
except: except:
return HttpResponseForbidden(render(request, "core/403.jinja", context={'next': request.path, 'form': AuthenticationForm()})) return HttpResponseForbidden(render(request, "core/403.jinja", context={'next': request.path, 'form': LoginForm()}))
def not_found(request): def not_found(request):
return HttpResponseNotFound(render(request, "core/404.jinja")) return HttpResponseNotFound(render(request, "core/404.jinja"))

View File

@ -8,6 +8,7 @@ from django.utils.translation import ugettext as _
from phonenumber_field.widgets import PhoneNumberInternationalFallbackWidget from phonenumber_field.widgets import PhoneNumberInternationalFallbackWidget
import logging import logging
import re
from core.models import User, Page, RealGroup, SithFile from core.models import User, Page, RealGroup, SithFile
@ -68,6 +69,23 @@ class SelectUser(TextInput):
# Forms # Forms
class LoginForm(AuthenticationForm):
def __init__(self, *arg, **kwargs):
if 'data' in kwargs.keys():
from counter.models import Customer
data = kwargs['data'].copy()
account_code = re.compile(r"^[0-9]+[A-Za-z]$")
if account_code.match(data['username']):
user = Customer.objects.filter(account_id=data['username']).first().user
elif '@' in data['username']:
user = User.objects.filter(email=data['username']).first()
else:
user = User.objects.filter(username=data['username']).first()
data['username'] = user.username
kwargs['data'] = data
super(LoginForm, self).__init__(*arg, **kwargs)
self.fields['username'].label = _("Username, email, or account number")
class RegisteringForm(UserCreationForm): class RegisteringForm(UserCreationForm):
error_css_class = 'error' error_css_class = 'error'
required_css_class = 'required' required_css_class = 'required'

View File

@ -16,7 +16,7 @@ from datetime import timedelta
import logging import logging
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin
from core.views.forms import RegisteringForm, UserPropForm, UserProfileForm from core.views.forms import RegisteringForm, UserPropForm, UserProfileForm, LoginForm
from core.models import User, SithFile from core.models import User, SithFile
def login(request): def login(request):
@ -25,7 +25,7 @@ def login(request):
Needs to be improve with correct handling of form exceptions Needs to be improve with correct handling of form exceptions
""" """
return views.login(request, template_name="core/login.jinja") return views.login(request, template_name="core/login.jinja", authentication_form=LoginForm)
def logout(request): def logout(request):
""" """

View File

@ -4,7 +4,6 @@ from django.views.generic.edit import UpdateView, CreateView, DeleteView, Proces
from django.forms.models import modelform_factory from django.forms.models import modelform_factory
from django.forms import CheckboxSelectMultiple from django.forms import CheckboxSelectMultiple
from django.core.urlresolvers import reverse_lazy from django.core.urlresolvers import reverse_lazy
from django.contrib.auth.forms import AuthenticationForm
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.utils import timezone from django.utils import timezone
from django import forms from django import forms
@ -18,7 +17,7 @@ from ajax_select.fields import AutoCompleteSelectField, AutoCompleteSelectMultip
from ajax_select import make_ajax_form, make_ajax_field from ajax_select import make_ajax_form, make_ajax_field
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin
from core.views.forms import SelectUser from core.views.forms import SelectUser, LoginForm
from core.models import User from core.models import User
from subscription.models import Subscriber from subscription.models import Subscriber
from subscription.views import get_subscriber from subscription.views import get_subscriber
@ -77,7 +76,7 @@ class CounterMain(DetailView, ProcessFormView, FormMixin):
if self.request.method == 'POST': if self.request.method == 'POST':
self.object = self.get_object() self.object = self.get_object()
kwargs = super(CounterMain, self).get_context_data(**kwargs) kwargs = super(CounterMain, self).get_context_data(**kwargs)
kwargs['login_form'] = AuthenticationForm() kwargs['login_form'] = LoginForm()
kwargs['login_form'].fields['username'].widget.attrs['autofocus'] = True kwargs['login_form'].fields['username'].widget.attrs['autofocus'] = True
kwargs['login_form'].cleaned_data = {} # add_error fails if there are no cleaned_data kwargs['login_form'].cleaned_data = {} # add_error fails if there are no cleaned_data
if "credentials" in self.request.GET: if "credentials" in self.request.GET:
@ -348,7 +347,7 @@ class CounterLogin(RedirectView):
""" """
self.counter_id = kwargs['counter_id'] self.counter_id = kwargs['counter_id']
self.counter = Counter.objects.filter(id=kwargs['counter_id']).first() self.counter = Counter.objects.filter(id=kwargs['counter_id']).first()
form = AuthenticationForm(request, data=request.POST) form = LoginForm(request, data=request.POST)
self.errors = [] self.errors = []
if form.is_valid(): if form.is_valid():
user = User.objects.filter(username=form.cleaned_data['username']).first() user = User.objects.filter(username=form.cleaned_data['username']).first()

Binary file not shown.

View File

@ -6,7 +6,7 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-08-29 03:22+0200\n" "POT-Creation-Date: 2016-08-31 02:41+0200\n"
"PO-Revision-Date: 2016-07-18\n" "PO-Revision-Date: 2016-07-18\n"
"Last-Translator: Skia <skia@libskia.so>\n" "Last-Translator: Skia <skia@libskia.so>\n"
"Language-Team: AE info <ae.info@utbm.fr>\n" "Language-Team: AE info <ae.info@utbm.fr>\n"
@ -103,7 +103,7 @@ msgid "club account"
msgstr "compte club" msgstr "compte club"
#: accounting/models.py:135 accounting/models.py:178 counter/models.py:25 #: accounting/models.py:135 accounting/models.py:178 counter/models.py:25
#: counter/models.py:197 #: counter/models.py:200
msgid "amount" msgid "amount"
msgstr "montant" msgstr "montant"
@ -124,7 +124,7 @@ msgid "journal"
msgstr "classeur" msgstr "classeur"
#: accounting/models.py:179 core/models.py:458 core/models.py:734 #: accounting/models.py:179 core/models.py:458 core/models.py:734
#: counter/models.py:200 counter/models.py:246 counter/models.py:296 #: counter/models.py:203 counter/models.py:246 counter/models.py:296
#: eboutic/models.py:15 eboutic/models.py:48 #: eboutic/models.py:15 eboutic/models.py:48
msgid "date" msgid "date"
msgstr "date" msgstr "date"
@ -133,7 +133,7 @@ msgstr "date"
msgid "comment" msgid "comment"
msgstr "commentaire" msgstr "commentaire"
#: accounting/models.py:181 counter/models.py:201 counter/models.py:247 #: accounting/models.py:181 counter/models.py:204 counter/models.py:247
#: subscription/models.py:52 #: subscription/models.py:52
msgid "payment method" msgid "payment method"
msgstr "méthode de paiement" msgstr "méthode de paiement"
@ -179,7 +179,7 @@ msgstr "Compte"
msgid "Company" msgid "Company"
msgstr "Entreprise" msgstr "Entreprise"
#: accounting/models.py:190 sith/settings.py:291 sith/settings_sample.py:273 #: accounting/models.py:190 sith/settings.py:287 sith/settings_sample.py:272
msgid "Other" msgid "Other"
msgstr "Autre" msgstr "Autre"
@ -468,7 +468,7 @@ msgid "Done"
msgstr "Effectué" msgstr "Effectué"
#: accounting/templates/accounting/journal_details.jinja:34 #: accounting/templates/accounting/journal_details.jinja:34
#: counter/views.py:561 #: counter/views.py:560
msgid "Comment" msgid "Comment"
msgstr "Commentaire" msgstr "Commentaire"
@ -1487,7 +1487,7 @@ msgstr "Cotisant jusqu'au %(subscription_end)s"
msgid "Not subscribed" msgid "Not subscribed"
msgstr "Non cotisant" msgstr "Non cotisant"
#: core/templates/core/user_detail.jinja:51 #: core/templates/core/user_detail.jinja:52
#: subscription/templates/subscription/subscription.jinja:4 #: subscription/templates/subscription/subscription.jinja:4
#: subscription/templates/subscription/subscription.jinja:8 #: subscription/templates/subscription/subscription.jinja:8
msgid "New subscription" msgid "New subscription"
@ -1576,7 +1576,7 @@ msgstr "Gestion de Sith"
msgid "Subscriptions" msgid "Subscriptions"
msgstr "Cotisations" msgstr "Cotisations"
#: core/templates/core/user_tools.jinja:22 counter/views.py:476 #: core/templates/core/user_tools.jinja:22 counter/views.py:475
msgid "Counters" msgid "Counters"
msgstr "Comptoirs" msgstr "Comptoirs"
@ -1613,20 +1613,24 @@ msgstr "Ajouter un nouveau dossier"
msgid "Error creating folder %(folder_name)s: %(msg)s" msgid "Error creating folder %(folder_name)s: %(msg)s"
msgstr "Erreur de création du dossier %(folder_name)s : %(msg)s" msgstr "Erreur de création du dossier %(folder_name)s : %(msg)s"
#: core/views/files.py:61 core/views/forms.py:152 core/views/forms.py:156 #: core/views/files.py:61 core/views/forms.py:170 core/views/forms.py:174
#, python-format #, python-format
msgid "Error uploading file %(file_name)s: %(msg)s" msgid "Error uploading file %(file_name)s: %(msg)s"
msgstr "Erreur d'envoie du fichier %(file_name)s : %(msg)s" msgstr "Erreur d'envoie du fichier %(file_name)s : %(msg)s"
#: core/views/forms.py:49 core/views/forms.py:52 #: core/views/forms.py:50 core/views/forms.py:53
msgid "Choose file" msgid "Choose file"
msgstr "Choisir un fichier" msgstr "Choisir un fichier"
#: core/views/forms.py:63 core/views/forms.py:66 #: core/views/forms.py:64 core/views/forms.py:67
msgid "Choose user" msgid "Choose user"
msgstr "Choisir un utilisateur" msgstr "Choisir un utilisateur"
#: core/views/forms.py:111 #: core/views/forms.py:87
msgid "Username, email, or account number"
msgstr "Nom d'utilisateur, email, ou numéro de compte AE"
#: core/views/forms.py:129
msgid "" msgid ""
"Profile: you need to be visible on the picture, in order to be recognized (e." "Profile: you need to be visible on the picture, in order to be recognized (e."
"g. by the barmen)" "g. by the barmen)"
@ -1634,15 +1638,15 @@ msgstr ""
"Photo de profil: vous devez être visible sur la photo afin d'être reconnu " "Photo de profil: vous devez être visible sur la photo afin d'être reconnu "
"(par exemple par les barmen)" "(par exemple par les barmen)"
#: core/views/forms.py:112 #: core/views/forms.py:130
msgid "Avatar: used on the forum" msgid "Avatar: used on the forum"
msgstr "Avatar : utilisé sur le forum" msgstr "Avatar : utilisé sur le forum"
#: core/views/forms.py:113 #: core/views/forms.py:131
msgid "Scrub: let other know how your scrub looks like!" msgid "Scrub: let other know how your scrub looks like!"
msgstr "Blouse : montrez aux autres à quoi ressemble votre blouse !" msgstr "Blouse : montrez aux autres à quoi ressemble votre blouse !"
#: core/views/forms.py:157 #: core/views/forms.py:175
msgid "Bad image format, only jpeg, png, and gif are accepted" msgid "Bad image format, only jpeg, png, and gif are accepted"
msgstr "Mauvais format d'image, seuls les jpeg, png, et gif sont acceptés" msgstr "Mauvais format d'image, seuls les jpeg, png, et gif sont acceptés"
@ -1726,8 +1730,8 @@ msgstr "Bureau"
#: eboutic/templates/eboutic/eboutic_main.jinja:24 #: eboutic/templates/eboutic/eboutic_main.jinja:24
#: eboutic/templates/eboutic/eboutic_makecommand.jinja:8 #: eboutic/templates/eboutic/eboutic_makecommand.jinja:8
#: eboutic/templates/eboutic/eboutic_payment_result.jinja:4 #: eboutic/templates/eboutic/eboutic_payment_result.jinja:4
#: sith/settings.py:290 sith/settings.py:298 sith/settings_sample.py:272 #: sith/settings.py:286 sith/settings.py:294 sith/settings_sample.py:271
#: sith/settings_sample.py:280 #: sith/settings_sample.py:279
msgid "Eboutic" msgid "Eboutic"
msgstr "Eboutic" msgstr "Eboutic"
@ -1740,15 +1744,15 @@ msgstr "vendeurs"
msgid "counter" msgid "counter"
msgstr "comptoir" msgstr "comptoir"
#: counter/models.py:203 #: counter/models.py:206
msgid "bank" msgid "bank"
msgstr "banque" msgstr "banque"
#: counter/models.py:205 counter/models.py:249 #: counter/models.py:208 counter/models.py:249
msgid "is validated" msgid "is validated"
msgstr "est validé" msgstr "est validé"
#: counter/models.py:208 #: counter/models.py:211
msgid "refilling" msgid "refilling"
msgstr "rechargement" msgstr "rechargement"
@ -1764,9 +1768,9 @@ msgstr "quantité"
msgid "Sith account" msgid "Sith account"
msgstr "Compte utilisateur" msgstr "Compte utilisateur"
#: counter/models.py:248 sith/settings.py:283 sith/settings.py:288 #: counter/models.py:248 sith/settings.py:279 sith/settings.py:284
#: sith/settings.py:310 sith/settings_sample.py:265 #: sith/settings.py:306 sith/settings_sample.py:264
#: sith/settings_sample.py:270 sith/settings_sample.py:292 #: sith/settings_sample.py:269 sith/settings_sample.py:291
msgid "Credit card" msgid "Credit card"
msgstr "Carte bancaire" msgstr "Carte bancaire"
@ -1937,93 +1941,93 @@ msgstr "Nouveau type de produit"
msgid "There is no product types in this website." msgid "There is no product types in this website."
msgstr "Il n'y a pas de types de produit dans ce site web." msgstr "Il n'y a pas de types de produit dans ce site web."
#: counter/views.py:36 #: counter/views.py:35
msgid "Select user" msgid "Select user"
msgstr "Choisir un utilisateur" msgstr "Choisir un utilisateur"
#: counter/views.py:52 #: counter/views.py:51
msgid "User not found" msgid "User not found"
msgstr "Utilisateur non trouvé" msgstr "Utilisateur non trouvé"
#: counter/views.py:84 #: counter/views.py:83
msgid "Bad credentials" msgid "Bad credentials"
msgstr "Mauvais identifiants" msgstr "Mauvais identifiants"
#: counter/views.py:86 #: counter/views.py:85
msgid "User is not subscriber" msgid "User is not subscriber"
msgstr "L'utilisateur n'est pas cotisant." msgstr "L'utilisateur n'est pas cotisant."
#: counter/views.py:261 #: counter/views.py:260
msgid "END" msgid "END"
msgstr "FIN" msgstr "FIN"
#: counter/views.py:263 #: counter/views.py:262
msgid "CAN" msgid "CAN"
msgstr "ANN" msgstr "ANN"
#: counter/views.py:293 #: counter/views.py:292
msgid "You have not enough money to buy all the basket" msgid "You have not enough money to buy all the basket"
msgstr "Vous n'avez pas assez d'argent pour acheter le panier" msgstr "Vous n'avez pas assez d'argent pour acheter le panier"
#: counter/views.py:473 #: counter/views.py:472
msgid "Parent product" msgid "Parent product"
msgstr "Produit parent" msgstr "Produit parent"
#: counter/views.py:474 #: counter/views.py:473
msgid "Buying groups" msgid "Buying groups"
msgstr "Groupes d'achat" msgstr "Groupes d'achat"
#: counter/views.py:541 #: counter/views.py:540
msgid "10 cents" msgid "10 cents"
msgstr "10 centimes" msgstr "10 centimes"
#: counter/views.py:542 #: counter/views.py:541
msgid "20 cents" msgid "20 cents"
msgstr "20 centimes" msgstr "20 centimes"
#: counter/views.py:543 #: counter/views.py:542
msgid "50 cents" msgid "50 cents"
msgstr "50 centimes" msgstr "50 centimes"
#: counter/views.py:544 #: counter/views.py:543
msgid "1 euro" msgid "1 euro"
msgstr "1 €" msgstr "1 €"
#: counter/views.py:545 #: counter/views.py:544
msgid "2 euros" msgid "2 euros"
msgstr "2 €" msgstr "2 €"
#: counter/views.py:546 #: counter/views.py:545
msgid "5 euros" msgid "5 euros"
msgstr "5 €" msgstr "5 €"
#: counter/views.py:547 #: counter/views.py:546
msgid "10 euros" msgid "10 euros"
msgstr "10 €" msgstr "10 €"
#: counter/views.py:548 #: counter/views.py:547
msgid "20 euros" msgid "20 euros"
msgstr "20 €" msgstr "20 €"
#: counter/views.py:549 #: counter/views.py:548
msgid "50 euros" msgid "50 euros"
msgstr "50 €" msgstr "50 €"
#: counter/views.py:550 #: counter/views.py:549
msgid "100 euros" msgid "100 euros"
msgstr "100 €" msgstr "100 €"
#: counter/views.py:551 counter/views.py:553 counter/views.py:555 #: counter/views.py:550 counter/views.py:552 counter/views.py:554
#: counter/views.py:557 counter/views.py:559 #: counter/views.py:556 counter/views.py:558
msgid "Check amount" msgid "Check amount"
msgstr "Montant du chèque" msgstr "Montant du chèque"
#: counter/views.py:552 counter/views.py:554 counter/views.py:556 #: counter/views.py:551 counter/views.py:553 counter/views.py:555
#: counter/views.py:558 counter/views.py:560 #: counter/views.py:557 counter/views.py:559
msgid "Check quantity" msgid "Check quantity"
msgstr "Nombre de chèque" msgstr "Nombre de chèque"
#: counter/views.py:562 #: counter/views.py:561
msgid "Emptied" msgid "Emptied"
msgstr "Coffre vidé" msgstr "Coffre vidé"
@ -2175,12 +2179,12 @@ msgid "Washing and drying"
msgstr "Lavage et séchage" msgstr "Lavage et séchage"
#: launderette/templates/launderette/launderette_book.jinja:26 #: launderette/templates/launderette/launderette_book.jinja:26
#: sith/settings.py:424 sith/settings_sample.py:406 #: sith/settings.py:420 sith/settings_sample.py:405
msgid "Washing" msgid "Washing"
msgstr "Lavage" msgstr "Lavage"
#: launderette/templates/launderette/launderette_book.jinja:30 #: launderette/templates/launderette/launderette_book.jinja:30
#: sith/settings.py:424 sith/settings_sample.py:406 #: sith/settings.py:420 sith/settings_sample.py:405
msgid "Drying" msgid "Drying"
msgstr "Séchage" msgstr "Séchage"
@ -2235,116 +2239,116 @@ msgstr "L'utilisateur n'a pas réservé de créneau"
msgid "Token not found" msgid "Token not found"
msgstr "Jeton non trouvé" msgstr "Jeton non trouvé"
#: sith/settings.py:174 sith/settings_sample.py:161 #: sith/settings.py:174 sith/settings_sample.py:160
msgid "English" msgid "English"
msgstr "Anglais" msgstr "Anglais"
#: sith/settings.py:175 sith/settings_sample.py:162 #: sith/settings.py:175 sith/settings_sample.py:161
msgid "French" msgid "French"
msgstr "Français" msgstr "Français"
#: sith/settings.py:280 sith/settings.py:287 sith/settings.py:308 #: sith/settings.py:276 sith/settings.py:283 sith/settings.py:304
#: sith/settings_sample.py:262 sith/settings_sample.py:269 #: sith/settings_sample.py:261 sith/settings_sample.py:268
#: sith/settings_sample.py:290 #: sith/settings_sample.py:289
msgid "Check" msgid "Check"
msgstr "Chèque" msgstr "Chèque"
#: sith/settings.py:281 sith/settings.py:289 sith/settings.py:309 #: sith/settings.py:277 sith/settings.py:285 sith/settings.py:305
#: sith/settings_sample.py:263 sith/settings_sample.py:271 #: sith/settings_sample.py:262 sith/settings_sample.py:270
#: sith/settings_sample.py:291 #: sith/settings_sample.py:290
msgid "Cash" msgid "Cash"
msgstr "Espèces" msgstr "Espèces"
#: sith/settings.py:282 sith/settings_sample.py:264 #: sith/settings.py:278 sith/settings_sample.py:263
msgid "Transfert" msgid "Transfert"
msgstr "Virement" msgstr "Virement"
#: sith/settings.py:295 sith/settings_sample.py:277 #: sith/settings.py:291 sith/settings_sample.py:276
msgid "Belfort" msgid "Belfort"
msgstr "Belfort" msgstr "Belfort"
#: sith/settings.py:296 sith/settings_sample.py:278 #: sith/settings.py:292 sith/settings_sample.py:277
msgid "Sevenans" msgid "Sevenans"
msgstr "Sevenans" msgstr "Sevenans"
#: sith/settings.py:297 sith/settings_sample.py:279 #: sith/settings.py:293 sith/settings_sample.py:278
msgid "Montbéliard" msgid "Montbéliard"
msgstr "Montbéliard" msgstr "Montbéliard"
#: sith/settings.py:337 sith/settings_sample.py:319 #: sith/settings.py:333 sith/settings_sample.py:318
msgid "One semester" msgid "One semester"
msgstr "Un semestre, 15 €" msgstr "Un semestre, 15 €"
#: sith/settings.py:342 sith/settings_sample.py:324 #: sith/settings.py:338 sith/settings_sample.py:323
msgid "Two semesters" msgid "Two semesters"
msgstr "Deux semestres, 28 €" msgstr "Deux semestres, 28 €"
#: sith/settings.py:347 sith/settings_sample.py:329 #: sith/settings.py:343 sith/settings_sample.py:328
msgid "Common core cursus" msgid "Common core cursus"
msgstr "Cursus tronc commun, 45 €" msgstr "Cursus tronc commun, 45 €"
#: sith/settings.py:352 sith/settings.py:357 sith/settings_sample.py:334 #: sith/settings.py:348 sith/settings.py:353 sith/settings_sample.py:333
#: sith/settings_sample.py:339 #: sith/settings_sample.py:338
msgid "Branch cursus" msgid "Branch cursus"
msgstr "Cursus branche, 45 €" msgstr "Cursus branche, 45 €"
#: sith/settings.py:362 sith/settings_sample.py:344 #: sith/settings.py:358 sith/settings_sample.py:343
msgid "Honorary member" msgid "Honorary member"
msgstr "Membre honoraire, 0 €" msgstr "Membre honoraire, 0 €"
#: sith/settings.py:367 sith/settings_sample.py:349 #: sith/settings.py:363 sith/settings_sample.py:348
msgid "Assidu member" msgid "Assidu member"
msgstr "Membre d'Assidu, 0 €" msgstr "Membre d'Assidu, 0 €"
#: sith/settings.py:372 sith/settings_sample.py:354 #: sith/settings.py:368 sith/settings_sample.py:353
msgid "Amicale/DOCEO member" msgid "Amicale/DOCEO member"
msgstr "Membre de l'Amicale/DOCEO, 0 €" msgstr "Membre de l'Amicale/DOCEO, 0 €"
#: sith/settings.py:377 sith/settings_sample.py:359 #: sith/settings.py:373 sith/settings_sample.py:358
msgid "UT network member" msgid "UT network member"
msgstr "Cotisant du réseau UT, 0 €" msgstr "Cotisant du réseau UT, 0 €"
#: sith/settings.py:382 sith/settings_sample.py:364 #: sith/settings.py:378 sith/settings_sample.py:363
msgid "CROUS member" msgid "CROUS member"
msgstr "Membres du CROUS, 0 €" msgstr "Membres du CROUS, 0 €"
#: sith/settings.py:387 sith/settings_sample.py:369 #: sith/settings.py:383 sith/settings_sample.py:368
msgid "Sbarro/ESTA member" msgid "Sbarro/ESTA member"
msgstr "Membre de Sbarro ou de l'ESTA, 15 €" msgstr "Membre de Sbarro ou de l'ESTA, 15 €"
#: sith/settings.py:395 sith/settings_sample.py:377 #: sith/settings.py:391 sith/settings_sample.py:376
msgid "President" msgid "President"
msgstr "Président" msgstr "Président"
#: sith/settings.py:396 sith/settings_sample.py:378 #: sith/settings.py:392 sith/settings_sample.py:377
msgid "Vice-President" msgid "Vice-President"
msgstr "Vice-Président" msgstr "Vice-Président"
#: sith/settings.py:397 sith/settings_sample.py:379 #: sith/settings.py:393 sith/settings_sample.py:378
msgid "Treasurer" msgid "Treasurer"
msgstr "Trésorier" msgstr "Trésorier"
#: sith/settings.py:398 sith/settings_sample.py:380 #: sith/settings.py:394 sith/settings_sample.py:379
msgid "Communication supervisor" msgid "Communication supervisor"
msgstr "Responsable com" msgstr "Responsable com"
#: sith/settings.py:399 sith/settings_sample.py:381 #: sith/settings.py:395 sith/settings_sample.py:380
msgid "Secretary" msgid "Secretary"
msgstr "Secrétaire" msgstr "Secrétaire"
#: sith/settings.py:400 sith/settings_sample.py:382 #: sith/settings.py:396 sith/settings_sample.py:381
msgid "IT supervisor" msgid "IT supervisor"
msgstr "Responsable info" msgstr "Responsable info"
#: sith/settings.py:401 sith/settings_sample.py:383 #: sith/settings.py:397 sith/settings_sample.py:382
msgid "Board member" msgid "Board member"
msgstr "Membre du bureau" msgstr "Membre du bureau"
#: sith/settings.py:402 sith/settings_sample.py:384 #: sith/settings.py:398 sith/settings_sample.py:383
msgid "Active member" msgid "Active member"
msgstr "Membre actif" msgstr "Membre actif"
#: sith/settings.py:403 sith/settings_sample.py:385 #: sith/settings.py:399 sith/settings_sample.py:384
msgid "Curious" msgid "Curious"
msgstr "Curieux" msgstr "Curieux"