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
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
 | 
			
		||||
from datetime import datetime, timezone
 | 
			
		||||
 | 
			
		||||
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 note.models import NoteUser, Alias, NoteSpecial
 | 
			
		||||
from permission.backends import PermissionBackend
 | 
			
		||||
from permission.views import ProtectQuerysetMixin
 | 
			
		||||
 | 
			
		||||
from .forms import ActivityForm, GuestForm
 | 
			
		||||
from .models import Activity, Guest, Entry
 | 
			
		||||
from .tables import ActivityTable, GuestTable, EntryTable
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ActivityCreateView(LoginRequiredMixin, CreateView):
 | 
			
		||||
class ActivityCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
 | 
			
		||||
    model = Activity
 | 
			
		||||
    form_class = ActivityForm
 | 
			
		||||
 | 
			
		||||
@@ -30,13 +32,12 @@ class ActivityCreateView(LoginRequiredMixin, CreateView):
 | 
			
		||||
        return reverse_lazy('activity:activity_detail', kwargs={"pk": self.object.pk})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ActivityListView(LoginRequiredMixin, SingleTableView):
 | 
			
		||||
class ActivityListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
 | 
			
		||||
    model = Activity
 | 
			
		||||
    table_class = ActivityTable
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        return super().get_queryset()\
 | 
			
		||||
            .filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view")).reverse()
 | 
			
		||||
        return super().get_queryset().reverse()
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        ctx = super().get_context_data(**kwargs)
 | 
			
		||||
@@ -50,7 +51,7 @@ class ActivityListView(LoginRequiredMixin, SingleTableView):
 | 
			
		||||
        return ctx
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ActivityDetailView(LoginRequiredMixin, DetailView):
 | 
			
		||||
class ActivityDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
 | 
			
		||||
    model = Activity
 | 
			
		||||
    context_object_name = "activity"
 | 
			
		||||
 | 
			
		||||
@@ -66,7 +67,7 @@ class ActivityDetailView(LoginRequiredMixin, DetailView):
 | 
			
		||||
        return ctx
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ActivityUpdateView(LoginRequiredMixin, UpdateView):
 | 
			
		||||
class ActivityUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
 | 
			
		||||
    model = Activity
 | 
			
		||||
    form_class = ActivityForm
 | 
			
		||||
 | 
			
		||||
@@ -74,18 +75,20 @@ class ActivityUpdateView(LoginRequiredMixin, UpdateView):
 | 
			
		||||
        return reverse_lazy('activity:activity_detail', kwargs={"pk": self.kwargs["pk"]})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ActivityInviteView(LoginRequiredMixin, CreateView):
 | 
			
		||||
class ActivityInviteView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
 | 
			
		||||
    model = Guest
 | 
			
		||||
    form_class = GuestForm
 | 
			
		||||
    template_name = "activity/activity_invite.html"
 | 
			
		||||
 | 
			
		||||
    def get_form(self, form_class=None):
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
 | 
			
		||||
    def get_success_url(self, **kwargs):
 | 
			
		||||
