mirror of
				https://gitlab.crans.org/bde/nk20
				synced 2025-11-03 08:58:47 +01:00 
			
		
		
		
	Improved permissions, 404 and 403 errors will be more frequent (when we type an invalid URL)
This commit is contained in:
		@@ -1,5 +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 datetime import datetime, timezone
 | 
					from datetime import datetime, timezone
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.contrib.auth.mixins import LoginRequiredMixin
 | 
					from django.contrib.auth.mixins import LoginRequiredMixin
 | 
				
			||||||
@@ -11,13 +12,14 @@ from django.utils.translation import gettext_lazy as _
 | 
				
			|||||||
from django_tables2.views import SingleTableView
 | 
					from django_tables2.views import SingleTableView
 | 
				
			||||||
from note.models import NoteUser, Alias, NoteSpecial
 | 
					from note.models import NoteUser, Alias, NoteSpecial
 | 
				
			||||||
from permission.backends import PermissionBackend
 | 
					from permission.backends import PermissionBackend
 | 
				
			||||||
 | 
					from permission.views import ProtectQuerysetMixin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .forms import ActivityForm, GuestForm
 | 
					from .forms import ActivityForm, GuestForm
 | 
				
			||||||
from .models import Activity, Guest, Entry
 | 
					from .models import Activity, Guest, Entry
 | 
				
			||||||
from .tables import ActivityTable, GuestTable, EntryTable
 | 
					from .tables import ActivityTable, GuestTable, EntryTable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ActivityCreateView(LoginRequiredMixin, CreateView):
 | 
					class ActivityCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
 | 
				
			||||||
    model = Activity
 | 
					    model = Activity
 | 
				
			||||||
    form_class = ActivityForm
 | 
					    form_class = ActivityForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -30,13 +32,12 @@ class ActivityCreateView(LoginRequiredMixin, CreateView):
 | 
				
			|||||||
        return reverse_lazy('activity:activity_detail', kwargs={"pk": self.object.pk})
 | 
					        return reverse_lazy('activity:activity_detail', kwargs={"pk": self.object.pk})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ActivityListView(LoginRequiredMixin, SingleTableView):
 | 
					class ActivityListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
 | 
				
			||||||
    model = Activity
 | 
					    model = Activity
 | 
				
			||||||
    table_class = ActivityTable
 | 
					    table_class = ActivityTable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_queryset(self):
 | 
					    def get_queryset(self):
 | 
				
			||||||
        return super().get_queryset()\
 | 
					        return super().get_queryset().reverse()
 | 
				
			||||||
            .filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view")).reverse()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        ctx = super().get_context_data(**kwargs)
 | 
					        ctx = super().get_context_data(**kwargs)
 | 
				
			||||||
@@ -50,7 +51,7 @@ class ActivityListView(LoginRequiredMixin, SingleTableView):
 | 
				
			|||||||
        return ctx
 | 
					        return ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ActivityDetailView(LoginRequiredMixin, DetailView):
 | 
					class ActivityDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
 | 
				
			||||||
    model = Activity
 | 
					    model = Activity
 | 
				
			||||||
    context_object_name = "activity"
 | 
					    context_object_name = "activity"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -66,7 +67,7 @@ class ActivityDetailView(LoginRequiredMixin, DetailView):
 | 
				
			|||||||
        return ctx
 | 
					        return ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ActivityUpdateView(LoginRequiredMixin, UpdateView):
 | 
					class ActivityUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
 | 
				
			||||||
    model = Activity
 | 
					    model = Activity
 | 
				
			||||||
    form_class = ActivityForm
 | 
					    form_class = ActivityForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -74,18 +75,20 @@ class ActivityUpdateView(LoginRequiredMixin, UpdateView):
 | 
				
			|||||||
        return reverse_lazy('activity:activity_detail', kwargs={"pk": self.kwargs["pk"]})
 | 
					        return reverse_lazy('activity:activity_detail', kwargs={"pk": self.kwargs["pk"]})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ActivityInviteView(LoginRequiredMixin, CreateView):
 | 
					class ActivityInviteView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
 | 
				
			||||||
    model = Guest
 | 
					    model = Guest
 | 
				
			||||||
    form_class = GuestForm
 | 
					    form_class = GuestForm
 | 
				
			||||||
    template_name = "activity/activity_invite.html"
 | 
					    template_name = "activity/activity_invite.html"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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.get(pk=self.kwargs["pk"])
 | 
					        form.activity = Activity.objects.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view"))\
 | 
				
			||||||
 | 
					            .get(pk=self.kwargs["pk"])
 | 
				
			||||||
        return form
 | 
					        return form
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def form_valid(self, form):
 | 
					    def form_valid(self, form):
 | 
				
			||||||
        form.instance.activity = Activity.objects.get(pk=self.kwargs["pk"])
 | 
					        form.instance.activity = Activity.objects\
 | 
				
			||||||
 | 
					            .filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view")).get(pk=self.kwargs["pk"])
 | 
				
			||||||
        return super().form_valid(form)
 | 
					        return super().form_valid(form)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_success_url(self, **kwargs):
 | 
					    def get_success_url(self, **kwargs):
 | 
				
			||||||
