Compare commits

..

13 Commits

Author SHA1 Message Date
Yohann D'ANELLO ad2cc22964 Transactions are not invalidable if the user doesn't have the right to 2020-07-30 17:52:04 +02:00
Yohann D'ANELLO ae629b55ad Add HTML titles 2020-07-30 17:30:21 +02:00
Yohann D'ANELLO a5e50e5de6 Display true note name next to the alias, whenever the user has low permissions 2020-07-30 16:48:34 +02:00
Yohann D'ANELLO 9da8d49223 Remove ... when invalidating transaction 2020-07-30 16:41:41 +02:00
Yohann D'ANELLO aa66361ac7 Update permissions to create clubs.
For now, only superusers can edit the roles of a user.
2020-07-30 16:36:44 +02:00
Yohann D'ANELLO c14d37eaeb Fix deletion of consumptions in double consumption mode 2020-07-30 16:06:21 +02:00
Yohann D'ANELLO e9cbc8e623 Fix linters 2020-07-30 15:53:23 +02:00
Yohann D'ANELLO 9d8c588b78 Buttons list didn't work as well 2020-07-30 15:49:59 +02:00
Yohann D'ANELLO 484560fe4b Fix emitter button 2020-07-30 15:14:13 +02:00
Yohann D'ANELLO 9361f3f2f0 Aliases should load really faster 2020-07-30 15:07:30 +02:00
Yohann D'ANELLO e63219f7ad Force delete some objects 2020-07-30 14:58:18 +02:00
Yohann D'ANELLO 0c0aed0234 🐛 Force delete didn't work as well when trying to check add permissions 2020-07-30 13:10:03 +02:00
Yohann D'ANELLO fb775de923 Add backdoor to login as other users (in debug mode only) 2020-07-30 12:50:48 +02:00
38 changed files with 862 additions and 399 deletions

View File

@ -23,6 +23,7 @@ from .tables import ActivityTable, GuestTable, EntryTable
class ActivityCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): class ActivityCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
model = Activity model = Activity
form_class = ActivityForm form_class = ActivityForm
extra_context = {"title": _("Create new activity")}
def form_valid(self, form): def form_valid(self, form):
form.instance.creater = self.request.user form.instance.creater = self.request.user
@ -37,6 +38,7 @@ class ActivityListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView
model = Activity model = Activity
table_class = ActivityTable table_class = ActivityTable
ordering = ('-date_start',) ordering = ('-date_start',)
extra_context = {"title": _("Activities")}
def get_queryset(self): def get_queryset(self):
return super().get_queryset().distinct() return super().get_queryset().distinct()
@ -44,8 +46,6 @@ class ActivityListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['title'] = _("Activities")
upcoming_activities = Activity.objects.filter(date_end__gt=datetime.now()) upcoming_activities = Activity.objects.filter(date_end__gt=datetime.now())
context['upcoming'] = ActivityTable( context['upcoming'] = ActivityTable(
data=upcoming_activities.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view")), data=upcoming_activities.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view")),
@ -58,6 +58,7 @@ class ActivityListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView
class ActivityDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): class ActivityDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
model = Activity model = Activity
context_object_name = "activity" context_object_name = "activity"
extra_context = {"title": _("Activity detail")}
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data() context = super().get_context_data()
@ -74,6 +75,7 @@ class ActivityDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
class ActivityUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): class ActivityUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
model = Activity model = Activity
form_class = ActivityForm form_class = ActivityForm
extra_context = {"title": _("Update activity")}
def get_success_url(self, **kwargs): def get_success_url(self, **kwargs):
return reverse_lazy('activity:activity_detail', kwargs={"pk": self.kwargs["pk"]}) return reverse_lazy('activity:activity_detail', kwargs={"pk": self.kwargs["pk"]})
@ -84,6 +86,12 @@ class ActivityInviteView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
form_class = GuestForm form_class = GuestForm
template_name = "activity/activity_invite.html" template_name = "activity/activity_invite.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
activity = context["form"].activity
context["title"] = _('Invite guest to the activity "{}"').format(activity.name)
return context
def get_form(self, form_class=None): def get_form(self, form_class=None):
form = super().get_form(form_class) form = super().get_form(form_class)
form.activity = Activity.objects.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view"))\ form.activity = Activity.objects.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view"))\

View File

@ -14,9 +14,11 @@ class ReadProtectedModelViewSet(viewsets.ModelViewSet):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
model = ContentType.objects.get_for_model(self.serializer_class.Meta.model).model_class() self.model = ContentType.objects.get_for_model(self.serializer_class.Meta.model).model_class()
def get_queryset(self):
user = get_current_authenticated_user() user = get_current_authenticated_user()
self.queryset = model.objects.filter(PermissionBackend.filter_queryset(user, model, "view")) return self.model.objects.filter(PermissionBackend.filter_queryset(user, self.model, "view"))
class ReadOnlyProtectedModelViewSet(viewsets.ReadOnlyModelViewSet): class ReadOnlyProtectedModelViewSet(viewsets.ReadOnlyModelViewSet):
@ -26,6 +28,8 @@ class ReadOnlyProtectedModelViewSet(viewsets.ReadOnlyModelViewSet):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
model = ContentType.objects.get_for_model(self.serializer_class.Meta.model).model_class() self.model = ContentType.objects.get_for_model(self.serializer_class.Meta.model).model_class()
def get_queryset(self):
user = get_current_authenticated_user() user = get_current_authenticated_user()
self.queryset = model.objects.filter(PermissionBackend.filter_queryset(user, model, "view")) return self.model.objects.filter(PermissionBackend.filter_queryset(user, self.model, "view"))

View File

@ -4,8 +4,8 @@
from django.contrib import admin from django.contrib import admin
from django.contrib.auth.admin import UserAdmin from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User from django.contrib.auth.models import User
from note_kfet.admin import admin_site from note_kfet.admin import admin_site
from .forms import ProfileForm from .forms import ProfileForm
from .models import Club, Membership, Profile from .models import Club, Membership, Profile

View File

@ -32,7 +32,6 @@ class UserForm(forms.ModelForm):
fields = ('first_name', 'last_name', 'username', 'email',) fields = ('first_name', 'last_name', 'username', 'email',)
class ProfileForm(forms.ModelForm): class ProfileForm(forms.ModelForm):
""" """
A form for the extras field provided by the :model:`member.Profile` model. A form for the extras field provided by the :model:`member.Profile` model.

View File

@ -3,8 +3,10 @@
import hashlib import hashlib
from django.conf import settings
from django.contrib.auth.hashers import PBKDF2PasswordHasher from django.contrib.auth.hashers import PBKDF2PasswordHasher
from django.utils.crypto import constant_time_compare from django.utils.crypto import constant_time_compare
from note_kfet.middlewares import get_current_authenticated_user, get_current_session
class CustomNK15Hasher(PBKDF2PasswordHasher): class CustomNK15Hasher(PBKDF2PasswordHasher):
@ -20,8 +22,37 @@ class CustomNK15Hasher(PBKDF2PasswordHasher):
""" """
algorithm = "custom_nk15" algorithm = "custom_nk15"
def must_update(self, encoded):
if settings.DEBUG:
current_user = get_current_authenticated_user()
if current_user is not None and current_user.is_superuser:
return False
return True
def verify(self, password, encoded): def verify(self, password, encoded):
if settings.DEBUG:
current_user = get_current_authenticated_user()
if current_user is not None and current_user.is_superuser\
and get_current_session().get("permission_mask", -1) >= 42:
return True
if '|' in encoded: if '|' in encoded:
salt, db_hashed_pass = encoded.split('$')[2].split('|') salt, db_hashed_pass = encoded.split('$')[2].split('|')
return constant_time_compare(hashlib.sha256((salt + password).encode("utf-8")).hexdigest(), db_hashed_pass) return constant_time_compare(hashlib.sha256((salt + password).encode("utf-8")).hexdigest(), db_hashed_pass)
return super().verify(password, encoded) return super().verify(password, encoded)
class DebugSuperuserBackdoor(PBKDF2PasswordHasher):
"""
In debug mode and during the beta, superusers can login into other accounts for tests.
"""
def must_update(self, encoded):
return False
def verify(self, password, encoded):
if settings.DEBUG:
current_user = get_current_authenticated_user()
if current_user is not None and current_user.is_superuser\
and get_current_session().get("permission_mask", -1) >= 42:
return True
return super().verify(password, encoded)

View File

@ -6,6 +6,7 @@ from datetime import datetime, timedelta
from PIL import Image from PIL import Image
from django.conf import settings from django.conf import settings
from django.contrib.auth import logout
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.auth.views import LoginView from django.contrib.auth.views import LoginView
@ -21,10 +22,10 @@ from note.forms import ImageForm
from note.models import Alias, NoteUser from note.models import Alias, NoteUser
from note.models.transactions import Transaction, SpecialTransaction from note.models.transactions import Transaction, SpecialTransaction
from note.tables import HistoryTable, AliasTable from note.tables import HistoryTable, AliasTable
from note_kfet.middlewares import _set_current_user_and_ip
from permission.backends import PermissionBackend from permission.backends import PermissionBackend
from permission.models import Role from permission.models import Role
from permission.views import ProtectQuerysetMixin from permission.views import ProtectQuerysetMixin
from wei.models import WEIClub
from .forms import ProfileForm, ClubForm, MembershipForm, CustomAuthenticationForm, UserForm from .forms import ProfileForm, ClubForm, MembershipForm, CustomAuthenticationForm, UserForm
from .models import Club, Membership from .models import Club, Membership
@ -38,6 +39,8 @@ class CustomLoginView(LoginView):
form_class = CustomAuthenticationForm form_class = CustomAuthenticationForm
def form_valid(self, form): def form_valid(self, form):
logout(self.request)
_set_current_user_and_ip(form.get_user(), self.request.session, None)
self.request.session['permission_mask'] = form.cleaned_data['permission_mask'].rank self.request.session['permission_mask'] = form.cleaned_data['permission_mask'].rank
return super().form_valid(form) return super().form_valid(form)
@ -50,6 +53,7 @@ class UserUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
form_class = UserForm form_class = UserForm
template_name = 'member/profile_update.html' template_name = 'member/profile_update.html'
context_object_name = 'user_object' context_object_name = 'user_object'
extra_context = {"title": _("Update Profile")}
profile_form = ProfileForm profile_form = ProfileForm
@ -65,7 +69,6 @@ class UserUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
form.fields['email'].help_text = _("This address must be valid.") form.fields['email'].help_text = _("This address must be valid.")
context['profile_form'] = self.profile_form(instance=context['user_object'].profile) context['profile_form'] = self.profile_form(instance=context['user_object'].profile)
context['title'] = _("Update Profile")
return context return context
def form_valid(self, form): def form_valid(self, form):
@ -120,6 +123,7 @@ class UserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
model = User model = User
context_object_name = "user_object" context_object_name = "user_object"
template_name = "member/profile_detail.html" template_name = "member/profile_detail.html"
extra_context = {"title": _("Profile detail")}
def get_queryset(self, **kwargs): def get_queryset(self, **kwargs):
""" """
@ -153,6 +157,7 @@ class UserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
model = User model = User
table_class = UserTable table_class = UserTable
template_name = 'member/user_list.html' template_name = 'member/user_list.html'
extra_context = {"title": _("Search user")}
def get_queryset(self, **kwargs): def get_queryset(self, **kwargs):
""" """
@ -178,13 +183,6 @@ class UserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
return qs[:20] return qs[:20]
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = _("Search user")
return context
class ProfileAliasView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): class ProfileAliasView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
""" """
@ -193,6 +191,7 @@ class ProfileAliasView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
model = User model = User
template_name = 'member/profile_alias.html' template_name = 'member/profile_alias.html'
context_object_name = 'user_object' context_object_name = 'user_object'
extra_context = {"title": _("Note aliases")}
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -206,6 +205,7 @@ class PictureUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin, Det
Update profile picture of the user note. Update profile picture of the user note.
""" """
form_class = ImageForm form_class = ImageForm
extra_context = {"title": _("Update note picture")}
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -263,6 +263,7 @@ class ManageAuthTokens(LoginRequiredMixin, TemplateView):
""" """
model = Token model = Token
template_name = "member/manage_auth_tokens.html" template_name = "member/manage_auth_tokens.html"
extra_context = {"title": _("Manage auth token")}
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
if 'regenerate' in request.GET and Token.objects.filter(user=request.user).exists(): if 'regenerate' in request.GET and Token.objects.filter(user=request.user).exists():
@ -290,6 +291,7 @@ class ClubCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
model = Club model = Club
form_class = ClubForm form_class = ClubForm
success_url = reverse_lazy('member:club_list') success_url = reverse_lazy('member:club_list')
extra_context = {"title": _("Create new club")}
def form_valid(self, form): def form_valid(self, form):
return super().form_valid(form) return super().form_valid(form)
@ -301,6 +303,7 @@ class ClubListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
""" """
model = Club model = Club
table_class = ClubTable table_class = ClubTable
extra_context = {"title": _("Search club")}
def get_queryset(self, **kwargs): def get_queryset(self, **kwargs):
""" """
@ -325,6 +328,7 @@ class ClubDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
""" """
model = Club model = Club
context_object_name = "club" context_object_name = "club"
extra_context = {"title": _("Club detail")}
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -369,6 +373,7 @@ class ClubAliasView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
model = Club model = Club
template_name = 'member/club_alias.html' template_name = 'member/club_alias.html'
context_object_name = 'club' context_object_name = 'club'
extra_context = {"title": _("Note aliases")}
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -385,6 +390,7 @@ class ClubUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
context_object_name = "club" context_object_name = "club"
form_class = ClubForm form_class = ClubForm
template_name = "member/club_form.html" template_name = "member/club_form.html"
extra_context = {"title": _("Update club")}
def get_queryset(self, **kwargs): def get_queryset(self, **kwargs):
qs = super().get_queryset(**kwargs) qs = super().get_queryset(**kwargs)
@ -418,6 +424,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
model = Membership model = Membership
form_class = MembershipForm form_class = MembershipForm
template_name = 'member/add_members.html' template_name = 'member/add_members.html'
extra_context = {"title": _("Add new member to the club")}
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -428,7 +435,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
club = Club.objects.filter(PermissionBackend.filter_queryset(self.request.user, Club, "view"))\ club = Club.objects.filter(PermissionBackend.filter_queryset(self.request.user, Club, "view"))\
.get(pk=self.kwargs["club_pk"], weiclub=None) .get(pk=self.kwargs["club_pk"], weiclub=None)
form.fields['credit_amount'].initial = club.membership_fee_paid form.fields['credit_amount'].initial = club.membership_fee_paid
form.fields['roles'].queryset = Role.objects.filter(Q(weirole__isnull=not isinstance(club, WEIClub)) form.fields['roles'].queryset = Role.objects.filter(Q(weirole__isnull=not hasattr(club, 'weiclub'))
& (Q(for_club__isnull=True) | Q(for_club=club))).all() & (Q(for_club__isnull=True) | Q(for_club=club))).all()
form.fields['roles'].initial = Role.objects.filter(name="Membre de club").all() form.fields['roles'].initial = Role.objects.filter(name="Membre de club").all()
@ -449,7 +456,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
user = old_membership.user user = old_membership.user
form.fields['user'].initial = user form.fields['user'].initial = user
form.fields['user'].disabled = True form.fields['user'].disabled = True
form.fields['roles'].queryset = Role.objects.filter(Q(weirole__isnull=not isinstance(club, WEIClub)) form.fields['roles'].queryset = Role.objects.filter(Q(weirole__isnull=not hasattr(club, 'weiclub'))
& (Q(for_club__isnull=True) | Q(for_club=club))).all() & (Q(for_club__isnull=True) | Q(for_club=club))).all()
form.fields['roles'].initial = old_membership.roles.all() form.fields['roles'].initial = old_membership.roles.all()
form.fields['date_start'].initial = old_membership.date_end + timedelta(days=1) form.fields['date_start'].initial = old_membership.date_end + timedelta(days=1)
@ -624,6 +631,7 @@ class ClubManageRolesView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
model = Membership model = Membership
form_class = MembershipForm form_class = MembershipForm
template_name = 'member/add_members.html' template_name = 'member/add_members.html'
extra_context = {"title": _("Manage roles of an user in the club")}
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -643,10 +651,10 @@ class ClubManageRolesView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
del form.fields['bank'] del form.fields['bank']
club = self.object.club club = self.object.club
form.fields['roles'].queryset = Role.objects.filter(Q(weirole__isnull=not isinstance(club, WEIClub)) form.fields['roles'].queryset = Role.objects.filter(Q(weirole__isnull=not hasattr(club, 'weiclub'))
& (Q(for_club__isnull=True) | Q(for_club=club))).all() & (Q(for_club__isnull=True) | Q(for_club=club))).all()
return form return form
def get_success_url(self): def get_success_url(self):
return reverse_lazy('member:club_detail', kwargs={'pk': self.object.club.id}) return reverse_lazy('member:user_detail', kwargs={'pk': self.object.user.id})

