mirror of
https://gitlab.crans.org/bde/nk20
synced 2024-12-22 23:42:25 +00:00
Improved permissions, 404 and 403 errors will be more frequent (when we type an invalid URL)
This commit is contained in:
parent
c384ee02eb
commit
1aae18e6a6
@ -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 %}
|
||||
|
Loading…
Reference in New Issue
Block a user