@@ -98,7 +101,8 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView):
 | 
				
			|||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        ctx = super().get_context_data(**kwargs)
 | 
					        ctx = super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        activity = Activity.objects.get(pk=self.kwargs["pk"])
 | 
					        activity = Activity.objects.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view"))\
 | 
				
			||||||
 | 
					            .get(pk=self.kwargs["pk"])
 | 
				
			||||||
        ctx["activity"] = activity
 | 
					        ctx["activity"] = activity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        matched = []
 | 
					        matched = []
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,7 +49,13 @@ class ClubForm(forms.ModelForm):
 | 
				
			|||||||
        model = Club
 | 
					        model = Club
 | 
				
			||||||
        fields = '__all__'
 | 
					        fields = '__all__'
 | 
				
			||||||
        widgets = {
 | 
					        widgets = {
 | 
				
			||||||
            "membership_fee": AmountInput()
 | 
					            "membership_fee": AmountInput(),
 | 
				
			||||||
 | 
					            "parent_club": Autocomplete(
 | 
				
			||||||
 | 
					                Club,
 | 
				
			||||||
 | 
					                attrs={
 | 
				
			||||||
 | 
					                    'api_url': '/api/members/club/',
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,6 +22,7 @@ from note.models.notes import NoteActivity
 | 
				
			|||||||
from note.models.transactions import Transaction
 | 
					from note.models.transactions import Transaction
 | 
				
			||||||
from note.tables import HistoryTable, AliasTable, NoteActivityTable
 | 
					from note.tables import HistoryTable, AliasTable, NoteActivityTable
 | 
				
			||||||
from permission.backends import PermissionBackend
 | 
					from permission.backends import PermissionBackend
 | 
				
			||||||
 | 
					from permission.views import ProtectQuerysetMixin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .filters import UserFilter, UserFilterFormHelper
 | 
					from .filters import UserFilter, UserFilterFormHelper
 | 
				
			||||||
from .forms import SignUpForm, ProfileForm, ClubForm, MembershipForm, MemberFormSet, FormSetHelper, \
 | 
					from .forms import SignUpForm, ProfileForm, ClubForm, MembershipForm, MemberFormSet, FormSetHelper, \
 | 
				
			||||||
@@ -64,7 +65,7 @@ class UserCreateView(CreateView):
 | 
				
			|||||||
        return super().form_valid(form)
 | 
					        return super().form_valid(form)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UserUpdateView(LoginRequiredMixin, UpdateView):
 | 
					class UserUpdateView(ProtectQuerysetMixin, 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'
 | 
				
			||||||
@@ -98,7 +99,8 @@ class UserUpdateView(LoginRequiredMixin, UpdateView):
 | 
				
			|||||||
        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(
 | 
					                similar = Alias.objects.filter(
 | 
				
			||||||
                    normalized_name=Alias.normalize(new_username))
 | 
					                    normalized_name=Alias.normalize(new_username))
 | 
				
			||||||
@@ -120,7 +122,7 @@ class UserUpdateView(LoginRequiredMixin, UpdateView):
 | 
				
			|||||||
            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(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Affiche les informations sur un utilisateur, sa note, ses clubs...
 | 
					    Affiche les informations sur un utilisateur, sa note, ses clubs...
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@@ -128,9 +130,6 @@ class UserDetailView(LoginRequiredMixin, DetailView):
 | 
				
			|||||||
    context_object_name = "user_object"
 | 
					    context_object_name = "user_object"
 | 
				
			||||||
    template_name = "member/profile_detail.html"
 | 
					    template_name = "member/profile_detail.html"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_queryset(self, **kwargs):
 | 
					 | 
				
			||||||
        return super().get_queryset().filter(PermissionBackend.filter_queryset(self.request.user, User, "view"))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        context = super().get_context_data(**kwargs)
 | 
					        context = super().get_context_data(**kwargs)
 | 
				
			||||||
        user = context['user_object']
 | 
					        user = context['user_object']
 | 
				
			||||||
@@ -138,13 +137,13 @@ class UserDetailView(LoginRequiredMixin, DetailView):
 | 
				
			|||||||
            Transaction.objects.all().filter(Q(source=user.note) | Q(destination=user.note)).order_by("-id")\
 | 
					            Transaction.objects.all().filter(Q(source=user.note) | Q(destination=user.note)).order_by("-id")\
 | 
				
			||||||
            .filter(PermissionBackend.filter_queryset(self.request.user, Transaction, "view"))
 | 
					            .filter(PermissionBackend.filter_queryset(self.request.user, Transaction, "view"))
 | 
				
			||||||
        context['history_list'] = HistoryTable(history_list)
 | 
					        context['history_list'] = HistoryTable(history_list)
 | 
				
			||||||
        club_list = \
 | 
					        club_list = Membership.objects.all().filter(user=user)\
 | 
				
			||||||
            Membership.objects.all().filter(user=user).only("club")
 | 
					            .filter(PermissionBackend.filter_queryset(self.request.user, Membership, "view")).only("club")
 | 
				
			||||||
        context['club_list'] = ClubTable(club_list)
 | 
					        context['club_list'] = ClubTable(club_list)
 | 
				
			||||||
        return context
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UserListView(LoginRequiredMixin, SingleTableView):
 | 
					class UserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Affiche la liste des utilisateurs, avec une fonction de recherche statique
 | 
					    Affiche la liste des utilisateurs, avec une fonction de recherche statique
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@@ -155,7 +154,7 @@ class UserListView(LoginRequiredMixin, SingleTableView):
 | 
				
			|||||||
    formhelper_class = UserFilterFormHelper
 | 
					    formhelper_class = UserFilterFormHelper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_queryset(self, **kwargs):
 | 
					    def get_queryset(self, **kwargs):
 | 
				
			||||||
        qs = super().get_queryset().filter(PermissionBackend.filter_queryset(self.request.user, User, "view"))
 | 
					        qs = super().get_queryset()
 | 
				
			||||||
        self.filter = self.filter_class(self.request.GET, queryset=qs)
 | 
					        self.filter = self.filter_class(self.request.GET, queryset=qs)
 | 
				
			||||||
        self.filter.form.helper = self.formhelper_class()
 | 
					        self.filter.form.helper = self.formhelper_class()
 | 
				
			||||||
        return self.filter.qs
 | 
					        return self.filter.qs
 | 
				
			||||||
@@ -166,7 +165,7 @@ class UserListView(LoginRequiredMixin, SingleTableView):
 | 
				
			|||||||
        return context
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ProfileAliasView(LoginRequiredMixin, DetailView):
 | 
					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'
 | 
				
			||||||
@@ -178,7 +177,7 @@ class ProfileAliasView(LoginRequiredMixin, DetailView):
 | 
				
			|||||||
        return context
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PictureUpdateView(LoginRequiredMixin, FormMixin, DetailView):
 | 
					class PictureUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin, DetailView):
 | 
				
			||||||
    form_class = ImageForm
 | 
					    form_class = ImageForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
@@ -239,8 +238,7 @@ 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(
 | 
					        if 'regenerate' in request.GET and Token.objects.filter(user=request.user).exists():
 | 
				
			||||||
                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",
 | 
					            return redirect(reverse_lazy('member:auth_token') + "?show",
 | 
				
			||||||
                            permanent=True)
 | 
					                            permanent=True)
 | 
				
			||||||
@@ -249,8 +247,7 @@ class ManageAuthTokens(LoginRequiredMixin, TemplateView):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    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(
 | 
					        context['token'] = Token.objects.get_or_create(user=self.request.user)[0]
 | 
				
			||||||
            user=self.request.user)[0]
 | 
					 | 
				
			||||||
        return context
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -259,7 +256,7 @@ class ManageAuthTokens(LoginRequiredMixin, TemplateView):
 | 
				
			|||||||
# ******************************* #
 | 
					# ******************************* #
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClubCreateView(LoginRequiredMixin, CreateView):
 | 
					class ClubCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Create Club
 | 
					    Create Club
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@@ -271,38 +268,32 @@ class ClubCreateView(LoginRequiredMixin, CreateView):
 | 
				
			|||||||
        return super().form_valid(form)
 | 
					        return super().form_valid(form)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClubListView(LoginRequiredMixin, SingleTableView):
 | 
					class ClubListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    List existing Clubs
 | 
					    List existing Clubs
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    model = Club
 | 
					    model = Club
 | 
				
			||||||
    table_class = ClubTable
 | 
					    table_class = ClubTable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_queryset(self, **kwargs):
 | 
					 | 
				
			||||||
        return super().get_queryset().filter(PermissionBackend.filter_queryset(self.request.user, Club, "view"))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ClubDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
 | 
				
			||||||
class ClubDetailView(LoginRequiredMixin, DetailView):
 | 
					 | 
				
			||||||
    model = Club
 | 
					    model = Club
 | 
				
			||||||
    context_object_name = "club"
 | 
					    context_object_name = "club"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_queryset(self, **kwargs):
 | 
					 | 
				
			||||||
        return super().get_queryset().filter(PermissionBackend.filter_queryset(self.request.user, Club, "view"))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        context = super().get_context_data(**kwargs)
 | 
					        context = super().get_context_data(**kwargs)
 | 
				
			||||||
        club = context["club"]
 | 
					        club = context["club"]
 | 
				
			||||||
        club_transactions = Transaction.objects.all().filter(Q(source=club.note) | Q(destination=club.note))\
 | 
					        club_transactions = Transaction.objects.all().filter(Q(source=club.note) | Q(destination=club.note))\
 | 
				
			||||||
            .filter(PermissionBackend.filter_queryset(self.request.user, Transaction, "view")).order_by('-id')
 | 
					            .filter(PermissionBackend.filter_queryset(self.request.user, Transaction, "view")).order_by('-id')
 | 
				
			||||||
        context['history_list'] = HistoryTable(club_transactions)
 | 
					        context['history_list'] = HistoryTable(club_transactions)
 | 
				
			||||||
        club_member = \
 | 
					        club_member = Membership.objects.filter(club=club)\
 | 
				
			||||||
            Membership.objects.all().filter(club=club)
 | 
					            .filter(PermissionBackend.filter_queryset(self.request.user, Membership, "view")).all()
 | 
				
			||||||
        # TODO: consider only valid Membership
 | 
					        # TODO: consider only valid Membership
 | 
				
			||||||
        context['member_list'] = club_member
 | 
					        context['member_list'] = club_member
 | 
				
			||||||
        return context
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClubAliasView(LoginRequiredMixin, DetailView):
 | 
					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'
 | 
				
			||||||
@@ -314,7 +305,7 @@ class ClubAliasView(LoginRequiredMixin, DetailView):
 | 
				
			|||||||
        return context
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClubUpdateView(LoginRequiredMixin, UpdateView):
 | 
					class ClubUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
 | 
				
			||||||
    model = Club
 | 
					    model = Club
 | 
				
			||||||
    context_object_name = "club"
 | 
					    context_object_name = "club"
 | 
				
			||||||
    form_class = ClubForm
 | 
					    form_class = ClubForm
 | 
				
			||||||
@@ -333,7 +324,7 @@ class ClubPictureUpdateView(PictureUpdateView):
 | 
				
			|||||||
        return reverse_lazy('member:club_detail', kwargs={'pk': self.object.id})
 | 
					        return reverse_lazy('member:club_detail', kwargs={'pk': self.object.id})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClubAddMemberView(LoginRequiredMixin, CreateView):
 | 
					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'
 | 
				
			||||||
@@ -344,7 +335,8 @@ class ClubAddMemberView(LoginRequiredMixin, CreateView):
 | 
				
			|||||||
                                                                                 "change"))
 | 
					                                                                                 "change"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        club = Club.objects.get(pk=self.kwargs["pk"])
 | 
					        club = Club.objects.filter(PermissionBackend.filter_queryset(self.request.user, Club, "view"))\
 | 
				
			||||||
 | 
					            .get(pk=self.kwargs["pk"])
 | 
				
			||||||
        context = super().get_context_data(**kwargs)
 | 
					        context = super().get_context_data(**kwargs)
 | 
				
			||||||
        context['formset'] = MemberFormSet()
 | 
					        context['formset'] = MemberFormSet()
 | 
				
			||||||
        context['helper'] = FormSetHelper()
 | 
					        context['helper'] = FormSetHelper()
 | 
				
			||||||
@@ -367,36 +359,40 @@ class ClubAddMemberView(LoginRequiredMixin, CreateView):
 | 
				
			|||||||
        return super().form_valid(formset)
 | 
					        return super().form_valid(formset)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClubLinkedNotesView(LoginRequiredMixin, SingleTableView):
 | 
					class ClubLinkedNotesView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
 | 
				
			||||||
    model = NoteActivity
 | 
					    model = NoteActivity
 | 
				
			||||||
    table_class = NoteActivityTable
 | 
					    table_class = NoteActivityTable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_queryset(self):
 | 
					    def get_queryset(self):
 | 
				
			||||||
        return super().get_queryset().filter(club=self.get_object())\
 | 
					        return super().get_queryset().filter(club=self.get_object())
 | 
				
			||||||
            .filter(PermissionBackend.filter_queryset(self.request.user, NoteActivity, "view"))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_object(self):
 | 
					    def get_object(self):
 | 
				
			||||||
        if hasattr(self, 'object'):
 | 
					        if hasattr(self, 'object'):
 | 
				
			||||||
            return self.object
 | 
					            return self.object
 | 
				
			||||||
        self.object = Club.objects.get(pk=int(self.kwargs["pk"]))
 | 
					        self.object = Club.objects.filter(PermissionBackend.filter_queryset(self.request.user, Club, "view"))\
 | 
				
			||||||
 | 
					            .get(pk=int(self.kwargs["pk"]))
 | 
				
			||||||
        return self.object
 | 
					        return self.object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        ctx = super().get_context_data(**kwargs)
 | 
					        ctx = super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ctx["object"] = ctx["club"] = self.get_object()
 | 
					        club = ctx["object"] = ctx["club"] = self.get_object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        empty_note = NoteActivity(note_name="", club=club, controller=self.request.user)
 | 
				
			||||||
 | 
					        ctx["can_create"] = PermissionBackend().has_perm(self.request.user, "note.add_noteactivity", empty_note)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return ctx
 | 
					        return ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClubLinkedNoteCreateView(LoginRequiredMixin, CreateView):
 | 
					class ClubLinkedNoteCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
 | 
				
			||||||
    model = NoteActivity
 | 
					    model = NoteActivity
 | 
				
			||||||
    form_class = NoteActivityForm
 | 
					    form_class = NoteActivityForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        ctx = super().get_context_data(**kwargs)
 | 
					        ctx = super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        club = Club.objects.get(pk=self.kwargs["club_pk"])
 | 
					        club = Club.objects.filter(PermissionBackend.filter_queryset(self.request.user, Club, "view"))\
 | 
				
			||||||
 | 
					            .get(pk=self.kwargs["club_pk"])
 | 
				
			||||||
        ctx["object"] = ctx["club"] = club
 | 
					        ctx["object"] = ctx["club"] = club
 | 
				
			||||||
        ctx["form"].fields["club"].initial = club
 | 
					        ctx["form"].fields["club"].initial = club
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -408,14 +404,15 @@ class ClubLinkedNoteCreateView(LoginRequiredMixin, CreateView):
 | 
				
			|||||||
                            kwargs={"club_pk": self.object.club.pk, "pk": self.object.pk})
 | 
					                            kwargs={"club_pk": self.object.club.pk, "pk": self.object.pk})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClubLinkedNoteUpdateView(LoginRequiredMixin, UpdateView):
 | 
					class ClubLinkedNoteUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
 | 
				
			||||||
    model = NoteActivity
 | 
					    model = NoteActivity
 | 
				
			||||||
    form_class = NoteActivityForm
 | 
					    form_class = NoteActivityForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        ctx = super().get_context_data(**kwargs)
 | 
					        ctx = super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ctx["club"] = Club.objects.get(pk=self.kwargs["club_pk"])
 | 
					        ctx["club"] = Club.objects.filter(PermissionBackend.filter_queryset(self.request.user, Club, "view"))\
 | 
				
			||||||
 | 
					            .get(pk=self.kwargs["club_pk"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return ctx
 | 
					        return ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -424,15 +421,15 @@ class ClubLinkedNoteUpdateView(LoginRequiredMixin, UpdateView):
 | 
				
			|||||||
                            kwargs={"club_pk": self.object.club.pk, "pk": self.object.pk})
 | 
					                            kwargs={"club_pk": self.object.club.pk, "pk": self.object.pk})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ClubLinkedNoteDetailView(LoginRequiredMixin, DetailView):
 | 
					class ClubLinkedNoteDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
 | 
				
			||||||
    model = NoteActivity
 | 
					    model = NoteActivity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        ctx = super().get_context_data(**kwargs)
 | 
					        ctx = super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        note = NoteActivity.objects.get(pk=self.kwargs["pk"])
 | 
					        note = self.get_queryset().filter(pk=self.kwargs["pk"]).get()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        transactions = Transaction.objects.all().filter(Q(source=note) | Q(destination=note))\
 | 
					        transactions = Transaction.objects.filter(Q(source=note) | Q(destination=note))\
 | 
				
			||||||
            .filter(PermissionBackend.filter_queryset(self.request.user, Transaction, "view")).order_by("-id")
 | 
					            .filter(PermissionBackend.filter_queryset(self.request.user, Transaction, "view")).order_by("-id")
 | 
				
			||||||
        ctx['history_list'] = HistoryTable(transactions)
 | 
					        ctx['history_list'] = HistoryTable(transactions)
 | 
				
			||||||
        ctx["note"] = note
 | 
					        ctx["note"] = note
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,13 @@
 | 
				
			|||||||
# 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 .notes import Alias, Note, NoteClub, NoteSpecial, NoteUser
 | 
					from .notes import Alias, Note, NoteClub, NoteSpecial, NoteUser, NoteActivity
 | 
				
			||||||
from .transactions import MembershipTransaction, Transaction, \
 | 
					from .transactions import MembershipTransaction, Transaction, \
 | 
				
			||||||
    TemplateCategory, TransactionTemplate, RecurrentTransaction, SpecialTransaction
 | 
					    TemplateCategory, TransactionTemplate, RecurrentTransaction, SpecialTransaction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__all__ = [
 | 
					__all__ = [
 | 
				
			||||||
    # Notes
 | 
					    # Notes
 | 
				
			||||||
    'Alias', 'Note', 'NoteClub', 'NoteSpecial', 'NoteUser',
 | 
					    'Alias', 'Note', 'NoteClub', 'NoteSpecial', 'NoteUser', 'NoteActivity',
 | 
				
			||||||
    # Transactions
 | 
					    # Transactions
 | 
				
			||||||
    'MembershipTransaction', 'Transaction', 'TemplateCategory', 'TransactionTemplate',
 | 
					    'MembershipTransaction', 'Transaction', 'TemplateCategory', 'TransactionTemplate',
 | 
				
			||||||
    'RecurrentTransaction', 'SpecialTransaction',
 | 
					    'RecurrentTransaction', 'SpecialTransaction',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@ from django_tables2 import SingleTableView
 | 
				
			|||||||
from django.urls import reverse_lazy
 | 
					from django.urls import reverse_lazy
 | 
				
			||||||
from note_kfet.inputs import AmountInput
 | 
					from note_kfet.inputs import AmountInput
 | 
				
			||||||
from permission.backends import PermissionBackend
 | 
					from permission.backends import PermissionBackend
 | 
				
			||||||
 | 
					from permission.views import ProtectQuerysetMixin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .forms import TransactionTemplateForm
 | 
					from .forms import TransactionTemplateForm
 | 
				
			||||||
from .models import Transaction, TransactionTemplate, RecurrentTransaction, NoteSpecial
 | 
					from .models import Transaction, TransactionTemplate, RecurrentTransaction, NoteSpecial
 | 
				
			||||||
@@ -16,7 +17,7 @@ from .models.transactions import SpecialTransaction
 | 
				
			|||||||
from .tables import HistoryTable, ButtonTable
 | 
					from .tables import HistoryTable, ButtonTable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TransactionCreateView(LoginRequiredMixin, SingleTableView):
 | 
					class TransactionCreateView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    View for the creation of Transaction between two note which are not :models:`transactions.RecurrentTransaction`.
 | 
					    View for the creation of Transaction between two note which are not :models:`transactions.RecurrentTransaction`.
 | 
				
			||||||
    e.g. for donation/transfer between people and clubs or for credit/debit with :models:`note.NoteSpecial`
 | 
					    e.g. for donation/transfer between people and clubs or for credit/debit with :models:`note.NoteSpecial`
 | 
				
			||||||
@@ -26,12 +27,9 @@ class TransactionCreateView(LoginRequiredMixin, SingleTableView):
 | 
				
			|||||||
    model = Transaction
 | 
					    model = Transaction
 | 
				
			||||||
    # Transaction history table
 | 
					    # Transaction history table
 | 
				
			||||||
    table_class = HistoryTable
 | 
					    table_class = HistoryTable
 | 
				
			||||||
    table_pagination = {"per_page": 50}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_queryset(self):
 | 
					    def get_queryset(self, **kwargs):
 | 
				
			||||||
        return Transaction.objects.filter(PermissionBackend.filter_queryset(
 | 
					        return super().get_queryset(**kwargs).order_by("-id").all()[:50]
 | 
				
			||||||
            self.request.user, Transaction, "view")
 | 
					 | 
				
			||||||
        ).order_by("-id").all()[:50]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
@@ -42,12 +40,14 @@ class TransactionCreateView(LoginRequiredMixin, SingleTableView):
 | 
				
			|||||||
        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
 | 
				
			||||||
        context['special_types'] = NoteSpecial.objects.order_by("special_type").all()
 | 
					        context['special_types'] = NoteSpecial.objects\
 | 
				
			||||||
 | 
					            .filter(PermissionBackend.filter_queryset(self.request.user, NoteSpecial, "view"))\
 | 
				
			||||||
 | 
					            .order_by("special_type").all()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return context
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TransactionTemplateCreateView(LoginRequiredMixin, CreateView):
 | 
					class TransactionTemplateCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Create TransactionTemplate
 | 
					    Create TransactionTemplate
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@@ -56,7 +56,7 @@ class TransactionTemplateCreateView(LoginRequiredMixin, CreateView):
 | 
				
			|||||||
    success_url = reverse_lazy('note:template_list')
 | 
					    success_url = reverse_lazy('note:template_list')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TransactionTemplateListView(LoginRequiredMixin, SingleTableView):
 | 
					class TransactionTemplateListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    List TransactionsTemplates
 | 
					    List TransactionsTemplates
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@@ -64,7 +64,7 @@ class TransactionTemplateListView(LoginRequiredMixin, SingleTableView):
 | 
				
			|||||||
    table_class = ButtonTable
 | 
					    table_class = ButtonTable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TransactionTemplateUpdateView(LoginRequiredMixin, UpdateView):
 | 
					class TransactionTemplateUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    model = TransactionTemplate
 | 
					    model = TransactionTemplate
 | 
				
			||||||
@@ -72,21 +72,19 @@ class TransactionTemplateUpdateView(LoginRequiredMixin, UpdateView):
 | 
				
			|||||||
    success_url = reverse_lazy('note:template_list')
 | 
					    success_url = reverse_lazy('note:template_list')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ConsoView(LoginRequiredMixin, SingleTableView):
 | 
					class ConsoView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    The Magic View that make people pay their beer and burgers.
 | 
					    The Magic View that make people pay their beer and burgers.
 | 
				
			||||||
    (Most of the magic happens in the dark world of Javascript see consos.js)
 | 
					    (Most of the magic happens in the dark world of Javascript see consos.js)
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					    model = Transaction
 | 
				
			||||||
    template_name = "note/conso_form.html"
 | 
					    template_name = "note/conso_form.html"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Transaction history table
 | 
					    # Transaction history table
 | 
				
			||||||
    table_class = HistoryTable
 | 
					    table_class = HistoryTable
 | 
				
			||||||
    table_pagination = {"per_page": 50}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_queryset(self):
 | 
					    def get_queryset(self, **kwargs):
 | 
				
			||||||
        return Transaction.objects.filter(
 | 
					        return super().get_queryset(**kwargs).order_by("-id").all()[:50]
 | 
				
			||||||
            PermissionBackend.filter_queryset(self.request.user, Transaction, "view")
 | 
					 | 
				
			||||||
        ).order_by("-id").all()[:50]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@ 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
 | 
				
			||||||
from django.db.models import Q, F
 | 
					from django.db.models import Q, F
 | 
				
			||||||
from note.models import Note, NoteUser, NoteClub, NoteSpecial
 | 
					from note.models import Note, NoteUser, NoteClub, NoteSpecial, NoteActivity
 | 
				
			||||||
from note_kfet.middlewares import get_current_session
 | 
					from note_kfet.middlewares import get_current_session
 | 
				
			||||||
from member.models import Membership, Club
 | 
					from member.models import Membership, Club
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -35,7 +35,7 @@ class PermissionBackend(ModelBackend):
 | 
				
			|||||||
            model__app_label=model.app_label,  # For polymorphic models, we don't filter on model type
 | 
					            model__app_label=model.app_label,  # For polymorphic models, we don't filter on model type
 | 
				
			||||||
            type=type,
 | 
					            type=type,
 | 
				
			||||||
        ).all():
 | 
					        ).all():
 | 
				
			||||||
            if not isinstance(model, permission.model.__class__):
 | 
					            if not isinstance(model, permission.model.__class__) or not permission.club:
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            club = Club.objects.get(pk=permission.club)
 | 
					            club = Club.objects.get(pk=permission.club)
 | 
				
			||||||
@@ -49,6 +49,7 @@ class PermissionBackend(ModelBackend):
 | 
				
			|||||||
                NoteUser=NoteUser,
 | 
					                NoteUser=NoteUser,
 | 
				
			||||||
                NoteClub=NoteClub,
 | 
					                NoteClub=NoteClub,
 | 
				
			||||||
                NoteSpecial=NoteSpecial,
 | 
					                NoteSpecial=NoteSpecial,
 | 
				
			||||||
 | 
					                NoteActivity=NoteActivity,
 | 
				
			||||||
                F=F,
 | 
					                F=F,
 | 
				
			||||||
                Q=Q
 | 
					                Q=Q
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -176,7 +176,7 @@
 | 
				
			|||||||
        "note",
 | 
					        "note",
 | 
				
			||||||
        "alias"
 | 
					        "alias"
 | 
				
			||||||
      ],
 | 
					      ],
 | 
				
			||||||
      "query": "[\"OR\", {\"note__in\": [\"NoteUser\", \"objects\", [\"filter\", {\"user__membership__club__name\": \"Kfet\"}], [\"all\"]]}, {\"note__in\": [\"NoteClub\", \"objects\", [\"all\"]]}]",
 | 
					      "query": "[\"OR\", {\"note__in\": [\"NoteUser\", \"objects\", [\"filter\", {\"user__membership__club__name\": \"Kfet\"}], [\"all\"]]}, {\"note__in\": [\"NoteClub\", \"objects\", [\"all\"]]}, {\"note__in\": [\"NoteActivity\", \"objects\", [\"all\"]]}]",
 | 
				
			||||||
      "type": "view",
 | 
					      "type": "view",
 | 
				
			||||||
      "mask": 1,
 | 
					      "mask": 1,
 | 
				
			||||||
      "field": "",
 | 
					      "field": "",
 | 
				
			||||||
