mirror of
				https://gitlab.crans.org/bde/nk20
				synced 2025-11-04 01:12:08 +01:00 
			
		
		
		
	Format code
This commit is contained in:
		@@ -5,6 +5,7 @@
 | 
				
			|||||||
from ..models import ActivityType, Activity, Guest
 | 
					from ..models import ActivityType, Activity, Guest
 | 
				
			||||||
from rest_framework import serializers
 | 
					from rest_framework import serializers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ActivityTypeSerializer(serializers.ModelSerializer):
 | 
					class ActivityTypeSerializer(serializers.ModelSerializer):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    REST API Serializer for Activity types.
 | 
					    REST API Serializer for Activity types.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,10 +17,13 @@ class UserSerializer(serializers.ModelSerializer):
 | 
				
			|||||||
    REST API Serializer for Users.
 | 
					    REST API Serializer for Users.
 | 
				
			||||||
    The djangorestframework plugin will analyse the model `User` and parse all fields in the API.
 | 
					    The djangorestframework plugin will analyse the model `User` and parse all fields in the API.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        model = User
 | 
					        model = User
 | 
				
			||||||
        exclude = ('password', 'groups', 'user_permissions',)
 | 
					        exclude = (
 | 
				
			||||||
 | 
					            'password',
 | 
				
			||||||
 | 
					            'groups',
 | 
				
			||||||
 | 
					            'user_permissions',
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UserViewSet(viewsets.ModelViewSet):
 | 
					class UserViewSet(viewsets.ModelViewSet):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@ from crispy_forms.layout import Layout, Submit
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
from .models import Club
 | 
					from .models import Club
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UserFilter(FilterSet):
 | 
					class UserFilter(FilterSet):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        model = User
 | 
					        model = User
 | 
				
			||||||
@@ -23,9 +24,13 @@ class UserFilter(FilterSet):
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UserFilterFormHelper(FormHelper):
 | 
					class UserFilterFormHelper(FormHelper):
 | 
				
			||||||
    form_method = 'GET'
 | 
					    form_method = 'GET'
 | 
				
			||||||
    layout = Layout(
 | 
					    layout = Layout(
 | 
				
			||||||
        'last_name','first_name','username','profile__section',
 | 
					        'last_name',
 | 
				
			||||||
 | 
					        'first_name',
 | 
				
			||||||
 | 
					        'username',
 | 
				
			||||||
 | 
					        'profile__section',
 | 
				
			||||||
        Submit('Submit', 'Apply Filter'),
 | 
					        Submit('Submit', 'Apply Filter'),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,12 +16,12 @@ from crispy_forms.bootstrap import InlineField, FormActions, StrictButton, Div,
 | 
				
			|||||||
from crispy_forms.layout import Layout
 | 
					from crispy_forms.layout import Layout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class SignUpForm(UserCreationForm):
 | 
					class SignUpForm(UserCreationForm):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        model = User
 | 
					        model = User
 | 
				
			||||||
        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.
 | 
				
			||||||
@@ -31,15 +31,18 @@ class ProfileForm(forms.ModelForm):
 | 
				
			|||||||
        fields = '__all__'
 | 
					        fields = '__all__'
 | 
				
			||||||
        exclude = ['user']
 | 
					        exclude = ['user']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClubForm(forms.ModelForm):
 | 
					class ClubForm(forms.ModelForm):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        model = Club
 | 
					        model = Club
 | 
				
			||||||
        fields = '__all__'
 | 
					        fields = '__all__'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AddMembersForm(forms.Form):
 | 
					class AddMembersForm(forms.Form):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        fields = ('', )
 | 
					        fields = ('', )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MembershipForm(forms.ModelForm):
 | 
					class MembershipForm(forms.ModelForm):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        model = Membership
 | 
					        model = Membership
 | 
				
			||||||
@@ -48,18 +51,24 @@ class MembershipForm(forms.ModelForm):
 | 
				
			|||||||
        # Quand des lettres sont tapées, une requête est envoyée sur l'API d'auto-complétion
 | 
					        # Quand des lettres sont tapées, une requête est envoyée sur l'API d'auto-complétion
 | 
				
			||||||
        # et récupère les noms d'utilisateur valides
 | 
					        # et récupère les noms d'utilisateur valides
 | 
				
			||||||
        widgets = {
 | 
					        widgets = {
 | 
				
			||||||
            'user': autocomplete.ModelSelect2(url='member:user_autocomplete',
 | 
					            'user':
 | 
				
			||||||
 | 
					            autocomplete.ModelSelect2(
 | 
				
			||||||
 | 
					                url='member:user_autocomplete',
 | 
				
			||||||
                attrs={
 | 
					                attrs={
 | 
				
			||||||
                    'data-placeholder': 'Nom ...',
 | 
					                    'data-placeholder': 'Nom ...',
 | 
				
			||||||
                    'data-minimum-input-length': 1,
 | 
					                    'data-minimum-input-length': 1,
 | 
				
			||||||
                                                     }),
 | 
					                },
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MemberFormSet = forms.modelformset_factory(Membership,
 | 
					MemberFormSet = forms.modelformset_factory(
 | 
				
			||||||
 | 
					    Membership,
 | 
				
			||||||
    form=MembershipForm,
 | 
					    form=MembershipForm,
 | 
				
			||||||
    extra=2,
 | 
					    extra=2,
 | 
				
			||||||
                                           can_delete=True)
 | 
					    can_delete=True,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FormSetHelper(FormHelper):
 | 
					class FormSetHelper(FormHelper):
 | 
				
			||||||
    def __init__(self, *args, **kwargs):
 | 
					    def __init__(self, *args, **kwargs):
 | 
				
			||||||
@@ -74,5 +83,4 @@ class FormSetHelper(FormHelper):
 | 
				
			|||||||
                Div('roles', css_class='col-sm-2'),
 | 
					                Div('roles', css_class='col-sm-2'),
 | 
				
			||||||
                Div('date_start', css_class='col-sm-2'),
 | 
					                Div('date_start', css_class='col-sm-2'),
 | 
				
			||||||
                css_class="row formset-row",
 | 
					                css_class="row formset-row",
 | 
				
			||||||
            )
 | 
					            ))
 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@ from django.dispatch import receiver
 | 
				
			|||||||
from django.utils.translation import gettext_lazy as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
from django.urls import reverse, reverse_lazy
 | 
					from django.urls import reverse, reverse_lazy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Profile(models.Model):
 | 
					class Profile(models.Model):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    An user profile
 | 
					    An user profile
 | 
				
			||||||
@@ -52,6 +53,7 @@ class Profile(models.Model):
 | 
				
			|||||||
    def get_absolute_url(self):
 | 
					    def get_absolute_url(self):
 | 
				
			||||||
        return reverse('user_detail', args=(self.pk, ))
 | 
					        return reverse('user_detail', args=(self.pk, ))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Club(models.Model):
 | 
					class Club(models.Model):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    A club is a group of people, whose membership is handle by their
 | 
					    A club is a group of people, whose membership is handle by their
 | 
				
			||||||
@@ -129,15 +131,15 @@ class Membership(models.Model):
 | 
				
			|||||||
    """
 | 
					    """
 | 
				
			||||||
    user = models.ForeignKey(
 | 
					    user = models.ForeignKey(
 | 
				
			||||||
        settings.AUTH_USER_MODEL,
 | 
					        settings.AUTH_USER_MODEL,
 | 
				
			||||||
        on_delete=models.PROTECT
 | 
					        on_delete=models.PROTECT,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    club = models.ForeignKey(
 | 
					    club = models.ForeignKey(
 | 
				
			||||||
        Club,
 | 
					        Club,
 | 
				
			||||||
        on_delete=models.PROTECT
 | 
					        on_delete=models.PROTECT,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    roles = models.ForeignKey(
 | 
					    roles = models.ForeignKey(
 | 
				
			||||||
        Role,
 | 
					        Role,
 | 
				
			||||||
        on_delete=models.PROTECT
 | 
					        on_delete=models.PROTECT,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    date_start = models.DateField(
 | 
					    date_start = models.DateField(
 | 
				
			||||||
        verbose_name=_('membership starts on'),
 | 
					        verbose_name=_('membership starts on'),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,3 @@
 | 
				
			|||||||
#!/usr/bin/env python
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# -*- mode: python; coding: utf-8 -*-
 | 
					# -*- mode: python; coding: utf-8 -*-
 | 
				
			||||||
# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
 | 
					# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay
 | 
				
			||||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
					# SPDX-License-Identifier: GPL-3.0-or-later
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,15 +5,20 @@ from .models import Club
 | 
				
			|||||||
from django.conf import settings
 | 
					from django.conf import settings
 | 
				
			||||||
from django.contrib.auth.models import User
 | 
					from django.contrib.auth.models import User
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClubTable(tables.Table):
 | 
					class ClubTable(tables.Table):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        attrs = {'class':'table table-bordered table-condensed table-striped table-hover'}
 | 
					        attrs = {
 | 
				
			||||||
 | 
					            'class':
 | 
				
			||||||
 | 
					            'table table-bordered table-condensed table-striped table-hover'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        model = Club
 | 
					        model = Club
 | 
				
			||||||
        template_name = 'django_tables2/bootstrap.html'
 | 
					        template_name = 'django_tables2/bootstrap.html'
 | 
				
			||||||
        fields = ('id', 'name', 'email')
 | 
					        fields = ('id', 'name', 'email')
 | 
				
			||||||
        row_attrs = {'class':'table-row',
 | 
					        row_attrs = {
 | 
				
			||||||
                     'data-href': lambda record: record.pk }
 | 
					            'class': 'table-row',
 | 
				
			||||||
 | 
					            'data-href': lambda record: record.pk
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UserTable(tables.Table):
 | 
					class UserTable(tables.Table):
 | 
				
			||||||
@@ -21,7 +26,10 @@ class UserTable(tables.Table):
 | 
				
			|||||||
    solde = tables.Column(accessor='note.balance')
 | 
					    solde = tables.Column(accessor='note.balance')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        attrs = {'class':'table table-bordered table-condensed table-striped table-hover'}
 | 
					        attrs = {
 | 
				
			||||||
 | 
					            'class':
 | 
				
			||||||
 | 
					            'table table-bordered table-condensed table-striped table-hover'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        template_name = 'django_tables2/bootstrap.html'
 | 
					        template_name = 'django_tables2/bootstrap.html'
 | 
				
			||||||
        fields = ('last_name', 'first_name', 'username', 'email')
 | 
					        fields = ('last_name', 'first_name', 'username', 'email')
 | 
				
			||||||
        model = User
 | 
					        model = User
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,10 +20,10 @@ from .forms import  SignUpForm, ProfileForm, ClubForm,MembershipForm, MemberForm
 | 
				
			|||||||
from .tables import ClubTable, UserTable
 | 
					from .tables import ClubTable, UserTable
 | 
				
			||||||
from .filters import UserFilter, UserFilterFormHelper
 | 
					from .filters import UserFilter, UserFilterFormHelper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
from note.models.transactions import Transaction
 | 
					from note.models.transactions import Transaction
 | 
				
			||||||
from note.tables import HistoryTable
 | 
					from note.tables import HistoryTable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UserCreateView(CreateView):
 | 
					class UserCreateView(CreateView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Une vue pour inscrire un utilisateur et lui créer un profile
 | 
					    Une vue pour inscrire un utilisateur et lui créer un profile
 | 
				
			||||||
@@ -49,17 +49,20 @@ class UserCreateView(CreateView):
 | 
				
			|||||||
            profile.save()
 | 
					            profile.save()
 | 
				
			||||||
        return super().form_valid(form)
 | 
					        return super().form_valid(form)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UserUpdateView(LoginRequiredMixin, UpdateView):
 | 
					class UserUpdateView(LoginRequiredMixin, UpdateView):
 | 
				
			||||||
    model = User
 | 
					    model = User
 | 
				
			||||||
    fields = ['first_name', 'last_name', 'username', 'email']
 | 
					    fields = ['first_name', 'last_name', 'username', 'email']
 | 
				
			||||||
    template_name = 'member/profile_update.html'
 | 
					    template_name = 'member/profile_update.html'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    second_form = ProfileForm
 | 
					    second_form = ProfileForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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['user_modified'] = context['user']
 | 
					        context['user_modified'] = context['user']
 | 
				
			||||||
        context['user'] = self.request.user
 | 
					        context['user'] = self.request.user
 | 
				
			||||||
        context["profile_form"] = self.second_form(instance=context['user_modified'].profile)
 | 
					        context["profile_form"] = self.second_form(
 | 
				
			||||||
 | 
					            instance=context['user_modified'].profile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return context
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -71,21 +74,26 @@ class UserUpdateView(LoginRequiredMixin,UpdateView):
 | 
				
			|||||||
        new_username = form.data['username']
 | 
					        new_username = form.data['username']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Si l'utilisateur cherche à modifier son pseudo, le nouveau pseudo ne doit pas être proche d'un alias existant
 | 
					        # Si l'utilisateur cherche à modifier son pseudo, le nouveau pseudo ne doit pas être proche d'un alias existant
 | 
				
			||||||
        note = NoteUser.objects.filter(alias__normalized_name=Alias.normalize(new_username))
 | 
					        note = NoteUser.objects.filter(
 | 
				
			||||||
 | 
					            alias__normalized_name=Alias.normalize(new_username))
 | 
				
			||||||
        if note.exists() and note.get().user != self.request.user:
 | 
					        if note.exists() and note.get().user != self.request.user:
 | 
				
			||||||
            form.add_error('username', _("An alias with a similar name already exists."))
 | 
					            form.add_error('username',
 | 
				
			||||||
 | 
					                           _("An alias with a similar name already exists."))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return form
 | 
					        return form
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def form_valid(self, form):
 | 
					    def form_valid(self, form):
 | 
				
			||||||
        profile_form = ProfileForm(data=self.request.POST,instance=self.request.user.profile)
 | 
					        profile_form = ProfileForm(
 | 
				
			||||||
 | 
					            data=self.request.POST,
 | 
				
			||||||
 | 
					            instance=self.request.user.profile,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        if form.is_valid() and profile_form.is_valid():
 | 
					        if form.is_valid() and profile_form.is_valid():
 | 
				
			||||||
            new_username = form.data['username']
 | 
					            new_username = form.data['username']
 | 
				
			||||||
            alias = Alias.objects.filter(name=new_username)
 | 
					            alias = Alias.objects.filter(name=new_username)
 | 
				
			||||||
            # Si le nouveau pseudo n'est pas un de nos alias, on supprime éventuellement un alias similaire pour le remplacer
 | 
					            # Si le nouveau pseudo n'est pas un de nos alias, on supprime éventuellement un alias similaire pour le remplacer
 | 
				
			||||||
            if not alias.exists():
 | 
					            if not alias.exists():
 | 
				
			||||||
                similar = Alias.objects.filter(normalized_name=Alias.normalize(new_username))
 | 
					                similar = Alias.objects.filter(
 | 
				
			||||||
 | 
					                    normalized_name=Alias.normalize(new_username))
 | 
				
			||||||
                if similar.exists():
 | 
					                if similar.exists():
 | 
				
			||||||
                    similar.delete()
 | 
					                    similar.delete()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -98,17 +106,20 @@ class UserUpdateView(LoginRequiredMixin,UpdateView):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def get_success_url(self, **kwargs):
 | 
					    def get_success_url(self, **kwargs):
 | 
				
			||||||
        if kwargs:
 | 
					        if kwargs:
 | 
				
			||||||
            return reverse_lazy('member:user_detail', kwargs = {'pk': kwargs['id']})
 | 
					            return reverse_lazy('member:user_detail',
 | 
				
			||||||
 | 
					                                kwargs={'pk': kwargs['id']})
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            return reverse_lazy('member:user_detail', args=(self.object.id, ))
 | 
					            return reverse_lazy('member:user_detail', args=(self.object.id, ))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UserDetailView(LoginRequiredMixin, DetailView):
 | 
					class UserDetailView(LoginRequiredMixin, DetailView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Affiche les informations sur un utilisateur, sa note, ses clubs ...
 | 
					    Affiche les informations sur un utilisateur, sa note, ses clubs ...
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    model = Profile
 | 
					    model = Profile
 | 
				
			||||||
    context_object_name = "profile"
 | 
					    context_object_name = "profile"
 | 
				
			||||||
    def get_context_data(slef,**kwargs):
 | 
					
 | 
				
			||||||
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        context = super().get_context_data(**kwargs)
 | 
					        context = super().get_context_data(**kwargs)
 | 
				
			||||||
        user = context['profile'].user
 | 
					        user = context['profile'].user
 | 
				
			||||||
        history_list = \
 | 
					        history_list = \
 | 
				
			||||||
@@ -119,6 +130,7 @@ class UserDetailView(LoginRequiredMixin,DetailView):
 | 
				
			|||||||
        context['club_list'] = ClubTable(club_list)
 | 
					        context['club_list'] = ClubTable(club_list)
 | 
				
			||||||
        return context
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UserListView(LoginRequiredMixin, SingleTableView):
 | 
					class UserListView(LoginRequiredMixin, SingleTableView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Affiche la liste des utilisateurs, avec une fonction de recherche statique
 | 
					    Affiche la liste des utilisateurs, avec une fonction de recherche statique
 | 
				
			||||||
@@ -149,22 +161,25 @@ class ManageAuthTokens(LoginRequiredMixin, TemplateView):
 | 
				
			|||||||
    template_name = "member/manage_auth_tokens.html"
 | 
					    template_name = "member/manage_auth_tokens.html"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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():
 | 
				
			||||||
            Token.objects.get(user=self.request.user).delete()
 | 
					            Token.objects.get(user=self.request.user).delete()
 | 
				
			||||||
            return redirect(reverse_lazy('member:auth_token') + "?show", permanent=True)
 | 
					            return redirect(reverse_lazy('member:auth_token') + "?show",
 | 
				
			||||||
 | 
					                            permanent=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return super().get(request, *args, **kwargs)
 | 
					        return super().get(request, *args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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['token'] = Token.objects.get_or_create(user=self.request.user)[0]
 | 
					        context['token'] = Token.objects.get_or_create(
 | 
				
			||||||
 | 
					            user=self.request.user)[0]
 | 
				
			||||||
        return context
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UserAutocomplete(autocomplete.Select2QuerySetView):
 | 
					class UserAutocomplete(autocomplete.Select2QuerySetView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Auto complete users by usernames
 | 
					    Auto complete users by usernames
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_queryset(self):
 | 
					    def get_queryset(self):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Quand une personne cherche un utilisateur par pseudo, une requête est envoyée sur l'API dédiée à l'auto-complétion.
 | 
					        Quand une personne cherche un utilisateur par pseudo, une requête est envoyée sur l'API dédiée à l'auto-complétion.
 | 
				
			||||||
@@ -181,10 +196,12 @@ class UserAutocomplete(autocomplete.Select2QuerySetView):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return qs
 | 
					        return qs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
###################################
 | 
					###################################
 | 
				
			||||||
############## CLUB ###############
 | 
					############## CLUB ###############
 | 
				
			||||||
###################################
 | 
					###################################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClubCreateView(LoginRequiredMixin, CreateView):
 | 
					class ClubCreateView(LoginRequiredMixin, CreateView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Create Club
 | 
					    Create Club
 | 
				
			||||||
@@ -195,6 +212,7 @@ class ClubCreateView(LoginRequiredMixin,CreateView):
 | 
				
			|||||||
    def form_valid(self, form):
 | 
					    def form_valid(self, form):
 | 
				
			||||||
        return super().form_valid(form)
 | 
					        return super().form_valid(form)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClubListView(LoginRequiredMixin, SingleTableView):
 | 
					class ClubListView(LoginRequiredMixin, SingleTableView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    List existing Clubs
 | 
					    List existing Clubs
 | 
				
			||||||
@@ -202,6 +220,7 @@ class ClubListView(LoginRequiredMixin,SingleTableView):
 | 
				
			|||||||
    model = Club
 | 
					    model = Club
 | 
				
			||||||
    table_class = ClubTable
 | 
					    table_class = ClubTable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClubDetailView(LoginRequiredMixin, DetailView):
 | 
					class ClubDetailView(LoginRequiredMixin, DetailView):
 | 
				
			||||||
    model = Club
 | 
					    model = Club
 | 
				
			||||||
    context_object_name = "club"
 | 
					    context_object_name = "club"
 | 
				
			||||||
@@ -218,10 +237,12 @@ class ClubDetailView(LoginRequiredMixin,DetailView):
 | 
				
			|||||||
        context['member_list'] = club_member
 | 
					        context['member_list'] = club_member
 | 
				
			||||||
        return context
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClubAddMemberView(LoginRequiredMixin, CreateView):
 | 
					class ClubAddMemberView(LoginRequiredMixin, CreateView):
 | 
				
			||||||
    model = Membership
 | 
					    model = Membership
 | 
				
			||||||
    form_class = MembershipForm
 | 
					    form_class = MembershipForm
 | 
				
			||||||
    template_name = 'member/add_members.html'
 | 
					    template_name = 'member/add_members.html'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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['formset'] = MemberFormSet()
 | 
					        context['formset'] = MemberFormSet()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,7 +25,10 @@ class NoteAdmin(PolymorphicParentModelAdmin):
 | 
				
			|||||||
    Parent regrouping all note types as children
 | 
					    Parent regrouping all note types as children
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    child_models = (NoteClub, NoteSpecial, NoteUser)
 | 
					    child_models = (NoteClub, NoteSpecial, NoteUser)
 | 
				
			||||||
    list_filter = (PolymorphicChildModelFilter, 'is_active',)
 | 
					    list_filter = (
 | 
				
			||||||
 | 
					        PolymorphicChildModelFilter,
 | 
				
			||||||
 | 
					        'is_active',
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Use a polymorphic list
 | 
					    # Use a polymorphic list
 | 
				
			||||||
    list_display = ('pretty', 'balance', 'is_active')
 | 
					    list_display = ('pretty', 'balance', 'is_active')
 | 
				
			||||||
@@ -49,6 +52,7 @@ class NoteClubAdmin(PolymorphicChildModelAdmin):
 | 
				
			|||||||
    # We can't change club after creation or the balance
 | 
					    # We can't change club after creation or the balance
 | 
				
			||||||
    readonly_fields = ('club', 'balance')
 | 
					    readonly_fields = ('club', 'balance')
 | 
				
			||||||
    search_fields = ('club', )
 | 
					    search_fields = ('club', )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def has_add_permission(self, request):
 | 
					    def has_add_permission(self, request):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        A club note should not be manually added
 | 
					        A club note should not be manually added
 | 
				
			||||||
@@ -101,7 +105,10 @@ class TransactionAdmin(admin.ModelAdmin):
 | 
				
			|||||||
    list_display = ('created_at', 'poly_source', 'poly_destination',
 | 
					    list_display = ('created_at', 'poly_source', 'poly_destination',
 | 
				
			||||||
                    'quantity', 'amount', 'transaction_type', 'valid')
 | 
					                    'quantity', 'amount', 'transaction_type', 'valid')
 | 
				
			||||||
    list_filter = ('transaction_type', 'valid')
 | 
					    list_filter = ('transaction_type', 'valid')
 | 
				
			||||||
    autocomplete_fields = ('source', 'destination',)
 | 
					    autocomplete_fields = (
 | 
				
			||||||
 | 
					        'source',
 | 
				
			||||||
 | 
					        'destination',
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def poly_source(self, obj):
 | 
					    def poly_source(self, obj):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,10 @@ class NoteSerializer(serializers.ModelSerializer):
 | 
				
			|||||||
        model = Note
 | 
					        model = Note
 | 
				
			||||||
        fields = '__all__'
 | 
					        fields = '__all__'
 | 
				
			||||||
        extra_kwargs = {
 | 
					        extra_kwargs = {
 | 
				
			||||||
            'url': {'view_name': 'project-detail', 'lookup_field': 'pk'},
 | 
					            'url': {
 | 
				
			||||||
 | 
					                'view_name': 'project-detail',
 | 
				
			||||||
 | 
					                'lookup_field': 'pk'
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -69,6 +72,7 @@ class NotePolymorphicSerializer(PolymorphicSerializer):
 | 
				
			|||||||
        NoteSpecial: NoteSpecialSerializer
 | 
					        NoteSpecial: NoteSpecialSerializer
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TransactionTemplateSerializer(serializers.ModelSerializer):
 | 
					class TransactionTemplateSerializer(serializers.ModelSerializer):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    REST API Serializer for Transaction templates.
 | 
					    REST API Serializer for Transaction templates.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -69,7 +69,9 @@ class NotePolymorphicViewSet(viewsets.ModelViewSet):
 | 
				
			|||||||
        queryset = Note.objects.all()
 | 
					        queryset = Note.objects.all()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        alias = self.request.query_params.get("alias", ".*")
 | 
					        alias = self.request.query_params.get("alias", ".*")
 | 
				
			||||||
        queryset = queryset.filter(Q(alias__name__regex=alias) | Q(alias__normalized_name__regex=alias.lower()))
 | 
					        queryset = queryset.filter(
 | 
				
			||||||
 | 
					            Q(alias__name__regex=alias)
 | 
				
			||||||
 | 
					            | Q(alias__normalized_name__regex=alias.lower()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        note_type = self.request.query_params.get("type", None)
 | 
					        note_type = self.request.query_params.get("type", None)
 | 
				
			||||||
        if note_type:
 | 
					        if note_type:
 | 
				
			||||||
@@ -79,7 +81,8 @@ class NotePolymorphicViewSet(viewsets.ModelViewSet):
 | 
				
			|||||||
            elif "club" in l:
 | 
					            elif "club" in l:
 | 
				
			||||||
                queryset = queryset.filter(polymorphic_ctype__model="noteclub")
 | 
					                queryset = queryset.filter(polymorphic_ctype__model="noteclub")
 | 
				
			||||||
            elif "special" in l:
 | 
					            elif "special" in l:
 | 
				
			||||||
                queryset = queryset.filter(polymorphic_ctype__model="notespecial")
 | 
					                queryset = queryset.filter(
 | 
				
			||||||
 | 
					                    polymorphic_ctype__model="notespecial")
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                queryset = queryset.none()
 | 
					                queryset = queryset.none()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -104,7 +107,8 @@ class AliasViewSet(viewsets.ModelViewSet):
 | 
				
			|||||||
        queryset = Alias.objects.all()
 | 
					        queryset = Alias.objects.all()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        alias = self.request.query_params.get("alias", ".*")
 | 
					        alias = self.request.query_params.get("alias", ".*")
 | 
				
			||||||
        queryset = queryset.filter(Q(name__regex=alias) | Q(normalized_name__regex=alias.lower()))
 | 
					        queryset = queryset.filter(
 | 
				
			||||||
 | 
					            Q(name__regex=alias) | Q(normalized_name__regex=alias.lower()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        note_id = self.request.query_params.get("note", None)
 | 
					        note_id = self.request.query_params.get("note", None)
 | 
				
			||||||
        if note_id:
 | 
					        if note_id:
 | 
				
			||||||
@@ -114,11 +118,14 @@ class AliasViewSet(viewsets.ModelViewSet):
 | 
				
			|||||||
        if note_type:
 | 
					        if note_type:
 | 
				
			||||||
            l = str(note_type).lower()
 | 
					            l = str(note_type).lower()
 | 
				
			||||||
            if "user" in l:
 | 
					            if "user" in l:
 | 
				
			||||||
                queryset = queryset.filter(note__polymorphic_ctype__model="noteuser")
 | 
					                queryset = queryset.filter(
 | 
				
			||||||
 | 
					                    note__polymorphic_ctype__model="noteuser")
 | 
				
			||||||
            elif "club" in l:
 | 
					            elif "club" in l:
 | 
				
			||||||
                queryset = queryset.filter(note__polymorphic_ctype__model="noteclub")
 | 
					                queryset = queryset.filter(
 | 
				
			||||||
 | 
					                    note__polymorphic_ctype__model="noteclub")
 | 
				
			||||||
            elif "special" in l:
 | 
					            elif "special" in l:
 | 
				
			||||||
                queryset = queryset.filter(note__polymorphic_ctype__model="notespecial")
 | 
					                queryset = queryset.filter(
 | 
				
			||||||
 | 
					                    note__polymorphic_ctype__model="notespecial")
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                queryset = queryset.none()
 | 
					                queryset = queryset.none()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,9 +20,9 @@ class NoteConfig(AppConfig):
 | 
				
			|||||||
        """
 | 
					        """
 | 
				
			||||||
        post_save.connect(
 | 
					        post_save.connect(
 | 
				
			||||||
            signals.save_user_note,
 | 
					            signals.save_user_note,
 | 
				
			||||||
            sender=settings.AUTH_USER_MODEL
 | 
					            sender=settings.AUTH_USER_MODEL,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        post_save.connect(
 | 
					        post_save.connect(
 | 
				
			||||||
            signals.save_club_note,
 | 
					            signals.save_club_note,
 | 
				
			||||||
            sender='member.Club'
 | 
					            sender='member.Club',
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@ from dal import autocomplete, forward
 | 
				
			|||||||
from django import forms
 | 
					from django import forms
 | 
				
			||||||
from .models import Transaction, TransactionTemplate
 | 
					from .models import Transaction, TransactionTemplate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TransactionTemplateForm(forms.ModelForm):
 | 
					class TransactionTemplateForm(forms.ModelForm):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        model = TransactionTemplate
 | 
					        model = TransactionTemplate
 | 
				
			||||||
@@ -15,11 +16,14 @@ class TransactionTemplateForm(forms.ModelForm):
 | 
				
			|||||||
        # Pour force le type d'une note, il faut rajouter le paramètre :
 | 
					        # Pour force le type d'une note, il faut rajouter le paramètre :
 | 
				
			||||||
        # forward=(forward.Const('TYPE', 'note_type') où TYPE est dans {user, club, special}
 | 
					        # forward=(forward.Const('TYPE', 'note_type') où TYPE est dans {user, club, special}
 | 
				
			||||||
        widgets = {
 | 
					        widgets = {
 | 
				
			||||||
            'destination': autocomplete.ModelSelect2(url='note:note_autocomplete',
 | 
					            'destination':
 | 
				
			||||||
 | 
					            autocomplete.ModelSelect2(
 | 
				
			||||||
 | 
					                url='note:note_autocomplete',
 | 
				
			||||||
                attrs={
 | 
					                attrs={
 | 
				
			||||||
                    'data-placeholder': 'Note ...',
 | 
					                    'data-placeholder': 'Note ...',
 | 
				
			||||||
                    'data-minimum-input-length': 1,
 | 
					                    'data-minimum-input-length': 1,
 | 
				
			||||||
                                                     }),
 | 
					                },
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -31,26 +35,38 @@ class TransactionForm(forms.ModelForm):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        model = Transaction
 | 
					        model = Transaction
 | 
				
			||||||
        fields = ('source', 'destination', 'reason', 'amount',)
 | 
					        fields = (
 | 
				
			||||||
 | 
					            'source',
 | 
				
			||||||
 | 
					            'destination',
 | 
				
			||||||
 | 
					            'reason',
 | 
				
			||||||
 | 
					            'amount',
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Voir ci-dessus
 | 
					        # Voir ci-dessus
 | 
				
			||||||
        widgets = {
 | 
					        widgets = {
 | 
				
			||||||
            'source': autocomplete.ModelSelect2(url='note:note_autocomplete',
 | 
					            'source':
 | 
				
			||||||
 | 
					            autocomplete.ModelSelect2(
 | 
				
			||||||
 | 
					                url='note:note_autocomplete',
 | 
				
			||||||
                attrs={
 | 
					                attrs={
 | 
				
			||||||
                    'data-placeholder': 'Note ...',
 | 
					                    'data-placeholder': 'Note ...',
 | 
				
			||||||
                    'data-minimum-input-length': 1,
 | 
					                    'data-minimum-input-length': 1,
 | 
				
			||||||
                                                     },),
 | 
					                },
 | 
				
			||||||
            'destination': autocomplete.ModelSelect2(url='note:note_autocomplete',
 | 
					            ),
 | 
				
			||||||
 | 
					            'destination':
 | 
				
			||||||
 | 
					            autocomplete.ModelSelect2(
 | 
				
			||||||
 | 
					                url='note:note_autocomplete',
 | 
				
			||||||
                attrs={
 | 
					                attrs={
 | 
				
			||||||
                    'data-placeholder': 'Note ...',
 | 
					                    'data-placeholder': 'Note ...',
 | 
				
			||||||
                    'data-minimum-input-length': 1,
 | 
					                    'data-minimum-input-length': 1,
 | 
				
			||||||
                                                     },),
 | 
					                },
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ConsoForm(forms.ModelForm):
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ConsoForm(forms.ModelForm):
 | 
				
			||||||
    def save(self, commit=True):
 | 
					    def save(self, commit=True):
 | 
				
			||||||
        button: TransactionTemplate = TransactionTemplate.objects.filter(name=self.data['button']).get()
 | 
					        button: TransactionTemplate = TransactionTemplate.objects.filter(
 | 
				
			||||||
 | 
					            name=self.data['button']).get()
 | 
				
			||||||
        self.instance.destination = button.destination
 | 
					        self.instance.destination = button.destination
 | 
				
			||||||
        self.instance.amount = button.amount
 | 
					        self.instance.amount = button.amount
 | 
				
			||||||
        self.instance.transaction_type = 'bouton'
 | 
					        self.instance.transaction_type = 'bouton'
 | 
				
			||||||
@@ -65,9 +81,12 @@ class ConsoForm(forms.ModelForm):
 | 
				
			|||||||
        # Quand des lettres sont tapées, une requête est envoyée sur l'API d'auto-complétion
 | 
					        # Quand des lettres sont tapées, une requête est envoyée sur l'API d'auto-complétion
 | 
				
			||||||
        # et récupère les aliases de note valides
 | 
					        # et récupère les aliases de note valides
 | 
				
			||||||
        widgets = {
 | 
					        widgets = {
 | 
				
			||||||
            'source': autocomplete.ModelSelect2(url='note:note_autocomplete',
 | 
					            'source':
 | 
				
			||||||
 | 
					            autocomplete.ModelSelect2(
 | 
				
			||||||
 | 
					                url='note:note_autocomplete',
 | 
				
			||||||
                attrs={
 | 
					                attrs={
 | 
				
			||||||
                    'data-placeholder': 'Note ...',
 | 
					                    'data-placeholder': 'Note ...',
 | 
				
			||||||
                    'data-minimum-input-length': 1,
 | 
					                    'data-minimum-input-length': 1,
 | 
				
			||||||
                                                }),
 | 
					                },
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,6 @@ from django.core.validators import RegexValidator
 | 
				
			|||||||
from django.db import models
 | 
					from django.db import models
 | 
				
			||||||
from django.utils.translation import gettext_lazy as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
from polymorphic.models import PolymorphicModel
 | 
					from polymorphic.models import PolymorphicModel
 | 
				
			||||||
 | 
					 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
Defines each note types
 | 
					Defines each note types
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
@@ -34,8 +33,7 @@ class Note(PolymorphicModel):
 | 
				
			|||||||
        default=True,
 | 
					        default=True,
 | 
				
			||||||
        help_text=_(
 | 
					        help_text=_(
 | 
				
			||||||
            'Designates whether this note should be treated as active. '
 | 
					            'Designates whether this note should be treated as active. '
 | 
				
			||||||
            'Unselect this instead of deleting notes.'
 | 
					            'Unselect this instead of deleting notes.'),
 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    display_image = models.ImageField(
 | 
					    display_image = models.ImageField(
 | 
				
			||||||
        verbose_name=_('display image'),
 | 
					        verbose_name=_('display image'),
 | 
				
			||||||
@@ -85,7 +83,8 @@ class Note(PolymorphicModel):
 | 
				
			|||||||
        """
 | 
					        """
 | 
				
			||||||
        Verify alias (simulate save)
 | 
					        Verify alias (simulate save)
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        aliases = Alias.objects.filter(normalized_name=Alias.normalize(str(self)))
 | 
					        aliases = Alias.objects.filter(
 | 
				
			||||||
 | 
					            normalized_name=Alias.normalize(str(self)))
 | 
				
			||||||
        if aliases.exists():
 | 
					        if aliases.exists():
 | 
				
			||||||
            # Alias exists, so check if it is linked to this note
 | 
					            # Alias exists, so check if it is linked to this note
 | 
				
			||||||
            if aliases.first().note != self:
 | 
					            if aliases.first().note != self:
 | 
				
			||||||
@@ -181,15 +180,15 @@ class Alias(models.Model):
 | 
				
			|||||||
        validators=[
 | 
					        validators=[
 | 
				
			||||||
            RegexValidator(
 | 
					            RegexValidator(
 | 
				
			||||||
                regex=settings.ALIAS_VALIDATOR_REGEX,
 | 
					                regex=settings.ALIAS_VALIDATOR_REGEX,
 | 
				
			||||||
                message=_('Invalid alias')
 | 
					                message=_('Invalid alias'),
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        ] if settings.ALIAS_VALIDATOR_REGEX else []
 | 
					        ] if settings.ALIAS_VALIDATOR_REGEX else [],
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    normalized_name = models.CharField(
 | 
					    normalized_name = models.CharField(
 | 
				
			||||||
        max_length=255,
 | 
					        max_length=255,
 | 
				
			||||||
        unique=True,
 | 
					        unique=True,
 | 
				
			||||||
        default='',
 | 
					        default='',
 | 
				
			||||||
        editable=False
 | 
					        editable=False,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    note = models.ForeignKey(
 | 
					    note = models.ForeignKey(
 | 
				
			||||||
        Note,
 | 
					        Note,
 | 
				
			||||||
@@ -209,11 +208,9 @@ class Alias(models.Model):
 | 
				
			|||||||
        Normalizes a string: removes most diacritics and does casefolding
 | 
					        Normalizes a string: removes most diacritics and does casefolding
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        return ''.join(
 | 
					        return ''.join(
 | 
				
			||||||
            char
 | 
					            char for char in unicodedata.normalize('NFKD', string.casefold())
 | 
				
			||||||
            for char in unicodedata.normalize('NFKD', string.casefold())
 | 
					 | 
				
			||||||
            if all(not unicodedata.category(char).startswith(cat)
 | 
					            if all(not unicodedata.category(char).startswith(cat)
 | 
				
			||||||
                   for cat in {'M', 'P', 'Z', 'C'})
 | 
					                   for cat in {'M', 'P', 'Z', 'C'})).casefold()
 | 
				
			||||||
        ).casefold()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def save(self, *args, **kwargs):
 | 
					    def save(self, *args, **kwargs):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
@@ -229,7 +226,8 @@ class Alias(models.Model):
 | 
				
			|||||||
            raise ValidationError(_('Alias too long.'))
 | 
					            raise ValidationError(_('Alias too long.'))
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            if self != Alias.objects.get(normalized_name=normalized_name):
 | 
					            if self != Alias.objects.get(normalized_name=normalized_name):
 | 
				
			||||||
                raise ValidationError(_('An alias with a similar name '
 | 
					                raise ValidationError(
 | 
				
			||||||
 | 
					                    _('An alias with a similar name '
 | 
				
			||||||
                      'already exists.'))
 | 
					                      'already exists.'))
 | 
				
			||||||
        except Alias.DoesNotExist:
 | 
					        except Alias.DoesNotExist:
 | 
				
			||||||
            pass
 | 
					            pass
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,10 @@ from .models.transactions import Transaction
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class HistoryTable(tables.Table):
 | 
					class HistoryTable(tables.Table):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        attrs = {'class':'table table-bordered table-condensed table-striped table-hover'}
 | 
					        attrs = {
 | 
				
			||||||
 | 
					            'class':
 | 
				
			||||||
 | 
					            'table table-bordered table-condensed table-striped table-hover'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        model = Transaction
 | 
					        model = Transaction
 | 
				
			||||||
        template_name = 'django_tables2/bootstrap.html'
 | 
					        template_name = 'django_tables2/bootstrap.html'
 | 
				
			||||||
        sequence = ('...', 'total', 'valid')
 | 
					        sequence = ('...', 'total', 'valid')
 | 
				
			||||||
@@ -17,6 +20,6 @@ class HistoryTable(tables.Table):
 | 
				
			|||||||
    def order_total(self, QuerySet, is_descending):
 | 
					    def order_total(self, QuerySet, is_descending):
 | 
				
			||||||
        # needed for rendering
 | 
					        # needed for rendering
 | 
				
			||||||
        QuerySet = QuerySet.annotate(
 | 
					        QuerySet = QuerySet.annotate(
 | 
				
			||||||
            total=F('amount') * F('quantity')
 | 
					            total=F('amount') *
 | 
				
			||||||
        ).order_by(('-' if is_descending else '') + 'total')
 | 
					            F('quantity')).order_by(('-' if is_descending else '') + 'total')
 | 
				
			||||||
        return (QuerySet, True)
 | 
					        return (QuerySet, True)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,9 +3,16 @@ from django import template
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
def pretty_money(value):
 | 
					def pretty_money(value):
 | 
				
			||||||
    if value % 100 == 0:
 | 
					    if value % 100 == 0:
 | 
				
			||||||
        return "{:s}{:d} €".format("- " if value < 0 else "", abs(value) // 100)
 | 
					        return "{:s}{:d} €".format(
 | 
				
			||||||
 | 
					            "- " if value < 0 else "",
 | 
				
			||||||
 | 
					            abs(value) // 100,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        return "{:s}{:d} € {:02d}".format("- " if value < 0 else "", abs(value) // 100, abs(value) % 100)
 | 
					        return "{:s}{:d} € {:02d}".format(
 | 
				
			||||||
 | 
					            "- " if value < 0 else "",
 | 
				
			||||||
 | 
					            abs(value) // 100,
 | 
				
			||||||
 | 
					            abs(value) % 100,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
register = template.Library()
 | 
					register = template.Library()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,7 @@ from django.views.generic import CreateView, ListView, DetailView, UpdateView
 | 
				
			|||||||
from .models import Note, Transaction, TransactionCategory, TransactionTemplate, Alias
 | 
					from .models import Note, Transaction, TransactionCategory, TransactionTemplate, Alias
 | 
				
			||||||
from .forms import TransactionForm, TransactionTemplateForm, ConsoForm
 | 
					from .forms import TransactionForm, TransactionTemplateForm, ConsoForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TransactionCreate(LoginRequiredMixin, CreateView):
 | 
					class TransactionCreate(LoginRequiredMixin, CreateView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Show transfer page
 | 
					    Show transfer page
 | 
				
			||||||
@@ -30,7 +31,6 @@ class TransactionCreate(LoginRequiredMixin, CreateView):
 | 
				
			|||||||
                             'to one or others')
 | 
					                             'to one or others')
 | 
				
			||||||
        return context
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_form(self, form_class=None):
 | 
					    def get_form(self, form_class=None):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        If the user has no right to transfer funds, then it won't have the choice of the source of the transfer.
 | 
					        If the user has no right to transfer funds, then it won't have the choice of the source of the transfer.
 | 
				
			||||||
@@ -56,7 +56,6 @@ class NoteAutocomplete(autocomplete.Select2QuerySetView):
 | 
				
			|||||||
    """
 | 
					    """
 | 
				
			||||||
    Auto complete note by aliases
 | 
					    Auto complete note by aliases
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_queryset(self):
 | 
					    def get_queryset(self):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Quand une personne cherche un alias, une requête est envoyée sur l'API dédiée à l'auto-complétion.
 | 
					        Quand une personne cherche un alias, une requête est envoyée sur l'API dédiée à l'auto-complétion.
 | 
				
			||||||
@@ -108,6 +107,7 @@ class TransactionTemplateCreateView(LoginRequiredMixin,CreateView):
 | 
				
			|||||||
    model = TransactionTemplate
 | 
					    model = TransactionTemplate
 | 
				
			||||||
    form_class = TransactionTemplateForm
 | 
					    form_class = TransactionTemplateForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TransactionTemplateListView(LoginRequiredMixin, ListView):
 | 
					class TransactionTemplateListView(LoginRequiredMixin, ListView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    List TransactionsTemplates
 | 
					    List TransactionsTemplates
 | 
				
			||||||
@@ -115,12 +115,14 @@ class TransactionTemplateListView(LoginRequiredMixin,ListView):
 | 
				
			|||||||
    model = TransactionTemplate
 | 
					    model = TransactionTemplate
 | 
				
			||||||
    form_class = TransactionTemplateForm
 | 
					    form_class = TransactionTemplateForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TransactionTemplateUpdateView(LoginRequiredMixin, UpdateView):
 | 
					class TransactionTemplateUpdateView(LoginRequiredMixin, UpdateView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    model = TransactionTemplate
 | 
					    model = TransactionTemplate
 | 
				
			||||||
    form_class = TransactionTemplateForm
 | 
					    form_class = TransactionTemplateForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ConsoView(LoginRequiredMixin, CreateView):
 | 
					class ConsoView(LoginRequiredMixin, CreateView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Consume
 | 
					    Consume
 | 
				
			||||||
@@ -139,11 +141,14 @@ class ConsoView(LoginRequiredMixin,CreateView):
 | 
				
			|||||||
        if 'template_type' not in self.kwargs.keys():
 | 
					        if 'template_type' not in self.kwargs.keys():
 | 
				
			||||||
            return context
 | 
					            return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        template_type = TransactionCategory.objects.filter(name=self.kwargs.get('template_type')).get()
 | 
					        template_type = TransactionCategory.objects.filter(
 | 
				
			||||||
        context['buttons'] = TransactionTemplate.objects.filter(template_type=template_type)
 | 
					            name=self.kwargs.get('template_type')).get()
 | 
				
			||||||
 | 
					        context['buttons'] = TransactionTemplate.objects.filter(
 | 
				
			||||||
 | 
					            template_type=template_type)
 | 
				
			||||||
        context['title'] = template_type
 | 
					        context['title'] = template_type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return context
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_success_url(self):
 | 
					    def get_success_url(self):
 | 
				
			||||||
        return reverse('note:consos',args=(self.kwargs.get('template_type'),))
 | 
					        return reverse('note:consos',
 | 
				
			||||||
 | 
					                       args=(self.kwargs.get('template_type'), ))
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user