View File

@ -5,7 +5,6 @@ from django.contrib import admin
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from polymorphic.admin import PolymorphicChildModelAdmin, \ from polymorphic.admin import PolymorphicChildModelAdmin, \
PolymorphicChildModelFilter, PolymorphicParentModelAdmin PolymorphicChildModelFilter, PolymorphicParentModelAdmin
from note_kfet.admin import admin_site from note_kfet.admin import admin_site
from .models.notes import Alias, Note, NoteClub, NoteSpecial, NoteUser from .models.notes import Alias, Note, NoteClub, NoteSpecial, NoteUser

View File

@ -119,7 +119,7 @@ class ConsumerSerializer(serializers.ModelSerializer):
# If the user has no right to see the note, then we only display the note identifier # If the user has no right to see the note, then we only display the note identifier
if PermissionBackend.check_perm(get_current_authenticated_user(), "note.view_note", obj.note): if PermissionBackend.check_perm(get_current_authenticated_user(), "note.view_note", obj.note):
return NotePolymorphicSerializer().to_representation(obj.note) return NotePolymorphicSerializer().to_representation(obj.note)
return dict(id=obj.note.id) return dict(id=obj.note.id, name=str(obj.note))
def get_email_confirmed(self, obj): def get_email_confirmed(self, obj):
if isinstance(obj.note, NoteUser): if isinstance(obj.note, NoteUser):

View File

@ -106,10 +106,8 @@ class ConsumerViewSet(ReadOnlyProtectedModelViewSet):
queryset = super().get_queryset() queryset = super().get_queryset()
alias = self.request.query_params.get("alias", ".*") alias = self.request.query_params.get("alias", ".*")
queryset = queryset.filter( queryset = queryset.filter(normalized_name__iregex="^" + Alias.normalize(alias))\
Q(name__regex="^" + alias) .order_by('name').prefetch_related('note')
| Q(normalized_name__regex="^" + Alias.normalize(alias))
| Q(normalized_name__regex="^" + alias.lower())).order_by('name')
return queryset return queryset

View File

@ -8,6 +8,8 @@ from django.db.models import F
from django.utils.html import format_html from django.utils.html import format_html
from django_tables2.utils import A from django_tables2.utils import A
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from note_kfet.middlewares import get_current_authenticated_user
from permission.backends import PermissionBackend
from .models.notes import Alias from .models.notes import Alias
from .models.transactions import Transaction, TransactionTemplate from .models.transactions import Transaction, TransactionTemplate
@ -52,14 +54,26 @@ class HistoryTable(tables.Table):
attrs={ attrs={
"td": { "td": {
"id": lambda record: "validate_" + str(record.id), "id": lambda record: "validate_" + str(record.id),
"class": lambda record: str(record.valid).lower() + ' validate', "class": lambda record:
str(record.valid).lower()
+ (' validate' if PermissionBackend.check_perm(get_current_authenticated_user(),
"note.change_transaction_invalidity_reason",
record) else ''),
"data-toggle": "tooltip", "data-toggle": "tooltip",
"title": lambda record: _("Click to invalidate") if record.valid else _("Click to validate"), "title": lambda record: (_("Click to invalidate") if record.valid else _("Click to validate"))
"onclick": lambda record: 'de_validate(' + str(record.id) + ', ' + str(record.valid).lower() + ')', if PermissionBackend.check_perm(get_current_authenticated_user(),
"note.change_transaction_invalidity_reason", record) else None,
"onclick": lambda record: 'de_validate(' + str(record.id) + ', ' + str(record.valid).lower() + ')'
if PermissionBackend.check_perm(get_current_authenticated_user(),
"note.change_transaction_invalidity_reason", record) else None,
"onmouseover": lambda record: '$("#invalidity_reason_' "onmouseover": lambda record: '$("#invalidity_reason_'
+ str(record.id) + '").show();$("#invalidity_reason_' + str(record.id) + '").show();$("#invalidity_reason_'
+ str(record.id) + '").focus();', + str(record.id) + '").focus();'
"onmouseout": lambda record: '$("#invalidity_reason_' + str(record.id) + '").hide()', if PermissionBackend.check_perm(get_current_authenticated_user(),
"note.change_transaction_invalidity_reason", record) else None,
"onmouseout": lambda record: '$("#invalidity_reason_' + str(record.id) + '").hide()'
if PermissionBackend.check_perm(get_current_authenticated_user(),
"note.change_transaction_invalidity_reason", record) else None,
} }
} }
) )
@ -88,6 +102,10 @@ class HistoryTable(tables.Table):
When the validation status is hovered, an input field is displayed to let the user specify an invalidity reason When the validation status is hovered, an input field is displayed to let the user specify an invalidity reason
""" """
val = "" if value else "" val = "" if value else ""
if not PermissionBackend\
.check_perm(get_current_authenticated_user(), "note.change_transaction_invalidity_reason", record):
return val
val += "<input type='text' class='form-control' id='invalidity_reason_" + str(record.id) \ val += "<input type='text' class='form-control' id='invalidity_reason_" + str(record.id) \
+ "' value='" + (html.escape(record.invalidity_reason) + "' value='" + (html.escape(record.invalidity_reason)
if record.invalidity_reason else ("" if value else str(_("No reason specified")))) \ if record.invalidity_reason else ("" if value else str(_("No reason specified")))) \
@ -131,12 +149,10 @@ class ButtonTable(tables.Table):
row_attrs = { row_attrs = {
'class': lambda record: 'table-row ' + ('table-success' if record.display else 'table-danger'), 'class': lambda record: 'table-row ' + ('table-success' if record.display else 'table-danger'),
'id': lambda record: "row-" + str(record.pk), 'id': lambda record: "row-" + str(record.pk),
'data-href': lambda record: record.pk
} }
model = TransactionTemplate model = TransactionTemplate
exclude = ('id',) exclude = ('id',)
order_by = ('type', '-display', 'destination__name', 'name',)
edit = tables.LinkColumn('note:template_update', edit = tables.LinkColumn('note:template_update',
args=[A('pk')], args=[A('pk')],

View File

@ -5,6 +5,7 @@ import json
from django.conf import settings from django.conf import settings
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.db.models import Q
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.views.generic import CreateView, UpdateView from django.views.generic import CreateView, UpdateView
from django_tables2 import SingleTableView from django_tables2 import SingleTableView
@ -29,6 +30,7 @@ class TransactionCreateView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTabl
model = Transaction model = Transaction
# Transaction history table # Transaction history table
table_class = HistoryTable table_class = HistoryTable
extra_context = {"title": _("Transfer money")}
def get_queryset(self, **kwargs): def get_queryset(self, **kwargs):
return super().get_queryset(**kwargs).order_by("-created_at").all()[:20] return super().get_queryset(**kwargs).order_by("-created_at").all()[:20]
@ -38,7 +40,6 @@ class TransactionCreateView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTabl
Add some context variables in template such as page title Add some context variables in template such as page title
""" """
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['title'] = _('Transfer money')
context['amount_widget'] = AmountInput(attrs={"id": "amount"}) context['amount_widget'] = AmountInput(attrs={"id": "amount"})
context['polymorphic_ctype'] = ContentType.objects.get_for_model(Transaction).pk context['polymorphic_ctype'] = ContentType.objects.get_for_model(Transaction).pk
context['special_polymorphic_ctype'] = ContentType.objects.get_for_model(SpecialTransaction).pk context['special_polymorphic_ctype'] = ContentType.objects.get_for_model(SpecialTransaction).pk
@ -63,6 +64,7 @@ class TransactionTemplateCreateView(ProtectQuerysetMixin, LoginRequiredMixin, Cr
model = TransactionTemplate model = TransactionTemplate
form_class = TransactionTemplateForm form_class = TransactionTemplateForm
success_url = reverse_lazy('note:template_list') success_url = reverse_lazy('note:template_list')
extra_context = {"title": _("Create new button")}
class TransactionTemplateListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView): class TransactionTemplateListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
@ -71,6 +73,20 @@ class TransactionTemplateListView(ProtectQuerysetMixin, LoginRequiredMixin, Sing
""" """
model = TransactionTemplate model = TransactionTemplate
table_class = ButtonTable table_class = ButtonTable
extra_context = {"title": _("Search button")}
def get_queryset(self, **kwargs):
"""
Filter the user list with the given pattern.
"""
qs = super().get_queryset().distinct()
if "search" in self.request.GET:
pattern = self.request.GET["search"]
qs = qs.filter(Q(name__iregex="^" + pattern) | Q(destination__club__name__iregex="^" + pattern))
qs = qs.order_by('-display', 'category__name', 'destination__club__name', 'name')
return qs
class TransactionTemplateUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): class TransactionTemplateUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
@ -80,6 +96,7 @@ class TransactionTemplateUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, Up
model = TransactionTemplate model = TransactionTemplate
form_class = TransactionTemplateForm form_class = TransactionTemplateForm
success_url = reverse_lazy('note:template_list') success_url = reverse_lazy('note:template_list')
extra_context = {"title": _("Update button")}
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -116,6 +133,7 @@ class ConsoView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
""" """
model = Transaction model = Transaction
template_name = "note/conso_form.html" template_name = "note/conso_form.html"
extra_context = {"title": _("Consumptions")}
# Transaction history table # Transaction history table
table_class = HistoryTable table_class = HistoryTable
@ -137,7 +155,6 @@ class ConsoView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
context['highlighted'] = TransactionTemplate.objects.filter(highlighted=True).filter( context['highlighted'] = TransactionTemplate.objects.filter(highlighted=True).filter(
PermissionBackend().filter_queryset(self.request.user, TransactionTemplate, "view") PermissionBackend().filter_queryset(self.request.user, TransactionTemplate, "view")
).order_by('name').all() ).order_by('name').all()
context['title'] = _("Consumptions")
context['polymorphic_ctype'] = ContentType.objects.get_for_model(RecurrentTransaction).pk context['polymorphic_ctype'] = ContentType.objects.get_for_model(RecurrentTransaction).pk
# select2 compatibility # select2 compatibility

View File

@ -2,8 +2,8 @@
# SPDX-License-Identifier: GPL-3.0-or-lateré # SPDX-License-Identifier: GPL-3.0-or-lateré
from django.contrib import admin from django.contrib import admin
from note_kfet.admin import admin_site from note_kfet.admin import admin_site
from .models import Permission, PermissionMask, Role from .models import Permission, PermissionMask, Role

View File

@ -1,7 +1,6 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
from django.conf import settings
from django.contrib.auth.backends import ModelBackend from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User, AnonymousUser from django.contrib.auth.models import User, AnonymousUser
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
@ -37,7 +36,7 @@ class PermissionBackend(ModelBackend):
return Permission.objects.none() return Permission.objects.none()
memberships = Membership.objects.filter(user=user).all() memberships = Membership.objects.filter(user=user).all()
perms = [] perms = []
for membership in memberships: for membership in memberships:
@ -50,7 +49,6 @@ class PermissionBackend(ModelBackend):
perms.append(perm) perms.append(perm)
return perms return perms
@staticmethod @staticmethod
def permissions(user, model, type): def permissions(user, model, type):
""" """
@ -137,7 +135,7 @@ class PermissionBackend(ModelBackend):
if sess is not None and sess.session_key is None: if sess is not None and sess.session_key is None:
return False return False
if user_obj.is_superuser and get_current_session().get("permission_mask", -1) >= 42: if user_obj.is_superuser and sess.get("permission_mask", -1) >= 42:
return True return True
if obj is None: if obj is None:

View File

@ -4,6 +4,7 @@
from functools import lru_cache from functools import lru_cache
from time import time from time import time
from django.conf import settings
from django.contrib.sessions.models import Session from django.contrib.sessions.models import Session
from note_kfet.middlewares import get_current_session from note_kfet.middlewares import get_current_session
@ -32,6 +33,10 @@ def memoize(f):
sess_funs = new_sess_funs sess_funs = new_sess_funs
def func(*args, **kwargs): def func(*args, **kwargs):
if settings.DEBUG:
# Don't memoize in DEBUG mode
return f(*args, **kwargs)
nonlocal last_collect nonlocal last_collect
if time() - last_collect > 60: if time() - last_collect > 60:

View File

@ -111,7 +111,7 @@
"note", "note",
"alias" "alias"
], ],
"query": "[\"AND\", [\"OR\", {\"note__in\": [\"NoteUser\", \"objects\", [\"filter\", {\"user__memberships__club__name\": \"Kfet\"}], [\"all\"]]}, {\"note__in\": [\"NoteClub\", \"objects\", [\"all\"]]}], {\"note__is_active\": true}]", "query": "[\"AND\", [\"OR\", {\"note__noteuser__user__memberships__club__name\": \"Kfet\", \"note__noteuser__user__memberships__date_start__lte\": [\"today\"], \"note__noteuser__user__memberships__date_end__gte\": [\"today\"]}, {\"note__noteclub__isnull\": false}], {\"note__is_active\": true}]",
"type": "view", "type": "view",
"mask": 1, "mask": 1,
"field": "", "field": "",
@ -319,7 +319,7 @@
"note", "note",
"note" "note"
], ],
"query": "[\"OR\", {\"pk\": [\"club\", \"note\", \"pk\"]}, {\"pk__in\": [\"NoteUser\", \"objects\", [\"filter\", {\"user__memberships__club\": [\"club\"]}], [\"all\"]]}]", "query": "[\"OR\", {\"pk\": [\"club\", \"note\", \"pk\"]}, {\"noteuser__user__memberships__club\": [\"club\"], \"noteuser__user__memberships__date_start__lte\": [\"today\"], \"noteuser__user__memberships__date_end__gte\": [\"today\"]}]",
"type": "view", "type": "view",
"mask": 2, "mask": 2,
"field": "", "field": "",
@ -801,7 +801,7 @@
], ],
"query": "{\"club\": [\"club\"]}", "query": "{\"club\": [\"club\"]}",
"type": "view", "type": "view",
"mask": 1, "mask": 3,
"field": "", "field": "",
"permanent": false, "permanent": false,
"description": "View club's memberships" "description": "View club's memberships"
@ -833,7 +833,7 @@
], ],
"query": "{\"club\": [\"club\"]}", "query": "{\"club\": [\"club\"]}",
"type": "change", "type": "change",
"mask": 2, "mask": 3,
"field": "roles", "field": "roles",
"permanent": false, "permanent": false,
"description": "Update user roles" "description": "Update user roles"
@ -2234,6 +2234,22 @@
{ {
"model": "permission.permission", "model": "permission.permission",
"pk": 139, "pk": 139,
"fields": {
"model": [
"note",
"noteclub"
],
"query": "{}",
"type": "add",
"mask": 3,
"field": "",
"permanent": false,
"description": "Create any noteclub"
}
},
{
"model": "permission.permission",
"pk": 140,
"fields": { "fields": {
"model": [ "model": [
"member", "member",
@ -2247,6 +2263,38 @@
"description": "Create any club" "description": "Create any club"
} }
}, },
{
"model": "permission.permission",
"pk": 141,
"fields": {
"model": [
"auth",
"user"
],
"query": "{\"memberships__club\": [\"club\"], \"memberships__date__start__lte\": [\"today\"], \"memberships__date__end__gte\": [\"today\"]}",
"type": "view",
"mask": 3,
"field": "",
"permanent": false,
"description": "View members of our club"
}
},
{
"model": "permission.permission",
"pk": 142,
"fields": {
"model": [
"note",
"noteclub"
],
"query": "{\"club\": [\"club\"]}",
"type": "view",
"mask": 2,
"field": "",
"permanent": false,
"description": "View club note"
}
},
{ {
"model": "permission.role", "model": "permission.role",
"pk": 1, "pk": 1,
@ -2323,7 +2371,8 @@
"permissions": [ "permissions": [
22, 22,
47, 47,
49 49,
140
] ]
} }
}, },
@ -2335,8 +2384,9 @@
"name": "Pr\u00e9sident\u00b7e de club", "name": "Pr\u00e9sident\u00b7e de club",
"permissions": [ "permissions": [
50, 50,
51, 62,
62 141,
142
] ]
} }
}, },
@ -2356,7 +2406,9 @@
61, 61,
62, 62,
127, 127,
133 133,
141,
142
] ]
} }
}, },
@ -2564,7 +2616,10 @@
136, 136,
137, 137,
138, 138,
139 139,
140,
141,
142
] ]
} }
}, },