@@ -386,7 +386,7 @@
 | 
				
			|||||||
        "note",
 | 
					        "note",
 | 
				
			||||||
        "transaction"
 | 
					        "transaction"
 | 
				
			||||||
      ],
 | 
					      ],
 | 
				
			||||||
      "query": "[\"AND\", [\"OR\", {\"source\": [\"club\", \"note\"]}, {\"destination\": [\"club\", \"note\"]}], {\"amount__lte\": {\"F\": [\"ADD\", [\"F\", \"source__balance\"], 5000]}}]",
 | 
					      "query": "[\"AND\", [\"OR\", {\"source\": [\"club\", \"note\"]}, {\"destination\": [\"club\", \"note\"]}], [\"OR\", {\"amount__lte\": {\"F\": [\"ADD\", [\"F\", \"source__balance\"], 5000]}}, {\"valid\": false}]]",
 | 
				
			||||||
      "type": "add",
 | 
					      "type": "add",
 | 
				
			||||||
      "mask": 2,
 | 
					      "mask": 2,
 | 
				
			||||||
      "field": "",
 | 
					      "field": "",
 | 
				
			||||||
@@ -783,6 +783,111 @@
 | 
				
			|||||||
      "description": "Validate invitation transactions"
 | 
					      "description": "Validate invitation transactions"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "model": "permission.permission",
 | 
				
			||||||
 | 
					    "pk": 47,
 | 
				
			||||||
 | 
					    "fields": {
 | 
				
			||||||
 | 
					      "model": [
 | 
				
			||||||
 | 
					        "member",
 | 
				
			||||||
 | 
					        "club"
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      "query": "{\"pk\": [\"club\", \"pk\"]}",
 | 
				
			||||||
 | 
					      "type": "change",
 | 
				
			||||||
 | 
					      "mask": 1,
 | 
				
			||||||
 | 
					      "field": "",
 | 
				
			||||||
 | 
					      "description": "Update club"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "model": "permission.permission",
 | 
				
			||||||
 | 
					    "pk": 48,
 | 
				
			||||||
 | 
					    "fields": {
 | 
				
			||||||
 | 
					      "model": [
 | 
				
			||||||
 | 
					        "note",
 | 
				
			||||||
 | 
					        "noteactivity"
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      "query": "{\"club\": [\"club\"]}",
 | 
				
			||||||
 | 
					      "type": "change",
 | 
				
			||||||
 | 
					      "mask": 1,
 | 
				
			||||||
 | 
					      "field": "",
 | 
				
			||||||
 | 
					      "description": "Manage notes that are linked to a club"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "model": "permission.permission",
 | 
				
			||||||
 | 
					    "pk": 49,
 | 
				
			||||||
 | 
					    "fields": {
 | 
				
			||||||
 | 
					      "model": [
 | 
				
			||||||
 | 
					        "note",
 | 
				
			||||||
 | 
					        "noteactivity"
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      "query": "{\"club\": [\"club\"]}",
 | 
				
			||||||
 | 
					      "type": "view",
 | 
				
			||||||
 | 
					      "mask": 1,
 | 
				
			||||||
 | 
					      "field": "",
 | 
				
			||||||
 | 
					      "description": "View notes that are linked to a club"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "model": "permission.permission",
 | 
				
			||||||
 | 
					    "pk": 50,
 | 
				
			||||||
 | 
					    "fields": {
 | 
				
			||||||
 | 
					      "model": [
 | 
				
			||||||
 | 
					        "note",
 | 
				
			||||||
 | 
					        "transaction"
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      "query": "[\"AND\", [\"OR\", {\"source__noteactivity__controller\": [\"user\"]}, {\"destination__noteactivity__controller\": [\"user\"]}], [\"OR\", {\"amount__lte\": {\"F\": [\"ADD\", [\"F\", \"source__balance\"], 5000]}}, {\"valid\": false}]]",
 | 
				
			||||||
 | 
					      "type": "add",
 | 
				
			||||||
 | 
					      "mask": 2,
 | 
				
			||||||
 | 
					      "field": "",
 | 
				
			||||||
 | 
					      "description": "Add transactions linked to a noteactivity"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "model": "permission.permission",
 | 
				
			||||||
 | 
					    "pk": 51,
 | 
				
			||||||
 | 
					    "fields": {
 | 
				
			||||||
 | 
					      "model": [
 | 
				
			||||||
 | 
					        "note",
 | 
				
			||||||
 | 
					        "transaction"
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      "query": "[\"AND\", [\"OR\", {\"source__noteactivity__controller\": [\"user\"]}, {\"destination__noteactivity__controller\": [\"user\"]}]]",
 | 
				
			||||||
 | 
					      "type": "view",
 | 
				
			||||||
 | 
					      "mask": 1,
 | 
				
			||||||
 | 
					      "field": "",
 | 
				
			||||||
 | 
					      "description": "View transactions linked to a noteactivity"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "model": "permission.permission",
 | 
				
			||||||
 | 
					    "pk": 52,
 | 
				
			||||||
 | 
					    "fields": {
 | 
				
			||||||
 | 
					      "model": [
 | 
				
			||||||
 | 
					        "note",
 | 
				
			||||||
 | 
					        "note"
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      "query": "{\"noteactivity__controller\": [\"user\"]}",
 | 
				
			||||||
 | 
					      "type": "view",
 | 
				
			||||||
 | 
					      "mask": 1,
 | 
				
			||||||
 | 
					      "field": "",
 | 
				
			||||||
 | 
					      "description": "View note activity"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "model": "permission.permission",
 | 
				
			||||||
 | 
					    "pk": 53,
 | 
				
			||||||
 | 
					    "fields": {
 | 
				
			||||||
 | 
					      "model": [
 | 
				
			||||||
 | 
					        "note",
 | 
				
			||||||
 | 
					        "noteactivity"
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      "query": "{\"controller\": [\"user\"]}",
 | 
				
			||||||
 | 
					      "type": "view",
 | 
				
			||||||
 | 
					      "mask": 1,
 | 
				
			||||||
 | 
					      "field": "",
 | 
				
			||||||
 | 
					      "description": "View note activity"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    "model": "permission.rolepermissions",
 | 
					    "model": "permission.rolepermissions",
 | 
				
			||||||
    "pk": 1,
 | 
					    "pk": 1,
 | 
				
			||||||
@@ -810,7 +915,6 @@
 | 
				
			|||||||
        3,
 | 
					        3,
 | 
				
			||||||
        4,
 | 
					        4,
 | 
				
			||||||
        5,
 | 
					        5,
 | 
				
			||||||
        6,
 | 
					 | 
				
			||||||
        7,
 | 
					        7,
 | 
				
			||||||
        8,
 | 
					        8,
 | 
				
			||||||
        9,
 | 
					        9,
 | 
				
			||||||
@@ -827,7 +931,12 @@
 | 
				
			|||||||
        35,
 | 
					        35,
 | 
				
			||||||
        36,
 | 
					        36,
 | 
				
			||||||
        39,
 | 
					        39,
 | 
				
			||||||
        40
 | 
					        40,
 | 
				
			||||||
 | 
					        6,
 | 
				
			||||||
 | 
					        52,
 | 
				
			||||||
 | 
					        53,
 | 
				
			||||||
 | 
					        51,
 | 
				
			||||||
 | 
					        50
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
@@ -838,9 +947,9 @@
 | 
				
			|||||||
      "role": 8,
 | 
					      "role": 8,
 | 
				
			||||||
      "permissions": [
 | 
					      "permissions": [
 | 
				
			||||||
        19,
 | 
					        19,
 | 
				
			||||||
        20,
 | 
					 | 
				
			||||||
        21,
 | 
					        21,
 | 
				
			||||||
        22
 | 
					        22,
 | 
				
			||||||
 | 
					        20
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
@@ -880,5 +989,18 @@
 | 
				
			|||||||
        46
 | 
					        46
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "model": "permission.rolepermissions",
 | 
				
			||||||
 | 
					    "pk": 6,
 | 
				
			||||||
 | 
					    "fields": {
 | 
				
			||||||
 | 
					      "role": 7,
 | 
				
			||||||
 | 
					      "permissions": [
 | 
				
			||||||
 | 
					        22,
 | 
				
			||||||
 | 
					        47,
 | 
				
			||||||
 | 
					        48,
 | 
				
			||||||
 | 
					        49
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,20 +38,29 @@ class InstancedPermission:
 | 
				
			|||||||
            if permission_type == self.type:
 | 
					            if permission_type == self.type:
 | 
				
			||||||
                self.update_query()
 | 
					                self.update_query()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                # Don't increase indexes
 | 
					                # Don't increase indexes, if the primary key is an AutoField
 | 
				
			||||||
 | 
					                if not hasattr(obj, "pk") or not obj.pk:
 | 
				
			||||||
                    obj.pk = 0
 | 
					                    obj.pk = 0
 | 
				
			||||||
 | 
					                    oldpk = None
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    oldpk = obj.pk
 | 
				
			||||||
 | 
					                # Ensure previous models are deleted
 | 
				
			||||||
 | 
					                self.model.model_class().objects.filter(pk=obj.pk).delete()
 | 
				
			||||||
                # Force insertion, no data verification, no trigger
 | 
					                # Force insertion, no data verification, no trigger
 | 
				
			||||||
                Model.save(obj, force_insert=True)
 | 
					                Model.save(obj, force_insert=True)
 | 
				
			||||||
                ret = obj in self.model.model_class().objects.filter(self.query).all()
 | 
					                ret = self.model.model_class().objects.filter(self.query & Q(pk=obj.pk)).exists()
 | 
				
			||||||
                # Delete testing object
 | 
					                # Delete testing object
 | 
				
			||||||
                Model.delete(obj)
 | 
					                Model.delete(obj)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # If the primary key was specified, we restore it
 | 
				
			||||||
 | 
					                obj.pk = oldpk
 | 
				
			||||||
                return ret
 | 
					                return ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if permission_type == self.type:
 | 
					        if permission_type == self.type:
 | 
				
			||||||
            if self.field and field_name != self.field:
 | 
					            if self.field and field_name != self.field:
 | 
				
			||||||
                return False
 | 
					                return False
 | 
				
			||||||
            self.update_query()
 | 
					            self.update_query()
 | 
				
			||||||
            return obj in self.model.model_class().objects.filter(self.query).all()
 | 
					            return self.model.model_class().objects.filter(self.query & Q(pk=obj.pk)).exists()
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								apps/permission/views.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								apps/permission/views.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 | 
				
			||||||
 | 
					# SPDX-License-Identifier: GPL-3.0-or-later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from permission.backends import PermissionBackend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ProtectQuerysetMixin:
 | 
				
			||||||
 | 
					    def get_queryset(self, **kwargs):
 | 
				
			||||||
 | 
					        qs = super().get_queryset(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return qs.filter(PermissionBackend.filter_queryset(self.request.user, qs.model, "view"))
 | 
				
			||||||
@@ -8,6 +8,7 @@ from crispy_forms.layout import Submit
 | 
				
			|||||||
from django import forms
 | 
					from django import forms
 | 
				
			||||||
from django.utils.translation import gettext_lazy as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
from note_kfet.inputs import DatePickerInput, AmountInput
 | 
					from note_kfet.inputs import DatePickerInput, AmountInput
 | 
				
			||||||
 | 
					from permission.backends import PermissionBackend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .models import Invoice, Product, Remittance, SpecialTransactionProxy
 | 
					from .models import Invoice, Product, Remittance, SpecialTransactionProxy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -131,7 +132,8 @@ class LinkTransactionToRemittanceForm(forms.ModelForm):
 | 
				
			|||||||
        # Add submit button
 | 
					        # Add submit button
 | 
				
			||||||
        self.helper.add_input(Submit('submit', _("Submit"), attr={'class': 'btn btn-block btn-primary'}))
 | 
					        self.helper.add_input(Submit('submit', _("Submit"), attr={'class': 'btn btn-block btn-primary'}))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.fields["remittance"].queryset = Remittance.objects.filter(closed=False)
 | 
					        self.fields["remittance"].queryset = Remittance.objects.filter(closed=False)\
 | 
				
			||||||
 | 
					            .filter(PermissionBackend.filter_queryset(self.request.user, Remittance, "view"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def clean_last_name(self):
 | 
					    def clean_last_name(self):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,13 +19,15 @@ from django.views.generic.base import View, TemplateView
 | 
				
			|||||||
from django_tables2 import SingleTableView
 | 
					from django_tables2 import SingleTableView
 | 
				
			||||||
from note.models import SpecialTransaction, NoteSpecial
 | 
					from note.models import SpecialTransaction, NoteSpecial
 | 
				
			||||||
from note_kfet.settings.base import BASE_DIR
 | 
					from note_kfet.settings.base import BASE_DIR
 | 
				
			||||||
 | 
					from permission.backends import PermissionBackend
 | 
				
			||||||
 | 
					from permission.views import ProtectQuerysetMixin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .forms import InvoiceForm, ProductFormSet, ProductFormSetHelper, RemittanceForm, LinkTransactionToRemittanceForm
 | 
					from .forms import InvoiceForm, ProductFormSet, ProductFormSetHelper, RemittanceForm, LinkTransactionToRemittanceForm
 | 
				
			||||||
from .models import Invoice, Product, Remittance, SpecialTransactionProxy
 | 
					from .models import Invoice, Product, Remittance, SpecialTransactionProxy
 | 
				
			||||||
from .tables import InvoiceTable, RemittanceTable, SpecialTransactionTable
 | 
					from .tables import InvoiceTable, RemittanceTable, SpecialTransactionTable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class InvoiceCreateView(LoginRequiredMixin, CreateView):
 | 
					class InvoiceCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Create Invoice
 | 
					    Create Invoice
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@@ -67,7 +69,7 @@ class InvoiceCreateView(LoginRequiredMixin, CreateView):
 | 
				
			|||||||
        return reverse_lazy('treasury:invoice_list')
 | 
					        return reverse_lazy('treasury:invoice_list')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class InvoiceListView(LoginRequiredMixin, SingleTableView):
 | 
					class InvoiceListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    List existing Invoices
 | 
					    List existing Invoices
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@@ -75,7 +77,7 @@ class InvoiceListView(LoginRequiredMixin, SingleTableView):
 | 
				
			|||||||
    table_class = InvoiceTable
 | 
					    table_class = InvoiceTable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class InvoiceUpdateView(LoginRequiredMixin, UpdateView):
 | 
					class InvoiceUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Create Invoice
 | 
					    Create Invoice
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@@ -130,7 +132,7 @@ class InvoiceRenderView(LoginRequiredMixin, View):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def get(self, request, **kwargs):
 | 
					    def get(self, request, **kwargs):
 | 
				
			||||||
        pk = kwargs["pk"]
 | 
					        pk = kwargs["pk"]
 | 
				
			||||||
        invoice = Invoice.objects.get(pk=pk)
 | 
					        invoice = Invoice.objects.filter(PermissionBackend.filter_queryset(request.user, Invoice, "view")).get(pk=pk)
 | 
				
			||||||
        products = Product.objects.filter(invoice=invoice).all()
 | 
					        products = Product.objects.filter(invoice=invoice).all()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Informations of the BDE. Should be updated when the school will move.
 | 
					        # Informations of the BDE. Should be updated when the school will move.
 | 
				
			||||||
@@ -188,7 +190,7 @@ class InvoiceRenderView(LoginRequiredMixin, View):
 | 
				
			|||||||
        return response
 | 
					        return response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RemittanceCreateView(LoginRequiredMixin, CreateView):
 | 
					class RemittanceCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Create Remittance
 | 
					    Create Remittance
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@@ -201,7 +203,9 @@ class RemittanceCreateView(LoginRequiredMixin, CreateView):
 | 
				
			|||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        ctx = super().get_context_data(**kwargs)
 | 
					        ctx = super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ctx["table"] = RemittanceTable(data=Remittance.objects.all())
 | 
					        ctx["table"] = RemittanceTable(data=Remittance.objects
 | 
				
			||||||
 | 
					                                       .filter(PermissionBackend.filter_queryset(self.request.user, Remittance, "view"))
 | 
				
			||||||
 | 
					                                       .all())
 | 
				
			||||||
        ctx["special_transactions"] = SpecialTransactionTable(data=SpecialTransaction.objects.none())
 | 
					        ctx["special_transactions"] = SpecialTransactionTable(data=SpecialTransaction.objects.none())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return ctx
 | 
					        return ctx
 | 
				
			||||||
@@ -216,22 +220,28 @@ class RemittanceListView(LoginRequiredMixin, TemplateView):
 | 
				
			|||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        ctx = super().get_context_data(**kwargs)
 | 
					        ctx = super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ctx["opened_remittances"] = RemittanceTable(data=Remittance.objects.filter(closed=False).all())
 | 
					        ctx["opened_remittances"] = RemittanceTable(
 | 
				
			||||||
        ctx["closed_remittances"] = RemittanceTable(data=Remittance.objects.filter(closed=True).reverse().all())
 | 
					            data=Remittance.objects.filter(closed=False).filter(
 | 
				
			||||||
 | 
					                PermissionBackend.filter_queryset(self.request.user, Remittance, "view")).all())
 | 
				
			||||||
 | 
					        ctx["closed_remittances"] = RemittanceTable(
 | 
				
			||||||
 | 
					            data=Remittance.objects.filter(closed=True).filter(
 | 
				
			||||||
 | 
					                PermissionBackend.filter_queryset(self.request.user, Remittance, "view")).reverse().all())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ctx["special_transactions_no_remittance"] = SpecialTransactionTable(
 | 
					        ctx["special_transactions_no_remittance"] = SpecialTransactionTable(
 | 
				
			||||||
            data=SpecialTransaction.objects.filter(source__in=NoteSpecial.objects.filter(~Q(remittancetype=None)),
 | 
					            data=SpecialTransaction.objects.filter(source__in=NoteSpecial.objects.filter(~Q(remittancetype=None)),
 | 
				
			||||||
                                                   specialtransactionproxy__remittance=None).all(),
 | 
					                                                   specialtransactionproxy__remittance=None).filter(
 | 
				
			||||||
 | 
					                PermissionBackend.filter_queryset(self.request.user, Remittance, "view")).all(),
 | 
				
			||||||
            exclude=('remittance_remove', ))
 | 
					            exclude=('remittance_remove', ))
 | 
				
			||||||
        ctx["special_transactions_with_remittance"] = SpecialTransactionTable(
 | 
					        ctx["special_transactions_with_remittance"] = SpecialTransactionTable(
 | 
				
			||||||
            data=SpecialTransaction.objects.filter(source__in=NoteSpecial.objects.filter(~Q(remittancetype=None)),
 | 
					            data=SpecialTransaction.objects.filter(source__in=NoteSpecial.objects.filter(~Q(remittancetype=None)),
 | 
				
			||||||
                                                   specialtransactionproxy__remittance__closed=False).all(),
 | 
					                                                   specialtransactionproxy__remittance__closed=False).filter(
 | 
				
			||||||
 | 
					                PermissionBackend.filter_queryset(self.request.user, Remittance, "view")).all(),
 | 
				
			||||||
            exclude=('remittance_add', ))
 | 
					            exclude=('remittance_add', ))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return ctx
 | 
					        return ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RemittanceUpdateView(LoginRequiredMixin, UpdateView):
 | 
					class RemittanceUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Update Remittance
 | 
					    Update Remittance
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@@ -244,8 +254,10 @@ class RemittanceUpdateView(LoginRequiredMixin, UpdateView):
 | 
				
			|||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        ctx = super().get_context_data(**kwargs)
 | 
					        ctx = super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ctx["table"] = RemittanceTable(data=Remittance.objects.all())
 | 
					        ctx["table"] = RemittanceTable(data=Remittance.objects.filter(
 | 
				
			||||||
        data = SpecialTransaction.objects.filter(specialtransactionproxy__remittance=self.object).all()
 | 
					                PermissionBackend.filter_queryset(self.request.user, Remittance, "view")).all())
 | 
				
			||||||
 | 
					        data = SpecialTransaction.objects.filter(specialtransactionproxy__remittance=self.object).filter(
 | 
				
			||||||
 | 
					                PermissionBackend.filter_queryset(self.request.user, Remittance, "view")).all()
 | 
				
			||||||
        ctx["special_transactions"] = SpecialTransactionTable(
 | 
					        ctx["special_transactions"] = SpecialTransactionTable(
 | 
				
			||||||
            data=data,
 | 
					            data=data,
 | 
				
			||||||
            exclude=('remittance_add', 'remittance_remove', ) if self.object.closed else ('remittance_add', ))
 | 
					            exclude=('remittance_add', 'remittance_remove', ) if self.object.closed else ('remittance_add', ))
 | 
				
			||||||
@@ -253,7 +265,7 @@ class RemittanceUpdateView(LoginRequiredMixin, UpdateView):
 | 
				
			|||||||
        return ctx
 | 
					        return ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class LinkTransactionToRemittanceView(LoginRequiredMixin, UpdateView):
 | 
					class LinkTransactionToRemittanceView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Attach a special transaction to a remittance
 | 
					    Attach a special transaction to a remittance
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@
 | 
				
			|||||||
{% load i18n %}
 | 
					{% load i18n %}
 | 
				
			||||||
{% load render_table from django_tables2 %}
 | 
					{% load render_table from django_tables2 %}
 | 
				
			||||||
{% load pretty_money %}
 | 
					{% load pretty_money %}
 | 
				
			||||||
 | 
					{% load perms %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block profile_info %}
 | 
					{% block profile_info %}
 | 
				
			||||||
{% include "member/club_info.html" %}
 | 
					{% include "member/club_info.html" %}
 | 
				
			||||||
@@ -25,9 +26,11 @@
 | 
				
			|||||||
                <dd class="col-xl-6">{{ note.balance|pretty_money }}</dd>
 | 
					                <dd class="col-xl-6">{{ note.balance|pretty_money }}</dd>
 | 
				
			||||||
            </dl>
 | 
					            </dl>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            {% if "change_"|has_perm:note %}
 | 
				
			||||||
                <div class="card-footer text-center">
 | 
					                <div class="card-footer text-center">
 | 
				
			||||||
                    <a class="btn btn-primary btn-sm my-1" href="{% url 'member:club_linked_note_update' club_pk=club.pk pk=note.pk %}"> {% trans "Edit" %}</a>
 | 
					                    <a class="btn btn-primary btn-sm my-1" href="{% url 'member:club_linked_note_update' club_pk=club.pk pk=note.pk %}"> {% trans "Edit" %}</a>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
 | 
					            {% endif %}
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,9 +19,11 @@
 | 
				
			|||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        {% if can_create %}
 | 
				
			||||||
            <a href="{% url 'member:club_linked_note_create' club_pk=club.pk %}">
 | 
					            <a href="{% url 'member:club_linked_note_create' club_pk=club.pk %}">
 | 
				
			||||||
                <button class="btn btn-primary btn-block">{% trans "Add new note" %}</button>
 | 
					                <button class="btn btn-primary btn-block">{% trans "Add new note" %}</button>
 | 
				
			||||||
            </a>
 | 
					            </a>
 | 
				
			||||||
 | 
					        {% endif %}
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user