@@ -98,7 +101,8 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView):
 | 
			
		||||
    def get_context_data(self, **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
 | 
			
		||||
 | 
			
		||||
        matched = []
 | 
			
		||||
 
 | 
			
		||||
@@ -49,7 +49,13 @@ class ClubForm(forms.ModelForm):
 | 
			
		||||
        model = Club
 | 
			
		||||
        fields = '__all__'
 | 
			
		||||
        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.tables import HistoryTable, AliasTable, NoteActivityTable
 | 
			
		||||
from permission.backends import PermissionBackend
 | 
			
		||||
from permission.views import ProtectQuerysetMixin
 | 
			
		||||
 | 
			
		||||
from .filters import UserFilter, UserFilterFormHelper
 | 
			
		||||
from .forms import SignUpForm, ProfileForm, ClubForm, MembershipForm, MemberFormSet, FormSetHelper, \
 | 
			
		||||
@@ -64,7 +65,7 @@ class UserCreateView(CreateView):
 | 
			
		||||
        return super().form_valid(form)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class UserUpdateView(LoginRequiredMixin, UpdateView):
 | 
			
		||||
class UserUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
 | 
			
		||||
    model = User
 | 
			
		||||
    fields = ['first_name', 'last_name', 'username', 'email']
 | 
			
		||||
    template_name = 'member/profile_update.html'
 | 
			
		||||
@@ -98,7 +99,8 @@ class UserUpdateView(LoginRequiredMixin, UpdateView):
 | 
			
		||||
        if form.is_valid() and profile_form.is_valid():
 | 
			
		||||
            new_username = form.data['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():
 | 
			
		||||
                similar = Alias.objects.filter(
 | 
			
		||||
                    normalized_name=Alias.normalize(new_username))
 | 
			
		||||
@@ -120,7 +122,7 @@ class UserUpdateView(LoginRequiredMixin, UpdateView):
 | 
			
		||||
            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...
 | 
			
		||||
    """
 | 
			
		||||
@@ -128,9 +130,6 @@ class UserDetailView(LoginRequiredMixin, DetailView):
 | 
			
		||||
    context_object_name = "user_object"
 | 
			
		||||
    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):
 | 
			
		||||
        context = super().get_context_data(**kwargs)
 | 
			
		||||
        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")\
 | 
			
		||||
            .filter(PermissionBackend.filter_queryset(self.request.user, Transaction, "view"))
 | 
			
		||||
        context['history_list'] = HistoryTable(history_list)
 | 
			
		||||
        club_list = \
 | 
			
		||||
            Membership.objects.all().filter(user=user).only("club")
 | 
			
		||||
        club_list = Membership.objects.all().filter(user=user)\
 | 
			
		||||
            .filter(PermissionBackend.filter_queryset(self.request.user, Membership, "view")).only("club")
 | 
			
		||||
        context['club_list'] = ClubTable(club_list)
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class UserListView(LoginRequiredMixin, SingleTableView):
 | 
			
		||||
class UserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
 | 
			
		||||
    """
 | 
			
		||||
    Affiche la liste des utilisateurs, avec une fonction de recherche statique
 | 
			
		||||
    """
 | 
			
		||||
@@ -155,7 +154,7 @@ class UserListView(LoginRequiredMixin, SingleTableView):
 | 
			
		||||
    formhelper_class = UserFilterFormHelper
 | 
			
		||||
 | 
			
		||||
    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.form.helper = self.formhelper_class()
 | 
			
		||||
        return self.filter.qs
 | 
			
		||||
@@ -166,7 +165,7 @@ class UserListView(LoginRequiredMixin, SingleTableView):
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProfileAliasView(LoginRequiredMixin, DetailView):
 | 
			
		||||
class ProfileAliasView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
 | 
			
		||||
    model = User
 | 
			
		||||
    template_name = 'member/profile_alias.html'
 | 
			
		||||
    context_object_name = 'user_object'
 | 
			
		||||
@@ -178,7 +177,7 @@ class ProfileAliasView(LoginRequiredMixin, DetailView):
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PictureUpdateView(LoginRequiredMixin, FormMixin, DetailView):
 | 
			
		||||
class PictureUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin, DetailView):
 | 
			
		||||
    form_class = ImageForm
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
@@ -239,8 +238,7 @@ class ManageAuthTokens(LoginRequiredMixin, TemplateView):
 | 
			
		||||
    template_name = "member/manage_auth_tokens.html"
 | 
			
		||||
 | 
			
		||||
    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()
 | 
			
		||||
            return redirect(reverse_lazy('member:auth_token') + "?show",
 | 
			
		||||
                            permanent=True)
 | 
			
		||||
@@ -249,8 +247,7 @@ class ManageAuthTokens(LoginRequiredMixin, TemplateView):
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -259,7 +256,7 @@ class ManageAuthTokens(LoginRequiredMixin, TemplateView):
 | 
			
		||||
# ******************************* #
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ClubCreateView(LoginRequiredMixin, CreateView):
 | 
			
		||||
class ClubCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
 | 
			
		||||
    """
 | 
			
		||||
    Create Club
 | 
			
		||||
    """
 | 
			
		||||
@@ -271,38 +268,32 @@ class ClubCreateView(LoginRequiredMixin, CreateView):
 | 
			
		||||
        return super().form_valid(form)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ClubListView(LoginRequiredMixin, SingleTableView):
 | 
			
		||||
class ClubListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
 | 
			
		||||
    """
 | 
			
		||||
    List existing Clubs
 | 
			
		||||
    """
 | 
			
		||||
    model = Club
 | 
			
		||||
    table_class = ClubTable
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self, **kwargs):
 | 
			
		||||
        return super().get_queryset().filter(PermissionBackend.filter_queryset(self.request.user, Club, "view"))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ClubDetailView(LoginRequiredMixin, DetailView):
 | 
			
		||||
class ClubDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
 | 
			
		||||
    model = 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):
 | 
			
		||||
        context = super().get_context_data(**kwargs)
 | 
			
		||||
        club = context["club"]
 | 
			
		||||
        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')
 | 
			
		||||
        context['history_list'] = HistoryTable(club_transactions)
 | 
			
		||||
        club_member = \
 | 
			
		||||
            Membership.objects.all().filter(club=club)
 | 
			
		||||
        club_member = Membership.objects.filter(club=club)\
 | 
			
		||||
            .filter(PermissionBackend.filter_queryset(self.request.user, Membership, "view")).all()
 | 
			
		||||
        # TODO: consider only valid Membership
 | 
			
		||||
        context['member_list'] = club_member
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ClubAliasView(LoginRequiredMixin, DetailView):
 | 
			
		||||
class ClubAliasView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
 | 
			
		||||
    model = Club
 | 
			
		||||
    template_name = 'member/club_alias.html'
 | 
			
		||||
    context_object_name = 'club'
 | 
			
		||||
@@ -314,7 +305,7 @@ class ClubAliasView(LoginRequiredMixin, DetailView):
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ClubUpdateView(LoginRequiredMixin, UpdateView):
 | 
			
		||||
class ClubUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
 | 
			
		||||
    model = Club
 | 
			
		||||
    context_object_name = "club"
 | 
			
		||||
    form_class = ClubForm
 | 
			
		||||
@@ -333,7 +324,7 @@ class ClubPictureUpdateView(PictureUpdateView):
 | 
			
		||||
        return reverse_lazy('member:club_detail', kwargs={'pk': self.object.id})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ClubAddMemberView(LoginRequiredMixin, CreateView):
 | 
			
		||||
class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
 | 
			
		||||
    model = Membership
 | 
			
		||||
    form_class = MembershipForm
 | 
			
		||||
    template_name = 'member/add_members.html'
 | 
			
		||||
@@ -344,7 +335,8 @@ class ClubAddMemberView(LoginRequiredMixin, CreateView):
 | 
			
		||||
                                                                                 "change"))
 | 
			
		||||
 | 
			
		||||
    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['formset'] = MemberFormSet()
 | 
			
		||||
        context['helper'] = FormSetHelper()
 | 
			
		||||
@@ -367,36 +359,40 @@ class ClubAddMemberView(LoginRequiredMixin, CreateView):
 | 
			
		||||
        return super().form_valid(formset)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ClubLinkedNotesView(LoginRequiredMixin, SingleTableView):
 | 
			
		||||
class ClubLinkedNotesView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
 | 
			
		||||
    model = NoteActivity
 | 
			
		||||
    table_class = NoteActivityTable
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        return super().get_queryset().filter(club=self.get_object())\
 | 
			
		||||
            .filter(PermissionBackend.filter_queryset(self.request.user, NoteActivity, "view"))
 | 
			
		||||
        return super().get_queryset().filter(club=self.get_object())
 | 
			
		||||
 | 
			
		||||
    def get_object(self):
 | 
			
		||||
        if hasattr(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
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ClubLinkedNoteCreateView(LoginRequiredMixin, CreateView):
 | 
			
		||||
class ClubLinkedNoteCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
 | 
			
		||||
    model = NoteActivity
 | 
			
		||||
    form_class = NoteActivityForm
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **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["form"].fields["club"].initial = club
 | 
			
		||||
 | 
			
		||||
@@ -408,14 +404,15 @@ class ClubLinkedNoteCreateView(LoginRequiredMixin, CreateView):
 | 
			
		||||
                            kwargs={"club_pk": self.object.club.pk, "pk": self.object.pk})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ClubLinkedNoteUpdateView(LoginRequiredMixin, UpdateView):
 | 
			
		||||
class ClubLinkedNoteUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
 | 
			
		||||
    model = NoteActivity
 | 
			
		||||
    form_class = NoteActivityForm
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **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
 | 
			
		||||
 | 
			
		||||
@@ -424,15 +421,15 @@ class ClubLinkedNoteUpdateView(LoginRequiredMixin, UpdateView):
 | 
			
		||||
                            kwargs={"club_pk": self.object.club.pk, "pk": self.object.pk})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ClubLinkedNoteDetailView(LoginRequiredMixin, DetailView):
 | 
			
		||||
class ClubLinkedNoteDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
 | 
			
		||||
    model = NoteActivity
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **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")
 | 
			
		||||
        ctx['history_list'] = HistoryTable(transactions)
 | 
			
		||||
        ctx["note"] = note
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,13 @@
 | 
			
		||||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 | 
			
		||||
# 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, \
 | 
			
		||||
    TemplateCategory, TransactionTemplate, RecurrentTransaction, SpecialTransaction
 | 
			
		||||
 | 
			
		||||
__all__ = [
 | 
			
		||||
    # Notes
 | 
			
		||||
    'Alias', 'Note', 'NoteClub', 'NoteSpecial', 'NoteUser',
 | 
			
		||||
    'Alias', 'Note', 'NoteClub', 'NoteSpecial', 'NoteUser', 'NoteActivity',
 | 
			
		||||
    # Transactions
 | 
			
		||||
    'MembershipTransaction', 'Transaction', 'TemplateCategory', 'TransactionTemplate',
 | 
			
		||||
    'RecurrentTransaction', 'SpecialTransaction',
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ from django_tables2 import SingleTableView
 | 
			
		||||
from django.urls import reverse_lazy
 | 
			
		||||
from note_kfet.inputs import AmountInput
 | 
			
		||||
from permission.backends import PermissionBackend
 | 
			
		||||
from permission.views import ProtectQuerysetMixin
 | 
			
		||||
 | 
			
		||||
from .forms import TransactionTemplateForm
 | 
			
		||||
from .models import Transaction, TransactionTemplate, RecurrentTransaction, NoteSpecial
 | 
			
		||||
@@ -16,7 +17,7 @@ from .models.transactions import SpecialTransaction
 | 
			
		||||
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`.
 | 
			
		||||
    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
 | 
			
		||||
    # Transaction history table
 | 
			
		||||
    table_class = HistoryTable
 | 
			
		||||
    table_pagination = {"per_page": 50}
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        return Transaction.objects.filter(PermissionBackend.filter_queryset(
 | 
			
		||||
            self.request.user, Transaction, "view")
 | 
			
		||||
        ).order_by("-id").all()[:50]
 | 
			
		||||
    def get_queryset(self, **kwargs):
 | 
			
		||||
        return super().get_queryset(**kwargs).order_by("-id").all()[:50]
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        """
 | 
			
		||||
@@ -42,12 +40,14 @@ class TransactionCreateView(LoginRequiredMixin, SingleTableView):
 | 
			
		||||
        context['amount_widget'] = AmountInput(attrs={"id": "amount"})
 | 
			
		||||
        context['polymorphic_ctype'] = ContentType.objects.get_for_model(Transaction).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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TransactionTemplateCreateView(LoginRequiredMixin, CreateView):
 | 
			
		||||
class TransactionTemplateCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
 | 
			
		||||
    """
 | 
			
		||||
    Create TransactionTemplate
 | 
			
		||||
    """
 | 
			
		||||
@@ -56,7 +56,7 @@ class TransactionTemplateCreateView(LoginRequiredMixin, CreateView):
 | 
			
		||||
    success_url = reverse_lazy('note:template_list')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TransactionTemplateListView(LoginRequiredMixin, SingleTableView):
 | 
			
		||||
class TransactionTemplateListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
 | 
			
		||||
    """
 | 
			
		||||
    List TransactionsTemplates
 | 
			
		||||
    """
 | 
			
		||||
@@ -64,7 +64,7 @@ class TransactionTemplateListView(LoginRequiredMixin, SingleTableView):
 | 
			
		||||
    table_class = ButtonTable
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TransactionTemplateUpdateView(LoginRequiredMixin, UpdateView):
 | 
			
		||||
class TransactionTemplateUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
 | 
			
		||||
    """
 | 
			
		||||
    """
 | 
			
		||||
    model = TransactionTemplate
 | 
			
		||||
@@ -72,21 +72,19 @@ class TransactionTemplateUpdateView(LoginRequiredMixin, UpdateView):
 | 
			
		||||
    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.
 | 
			
		||||
    (Most of the magic happens in the dark world of Javascript see consos.js)
 | 
			
		||||
    """
 | 
			
		||||
    model = Transaction
 | 
			
		||||
    template_name = "note/conso_form.html"
 | 
			
		||||
 | 
			
		||||
    # Transaction history table
 | 
			
		||||
    table_class = HistoryTable
 | 
			
		||||
    table_pagination = {"per_page": 50}
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        return Transaction.objects.filter(
 | 
			
		||||
            PermissionBackend.filter_queryset(self.request.user, Transaction, "view")
 | 
			
		||||
        ).order_by("-id").all()[:50]
 | 
			
		||||
    def get_queryset(self, **kwargs):
 | 
			
		||||
        return super().get_queryset(**kwargs).order_by("-id").all()[:50]
 | 
			
		||||
 | 
			
		||||
    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.contenttypes.models import ContentType
 | 
			
		||||
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 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
 | 
			
		||||
            type=type,
 | 
			
		||||
        ).all():
 | 
			
		||||
            if not isinstance(model, permission.model.__class__):
 | 
			
		||||
            if not isinstance(model, permission.model.__class__) or not permission.club:
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            club = Club.objects.get(pk=permission.club)
 | 
			
		||||
@@ -49,6 +49,7 @@ class PermissionBackend(ModelBackend):
 | 
			
		||||
                NoteUser=NoteUser,
 | 
			
		||||
                NoteClub=NoteClub,
 | 
			
		||||
                NoteSpecial=NoteSpecial,
 | 
			
		||||
                NoteActivity=NoteActivity,
 | 
			
		||||
                F=F,
 | 
			
		||||
                Q=Q
 | 
			
		||||
            )
 | 
			
		||||
 
 | 
			
		||||
@@ -176,7 +176,7 @@
 | 
			
		||||
        "note",
 | 
			
		||||
        "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",
 | 
			
		||||
      "mask": 1,
 | 
			
		||||
      "field": "",
 | 
			
		||||
@@ -386,7 +386,7 @@
 | 
			
		||||
        "note",
 | 
			
		||||
        "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",
 | 
			
		||||
      "mask": 2,
 | 
			
		||||
      "field": "",
 | 
			
		||||
@@ -783,6 +783,111 @@
 | 
			
		||||
      "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",
 | 
			
		||||
    "pk": 1,
 | 
			
		||||
@@ -810,7 +915,6 @@
 | 
			
		||||
        3,
 | 
			
		||||
        4,
 | 
			
		||||
        5,
 | 
			
		||||
        6,
 | 
			
		||||
        7,
 | 
			
		||||
        8,
 | 
			
		||||
        9,
 | 
			
		||||
@@ -827,7 +931,12 @@
 | 
			
		||||
        35,
 | 
			
		||||
        36,
 | 
			
		||||
        39,
 | 
			
		||||
        40
 | 
			
		||||
        40,
 | 
			
		||||
        6,
 | 
			
		||||
        52,
 | 
			
		||||
        53,
 | 
			
		||||
        51,
 | 
			
		||||
        50
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
@@ -838,9 +947,9 @@
 | 
			
		||||
      "role": 8,
 | 
			
		||||
      "permissions": [
 | 
			
		||||
        19,
 | 
			
		||||
        20,
 | 
			
		||||
        21,
 | 
			
		||||
        22
 | 
			
		||||
        22,
 | 
			
		||||
        20
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
@@ -880,5 +989,18 @@
 | 
			
		||||
        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:
 | 
			
		||||
                self.update_query()
 | 
			
		||||
 | 
			
		||||
                # Don't increase indexes
 | 
			
		||||
                obj.pk = 0
 | 
			
		||||
                # Don't increase indexes, if the primary key is an AutoField
 | 
			
		||||
                if not hasattr(obj, "pk") or not obj.pk:
 | 
			
		||||
                    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
 | 
			
		||||
                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
 | 
			
		||||
                Model.delete(obj)
 | 
			
		||||
 | 
			
		||||
                # If the primary key was specified, we restore it
 | 
			
		||||
                obj.pk = oldpk
 | 
			
		||||
                return ret
 | 
			
		||||
 | 
			
		||||
        if permission_type == self.type:
 | 
			
		||||
            if self.field and field_name != self.field:
 | 
			
		||||
                return False
 | 
			
		||||
            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:
 | 
			
		||||
            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.utils.translation import gettext_lazy as _
 | 
			
		||||
from note_kfet.inputs import DatePickerInput, AmountInput
 | 
			
		||||
from permission.backends import PermissionBackend
 | 
			
		||||
 | 
			
		||||
from .models import Invoice, Product, Remittance, SpecialTransactionProxy
 | 
			
		||||
 | 
			
		||||
@@ -131,7 +132,8 @@ class LinkTransactionToRemittanceForm(forms.ModelForm):
 | 
			
		||||
        # Add submit button
 | 
			
		||||
        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):
 | 
			
		||||
        """
 | 
			
		||||
 
 | 
			
		||||
@@ -19,13 +19,15 @@ from django.views.generic.base import View, TemplateView
 | 
			
		||||
from django_tables2 import SingleTableView
 | 
			
		||||
from note.models import SpecialTransaction, NoteSpecial
 | 
			
		||||
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 .models import Invoice, Product, Remittance, SpecialTransactionProxy
 | 
			
		||||
from .tables import InvoiceTable, RemittanceTable, SpecialTransactionTable
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class InvoiceCreateView(LoginRequiredMixin, CreateView):
 | 
			
		||||
class InvoiceCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
 | 
			
		||||
    """
 | 
			
		||||
    Create Invoice
 | 
			
		||||
    """
 | 
			
		||||
@@ -67,7 +69,7 @@ class InvoiceCreateView(LoginRequiredMixin, CreateView):
 | 
			
		||||
        return reverse_lazy('treasury:invoice_list')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class InvoiceListView(LoginRequiredMixin, SingleTableView):
 | 
			
		||||
class InvoiceListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
 | 
			
		||||
    """
 | 
			
		||||
    List existing Invoices
 | 
			
		||||
    """
 | 
			
		||||
@@ -75,7 +77,7 @@ class InvoiceListView(LoginRequiredMixin, SingleTableView):
 | 
			
		||||
    table_class = InvoiceTable
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class InvoiceUpdateView(LoginRequiredMixin, UpdateView):
 | 
			
		||||
class InvoiceUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
 | 
			
		||||
    """
 | 
			
		||||
    Create Invoice
 | 
			
		||||
    """
 | 
			
		||||
@@ -130,7 +132,7 @@ class InvoiceRenderView(LoginRequiredMixin, View):
 | 
			
		||||
 | 
			
		||||
    def get(self, request, **kwargs):
 | 
			
		||||
        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()
 | 
			
		||||
 | 
			
		||||
        # Informations of the BDE. Should be updated when the school will move.
 | 
			
		||||
@@ -188,7 +190,7 @@ class InvoiceRenderView(LoginRequiredMixin, View):
 | 
			
		||||
        return response
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class RemittanceCreateView(LoginRequiredMixin, CreateView):
 | 
			
		||||
class RemittanceCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
 | 
			
		||||
    """
 | 
			
		||||
    Create Remittance
 | 
			
		||||
    """
 | 
			
		||||
@@ -201,7 +203,9 @@ class RemittanceCreateView(LoginRequiredMixin, CreateView):
 | 
			
		||||
    def get_context_data(self, **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())
 | 
			
		||||
 | 
			
		||||
        return ctx
 | 
			
		||||
@@ -216,22 +220,28 @@ class RemittanceListView(LoginRequiredMixin, TemplateView):
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        ctx = super().get_context_data(**kwargs)
 | 
			
		||||
 | 
			
		||||
        ctx["opened_remittances"] = RemittanceTable(data=Remittance.objects.filter(closed=False).all())
 | 
			
		||||
        ctx["closed_remittances"] = RemittanceTable(data=Remittance.objects.filter(closed=True).reverse().all())
 | 
			
		||||
        ctx["opened_remittances"] = RemittanceTable(
 | 
			
		||||
            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(
 | 
			
		||||
            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', ))
 | 
			
		||||
        ctx["special_transactions_with_remittance"] = SpecialTransactionTable(
 | 
			
		||||
            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', ))
 | 
			
		||||
 | 
			
		||||
        return ctx
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class RemittanceUpdateView(LoginRequiredMixin, UpdateView):
 | 
			
		||||
class RemittanceUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
 | 
			
		||||
    """
 | 
			
		||||
    Update Remittance
 | 
			
		||||
    """
 | 
			
		||||
@@ -244,8 +254,10 @@ class RemittanceUpdateView(LoginRequiredMixin, UpdateView):
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        ctx = super().get_context_data(**kwargs)
 | 
			
		||||
 | 
			
		||||
        ctx["table"] = RemittanceTable(data=Remittance.objects.all())
 | 
			
		||||
        data = SpecialTransaction.objects.filter(specialtransactionproxy__remittance=self.object).all()
 | 
			
		||||
        ctx["table"] = RemittanceTable(data=Remittance.objects.filter(
 | 
			
		||||
                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(
 | 
			
		||||
            data=data,
 | 
			
		||||
            exclude=('remittance_add', 'remittance_remove', ) if self.object.closed else ('remittance_add', ))
 | 
			
		||||
@@ -253,7 +265,7 @@ class RemittanceUpdateView(LoginRequiredMixin, UpdateView):
 | 
			
		||||
        return ctx
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LinkTransactionToRemittanceView(LoginRequiredMixin, UpdateView):
 | 
			
		||||
class LinkTransactionToRemittanceView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
 | 
			
		||||
    """
 | 
			
		||||
    Attach a special transaction to a remittance
 | 
			
		||||
    """
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
{% load i18n %}
 | 
			
		||||
{% load render_table from django_tables2 %}
 | 
			
		||||
{% load pretty_money %}
 | 
			
		||||
{% load perms %}
 | 
			
		||||
 | 
			
		||||
{% block profile_info %}
 | 
			
		||||
{% include "member/club_info.html" %}
 | 
			
		||||
@@ -25,9 +26,11 @@
 | 
			
		||||
                <dd class="col-xl-6">{{ note.balance|pretty_money }}</dd>
 | 
			
		||||
            </dl>
 | 
			
		||||
 | 
			
		||||
            <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>
 | 
			
		||||
            </div>
 | 
			
		||||
            {% if "change_"|has_perm:note %}
 | 
			
		||||
                <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>
 | 
			
		||||
                </div>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,9 +19,11 @@
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <a href="{% url 'member:club_linked_note_create' club_pk=club.pk %}">
 | 
			
		||||
            <button class="btn btn-primary btn-block">{% trans "Add new note" %}</button>
 | 
			
		||||
        </a>
 | 
			
		||||
        {% if can_create %}
 | 
			
		||||
            <a href="{% url 'member:club_linked_note_create' club_pk=club.pk %}">
 | 
			
		||||
                <button class="btn btn-primary btn-block">{% trans "Add new note" %}</button>
 | 
			
		||||
            </a>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user