View File

@ -44,7 +44,9 @@ class InstancedPermission:
else: else:
oldpk = obj.pk oldpk = obj.pk
# Ensure previous models are deleted # Ensure previous models are deleted
self.model.model_class().objects.filter(pk=obj.pk).annotate(_force_delete=F("pk")).delete() for o in self.model.model_class().objects.filter(pk=obj.pk).all():
o._force_delete = True
Model.delete(o)
# Force insertion, no data verification, no trigger # Force insertion, no data verification, no trigger
obj._force_save = True obj._force_save = True
Model.save(obj, force_insert=True) Model.save(obj, force_insert=True)

View File

@ -50,6 +50,7 @@ def pre_save_object(sender, instance, **kwargs):
# In the other case, we check if he/she has the right to change one field # In the other case, we check if he/she has the right to change one field
previous = qs.get() previous = qs.get()
for field in instance._meta.fields: for field in instance._meta.fields:
field_name = field.name field_name = field.name
old_value = getattr(previous, field.name) old_value = getattr(previous, field.name)
@ -81,7 +82,8 @@ def pre_delete_object(instance, **kwargs):
if instance._meta.label_lower in EXCLUDED: if instance._meta.label_lower in EXCLUDED:
return return
if hasattr(instance, "_force_delete"): if hasattr(instance, "_force_delete") or hasattr(instance, "pk") and instance.pk == 0:
# Don't check permissions on force-deleted objects
return return
user = get_current_authenticated_user() user = get_current_authenticated_user()

View File

@ -41,6 +41,7 @@ class ProtectQuerysetMixin:
class RightsView(TemplateView): class RightsView(TemplateView):
template_name = "permission/all_rights.html" template_name = "permission/all_rights.html"
extra_context = {"title": _("Rights")}
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)

View File

@ -35,6 +35,7 @@ class UserCreateView(CreateView):
form_class = SignUpForm form_class = SignUpForm
template_name = 'registration/signup.html' template_name = 'registration/signup.html'
second_form = ProfileForm second_form = ProfileForm
extra_context = {"title": _("Register new user")}
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -78,6 +79,7 @@ class UserValidateView(TemplateView):
""" """
title = _("Email validation") title = _("Email validation")
template_name = 'registration/email_validation_complete.html' template_name = 'registration/email_validation_complete.html'
extra_context = {"title": _("Validate a registration")}
def get(self, *args, **kwargs): def get(self, *args, **kwargs):
""" """
@ -133,7 +135,7 @@ class UserValidationEmailSentView(TemplateView):
Display the information that the validation link has been sent. Display the information that the validation link has been sent.
""" """
template_name = 'registration/email_validation_email_sent.html' template_name = 'registration/email_validation_email_sent.html'
title = _('Email validation email sent') extra_context = {"title": _('Email validation email sent')}
class UserResendValidationEmailView(LoginRequiredMixin, ProtectQuerysetMixin, DetailView): class UserResendValidationEmailView(LoginRequiredMixin, ProtectQuerysetMixin, DetailView):
@ -141,6 +143,7 @@ class UserResendValidationEmailView(LoginRequiredMixin, ProtectQuerysetMixin, De
Rensend the email validation link. Rensend the email validation link.
""" """
model = User model = User
extra_context = {"title": _("Resend email validation link")}
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
user = self.get_object() user = self.get_object()
@ -158,6 +161,7 @@ class FutureUserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableVi
model = User model = User
table_class = FutureUserTable table_class = FutureUserTable
template_name = 'registration/future_user_list.html' template_name = 'registration/future_user_list.html'
extra_context = {"title": _("Pre-registered users list")}
def get_queryset(self, **kwargs): def get_queryset(self, **kwargs):
""" """
@ -199,6 +203,7 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin,
form_class = ValidationForm form_class = ValidationForm
context_object_name = "user_object" context_object_name = "user_object"
template_name = "registration/future_profile_detail.html" template_name = "registration/future_profile_detail.html"
extra_context = {"title": _("Registration detail")}
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
form = self.get_form() form = self.get_form()
@ -355,6 +360,7 @@ class FutureUserInvalidateView(ProtectQuerysetMixin, LoginRequiredMixin, View):
""" """
Delete a pre-registered user. Delete a pre-registered user.
""" """
extra_context = {"title": _("Invalidate pre-registration")}
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
""" """

View File

@ -2,8 +2,8 @@
# SPDX-License-Identifier: GPL-3.0-or-lateré # SPDX-License-Identifier: GPL-3.0-or-lateré
from django.contrib import admin from django.contrib import admin
from note_kfet.admin import admin_site from note_kfet.admin import admin_site
from .models import RemittanceType, Remittance, SogeCredit from .models import RemittanceType, Remittance, SogeCredit

View File

@ -15,6 +15,7 @@ from django.http import HttpResponse
from django.shortcuts import redirect from django.shortcuts import redirect
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.utils.translation import gettext_lazy as _
from django.views.generic import CreateView, UpdateView, DetailView from django.views.generic import CreateView, UpdateView, DetailView
from django.views.generic.base import View, TemplateView from django.views.generic.base import View, TemplateView
from django.views.generic.edit import BaseFormView from django.views.generic.edit import BaseFormView
@ -35,6 +36,7 @@ class InvoiceCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
""" """
model = Invoice model = Invoice
form_class = InvoiceForm form_class = InvoiceForm
extra_context = {"title": _("Create new invoice")}
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -77,6 +79,7 @@ class InvoiceListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView)
""" """
model = Invoice model = Invoice
table_class = InvoiceTable table_class = InvoiceTable
extra_context = {"title": _("Invoices list")}
class InvoiceUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): class InvoiceUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
@ -85,6 +88,7 @@ class InvoiceUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
""" """
model = Invoice model = Invoice
form_class = InvoiceForm form_class = InvoiceForm
extra_context = {"title": _("Update an invoice")}
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -167,7 +171,7 @@ class InvoiceRenderView(LoginRequiredMixin, View):
del tex del tex
# The file has to be rendered twice # The file has to be rendered twice
for _ in range(2): for ignored in range(2):
error = subprocess.Popen( error = subprocess.Popen(
["pdflatex", "invoice-{}.tex".format(pk)], ["pdflatex", "invoice-{}.tex".format(pk)],
cwd=tmp_dir, cwd=tmp_dir,
@ -198,6 +202,7 @@ class RemittanceCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView)
""" """
model = Remittance model = Remittance
form_class = RemittanceForm form_class = RemittanceForm
extra_context = {"title": _("Create a new remittance")}
def get_success_url(self): def get_success_url(self):
return reverse_lazy('treasury:remittance_list') return reverse_lazy('treasury:remittance_list')
@ -218,6 +223,7 @@ class RemittanceListView(LoginRequiredMixin, TemplateView):
List existing Remittances List existing Remittances
""" """
template_name = "treasury/remittance_list.html" template_name = "treasury/remittance_list.html"
extra_context = {"title": _("Remittances list")}
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -267,6 +273,7 @@ class RemittanceUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView)
""" """
model = Remittance model = Remittance
form_class = RemittanceForm form_class = RemittanceForm
extra_context = {"title": _("Update a remittance")}
def get_success_url(self): def get_success_url(self):
return reverse_lazy('treasury:remittance_list') return reverse_lazy('treasury:remittance_list')
@ -289,9 +296,9 @@ class LinkTransactionToRemittanceView(ProtectQuerysetMixin, LoginRequiredMixin,
""" """
Attach a special transaction to a remittance Attach a special transaction to a remittance
""" """
model = SpecialTransactionProxy model = SpecialTransactionProxy
form_class = LinkTransactionToRemittanceForm form_class = LinkTransactionToRemittanceForm
extra_context = {"title": _("Attach a transaction to a remittance")}
def get_success_url(self): def get_success_url(self):
return reverse_lazy('treasury:remittance_list') return reverse_lazy('treasury:remittance_list')
@ -335,6 +342,7 @@ class SogeCreditListView(LoginRequiredMixin, ProtectQuerysetMixin, SingleTableVi
""" """
model = SogeCredit model = SogeCredit
table_class = SogeCreditTable table_class = SogeCreditTable
extra_context = {"title": _("List of credits from the Société générale")}
def get_queryset(self, **kwargs): def get_queryset(self, **kwargs):
""" """
@ -373,6 +381,7 @@ class SogeCreditManageView(LoginRequiredMixin, ProtectQuerysetMixin, BaseFormVie
""" """
model = SogeCredit model = SogeCredit
form_class = Form form_class = Form
extra_context = {"title": _("Manage credits from the Société générale")}
def form_valid(self, form): def form_valid(self, form):
if "validate" in form.data: if "validate" in form.data:

View File

@ -2,6 +2,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
from note_kfet.admin import admin_site from note_kfet.admin import admin_site
from .models import WEIClub, WEIRegistration, WEIMembership, WEIRole, Bus, BusTeam from .models import WEIClub, WEIRegistration, WEIMembership, WEIRole, Bus, BusTeam
admin_site.register(WEIClub) admin_site.register(WEIClub)

View File

@ -202,7 +202,7 @@ class WEIRegistration(models.Model):
clothing_size = models.CharField( clothing_size = models.CharField(
max_length=4, max_length=4,
choices=( choices=(
('XS',"XS"), ('XS', "XS"),
('S', "S"), ('S', "S"),
('M', "M"), ('M', "M"),
('L', "L"), ('L', "L"),

View File

@ -52,6 +52,7 @@ class WEIListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
model = WEIClub model = WEIClub
table_class = WEITable table_class = WEITable
ordering = '-year' ordering = '-year'
extra_context = {"title": _("Search WEI")}
class WEICreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): class WEICreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
@ -60,6 +61,7 @@ class WEICreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
""" """
model = WEIClub model = WEIClub
form_class = WEIForm form_class = WEIForm
extra_context = {"title": _("Create WEI")}
def form_valid(self, form): def form_valid(self, form):
form.instance.requires_membership = True form.instance.requires_membership = True
@ -79,6 +81,7 @@ class WEIDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
""" """
model = WEIClub model = WEIClub
context_object_name = "club" context_object_name = "club"
extra_context = {"title": _("WEI Detail")}
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -173,6 +176,7 @@ class WEIMembershipsView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableVi
""" """
model = WEIMembership model = WEIMembership
table_class = WEIMembershipTable table_class = WEIMembershipTable
extra_context = {"title": _("View members of the WEI")}
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
self.club = WEIClub.objects.get(pk=self.kwargs["pk"]) self.club = WEIClub.objects.get(pk=self.kwargs["pk"])
@ -210,6 +214,7 @@ class WEIRegistrationsView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTable
""" """
model = WEIRegistration model = WEIRegistration
table_class = WEIRegistrationTable table_class = WEIRegistrationTable
extra_context = {"title": _("View registrations to the WEI")}
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
self.club = WEIClub.objects.get(pk=self.kwargs["pk"]) self.club = WEIClub.objects.get(pk=self.kwargs["pk"])
@ -246,6 +251,7 @@ class WEIUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
model = WEIClub model = WEIClub
context_object_name = "club" context_object_name = "club"
form_class = WEIForm form_class = WEIForm
extra_context = {"title": _("Update the WEI")}
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
wei = self.get_object() wei = self.get_object()
@ -266,6 +272,7 @@ class BusCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
""" """
model = Bus model = Bus
form_class = BusForm form_class = BusForm
extra_context = {"title": _("Create new bus")}
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
wei = WEIClub.objects.get(pk=self.kwargs["pk"]) wei = WEIClub.objects.get(pk=self.kwargs["pk"])
@ -296,6 +303,7 @@ class BusUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
""" """
model = Bus model = Bus
form_class = BusForm form_class = BusForm
extra_context = {"title": _("Update bus")}
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
wei = self.get_object().wei wei = self.get_object().wei
@ -325,6 +333,7 @@ class BusManageView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
Manage Bus Manage Bus
""" """
model = Bus model = Bus
extra_context = {"title": _("Manage bus")}
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -351,6 +360,7 @@ class BusTeamCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
""" """
model = BusTeam model = BusTeam
form_class = BusTeamForm form_class = BusTeamForm
extra_context = {"title": _("Create new team")}
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
wei = WEIClub.objects.get(buses__pk=self.kwargs["pk"]) wei = WEIClub.objects.get(buses__pk=self.kwargs["pk"])
@ -382,6 +392,7 @@ class BusTeamUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
""" """
model = BusTeam model = BusTeam
form_class = BusTeamForm form_class = BusTeamForm
extra_context = {"title": _("Update team")}
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
wei = self.get_object().bus.wei wei = self.get_object().bus.wei
@ -412,6 +423,7 @@ class BusTeamManageView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
Manage Bus team Manage Bus team
""" """
model = BusTeam model = BusTeam
extra_context = {"title": _("Manage WEI team")}
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -433,6 +445,7 @@ class WEIRegister1AView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
""" """
model = WEIRegistration model = WEIRegistration
form_class = WEIRegistrationForm form_class = WEIRegistrationForm
extra_context = {"title": _("Register first year student to the WEI")}
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
wei = WEIClub.objects.get(pk=self.kwargs["wei_pk"]) wei = WEIClub.objects.get(pk=self.kwargs["wei_pk"])
@ -487,6 +500,7 @@ class WEIRegister2AView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
""" """
model = WEIRegistration model = WEIRegistration
form_class = WEIRegistrationForm form_class = WEIRegistrationForm
extra_context = {"title": _("Register old student to the WEI")}
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
wei = WEIClub.objects.get(pk=self.kwargs["wei_pk"]) wei = WEIClub.objects.get(pk=self.kwargs["wei_pk"])
@ -564,6 +578,7 @@ class WEIUpdateRegistrationView(ProtectQuerysetMixin, LoginRequiredMixin, Update
""" """
model = WEIRegistration model = WEIRegistration
form_class = WEIRegistrationForm form_class = WEIRegistrationForm
extra_context = {"title": _("Update WEI Registration")}
def get_queryset(self, **kwargs): def get_queryset(self, **kwargs):
return WEIRegistration.objects return WEIRegistration.objects
@ -653,6 +668,7 @@ class WEIDeleteRegistrationView(ProtectQuerysetMixin, LoginRequiredMixin, Delete
Delete a non-validated WEI registration Delete a non-validated WEI registration
""" """
model = WEIRegistration model = WEIRegistration
extra_context = {"title": _("Delete WEI registration")}
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
object = self.get_object() object = self.get_object()
@ -682,6 +698,7 @@ class WEIValidateRegistrationView(ProtectQuerysetMixin, LoginRequiredMixin, Crea
""" """
model = WEIMembership model = WEIMembership
form_class = WEIMembershipForm form_class = WEIMembershipForm
extra_context = {"title": _("Validate WEI registration")}
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
wei = WEIRegistration.objects.get(pk=self.kwargs["pk"]).wei wei = WEIRegistration.objects.get(pk=self.kwargs["pk"]).wei
@ -799,6 +816,7 @@ class WEISurveyView(LoginRequiredMixin, BaseFormView, DetailView):
model = WEIRegistration model = WEIRegistration
template_name = "wei/survey.html" template_name = "wei/survey.html"
survey = None survey = None
extra_context = {"title": _("Survey WEI")}
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
obj = self.get_object() obj = self.get_object()
@ -836,7 +854,6 @@ class WEISurveyView(LoginRequiredMixin, BaseFormView, DetailView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context["club"] = self.object.wei context["club"] = self.object.wei
context["title"] = _("Survey WEI")
return context return context
def form_valid(self, form): def form_valid(self, form):
@ -852,21 +869,21 @@ class WEISurveyView(LoginRequiredMixin, BaseFormView, DetailView):
class WEISurveyEndView(LoginRequiredMixin, TemplateView): class WEISurveyEndView(LoginRequiredMixin, TemplateView):
template_name = "wei/survey_end.html" template_name = "wei/survey_end.html"
extra_context = {"title": _("Survey WEI")}
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context["club"] = WEIRegistration.objects.get(pk=self.kwargs["pk"]).wei context["club"] = WEIRegistration.objects.get(pk=self.kwargs["pk"]).wei
context["title"] = _("Survey WEI")
return context return context
class WEIClosedView(LoginRequiredMixin, TemplateView): class WEIClosedView(LoginRequiredMixin, TemplateView):
template_name = "wei/survey_closed.html" template_name = "wei/survey_closed.html"
extra_context = {"title": _("Survey WEI")}
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context["club"] = WEIClub.objects.get(pk=self.kwargs["pk"]) context["club"] = WEIClub.objects.get(pk=self.kwargs["pk"])
context["title"] = _("Survey WEI")
return context return context

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-07-29 22:54+0200\n" "POT-Creation-Date: 2020-07-30 17:22+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -46,7 +46,7 @@ msgstr ""
#: apps/activity/models.py:23 apps/activity/models.py:48 #: apps/activity/models.py:23 apps/activity/models.py:48
#: apps/member/models.py:151 apps/note/models/notes.py:188 #: apps/member/models.py:151 apps/note/models/notes.py:188
#: apps/note/models/transactions.py:25 apps/note/models/transactions.py:45 #: apps/note/models/transactions.py:25 apps/note/models/transactions.py:45
#: apps/note/models/transactions.py:261 apps/permission/models.py:321 #: apps/note/models/transactions.py:261 apps/permission/models.py:323
#: apps/wei/models.py:65 apps/wei/models.py:117 #: apps/wei/models.py:65 apps/wei/models.py:117
#: templates/member/club_info.html:13 templates/member/profile_info.html:14 #: templates/member/club_info.html:13 templates/member/profile_info.html:14
#: templates/registration/future_profile_detail.html:16 #: templates/registration/future_profile_detail.html:16
@ -71,14 +71,14 @@ msgid "activity types"
msgstr "" msgstr ""
#: apps/activity/models.py:53 apps/note/models/transactions.py:81 #: apps/activity/models.py:53 apps/note/models/transactions.py:81
#: apps/permission/models.py:102 apps/permission/models.py:181 #: apps/permission/models.py:104 apps/permission/models.py:183
#: apps/wei/models.py:71 apps/wei/models.py:128 #: apps/wei/models.py:71 apps/wei/models.py:128
#: templates/activity/activity_detail.html:16 #: templates/activity/activity_detail.html:16
msgid "description" msgid "description"
msgstr "" msgstr ""
#: apps/activity/models.py:60 apps/note/models/notes.py:164 #: apps/activity/models.py:60 apps/note/models/notes.py:164
#: apps/note/models/transactions.py:66 apps/permission/models.py:156 #: apps/note/models/transactions.py:66 apps/permission/models.py:158
#: templates/activity/activity_detail.html:19 #: templates/activity/activity_detail.html:19
msgid "type" msgid "type"
msgstr "" msgstr ""
@ -186,12 +186,12 @@ msgstr ""
msgid "Type" msgid "Type"
msgstr "" msgstr ""
#: apps/activity/tables.py:77 apps/member/forms.py:105 #: apps/activity/tables.py:77 apps/member/forms.py:104
#: apps/registration/forms.py:64 apps/treasury/forms.py:120 #: apps/registration/forms.py:64 apps/treasury/forms.py:120
msgid "Last name" msgid "Last name"
msgstr "" msgstr ""
#: apps/activity/tables.py:79 apps/member/forms.py:110 #: apps/activity/tables.py:79 apps/member/forms.py:109
#: apps/registration/forms.py:69 apps/treasury/forms.py:122 #: apps/registration/forms.py:69 apps/treasury/forms.py:122
#: templates/note/transaction_form.html:126 #: templates/note/transaction_form.html:126
msgid "First name" msgid "First name"
@ -205,11 +205,27 @@ msgstr ""
msgid "Balance" msgid "Balance"
msgstr "" msgstr ""
#: apps/activity/views.py:47 templates/base.html:121 #: apps/activity/views.py:26
msgid "Create new activity"
msgstr ""
#: apps/activity/views.py:41 templates/base.html:121
msgid "Activities" msgid "Activities"
msgstr "" msgstr ""
#: apps/activity/views.py:163 #: apps/activity/views.py:61
msgid "Activity detail"
msgstr ""
#: apps/activity/views.py:78
msgid "Update activity"
msgstr ""
#: apps/activity/views.py:92
msgid "Invite guest to the activity \"{}\""
msgstr ""
#: apps/activity/views.py:171
msgid "Entry for activity \"{}\"" msgid "Entry for activity \"{}\""
msgstr "" msgstr ""
@ -225,7 +241,7 @@ msgstr ""
msgid "IP Address" msgid "IP Address"
msgstr "" msgstr ""
#: apps/logs/models.py:35 apps/permission/models.py:126 #: apps/logs/models.py:35 apps/permission/models.py:128
msgid "model" msgid "model"
msgstr "" msgstr ""
@ -245,12 +261,12 @@ msgstr ""
msgid "create" msgid "create"
msgstr "" msgstr ""
#: apps/logs/models.py:61 apps/note/tables.py:145 #: apps/logs/models.py:61 apps/note/tables.py:143
#: templates/activity/activity_detail.html:67 #: templates/activity/activity_detail.html:67
msgid "edit" msgid "edit"
msgstr "" msgstr ""
#: apps/logs/models.py:62 apps/note/tables.py:120 apps/note/tables.py:150 #: apps/logs/models.py:62 apps/note/tables.py:120 apps/note/tables.py:148
#: apps/wei/tables.py:65 #: apps/wei/tables.py:65
msgid "delete" msgid "delete"
msgstr "" msgstr ""
@ -279,35 +295,35 @@ msgstr ""
msgid "member" msgid "member"
msgstr "" msgstr ""
#: apps/member/forms.py:59 apps/member/views.py:78 #: apps/member/forms.py:58 apps/member/views.py:81
msgid "An alias with a similar name already exists." msgid "An alias with a similar name already exists."
msgstr "" msgstr ""
#: apps/member/forms.py:84 apps/registration/forms.py:44 #: apps/member/forms.py:83 apps/registration/forms.py:44
msgid "Inscription paid by Société Générale" msgid "Inscription paid by Société Générale"
msgstr "" msgstr ""
#: apps/member/forms.py:86 apps/registration/forms.py:46 #: apps/member/forms.py:85 apps/registration/forms.py:46
msgid "Check this case is the Société Générale paid the inscription." msgid "Check this case is the Société Générale paid the inscription."
msgstr "" msgstr ""
#: apps/member/forms.py:91 apps/registration/forms.py:51 #: apps/member/forms.py:90 apps/registration/forms.py:51
msgid "Credit type" msgid "Credit type"
msgstr "" msgstr ""
#: apps/member/forms.py:92 apps/registration/forms.py:52 #: apps/member/forms.py:91 apps/registration/forms.py:52
msgid "No credit" msgid "No credit"
msgstr "" msgstr ""
#: apps/member/forms.py:94 #: apps/member/forms.py:93
msgid "You can credit the note of the user." msgid "You can credit the note of the user."
msgstr "" msgstr ""
#: apps/member/forms.py:98 apps/registration/forms.py:57 #: apps/member/forms.py:97 apps/registration/forms.py:57
msgid "Credit amount" msgid "Credit amount"
msgstr "" msgstr ""
#: apps/member/forms.py:115 apps/registration/forms.py:74 #: apps/member/forms.py:114 apps/registration/forms.py:74
#: apps/treasury/forms.py:124 templates/note/transaction_form.html:132 #: apps/treasury/forms.py:124 templates/note/transaction_form.html:132
msgid "Bank" msgid "Bank"
msgstr "" msgstr ""
@ -509,7 +525,7 @@ msgstr ""
msgid "fee" msgid "fee"
msgstr "" msgstr ""
#: apps/member/models.py:303 apps/member/views.py:528 apps/wei/views.py:770 #: apps/member/models.py:303 apps/member/views.py:535 apps/wei/views.py:787
msgid "User is not a member of the parent club" msgid "User is not a member of the parent club"
msgstr "" msgstr ""
@ -518,7 +534,7 @@ msgstr ""
msgid "The role {role} does not apply to the club {club}." msgid "The role {role} does not apply to the club {club}."
msgstr "" msgstr ""
#: apps/member/models.py:321 apps/member/views.py:537 #: apps/member/models.py:321 apps/member/views.py:544
msgid "User is already a member of the club" msgid "User is already a member of the club"
msgstr "" msgstr ""
@ -539,45 +555,85 @@ msgstr ""
msgid "Renew" msgid "Renew"
msgstr "" msgstr ""
#: apps/member/views.py:65 apps/registration/forms.py:23 #: apps/member/views.py:56 templates/member/profile_info.html:47
msgid "This address must be valid."
msgstr ""
#: apps/member/views.py:68 templates/member/profile_info.html:47
#: templates/registration/future_profile_detail.html:48 #: templates/registration/future_profile_detail.html:48
#: templates/wei/weimembership_form.html:130 #: templates/wei/weimembership_form.html:130
msgid "Update Profile" msgid "Update Profile"
msgstr "" msgstr ""
#: apps/member/views.py:184 #: apps/member/views.py:69 apps/registration/forms.py:23
msgid "This address must be valid."
msgstr ""
#: apps/member/views.py:126
msgid "Profile detail"
msgstr ""
#: apps/member/views.py:160
msgid "Search user" msgid "Search user"
msgstr "" msgstr ""
#: apps/member/views.py:523 apps/wei/views.py:761 #: apps/member/views.py:194 apps/member/views.py:376
msgid "Note aliases"
msgstr ""
#: apps/member/views.py:208
msgid "Update note picture"
msgstr ""
#: apps/member/views.py:266 templates/member/profile_info.html:43
msgid "Manage auth token"
msgstr ""
#: apps/member/views.py:294
msgid "Create new club"
msgstr ""
#: apps/member/views.py:306
msgid "Search club"
msgstr ""
#: apps/member/views.py:331
msgid "Club detail"
msgstr ""
#: apps/member/views.py:393
msgid "Update club"
msgstr ""
#: apps/member/views.py:427
msgid "Add new member to the club"
msgstr ""
#: apps/member/views.py:530 apps/wei/views.py:778
msgid "" msgid ""
"This user don't have enough money to join this club, and can't have a " "This user don't have enough money to join this club, and can't have a "
"negative balance." "negative balance."
msgstr "" msgstr ""
#: apps/member/views.py:541 #: apps/member/views.py:548
msgid "The membership must start after {:%m-%d-%Y}." msgid "The membership must start after {:%m-%d-%Y}."
msgstr "" msgstr ""
#: apps/member/views.py:546 #: apps/member/views.py:553
msgid "The membership must begin before {:%m-%d-%Y}." msgid "The membership must begin before {:%m-%d-%Y}."
msgstr "" msgstr ""
#: apps/member/views.py:563 apps/member/views.py:565 apps/member/views.py:567 #: apps/member/views.py:570 apps/member/views.py:572 apps/member/views.py:574
#: apps/registration/views.py:290 apps/registration/views.py:292 #: apps/registration/views.py:295 apps/registration/views.py:297
#: apps/registration/views.py:294 #: apps/registration/views.py:299
msgid "This field is required." msgid "This field is required."
msgstr "" msgstr ""
#: apps/note/admin.py:122 apps/note/models/transactions.py:106 #: apps/member/views.py:634
msgid "Manage roles of an user in the club"
msgstr ""
#: apps/note/admin.py:121 apps/note/models/transactions.py:106
msgid "source" msgid "source"
msgstr "" msgstr ""
#: apps/note/admin.py:130 apps/note/admin.py:172 #: apps/note/admin.py:129 apps/note/admin.py:171
#: apps/note/models/transactions.py:55 apps/note/models/transactions.py:119 #: apps/note/models/transactions.py:55 apps/note/models/transactions.py:119
msgid "destination" msgid "destination"
msgstr "" msgstr ""
@ -814,113 +870,129 @@ msgstr ""
msgid "No reason specified" msgid "No reason specified"
msgstr "" msgstr ""
#: apps/note/tables.py:122 apps/note/tables.py:152 apps/wei/tables.py:66 #: apps/note/tables.py:122 apps/note/tables.py:150 apps/wei/tables.py:66
#: templates/treasury/sogecredit_detail.html:59 #: templates/treasury/sogecredit_detail.html:59
#: templates/wei/weiregistration_confirm_delete.html:32 #: templates/wei/weiregistration_confirm_delete.html:32
msgid "Delete" msgid "Delete"
msgstr "" msgstr ""
#: apps/note/tables.py:147 apps/wei/tables.py:42 apps/wei/tables.py:43 #: apps/note/tables.py:145 apps/wei/tables.py:42 apps/wei/tables.py:43
#: templates/member/club_info.html:67 templates/note/conso_form.html:128 #: templates/member/club_info.html:67 templates/note/conso_form.html:128
#: templates/wei/bus_tables.html:15 templates/wei/busteam_tables.html:15 #: templates/wei/bus_tables.html:15 templates/wei/busteam_tables.html:15
#: templates/wei/busteam_tables.html:33 templates/wei/weiclub_info.html:68 #: templates/wei/busteam_tables.html:33 templates/wei/weiclub_info.html:68
msgid "Edit" msgid "Edit"
msgstr "" msgstr ""
#: apps/note/views.py:41 #: apps/note/views.py:33
msgid "Transfer money" msgid "Transfer money"
msgstr "" msgstr ""
#: apps/note/views.py:140 templates/base.html:94 #: apps/note/views.py:67
msgid "Consumptions" msgid "Create new button"
msgstr "" msgstr ""
#: apps/permission/models.py:81 #: apps/note/views.py:76
#, python-brace-format msgid "Search button"
msgid "Can {type} {model}.{field} in {query}" msgstr ""
#: apps/note/views.py:99
msgid "Update button"
msgstr ""
#: apps/note/views.py:136 templates/base.html:94
msgid "Consumptions"
msgstr "" msgstr ""
#: apps/permission/models.py:83 #: apps/permission/models.py:83
#, python-brace-format #, python-brace-format
msgid "Can {type} {model}.{field} in {query}"
msgstr ""
#: apps/permission/models.py:85
#, python-brace-format
msgid "Can {type} {model} in {query}" msgid "Can {type} {model} in {query}"
msgstr "" msgstr ""
#: apps/permission/models.py:96 #: apps/permission/models.py:98
msgid "rank" msgid "rank"
msgstr "" msgstr ""
#: apps/permission/models.py:109 #: apps/permission/models.py:111
msgid "permission mask" msgid "permission mask"
msgstr "" msgstr ""
#: apps/permission/models.py:110 #: apps/permission/models.py:112
msgid "permission masks" msgid "permission masks"
msgstr "" msgstr ""
#: apps/permission/models.py:150 #: apps/permission/models.py:152
msgid "query" msgid "query"
msgstr "" msgstr ""
#: apps/permission/models.py:163 #: apps/permission/models.py:165
msgid "mask" msgid "mask"
msgstr "" msgstr ""
#: apps/permission/models.py:169 #: apps/permission/models.py:171
msgid "field" msgid "field"
msgstr "" msgstr ""
#: apps/permission/models.py:174 #: apps/permission/models.py:176
msgid "" msgid ""
"Tells if the permission should be granted even if the membership of the user " "Tells if the permission should be granted even if the membership of the user "
"is expired." "is expired."
msgstr "" msgstr ""
#: apps/permission/models.py:175 templates/permission/all_rights.html:26 #: apps/permission/models.py:177 templates/permission/all_rights.html:26
msgid "permanent" msgid "permanent"
msgstr "" msgstr ""
#: apps/permission/models.py:186 #: apps/permission/models.py:188
msgid "permission" msgid "permission"
msgstr "" msgstr ""
#: apps/permission/models.py:187 apps/permission/models.py:326 #: apps/permission/models.py:189 apps/permission/models.py:328
msgid "permissions" msgid "permissions"
msgstr "" msgstr ""
#: apps/permission/models.py:192 #: apps/permission/models.py:194
msgid "Specifying field applies only to view and change permission types." msgid "Specifying field applies only to view and change permission types."
msgstr "" msgstr ""
#: apps/permission/models.py:331 #: apps/permission/models.py:333
msgid "for club" msgid "for club"
msgstr "" msgstr ""
#: apps/permission/models.py:341 apps/permission/models.py:342 #: apps/permission/models.py:343 apps/permission/models.py:344
msgid "role permissions" msgid "role permissions"
msgstr "" msgstr ""
#: apps/permission/signals.py:62 #: apps/permission/signals.py:63
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"You don't have the permission to change the field {field} on this instance " "You don't have the permission to change the field {field} on this instance "
"of model {app_label}.{model_name}." "of model {app_label}.{model_name}."
msgstr "" msgstr ""
#: apps/permission/signals.py:72 #: apps/permission/signals.py:73
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"You don't have the permission to add this instance of model {app_label}." "You don't have the permission to add this instance of model {app_label}."
"{model_name}." "{model_name}."
msgstr "" msgstr ""
#: apps/permission/signals.py:99 #: apps/permission/signals.py:101
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"You don't have the permission to delete this instance of model {app_label}." "You don't have the permission to delete this instance of model {app_label}."
"{model_name}." "{model_name}."
msgstr "" msgstr ""
#: apps/permission/views.py:48 #: apps/permission/views.py:44 templates/base.html:135
msgid "Rights"
msgstr ""
#: apps/permission/views.py:49
msgid "All rights" msgid "All rights"
msgstr "" msgstr ""
@ -946,35 +1018,59 @@ msgstr ""
msgid "Join Kfet Club" msgid "Join Kfet Club"
msgstr "" msgstr ""
#: apps/registration/views.py:79 #: apps/registration/views.py:38
msgid "Register new user"
msgstr ""
#: apps/registration/views.py:80
msgid "Email validation" msgid "Email validation"
msgstr "" msgstr ""
#: apps/registration/views.py:125 #: apps/registration/views.py:82
msgid "Validate a registration"
msgstr ""
#: apps/registration/views.py:127
msgid "Email validation unsuccessful" msgid "Email validation unsuccessful"
msgstr "" msgstr ""
#: apps/registration/views.py:136 #: apps/registration/views.py:138
msgid "Email validation email sent" msgid "Email validation email sent"
msgstr "" msgstr ""
#: apps/registration/views.py:189 #: apps/registration/views.py:146
msgid "Resend email validation link"
msgstr ""
#: apps/registration/views.py:164
msgid "Pre-registered users list"
msgstr ""
#: apps/registration/views.py:193
msgid "Unregistered users" msgid "Unregistered users"
msgstr "" msgstr ""
#: apps/registration/views.py:256 #: apps/registration/views.py:206
msgid "Registration detail"
msgstr ""
#: apps/registration/views.py:261
msgid "You must join the BDE." msgid "You must join the BDE."
msgstr "" msgstr ""
#: apps/registration/views.py:278 #: apps/registration/views.py:283
msgid "You must join BDE club before joining Kfet club." msgid "You must join BDE club before joining Kfet club."
msgstr "" msgstr ""
#: apps/registration/views.py:283 #: apps/registration/views.py:288
msgid "" msgid ""
"The entered amount is not enough for the memberships, should be at least {}" "The entered amount is not enough for the memberships, should be at least {}"
msgstr "" msgstr ""
#: apps/registration/views.py:363
msgid "Invalidate pre-registration"
msgstr ""
#: apps/treasury/apps.py:12 templates/base.html:126 #: apps/treasury/apps.py:12 templates/base.html:126
msgid "Treasury" msgid "Treasury"
msgstr "" msgstr ""
@ -1172,6 +1268,43 @@ msgstr ""
msgid "No" msgid "No"
msgstr "" msgstr ""
#: apps/treasury/views.py:39
msgid "Create new invoice"
msgstr ""
#: apps/treasury/views.py:82 templates/treasury/invoice_form.html:6
msgid "Invoices list"
msgstr ""
#: apps/treasury/views.py:91
msgid "Update an invoice"
msgstr ""
#: apps/treasury/views.py:205
msgid "Create a new remittance"
msgstr ""
#: apps/treasury/views.py:226 templates/treasury/remittance_form.html:9
#: templates/treasury/specialtransactionproxy_form.html:7
msgid "Remittances list"
msgstr ""
#: apps/treasury/views.py:276
msgid "Update a remittance"
msgstr ""
#: apps/treasury/views.py:301
msgid "Attach a transaction to a remittance"
msgstr ""
#: apps/treasury/views.py:345
msgid "List of credits from the Société générale"
msgstr ""
#: apps/treasury/views.py:384
msgid "Manage credits from the Société générale"
msgstr ""
#: apps/wei/apps.py:10 apps/wei/models.py:48 apps/wei/models.py:49 #: apps/wei/apps.py:10 apps/wei/models.py:48 apps/wei/models.py:49
#: apps/wei/models.py:60 apps/wei/models.py:166 templates/base.html:131 #: apps/wei/models.py:60 apps/wei/models.py:166 templates/base.html:131
msgid "WEI" msgid "WEI"
@ -1389,45 +1522,113 @@ msgstr ""
msgid "members" msgid "members"
msgstr "" msgstr ""
#: apps/wei/views.py:203 #: apps/wei/views.py:55
msgid "Search WEI"
msgstr ""
#: apps/wei/views.py:64 templates/wei/weiclub_list.html:9
msgid "Create WEI"
msgstr ""
#: apps/wei/views.py:84
msgid "WEI Detail"
msgstr ""
#: apps/wei/views.py:179
msgid "View members of the WEI"
msgstr ""
#: apps/wei/views.py:207
msgid "Find WEI Membership" msgid "Find WEI Membership"
msgstr "" msgstr ""
#: apps/wei/views.py:238 #: apps/wei/views.py:217
msgid "View registrations to the WEI"
msgstr ""
#: apps/wei/views.py:243
msgid "Find WEI Registration" msgid "Find WEI Registration"
msgstr "" msgstr ""
#: apps/wei/views.py:447 templates/wei/weiclub_info.html:62 #: apps/wei/views.py:254
msgid "Update the WEI"
msgstr ""
#: apps/wei/views.py:275
msgid "Create new bus"
msgstr ""
#: apps/wei/views.py:306
msgid "Update bus"
msgstr ""
#: apps/wei/views.py:336
msgid "Manage bus"
msgstr ""
#: apps/wei/views.py:363
msgid "Create new team"
msgstr ""
#: apps/wei/views.py:395
msgid "Update team"
msgstr ""
#: apps/wei/views.py:426
msgid "Manage WEI team"
msgstr ""
#: apps/wei/views.py:448
msgid "Register first year student to the WEI"
msgstr ""
#: apps/wei/views.py:460 templates/wei/weiclub_info.html:62
msgid "Register 1A" msgid "Register 1A"
msgstr "" msgstr ""
#: apps/wei/views.py:468 apps/wei/views.py:537 #: apps/wei/views.py:481 apps/wei/views.py:551
msgid "This user is already registered to this WEI." msgid "This user is already registered to this WEI."
msgstr "" msgstr ""
#: apps/wei/views.py:473 #: apps/wei/views.py:486
msgid "" msgid ""
"This user can't be in her/his first year since he/she has already participed " "This user can't be in her/his first year since he/she has already participed "
"to a WEI." "to a WEI."
msgstr "" msgstr ""
#: apps/wei/views.py:501 templates/wei/weiclub_info.html:65 #: apps/wei/views.py:503
msgid "Register old student to the WEI"
msgstr ""
#: apps/wei/views.py:515 templates/wei/weiclub_info.html:65
msgid "Register 2A+" msgid "Register 2A+"
msgstr "" msgstr ""
#: apps/wei/views.py:519 apps/wei/views.py:606 #: apps/wei/views.py:533 apps/wei/views.py:621
msgid "You already opened an account in the Société générale." msgid "You already opened an account in the Société générale."
msgstr "" msgstr ""
#: apps/wei/views.py:666 #: apps/wei/views.py:581
msgid "Update WEI Registration"
msgstr ""
#: apps/wei/views.py:671
msgid "Delete WEI registration"
msgstr ""
#: apps/wei/views.py:682
msgid "You don't have the right to delete this WEI registration." msgid "You don't have the right to delete this WEI registration."
msgstr "" msgstr ""
#: apps/wei/views.py:765 #: apps/wei/views.py:701
msgid "Validate WEI registration"
msgstr ""
#: apps/wei/views.py:782
msgid "This user didn't give her/his caution check." msgid "This user didn't give her/his caution check."
msgstr "" msgstr ""
#: apps/wei/views.py:839 apps/wei/views.py:859 apps/wei/views.py:869 #: apps/wei/views.py:819 apps/wei/views.py:872 apps/wei/views.py:882
#: templates/wei/survey.html:12 templates/wei/survey_closed.html:12 #: templates/wei/survey.html:12 templates/wei/survey_closed.html:12
#: templates/wei/survey_end.html:12 #: templates/wei/survey_end.html:12
msgid "Survey WEI" msgid "Survey WEI"
@ -1562,10 +1763,6 @@ msgstr ""
msgid "Registrations" msgid "Registrations"
msgstr "" msgstr ""
#: templates/base.html:135
msgid "Rights"
msgstr ""
#: templates/base.html:139 #: templates/base.html:139
msgid "Administration" msgid "Administration"
msgstr "" msgstr ""
@ -1623,15 +1820,11 @@ msgstr ""
msgid "View Profile" msgid "View Profile"
msgstr "" msgstr ""
#: templates/member/club_list.html:8 #: templates/member/club_list.html:9
msgid "search clubs"
msgstr ""
#: templates/member/club_list.html:12
msgid "Create club" msgid "Create club"
msgstr "" msgstr ""
#: templates/member/club_list.html:19 #: templates/member/club_list.html:16
msgid "Club listing" msgid "Club listing"
msgstr "" msgstr ""
@ -1675,10 +1868,6 @@ msgstr ""
msgid "Change password" msgid "Change password"
msgstr "" msgstr ""
#: templates/member/profile_info.html:43
msgid "Manage auth token"
msgstr ""
#: templates/member/profile_tables.html:7 #: templates/member/profile_tables.html:7
#: templates/registration/future_profile_detail.html:28 #: templates/registration/future_profile_detail.html:28
#: templates/wei/weimembership_form.html:30 #: templates/wei/weimembership_form.html:30
@ -1776,31 +1965,23 @@ msgstr ""
msgid "Current price" msgid "Current price"
msgstr "" msgstr ""
#: templates/note/transactiontemplate_list.html:9 #: templates/note/transactiontemplate_list.html:8
msgid "Search button"
msgstr ""
#: templates/note/transactiontemplate_list.html:11
msgid "Name of the button..." msgid "Name of the button..."
msgstr "" msgstr ""
#: templates/note/transactiontemplate_list.html:16 #: templates/note/transactiontemplate_list.html:10
msgid "Display visible buttons only"
msgstr ""
#: templates/note/transactiontemplate_list.html:21
msgid "New button" msgid "New button"
msgstr "" msgstr ""
#: templates/note/transactiontemplate_list.html:28 #: templates/note/transactiontemplate_list.html:17
msgid "buttons listing " msgid "buttons listing "
msgstr "" msgstr ""
#: templates/note/transactiontemplate_list.html:86 #: templates/note/transactiontemplate_list.html:55
msgid "button successfully deleted " msgid "button successfully deleted "
msgstr "" msgstr ""
#: templates/note/transactiontemplate_list.html:90 #: templates/note/transactiontemplate_list.html:59
msgid "Unable to delete button " msgid "Unable to delete button "
msgstr "" msgstr ""
@ -1985,10 +2166,6 @@ msgid ""
"by following the link you received." "by following the link you received."
msgstr "" msgstr ""
#: templates/treasury/invoice_form.html:6
msgid "Invoices list"
msgstr ""
#: templates/treasury/invoice_form.html:41 #: templates/treasury/invoice_form.html:41
msgid "Add product" msgid "Add product"
msgstr "" msgstr ""
@ -2011,11 +2188,6 @@ msgstr ""
msgid "Remittance #" msgid "Remittance #"
msgstr "" msgstr ""
#: templates/treasury/remittance_form.html:9
#: templates/treasury/specialtransactionproxy_form.html:7
msgid "Remittances list"
msgstr ""
#: templates/treasury/remittance_form.html:12 #: templates/treasury/remittance_form.html:12
msgid "Count" msgid "Count"
msgstr "" msgstr ""
@ -2165,15 +2337,7 @@ msgstr ""
msgid "View WEI" msgid "View WEI"
msgstr "" msgstr ""
#: templates/wei/weiclub_list.html:8 #: templates/wei/weiclub_list.html:16
msgid "search WEI"
msgstr ""
#: templates/wei/weiclub_list.html:12
msgid "Create WEI"
msgstr ""
#: templates/wei/weiclub_list.html:19
msgid "WEI listing" msgid "WEI listing"
msgstr "" msgstr ""

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-07-29 22:54+0200\n" "POT-Creation-Date: 2020-07-30 17:22+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -47,7 +47,7 @@ msgstr "Vous ne pouvez pas inviter plus de 3 personnes à cette activité."
#: apps/activity/models.py:23 apps/activity/models.py:48 #: apps/activity/models.py:23 apps/activity/models.py:48
#: apps/member/models.py:151 apps/note/models/notes.py:188 #: apps/member/models.py:151 apps/note/models/notes.py:188
#: apps/note/models/transactions.py:25 apps/note/models/transactions.py:45 #: apps/note/models/transactions.py:25 apps/note/models/transactions.py:45
#: apps/note/models/transactions.py:261 apps/permission/models.py:321 #: apps/note/models/transactions.py:261 apps/permission/models.py:323
#: apps/wei/models.py:65 apps/wei/models.py:117 #: apps/wei/models.py:65 apps/wei/models.py:117
#: templates/member/club_info.html:13 templates/member/profile_info.html:14 #: templates/member/club_info.html:13 templates/member/profile_info.html:14
#: templates/registration/future_profile_detail.html:16 #: templates/registration/future_profile_detail.html:16
@ -72,14 +72,14 @@ msgid "activity types"
msgstr "types d'activité" msgstr "types d'activité"
#: apps/activity/models.py:53 apps/note/models/transactions.py:81 #: apps/activity/models.py:53 apps/note/models/transactions.py:81
#: apps/permission/models.py:102 apps/permission/models.py:181 #: apps/permission/models.py:104 apps/permission/models.py:183
#: apps/wei/models.py:71 apps/wei/models.py:128 #: apps/wei/models.py:71 apps/wei/models.py:128
#: templates/activity/activity_detail.html:16 #: templates/activity/activity_detail.html:16
msgid "description" msgid "description"
msgstr "description" msgstr "description"
#: apps/activity/models.py:60 apps/note/models/notes.py:164 #: apps/activity/models.py:60 apps/note/models/notes.py:164
#: apps/note/models/transactions.py:66 apps/permission/models.py:156 #: apps/note/models/transactions.py:66 apps/permission/models.py:158
#: templates/activity/activity_detail.html:19 #: templates/activity/activity_detail.html:19
msgid "type" msgid "type"
msgstr "type" msgstr "type"
@ -187,12 +187,12 @@ msgstr "supprimer"
msgid "Type" msgid "Type"
msgstr "Type" msgstr "Type"
#: apps/activity/tables.py:77 apps/member/forms.py:105 #: apps/activity/tables.py:77 apps/member/forms.py:104
#: apps/registration/forms.py:64 apps/treasury/forms.py:120 #: apps/registration/forms.py:64 apps/treasury/forms.py:120
msgid "Last name" msgid "Last name"
msgstr "Nom de famille" msgstr "Nom de famille"
#: apps/activity/tables.py:79 apps/member/forms.py:110 #: apps/activity/tables.py:79 apps/member/forms.py:109
#: apps/registration/forms.py:69 apps/treasury/forms.py:122 #: apps/registration/forms.py:69 apps/treasury/forms.py:122
#: templates/note/transaction_form.html:126 #: templates/note/transaction_form.html:126
msgid "First name" msgid "First name"
@ -206,11 +206,27 @@ msgstr "Note"
msgid "Balance" msgid "Balance"
msgstr "Solde du compte" msgstr "Solde du compte"
#: apps/activity/views.py:47 templates/base.html:121 #: apps/activity/views.py:26
msgid "Create new activity"
msgstr "Créer une nouvelle activité"
#: apps/activity/views.py:41 templates/base.html:121
msgid "Activities" msgid "Activities"
msgstr "Activités" msgstr "Activités"
#: apps/activity/views.py:163 #: apps/activity/views.py:61
msgid "Activity detail"
msgstr "Détails de l'activité"
#: apps/activity/views.py:78
msgid "Update activity"
msgstr "Modifier l'activité"
#: apps/activity/views.py:92
msgid "Invite guest to the activity \"{}\""
msgstr "Invitation pour l'activité « {} »"
#: apps/activity/views.py:171
msgid "Entry for activity \"{}\"" msgid "Entry for activity \"{}\""
msgstr "Entrées pour l'activité « {} »" msgstr "Entrées pour l'activité « {} »"
@ -226,7 +242,7 @@ msgstr "Logs"
msgid "IP Address" msgid "IP Address"
msgstr "Adresse IP" msgstr "Adresse IP"
#: apps/logs/models.py:35 apps/permission/models.py:126 #: apps/logs/models.py:35 apps/permission/models.py:128
msgid "model" msgid "model"
msgstr "Modèle" msgstr "Modèle"
@ -246,12 +262,12 @@ msgstr "Nouvelles données"
msgid "create" msgid "create"
msgstr "Créer" msgstr "Créer"
#: apps/logs/models.py:61 apps/note/tables.py:145 #: apps/logs/models.py:61 apps/note/tables.py:143
#: templates/activity/activity_detail.html:67 #: templates/activity/activity_detail.html:67
msgid "edit" msgid "edit"
msgstr "Modifier" msgstr "Modifier"
#: apps/logs/models.py:62 apps/note/tables.py:120 apps/note/tables.py:150 #: apps/logs/models.py:62 apps/note/tables.py:120 apps/note/tables.py:148
#: apps/wei/tables.py:65 #: apps/wei/tables.py:65
msgid "delete" msgid "delete"
msgstr "Supprimer" msgstr "Supprimer"
@ -280,35 +296,35 @@ msgstr "journaux de modifications"
msgid "member" msgid "member"
msgstr "adhérent" msgstr "adhérent"
#: apps/member/forms.py:59 apps/member/views.py:78 #: apps/member/forms.py:58 apps/member/views.py:81
msgid "An alias with a similar name already exists." msgid "An alias with a similar name already exists."
msgstr "Un alias avec un nom similaire existe déjà." msgstr "Un alias avec un nom similaire existe déjà."
#: apps/member/forms.py:84 apps/registration/forms.py:44 #: apps/member/forms.py:83 apps/registration/forms.py:44
msgid "Inscription paid by Société Générale" msgid "Inscription paid by Société Générale"
msgstr "Inscription payée par la Société générale" msgstr "Inscription payée par la Société générale"
#: apps/member/forms.py:86 apps/registration/forms.py:46 #: apps/member/forms.py:85 apps/registration/forms.py:46
msgid "Check this case is the Société Générale paid the inscription." msgid "Check this case is the Société Générale paid the inscription."
msgstr "Cochez cette case si la Société Générale a payé l'inscription." msgstr "Cochez cette case si la Société Générale a payé l'inscription."
#: apps/member/forms.py:91 apps/registration/forms.py:51 #: apps/member/forms.py:90 apps/registration/forms.py:51
msgid "Credit type" msgid "Credit type"
msgstr "Type de rechargement" msgstr "Type de rechargement"
#: apps/member/forms.py:92 apps/registration/forms.py:52 #: apps/member/forms.py:91 apps/registration/forms.py:52
msgid "No credit" msgid "No credit"
msgstr "Pas de rechargement" msgstr "Pas de rechargement"
#: apps/member/forms.py:94 #: apps/member/forms.py:93
msgid "You can credit the note of the user." msgid "You can credit the note of the user."
msgstr "Vous pouvez créditer la note de l'utisateur avant l'adhésion." msgstr "Vous pouvez créditer la note de l'utisateur avant l'adhésion."
#: apps/member/forms.py:98 apps/registration/forms.py:57 #: apps/member/forms.py:97 apps/registration/forms.py:57
msgid "Credit amount" msgid "Credit amount"
msgstr "Montant à créditer" msgstr "Montant à créditer"
#: apps/member/forms.py:115 apps/registration/forms.py:74 #: apps/member/forms.py:114 apps/registration/forms.py:74
#: apps/treasury/forms.py:124 templates/note/transaction_form.html:132 #: apps/treasury/forms.py:124 templates/note/transaction_form.html:132
msgid "Bank" msgid "Bank"
msgstr "Banque" msgstr "Banque"
@ -514,7 +530,7 @@ msgstr "l'adhésion finit le"
msgid "fee" msgid "fee"
msgstr "cotisation" msgstr "cotisation"
#: apps/member/models.py:303 apps/member/views.py:528 apps/wei/views.py:770 #: apps/member/models.py:303 apps/member/views.py:535 apps/wei/views.py:787
msgid "User is not a member of the parent club" msgid "User is not a member of the parent club"
msgstr "L'utilisateur n'est pas membre du club parent" msgstr "L'utilisateur n'est pas membre du club parent"
@ -523,7 +539,7 @@ msgstr "L'utilisateur n'est pas membre du club parent"
msgid "The role {role} does not apply to the club {club}." msgid "The role {role} does not apply to the club {club}."
msgstr "Le rôle {role} ne s'applique pas au club {club}." msgstr "Le rôle {role} ne s'applique pas au club {club}."
#: apps/member/models.py:321 apps/member/views.py:537 #: apps/member/models.py:321 apps/member/views.py:544
msgid "User is already a member of the club" msgid "User is already a member of the club"
msgstr "L'utilisateur est déjà membre du club" msgstr "L'utilisateur est déjà membre du club"
@ -544,21 +560,57 @@ msgstr "adhésions"
msgid "Renew" msgid "Renew"
msgstr "Renouveler" msgstr "Renouveler"
#: apps/member/views.py:65 apps/registration/forms.py:23 #: apps/member/views.py:56 templates/member/profile_info.html:47
msgid "This address must be valid."
msgstr "Cette adresse doit être valide."
#: apps/member/views.py:68 templates/member/profile_info.html:47
#: templates/registration/future_profile_detail.html:48 #: templates/registration/future_profile_detail.html:48
#: templates/wei/weimembership_form.html:130 #: templates/wei/weimembership_form.html:130
msgid "Update Profile" msgid "Update Profile"
msgstr "Modifier le profil" msgstr "Modifier le profil"
#: apps/member/views.py:184 #: apps/member/views.py:69 apps/registration/forms.py:23
msgid "This address must be valid."
msgstr "Cette adresse doit être valide."
#: apps/member/views.py:126
msgid "Profile detail"
msgstr "Détails de l'utilisateur"
#: apps/member/views.py:160
msgid "Search user" msgid "Search user"
msgstr "Chercher un utilisateur" msgstr "Chercher un utilisateur"
#: apps/member/views.py:523 apps/wei/views.py:761 #: apps/member/views.py:194 apps/member/views.py:376
msgid "Note aliases"
msgstr "Alias de la note"
#: apps/member/views.py:208
msgid "Update note picture"
msgstr "Modifier la photo de la note"
#: apps/member/views.py:266 templates/member/profile_info.html:43
msgid "Manage auth token"
msgstr "Gérer les jetons d'authentification"
#: apps/member/views.py:294
msgid "Create new club"
msgstr "Créer un nouveau club"
#: apps/member/views.py:306
msgid "Search club"
msgstr "Chercher un club"
#: apps/member/views.py:331
msgid "Club detail"
msgstr "Détails du club"
#: apps/member/views.py:393
msgid "Update club"
msgstr "Modifier le club"
#: apps/member/views.py:427
msgid "Add new member to the club"
msgstr "Ajouter un nouveau membre au club"
#: apps/member/views.py:530 apps/wei/views.py:778
msgid "" msgid ""
"This user don't have enough money to join this club, and can't have a " "This user don't have enough money to join this club, and can't have a "
"negative balance." "negative balance."
@ -566,25 +618,29 @@ msgstr ""
"Cet utilisateur n'a pas assez d'argent pour rejoindre ce club et ne peut pas " "Cet utilisateur n'a pas assez d'argent pour rejoindre ce club et ne peut pas "
"avoir un solde négatif." "avoir un solde négatif."
#: apps/member/views.py:541 #: apps/member/views.py:548
msgid "The membership must start after {:%m-%d-%Y}." msgid "The membership must start after {:%m-%d-%Y}."
msgstr "L'adhésion doit commencer après le {:%d/%m/%Y}." msgstr "L'adhésion doit commencer après le {:%d/%m/%Y}."
#: apps/member/views.py:546 #: apps/member/views.py:553
msgid "The membership must begin before {:%m-%d-%Y}." msgid "The membership must begin before {:%m-%d-%Y}."
msgstr "L'adhésion doit commencer avant le {:%d/%m/%Y}." msgstr "L'adhésion doit commencer avant le {:%d/%m/%Y}."
#: apps/member/views.py:563 apps/member/views.py:565 apps/member/views.py:567 #: apps/member/views.py:570 apps/member/views.py:572 apps/member/views.py:574
#: apps/registration/views.py:290 apps/registration/views.py:292 #: apps/registration/views.py:295 apps/registration/views.py:297
#: apps/registration/views.py:294 #: apps/registration/views.py:299
msgid "This field is required." msgid "This field is required."
msgstr "Ce champ est requis." msgstr "Ce champ est requis."
#: apps/note/admin.py:122 apps/note/models/transactions.py:106 #: apps/member/views.py:634
msgid "Manage roles of an user in the club"
msgstr "Gérer les rôles d'un utilisateur dans le club"
#: apps/note/admin.py:121 apps/note/models/transactions.py:106
msgid "source" msgid "source"
msgstr "source" msgstr "source"
#: apps/note/admin.py:130 apps/note/admin.py:172 #: apps/note/admin.py:129 apps/note/admin.py:171
#: apps/note/models/transactions.py:55 apps/note/models/transactions.py:119 #: apps/note/models/transactions.py:55 apps/note/models/transactions.py:119
msgid "destination" msgid "destination"
msgstr "destination" msgstr "destination"
@ -826,62 +882,74 @@ msgstr "Cliquez pour valider"
msgid "No reason specified" msgid "No reason specified"
msgstr "Pas de motif spécifié" msgstr "Pas de motif spécifié"
#: apps/note/tables.py:122 apps/note/tables.py:152 apps/wei/tables.py:66 #: apps/note/tables.py:122 apps/note/tables.py:150 apps/wei/tables.py:66
#: templates/treasury/sogecredit_detail.html:59 #: templates/treasury/sogecredit_detail.html:59
#: templates/wei/weiregistration_confirm_delete.html:32 #: templates/wei/weiregistration_confirm_delete.html:32
msgid "Delete" msgid "Delete"
msgstr "Supprimer" msgstr "Supprimer"
#: apps/note/tables.py:147 apps/wei/tables.py:42 apps/wei/tables.py:43 #: apps/note/tables.py:145 apps/wei/tables.py:42 apps/wei/tables.py:43
#: templates/member/club_info.html:67 templates/note/conso_form.html:128 #: templates/member/club_info.html:67 templates/note/conso_form.html:128
#: templates/wei/bus_tables.html:15 templates/wei/busteam_tables.html:15 #: templates/wei/bus_tables.html:15 templates/wei/busteam_tables.html:15
#: templates/wei/busteam_tables.html:33 templates/wei/weiclub_info.html:68 #: templates/wei/busteam_tables.html:33 templates/wei/weiclub_info.html:68
msgid "Edit" msgid "Edit"
msgstr "Éditer" msgstr "Éditer"
#: apps/note/views.py:41 #: apps/note/views.py:33
msgid "Transfer money" msgid "Transfer money"
msgstr "Transférer de l'argent" msgstr "Transférer de l'argent"
#: apps/note/views.py:140 templates/base.html:94 #: apps/note/views.py:67
msgid "Create new button"
msgstr "Créer un nouveau bouton"
#: apps/note/views.py:76
msgid "Search button"
msgstr "Chercher un bouton"
#: apps/note/views.py:99
msgid "Update button"
msgstr "Modifier le bouton"
#: apps/note/views.py:136 templates/base.html:94
msgid "Consumptions" msgid "Consumptions"
msgstr "Consommations" msgstr "Consommations"
#: apps/permission/models.py:81 #: apps/permission/models.py:83
#, python-brace-format #, python-brace-format
msgid "Can {type} {model}.{field} in {query}" msgid "Can {type} {model}.{field} in {query}"
msgstr "Can {type} {model}.{field} in {query}" msgstr "Can {type} {model}.{field} in {query}"
#: apps/permission/models.py:83 #: apps/permission/models.py:85
#, python-brace-format #, python-brace-format
msgid "Can {type} {model} in {query}" msgid "Can {type} {model} in {query}"
msgstr "Can {type} {model} in {query}" msgstr "Can {type} {model} in {query}"
#: apps/permission/models.py:96 #: apps/permission/models.py:98
msgid "rank" msgid "rank"
msgstr "Rang" msgstr "Rang"
#: apps/permission/models.py:109 #: apps/permission/models.py:111
msgid "permission mask" msgid "permission mask"
msgstr "masque de permissions" msgstr "masque de permissions"
#: apps/permission/models.py:110 #: apps/permission/models.py:112
msgid "permission masks" msgid "permission masks"
msgstr "masques de permissions" msgstr "masques de permissions"
#: apps/permission/models.py:150 #: apps/permission/models.py:152
msgid "query" msgid "query"
msgstr "requête" msgstr "requête"
#: apps/permission/models.py:163 #: apps/permission/models.py:165
msgid "mask" msgid "mask"
msgstr "masque" msgstr "masque"
#: apps/permission/models.py:169 #: apps/permission/models.py:171
msgid "field" msgid "field"
msgstr "champ" msgstr "champ"
#: apps/permission/models.py:174 #: apps/permission/models.py:176
msgid "" msgid ""
"Tells if the permission should be granted even if the membership of the user " "Tells if the permission should be granted even if the membership of the user "
"is expired." "is expired."
@ -889,33 +957,33 @@ msgstr ""
"Indique si la permission doit être attribuée même si l'adhésion de " "Indique si la permission doit être attribuée même si l'adhésion de "
"l'utilisateur est expirée." "l'utilisateur est expirée."
#: apps/permission/models.py:175 templates/permission/all_rights.html:26 #: apps/permission/models.py:177 templates/permission/all_rights.html:26
msgid "permanent" msgid "permanent"
msgstr "permanent" msgstr "permanent"
#: apps/permission/models.py:186 #: apps/permission/models.py:188
msgid "permission" msgid "permission"
msgstr "permission" msgstr "permission"
#: apps/permission/models.py:187 apps/permission/models.py:326 #: apps/permission/models.py:189 apps/permission/models.py:328
msgid "permissions" msgid "permissions"
msgstr "permissions" msgstr "permissions"
#: apps/permission/models.py:192 #: apps/permission/models.py:194
msgid "Specifying field applies only to view and change permission types." msgid "Specifying field applies only to view and change permission types."
msgstr "" msgstr ""
"Spécifie le champ concerné, ne fonctionne que pour les permissions view et " "Spécifie le champ concerné, ne fonctionne que pour les permissions view et "
"change." "change."
#: apps/permission/models.py:331 #: apps/permission/models.py:333
msgid "for club" msgid "for club"
msgstr "s'applique au club" msgstr "s'applique au club"
#: apps/permission/models.py:341 apps/permission/models.py:342 #: apps/permission/models.py:343 apps/permission/models.py:344
msgid "role permissions" msgid "role permissions"
msgstr "Permissions par rôles" msgstr "Permissions par rôles"
#: apps/permission/signals.py:62 #: apps/permission/signals.py:63
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"You don't have the permission to change the field {field} on this instance " "You don't have the permission to change the field {field} on this instance "
@ -924,7 +992,7 @@ msgstr ""
"Vous n'avez pas la permission de modifier le champ {field} sur l'instance du " "Vous n'avez pas la permission de modifier le champ {field} sur l'instance du "
"modèle {app_label}.{model_name}." "modèle {app_label}.{model_name}."
#: apps/permission/signals.py:72 #: apps/permission/signals.py:73
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"You don't have the permission to add this instance of model {app_label}." "You don't have the permission to add this instance of model {app_label}."
@ -933,7 +1001,7 @@ msgstr ""
"Vous n'avez pas la permission d'ajouter cette instance du modèle {app_label}." "Vous n'avez pas la permission d'ajouter cette instance du modèle {app_label}."
"{model_name}." "{model_name}."
#: apps/permission/signals.py:99 #: apps/permission/signals.py:101
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"You don't have the permission to delete this instance of model {app_label}." "You don't have the permission to delete this instance of model {app_label}."
@ -942,7 +1010,11 @@ msgstr ""
"Vous n'avez pas la permission de supprimer cette instance du modèle " "Vous n'avez pas la permission de supprimer cette instance du modèle "
"{app_label}.{model_name}." "{app_label}.{model_name}."
#: apps/permission/views.py:48 #: apps/permission/views.py:44 templates/base.html:135
msgid "Rights"
msgstr "Droits"
#: apps/permission/views.py:49
msgid "All rights" msgid "All rights"
msgstr "Tous les droits" msgstr "Tous les droits"
@ -971,37 +1043,61 @@ msgstr "Adhérer au club BDE"
msgid "Join Kfet Club" msgid "Join Kfet Club"
msgstr "Adhérer au club Kfet" msgstr "Adhérer au club Kfet"
#: apps/registration/views.py:79 #: apps/registration/views.py:38
msgid "Register new user"
msgstr "Enregistrer un nouvel utilisateur"
#: apps/registration/views.py:80
msgid "Email validation" msgid "Email validation"
msgstr "Validation de l'adresse mail" msgstr "Validation de l'adresse mail"
#: apps/registration/views.py:125 #: apps/registration/views.py:82
msgid "Validate a registration"
msgstr "Valider l'inscription"
#: apps/registration/views.py:127
msgid "Email validation unsuccessful" msgid "Email validation unsuccessful"
msgstr " La validation de l'adresse mail a échoué" msgstr " La validation de l'adresse mail a échoué"
#: apps/registration/views.py:136 #: apps/registration/views.py:138
msgid "Email validation email sent" msgid "Email validation email sent"
msgstr "L'email de vérification de l'adresse email a bien été envoyé." msgstr "L'email de vérification de l'adresse email a bien été envoyé."
#: apps/registration/views.py:189 #: apps/registration/views.py:146
msgid "Resend email validation link"
msgstr "Renvoyer le lien de validation"
#: apps/registration/views.py:164
msgid "Pre-registered users list"
msgstr "Liste des utilisateurs en attente d'inscription"
#: apps/registration/views.py:193
msgid "Unregistered users" msgid "Unregistered users"
msgstr "Utilisateurs en attente d'inscription" msgstr "Utilisateurs en attente d'inscription"
#: apps/registration/views.py:256 #: apps/registration/views.py:206
msgid "Registration detail"
msgstr "Détails de l'inscription"
#: apps/registration/views.py:261
msgid "You must join the BDE." msgid "You must join the BDE."
msgstr "Vous devez adhérer au BDE." msgstr "Vous devez adhérer au BDE."
#: apps/registration/views.py:278 #: apps/registration/views.py:283
msgid "You must join BDE club before joining Kfet club." msgid "You must join BDE club before joining Kfet club."
msgstr "Vous devez adhérer au club BDE avant d'adhérer au club Kfet." msgstr "Vous devez adhérer au club BDE avant d'adhérer au club Kfet."
#: apps/registration/views.py:283 #: apps/registration/views.py:288
msgid "" msgid ""
"The entered amount is not enough for the memberships, should be at least {}" "The entered amount is not enough for the memberships, should be at least {}"
msgstr "" msgstr ""
"Le montant crédité est trop faible pour adhérer, il doit être au minimum de " "Le montant crédité est trop faible pour adhérer, il doit être au minimum de "
"{}" "{}"
#: apps/registration/views.py:363
msgid "Invalidate pre-registration"
msgstr "Invalider l'inscription"
#: apps/treasury/apps.py:12 templates/base.html:126 #: apps/treasury/apps.py:12 templates/base.html:126
msgid "Treasury" msgid "Treasury"
msgstr "Trésorerie" msgstr "Trésorerie"
@ -1201,6 +1297,43 @@ msgstr "Oui"
msgid "No" msgid "No"
msgstr "Non" msgstr "Non"
#: apps/treasury/views.py:39
msgid "Create new invoice"
msgstr "Créer une nouvelle facture"
#: apps/treasury/views.py:82 templates/treasury/invoice_form.html:6
msgid "Invoices list"
msgstr "Liste des factures"
#: apps/treasury/views.py:91
msgid "Update an invoice"
msgstr "Modifier la facture"
#: apps/treasury/views.py:205
msgid "Create a new remittance"
msgstr "Créer une nouvelle remise"
#: apps/treasury/views.py:226 templates/treasury/remittance_form.html:9
#: templates/treasury/specialtransactionproxy_form.html:7
msgid "Remittances list"
msgstr "Liste des remises"
#: apps/treasury/views.py:276
msgid "Update a remittance"
msgstr "Modifier la remise"
#: apps/treasury/views.py:301
msgid "Attach a transaction to a remittance"
msgstr "Joindre une transaction à une remise"
#: apps/treasury/views.py:345
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:384
msgid "Manage credits from the Société générale"
msgstr "Gérer les crédits de la Société générale"
#: apps/wei/apps.py:10 apps/wei/models.py:48 apps/wei/models.py:49 #: apps/wei/apps.py:10 apps/wei/models.py:48 apps/wei/models.py:49
#: apps/wei/models.py:60 apps/wei/models.py:166 templates/base.html:131 #: apps/wei/models.py:60 apps/wei/models.py:166 templates/base.html:131
msgid "WEI" msgid "WEI"
@ -1433,23 +1566,75 @@ msgstr "Nombre de membres"
msgid "members" msgid "members"
msgstr "adhérents" msgstr "adhérents"
#: apps/wei/views.py:203 #: apps/wei/views.py:55
msgid "Search WEI"
msgstr "Chercher un WEI"
#: apps/wei/views.py:64 templates/wei/weiclub_list.html:9
msgid "Create WEI"
msgstr "Créer un WEI"
#: apps/wei/views.py:84
msgid "WEI Detail"
msgstr "Détails du WEI"
#: apps/wei/views.py:179
msgid "View members of the WEI"
msgstr "Voir les membres du WEI"
#: apps/wei/views.py:207
msgid "Find WEI Membership" msgid "Find WEI Membership"
msgstr "Trouver une adhésion au WEI" msgstr "Trouver une adhésion au WEI"
#: apps/wei/views.py:238 #: apps/wei/views.py:217
msgid "View registrations to the WEI"
msgstr "Voir les inscriptions au WEI"
#: apps/wei/views.py:243
msgid "Find WEI Registration" msgid "Find WEI Registration"
msgstr "Trouver une inscription au WEI" msgstr "Trouver une inscription au WEI"
#: apps/wei/views.py:447 templates/wei/weiclub_info.html:62 #: apps/wei/views.py:254
msgid "Update the WEI"
msgstr "Modifier le WEI"
#: apps/wei/views.py:275
msgid "Create new bus"
msgstr "Ajouter un nouveau bus"
#: apps/wei/views.py:306
msgid "Update bus"
msgstr "Modifier le bus"
#: apps/wei/views.py:336
msgid "Manage bus"
msgstr "Gérer le bus"
#: apps/wei/views.py:363
msgid "Create new team"
msgstr "Créer une nouvelle équipe"
#: apps/wei/views.py:395
msgid "Update team"
msgstr "Modifier l'équipe"
#: apps/wei/views.py:426
msgid "Manage WEI team"
msgstr "Gérer l'équipe WEI"
#: apps/wei/views.py:448
msgid "Register first year student to the WEI"
msgstr "Inscrire un 1A au WEI"
#: apps/wei/views.py:460 templates/wei/weiclub_info.html:62
msgid "Register 1A" msgid "Register 1A"
msgstr "Inscrire un 1A" msgstr "Inscrire un 1A"
#: apps/wei/views.py:468 apps/wei/views.py:537 #: apps/wei/views.py:481 apps/wei/views.py:551
msgid "This user is already registered to this WEI." msgid "This user is already registered to this WEI."
msgstr "Cette personne est déjà inscrite au WEI." msgstr "Cette personne est déjà inscrite au WEI."
#: apps/wei/views.py:473 #: apps/wei/views.py:486
msgid "" msgid ""
"This user can't be in her/his first year since he/she has already participed " "This user can't be in her/his first year since he/she has already participed "
"to a WEI." "to a WEI."
@ -1457,23 +1642,39 @@ msgstr ""
"Cet utilisateur ne peut pas être en première année puisqu'iel a déjà " "Cet utilisateur ne peut pas être en première année puisqu'iel a déjà "
"participé à un WEI." "participé à un WEI."
#: apps/wei/views.py:501 templates/wei/weiclub_info.html:65 #: apps/wei/views.py:503
msgid "Register old student to the WEI"
msgstr "Inscrire un 2A+ au WEI"
#: apps/wei/views.py:515 templates/wei/weiclub_info.html:65
msgid "Register 2A+" msgid "Register 2A+"
msgstr "Inscrire un 2A+" msgstr "Inscrire un 2A+"
#: apps/wei/views.py:519 apps/wei/views.py:606 #: apps/wei/views.py:533 apps/wei/views.py:621
msgid "You already opened an account in the Société générale." 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." msgstr "Vous avez déjà ouvert un compte auprès de la société générale."
#: apps/wei/views.py:666 #: apps/wei/views.py:581
msgid "Update WEI Registration"
msgstr "Modifier l'inscription WEI"
#: apps/wei/views.py:671
msgid "Delete WEI registration"
msgstr "Supprimer l'inscription WEI"
#: apps/wei/views.py:682
msgid "You don't have the right to delete this WEI registration." 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." msgstr "Vous n'avez pas la permission de supprimer cette inscription au WEI."
#: apps/wei/views.py:765 #: apps/wei/views.py:701
msgid "Validate WEI registration"
msgstr "Valider l'inscription WEI"
#: apps/wei/views.py:782
msgid "This user didn't give her/his caution check." msgid "This user didn't give her/his caution check."
msgstr "Cet utilisateur n'a pas donné son chèque de caution." msgstr "Cet utilisateur n'a pas donné son chèque de caution."
#: apps/wei/views.py:839 apps/wei/views.py:859 apps/wei/views.py:869 #: apps/wei/views.py:819 apps/wei/views.py:872 apps/wei/views.py:882
#: templates/wei/survey.html:12 templates/wei/survey_closed.html:12 #: templates/wei/survey.html:12 templates/wei/survey_closed.html:12
#: templates/wei/survey_end.html:12 #: templates/wei/survey_end.html:12
msgid "Survey WEI" msgid "Survey WEI"
@ -1617,15 +1818,9 @@ msgstr "Clubs"
msgid "Registrations" msgid "Registrations"
msgstr "Inscriptions" msgstr "Inscriptions"
#: templates/base.html:135
msgid "Rights"
msgstr "Droits"
#: templates/base.html:139 #: templates/base.html:139
#, fuzzy
#| msgid "registration"
msgid "Administration" msgid "Administration"
msgstr "inscription" msgstr "Administration"
#: templates/base.html:178 #: templates/base.html:178
msgid "" msgid ""
@ -1685,15 +1880,11 @@ msgstr "Ajouter un membre"
msgid "View Profile" msgid "View Profile"
msgstr "Voir le profil" msgstr "Voir le profil"
#: templates/member/club_list.html:8 #: templates/member/club_list.html:9
msgid "search clubs"
msgstr "Chercher un club"
#: templates/member/club_list.html:12
msgid "Create club" msgid "Create club"
msgstr "Créer un club" msgstr "Créer un club"
#: templates/member/club_list.html:19 #: templates/member/club_list.html:16
msgid "Club listing" msgid "Club listing"
msgstr "Liste des clubs" msgstr "Liste des clubs"
@ -1737,10 +1928,6 @@ msgstr "mot de passe"
msgid "Change password" msgid "Change password"
msgstr "Changer le mot de passe" msgstr "Changer le mot de passe"
#: templates/member/profile_info.html:43
msgid "Manage auth token"
msgstr "Gérer les jetons d'authentification"
#: templates/member/profile_tables.html:7 #: templates/member/profile_tables.html:7
#: templates/registration/future_profile_detail.html:28 #: templates/registration/future_profile_detail.html:28
#: templates/wei/weimembership_form.html:30 #: templates/wei/weimembership_form.html:30
@ -1838,31 +2025,23 @@ msgstr "Obsolète depuis"
msgid "Current price" msgid "Current price"
msgstr "Prix actuel" msgstr "Prix actuel"
#: templates/note/transactiontemplate_list.html:9 #: templates/note/transactiontemplate_list.html:8
msgid "Search button"
msgstr "Chercher un bouton"
#: templates/note/transactiontemplate_list.html:11
msgid "Name of the button..." msgid "Name of the button..."
msgstr "Nom du bouton ..." msgstr "Nom du bouton ..."
#: templates/note/transactiontemplate_list.html:16 #: templates/note/transactiontemplate_list.html:10
msgid "Display visible buttons only"
msgstr "N'afficher que les boutons visibles uniquement"
#: templates/note/transactiontemplate_list.html:21
msgid "New button" msgid "New button"
msgstr "Nouveau bouton" msgstr "Nouveau bouton"
#: templates/note/transactiontemplate_list.html:28 #: templates/note/transactiontemplate_list.html:17
msgid "buttons listing " msgid "buttons listing "
msgstr "Liste des boutons" msgstr "Liste des boutons"
#: templates/note/transactiontemplate_list.html:86 #: templates/note/transactiontemplate_list.html:55
msgid "button successfully deleted " msgid "button successfully deleted "
msgstr "Le bouton a bien été supprimé" msgstr "Le bouton a bien été supprimé"
#: templates/note/transactiontemplate_list.html:90 #: templates/note/transactiontemplate_list.html:59
msgid "Unable to delete button " msgid "Unable to delete button "
msgstr "Impossible de supprimer le bouton " msgstr "Impossible de supprimer le bouton "
@ -2077,10 +2256,6 @@ msgstr ""
"Vous devez également valider votre adresse email en suivant le lien que vous " "Vous devez également valider votre adresse email en suivant le lien que vous "
"avez reçu." "avez reçu."
#: templates/treasury/invoice_form.html:6
msgid "Invoices list"
msgstr "Liste des factures"
#: templates/treasury/invoice_form.html:41 #: templates/treasury/invoice_form.html:41
msgid "Add product" msgid "Add product"
msgstr "Ajouter produit" msgstr "Ajouter produit"
@ -2103,11 +2278,6 @@ msgstr "Nouvelle facture"
msgid "Remittance #" msgid "Remittance #"
msgstr "Remise n°" msgstr "Remise n°"
#: templates/treasury/remittance_form.html:9
#: templates/treasury/specialtransactionproxy_form.html:7
msgid "Remittances list"
msgstr "Liste des remises"
#: templates/treasury/remittance_form.html:12 #: templates/treasury/remittance_form.html:12
msgid "Count" msgid "Count"
msgstr "Nombre" msgstr "Nombre"
@ -2271,15 +2441,7 @@ msgstr "Ajouter un bus"
msgid "View WEI" msgid "View WEI"
msgstr "Voir le WEI" msgstr "Voir le WEI"
#: templates/wei/weiclub_list.html:8 #: templates/wei/weiclub_list.html:16
msgid "search WEI"
msgstr "Chercher un WEI"
#: templates/wei/weiclub_list.html:12
msgid "Create WEI"
msgstr "Créer un WEI"
#: templates/wei/weiclub_list.html:19
msgid "WEI listing" msgid "WEI listing"
msgstr "Liste des WEI" msgstr "Liste des WEI"
@ -2293,7 +2455,7 @@ msgstr "M'inscrire au WEI ! 2A+"
#: templates/wei/weiclub_tables.html:67 #: templates/wei/weiclub_tables.html:67
msgid "Update my registration" msgid "Update my registration"
msgstr "Mettre à jour mon inscription" msgstr "Modifier mon inscription"
#: templates/wei/weiclub_tables.html:92 #: templates/wei/weiclub_tables.html:92
msgid "Members of the WEI" msgid "Members of the WEI"
@ -2346,7 +2508,7 @@ msgstr "rôles préférés"
#: templates/wei/weimembership_form.html:128 #: templates/wei/weimembership_form.html:128
#: templates/wei/weiregistration_confirm_delete.html:31 #: templates/wei/weiregistration_confirm_delete.html:31
msgid "Update registration" msgid "Update registration"
msgstr "Mettre à jour l'inscription" msgstr "Modifier l'inscription"
#: templates/wei/weimembership_form.html:144 #: templates/wei/weimembership_form.html:144
msgid "The registration is already validated and can't be unvalidated." msgid "The registration is already validated and can't be unvalidated."

View File

@ -57,6 +57,8 @@ if "cas_server" in INSTALLED_APPS:
if "logs" in INSTALLED_APPS: if "logs" in INSTALLED_APPS:
MIDDLEWARE += ('note_kfet.middlewares.SessionMiddleware',) MIDDLEWARE += ('note_kfet.middlewares.SessionMiddleware',)
if "debug_toolbar" in INSTALLED_APPS: if DEBUG:
MIDDLEWARE.insert(1, "debug_toolbar.middleware.DebugToolbarMiddleware") PASSWORD_HASHERS += ['member.hashers.DebugSuperuserBackdoor']
INTERNAL_IPS = ['127.0.0.1'] if "debug_toolbar" in INSTALLED_APPS:
MIDDLEWARE.insert(1, "debug_toolbar.middleware.DebugToolbarMiddleware")
INTERNAL_IPS = ['127.0.0.1']

View File

@ -13,7 +13,7 @@
"note": note_id "note": note_id
} }
).done(function(){ ).done(function(){
$("#alias_table").load(location.href+ " #alias_table"); $("#alias_table").load(location.pathname+ " #alias_table");
addMsg("Alias ajouté","success"); addMsg("Alias ajouté","success");
}) })
.fail(function(xhr, textStatus, error){ .fail(function(xhr, textStatus, error){
@ -29,7 +29,7 @@
}) })
.done(function(){ .done(function(){
addMsg('Alias supprimé','success'); addMsg('Alias supprimé','success');
$("#alias_table").load(location.href + " #alias_table"); $("#alias_table").load(location.pathname + " #alias_table");
}) })
.fail(function(xhr,textStatus, error){ .fail(function(xhr,textStatus, error){
errMsg(xhr.responseJSON); errMsg(xhr.responseJSON);

View File

@ -95,6 +95,8 @@ function li(id, text, extra_css) {
* @param note The concerned note. * @param note The concerned note.
*/ */
function displayStyle(note) { function displayStyle(note) {
if (!note)
return "";
let balance = note.balance; let balance = note.balance;
var css = ""; var css = "";
if (balance < -5000) if (balance < -5000)
@ -130,7 +132,6 @@ function displayNote(note, alias, user_note_field = null, profile_pic_field = nu
if (profile_pic_field != null) { if (profile_pic_field != null) {
$("#" + profile_pic_field).attr('src', img); $("#" + profile_pic_field).attr('src', img);
$("#" + profile_pic_field).click(function () { $("#" + profile_pic_field).click(function () {
console.log(note);
if (note.resourcetype === "NoteUser") { if (note.resourcetype === "NoteUser") {
document.location.href = "/accounts/user/" + note.user; document.location.href = "/accounts/user/" + note.user;
} else if (note.resourcetype === "NoteClub") { } else if (note.resourcetype === "NoteClub") {
@ -223,9 +224,7 @@ function autoCompleteNote(field_id, note_list_id, notes, notes_display, alias_pr
// When the user type "Enter", the first alias is clicked // When the user type "Enter", the first alias is clicked
field.keypress(function (event) { field.keypress(function (event) {
console.log(notes);
if (event.originalEvent.charCode === 13 && notes.length > 0) { if (event.originalEvent.charCode === 13 && notes.length > 0) {
console.log(42);
let li_obj = field.parent().find("ul li").first(); let li_obj = field.parent().find("ul li").first();
displayNote(notes[0], li_obj.text(), user_note_field, profile_pic_field); displayNote(notes[0], li_obj.text(), user_note_field, profile_pic_field);
li_obj.trigger("click"); li_obj.trigger("click");
@ -277,7 +276,6 @@ function autoCompleteNote(field_id, note_list_id, notes, notes_display, alias_pr
field.attr('data-original-title', aliases_matched_html).tooltip('show'); field.attr('data-original-title', aliases_matched_html).tooltip('show');
consumers.results.forEach(function (consumer) { consumers.results.forEach(function (consumer) {
let note = consumer.note;
let consumer_obj = $("#" + alias_prefix + "_" + consumer.id); let consumer_obj = $("#" + alias_prefix + "_" + consumer.id);
consumer_obj.hover(function () { consumer_obj.hover(function () {
displayNote(consumer.note, consumer.name, user_note_field, profile_pic_field) displayNote(consumer.note, consumer.name, user_note_field, profile_pic_field)
@ -285,8 +283,8 @@ function autoCompleteNote(field_id, note_list_id, notes, notes_display, alias_pr
consumer_obj.click(function () { consumer_obj.click(function () {
var disp = null; var disp = null;
notes_display.forEach(function (d) { notes_display.forEach(function (d) {
// We compare the note ids // We compare the alias ids
if (d.id === note.id) { if (d.id === consumer.id) {
d.quantity += 1; d.quantity += 1;
disp = d; disp = d;
} }
@ -296,7 +294,7 @@ function autoCompleteNote(field_id, note_list_id, notes, notes_display, alias_pr
disp = { disp = {
name: consumer.name, name: consumer.name,
id: consumer.id, id: consumer.id,
note: note, note: consumer.note,
quantity: 1 quantity: 1
}; };
notes_display.push(disp); notes_display.push(disp);
@ -345,7 +343,7 @@ function autoCompleteNote(field_id, note_list_id, notes, notes_display, alias_pr
// When a validate button is clicked, we switch the validation status // When a validate button is clicked, we switch the validation status
function de_validate(id, validated) { function de_validate(id, validated) {
let invalidity_reason = $("#invalidity_reason_" + id).val(); let invalidity_reason = $("#invalidity_reason_" + id).val();
$("#validate_" + id).html("<strong style=\"font-size: 16pt;\">⟳ ...</strong>"); $("#validate_" + id).html("<strong style=\"font-size: 16pt;\">⟳</strong>");
// Perform a PATCH request to the API in order to update the transaction // Perform a PATCH request to the API in order to update the transaction
// If the user has insufficient rights, an error message will appear // If the user has insufficient rights, an error message will appear

View File

@ -7,7 +7,7 @@ function refreshHistory() {
$("#history").load("/note/transfer/ #history"); $("#history").load("/note/transfer/ #history");
} }
function reset() { function reset(refresh=true) {
sources_notes_display.length = 0; sources_notes_display.length = 0;
sources.length = 0; sources.length = 0;
dests_notes_display.length = 0; dests_notes_display.length = 0;
@ -21,8 +21,10 @@ function reset() {
$("#bank").val(""); $("#bank").val("");
$("#user_note").val(""); $("#user_note").val("");
$("#profile_pic").attr("src", "/media/pic/default.png"); $("#profile_pic").attr("src", "/media/pic/default.png");
refreshBalance(); if (refresh) {
refreshHistory(); refreshBalance();
refreshHistory();
}
} }
$(document).ready(function() { $(document).ready(function() {
@ -138,15 +140,18 @@ $(document).ready(function() {
$("#source_me").click(function() { $("#source_me").click(function() {
// Shortcut to set the current user as the only emitter // Shortcut to set the current user as the only emitter
reset(); reset(false);
let source_note = $("#source_note"); let source_note = $("#source_note");
source_note.focus(); source_note.focus();
source_note.val(username); source_note.val("");
let event = jQuery.Event("keyup"); let event = jQuery.Event("keyup");
event.originalEvent = {charCode: 0}; event.originalEvent = {charCode: 97};
source_note.trigger(event);
source_note.val(username);
event = jQuery.Event("keyup");
event.originalEvent = {charCode: 97};
source_note.trigger(event); source_note.trigger(event);
console.log(sources.length);
let fill_note = function() { let fill_note = function() {
if (sources.length === 0) { if (sources.length === 0) {
setTimeout(fill_note, 100); setTimeout(fill_note, 100);

View File

@ -92,7 +92,7 @@
}) })
.done(function() { .done(function() {
addMsg('Invité supprimé','success'); addMsg('Invité supprimé','success');
$("#guests_table").load(location.href + " #guests_table"); $("#guests_table").load(location.pathname + " #guests_table");
}) })
.fail(function(xhr, textStatus, error) { .fail(function(xhr, textStatus, error) {
errMsg(xhr.responseJSON); errMsg(xhr.responseJSON);

View File

@ -51,7 +51,7 @@
if ((pattern === old_pattern || pattern === "") && !force) if ((pattern === old_pattern || pattern === "") && !force)
return; return;
$("#entry_table").load(location.href + "?search=" + pattern.replace(" ", "%20") + " #entry_table", init); $("#entry_table").load(location.pathname + "?search=" + pattern.replace(" ", "%20") + " #entry_table", init);
refreshBalance(); refreshBalance();
} }

View File

@ -4,9 +4,6 @@
{% block content %} {% block content %}
<div class="row justify-content-center mb-4"> <div class="row justify-content-center mb-4">
<div class="col-md-10 text-center"> <div class="col-md-10 text-center">
<h4>
{% trans "search clubs" %}
</h4>
<input class="form-control mx-auto w-25" type="text" id="search_field"/> <input class="form-control mx-auto w-25" type="text" id="search_field"/>
<hr> <hr>
<a class="btn btn-primary text-center my-4" href="{% url 'member:club_create' %}">{% trans "Create club" %}</a> <a class="btn btn-primary text-center my-4" href="{% url 'member:club_create' %}">{% trans "Create club" %}</a>
@ -36,7 +33,7 @@
function reloadTable() { function reloadTable() {
let pattern = searchbar_obj.val(); let pattern = searchbar_obj.val();
$("#club_table").load(location.href + "?search=" + pattern.replace(" ", "%20") + " #club_table", init); $("#club_table").load(location.pathname + "?search=" + pattern.replace(" ", "%20") + " #club_table", init);
} }
searchbar_obj.keyup(function() { searchbar_obj.keyup(function() {

View File

@ -34,7 +34,7 @@
if (pattern === old_pattern || pattern === "") if (pattern === old_pattern || pattern === "")
return; return;
$("#user_table").load(location.href + "?search=" + pattern.replace(" ", "%20") + " #user_table", init); $("#user_table").load(location.pathname + "?search=" + pattern.replace(" ", "%20") + " #user_table", init);
} }
searchbar_obj.keyup(function() { searchbar_obj.keyup(function() {

View File

@ -56,9 +56,9 @@ SPDX-License-Identifier: GPL-2.0-or-later
<div class="card-body"> <div class="card-body">
<input class="form-control mx-auto d-block" type="text" id="source_note" placeholder="{% trans "Name or alias..." %}" /> <input class="form-control mx-auto d-block" type="text" id="source_note" placeholder="{% trans "Name or alias..." %}" />
<hr> <hr>
<button class="form-control mx-auto d-block btn btn-secondary" id="source_me"> <span class="form-control mx-auto d-block btn btn-secondary" id="source_me">
{% trans "I am the emitter" %} {% trans "I am the emitter" %}
</button> </span>
</div> </div>
</div> </div>
</div> </div>

View File

@ -5,18 +5,7 @@
{% block content %} {% block content %}
<div class="row justify-content-center mb-4"> <div class="row justify-content-center mb-4">
<div class="col-md-10 text-center"> <div class="col-md-10 text-center">
<h4>
{% trans "Search button" %}
</h4>
<input class="form-control mx-auto w-25" type="text" id="search_field" placeholder="{% trans "Name of the button..." %}"> <input class="form-control mx-auto w-25" type="text" id="search_field" placeholder="{% trans "Name of the button..." %}">
<div class="form-group">
<div id="div_active_only" class="form-check">
<label for="active_only" class="form-check-label">
<input type="checkbox" name="active_only" class="checkboxinput form-check-input" checked="" id="active_only">
{% trans "Display visible buttons only" %}
</label>
</div>
</div>
<hr> <hr>
<a class="btn btn-primary text-center my-1" href="{% url 'note:template_create' %}">{% trans "New button" %}</a> <a class="btn btn-primary text-center my-1" href="{% url 'note:template_create' %}">{% trans "New button" %}</a>
</div> </div>
@ -36,66 +25,39 @@
{% endblock %} {% endblock %}
{% block extrajavascript %} {% block extrajavascript %}
<script> <script type="text/javascript">
/* fonction appelée à la fin du timer */ $(document).ready(function() {
function getInfo() { let searchbar_obj = $("#search_field");
var asked = $("#search_field").val(); var timer_on = false;
/* on ne fait la requête que si on a au moins un caractère pour chercher */ var timer;
if (asked.length >= 1) {
$.getJSON("/api/note/transaction/template/?format=json&search=" + asked + ($("#active_only").is(":checked") ? "&display=true" : ""), function(buttons) {
console.log(buttons);
let selected_id = buttons.results.map((a => "#row-" + a.id));
console.log(".table-row " + selected_id.join());
$(".table-row " + selected_id.join()).removeClass('d-none');
$(".table-row").not(selected_id.join()).addClass('d-none');
});
}
else {
if ($("#active_only").is(":checked")) {
$('.table-success').removeClass('d-none');
$('.table-danger').addClass('d-none');
}
else {
// show everything
$('table tr').removeClass('d-none');
}
}
}
var timer; function reloadTable() {
var timer_on; let pattern = searchbar_obj.val();
/* Fontion appelée quand le texte change (délenche le timer) */ $("#buttons_table").load(location.pathname + "?search=" + pattern.replace(" ", "%20") + " #buttons_table");
function search_field_moved() {
if (timer_on) { // Si le timer a déjà été lancé, on réinitialise le compteur.
clearTimeout(timer);
timer = setTimeout(getInfo, 300);
} }
else { // Sinon, on le lance et on enregistre le fait qu'il tourne.
timer = setTimeout(getInfo, 300); searchbar_obj.keyup(function() {
if (timer_on)
clearTimeout(timer);
timer_on = true; timer_on = true;
} setTimeout(reloadTable, 0);
} });
});
// on click of button "delete" , call the API // on click of button "delete" , call the API
function delete_button(button_id) { function delete_button(button_id) {
$.ajax({ $.ajax({
url:"/api/note/transaction/template/"+button_id+"/", url:"/api/note/transaction/template/" + button_id + "/",
method:"DELETE", method:"DELETE",
headers: {"X-CSRFTOKEN": CSRF_TOKEN} headers: {"X-CSRFTOKEN": CSRF_TOKEN}
}) })
.done(function(){ .done(function() {
addMsg('{% trans "button successfully deleted "%}','success'); addMsg('{% trans "button successfully deleted "%}','success');
$("#buttons_table").load("{% url 'note:template_list' %} #buttons_table"); $("#buttons_table").load(location.pathname + "?search=" + $("#search_field").val().replace(" ", "%20") + " #buttons_table");
}) })
.fail(function(){ .fail(function() {
addMsg(' {% trans "Unable to delete button "%} #' + button_id,'danger' ) addMsg('{% trans "Unable to delete button "%} #' + button_id, 'danger')
}); });
} }
$(document).ready(function() {
$("#search_field").keyup(search_field_moved);
$("#active_only").change(search_field_moved);
search_field_moved();
});
</script> </script>
{% endblock %} {% endblock %}

View File

@ -32,7 +32,7 @@
if (pattern === old_pattern || pattern === "") if (pattern === old_pattern || pattern === "")
return; return;
$("#user_table").load(location.href + "?search=" + pattern.replace(" ", "%20") + " #user_table", init); $("#user_table").load(location.pathname + "?search=" + pattern.replace(" ", "%20") + " #user_table", init);
$(".table-row").click(function() { $(".table-row").click(function() {
window.document.location = $(this).data("href"); window.document.location = $(this).data("href");

View File

@ -4,9 +4,6 @@
{% block content %} {% block content %}
<div class="row justify-content-center mb-4"> <div class="row justify-content-center mb-4">
<div class="col-md-10 text-center"> <div class="col-md-10 text-center">
<h4>
{% trans "search WEI" %}
</h4>
<input class="form-control mx-auto w-25" type="text" onkeyup="search_field_moved()" id="search_field"/> <input class="form-control mx-auto w-25" type="text" onkeyup="search_field_moved()" id="search_field"/>
<hr> <hr>
<a class="btn btn-primary text-center my-4" href="{% url 'wei:wei_create' %}">{% trans "Create WEI" %}</a> <a class="btn btn-primary text-center my-4" href="{% url 'wei:wei_create' %}">{% trans "Create WEI" %}</a>