mirror of https://gitlab.crans.org/bde/nk20
Full membership support
This commit is contained in:
parent
bf9789bd9e
commit
d5b010980b
|
@ -50,6 +50,9 @@ def save_object(sender, instance, **kwargs):
|
||||||
if instance._meta.label_lower in EXCLUDED:
|
if instance._meta.label_lower in EXCLUDED:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if hasattr(instance, "_force_save"):
|
||||||
|
return
|
||||||
|
|
||||||
# noinspection PyProtectedMember
|
# noinspection PyProtectedMember
|
||||||
previous = instance._previous
|
previous = instance._previous
|
||||||
|
|
||||||
|
@ -106,6 +109,9 @@ def delete_object(sender, instance, **kwargs):
|
||||||
if instance._meta.label_lower in EXCLUDED:
|
if instance._meta.label_lower in EXCLUDED:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if hasattr(instance, "_force_delete"):
|
||||||
|
return
|
||||||
|
|
||||||
# Si un utilisateur est connecté, on récupère l'utilisateur courant ainsi que son adresse IP
|
# Si un utilisateur est connecté, on récupère l'utilisateur courant ainsi que son adresse IP
|
||||||
user, ip = get_current_authenticated_user(), get_current_ip()
|
user, ip = get_current_authenticated_user(), get_current_ip()
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
"fields": {
|
"fields": {
|
||||||
"name": "Kfet",
|
"name": "Kfet",
|
||||||
"email": "tresorerie.bde@example.com",
|
"email": "tresorerie.bde@example.com",
|
||||||
|
"parent_club": 1,
|
||||||
"require_memberships": true,
|
"require_memberships": true,
|
||||||
"membership_fee": 3500,
|
"membership_fee": 3500,
|
||||||
"membership_duration": 396,
|
"membership_duration": 396,
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
|
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
from note_kfet.inputs import Autocomplete, AmountInput, DatePickerInput
|
from note_kfet.inputs import Autocomplete, AmountInput, DatePickerInput
|
||||||
from permission.models import PermissionMask
|
from permission.models import PermissionMask
|
||||||
|
|
||||||
|
@ -57,11 +58,6 @@ class ClubForm(forms.ModelForm):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class AddMembersForm(forms.Form):
|
|
||||||
class Meta:
|
|
||||||
fields = ('',)
|
|
||||||
|
|
||||||
|
|
||||||
class MembershipForm(forms.ModelForm):
|
class MembershipForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Membership
|
model = Membership
|
||||||
|
|
|
@ -4,11 +4,14 @@
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import ValidationError
|
from django.contrib.auth.models import User
|
||||||
|
from django.core.exceptions import ValidationError, PermissionDenied
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.urls import reverse, reverse_lazy
|
from django.urls import reverse, reverse_lazy
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from note.models import MembershipTransaction
|
||||||
|
|
||||||
|
|
||||||
class Profile(models.Model):
|
class Profile(models.Model):
|
||||||
"""
|
"""
|
||||||
|
@ -91,7 +94,7 @@ class Club(models.Model):
|
||||||
verbose_name=_('membership fee'),
|
verbose_name=_('membership fee'),
|
||||||
)
|
)
|
||||||
|
|
||||||
membership_duration = models.IntegerField(
|
membership_duration = models.PositiveIntegerField(
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
verbose_name=_('membership duration'),
|
verbose_name=_('membership duration'),
|
||||||
|
@ -174,7 +177,7 @@ class Membership(models.Model):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
user = models.ForeignKey(
|
user = models.ForeignKey(
|
||||||
settings.AUTH_USER_MODEL,
|
User,
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.PROTECT,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -185,6 +188,7 @@ class Membership(models.Model):
|
||||||
|
|
||||||
roles = models.ManyToManyField(
|
roles = models.ManyToManyField(
|
||||||
Role,
|
Role,
|
||||||
|
verbose_name=_("roles"),
|
||||||
)
|
)
|
||||||
|
|
||||||
date_start = models.DateField(
|
date_start = models.DateField(
|
||||||
|
@ -209,17 +213,41 @@ class Membership(models.Model):
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if self.club.parent_club is not None:
|
if self.club.parent_club is not None:
|
||||||
if not Membership.objects.filter(user=self.user, club=self.club.parent_club).exists():
|
if not Membership.objects.filter(user=self.user, club=self.club.parent_club).exists():
|
||||||
raise ValidationError(_('User is not a member of the parent club'))
|
raise ValidationError(_('User is not a member of the parent club') + ' ' + self.club.parent_club.name)
|
||||||
|
|
||||||
created = not self.pk
|
created = not self.pk
|
||||||
if created:
|
if created:
|
||||||
|
if Membership.objects.filter(
|
||||||
|
user=self.user,
|
||||||
|
club=self.club,
|
||||||
|
date_start__lte=datetime.datetime.now().date(),
|
||||||
|
date_end__gte=datetime.datetime.now().date(),
|
||||||
|
).exists():
|
||||||
|
raise ValidationError(_('User is already a member of the club'))
|
||||||
|
|
||||||
self.fee = self.club.membership_fee
|
self.fee = self.club.membership_fee
|
||||||
self.date_end = self.date_start + datetime.timedelta(days=self.club.membership_duration)
|
if self.club.membership_duration is not None:
|
||||||
if self.date_end > self.club.membership_end:
|
self.date_end = self.date_start + datetime.timedelta(days=self.club.membership_duration)
|
||||||
|
else:
|
||||||
|
self.date_end = self.date_start + datetime.timedelta(days=0x7FFFFFFF)
|
||||||
|
if self.club.membership_end is not None and self.date_end > self.club.membership_end:
|
||||||
self.date_end = self.club.membership_end
|
self.date_end = self.club.membership_end
|
||||||
|
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
if created and self.fee:
|
||||||
|
try:
|
||||||
|
MembershipTransaction.objects.create(
|
||||||
|
membership=self,
|
||||||
|
source=self.user.note,
|
||||||
|
destination=self.club.note,
|
||||||
|
quantity=1,
|
||||||
|
amount=self.fee,
|
||||||
|
reason="Adhésion",
|
||||||
|
)
|
||||||
|
except PermissionDenied:
|
||||||
|
self.delete()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('membership')
|
verbose_name = _('membership')
|
||||||
verbose_name_plural = _('memberships')
|
verbose_name_plural = _('memberships')
|
||||||
|
|
|
@ -3,8 +3,14 @@
|
||||||
|
|
||||||
import django_tables2 as tables
|
import django_tables2 as tables
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.urls import reverse_lazy
|
||||||
|
from django.utils.html import format_html
|
||||||
|
from django_tables2 import A
|
||||||
|
|
||||||
from .models import Club
|
from note.templatetags.pretty_money import pretty_money
|
||||||
|
from note_kfet.middlewares import get_current_authenticated_user
|
||||||
|
from permission.backends import PermissionBackend
|
||||||
|
from .models import Club, Membership
|
||||||
|
|
||||||
|
|
||||||
class ClubTable(tables.Table):
|
class ClubTable(tables.Table):
|
||||||
|
@ -33,3 +39,33 @@ class UserTable(tables.Table):
|
||||||
template_name = 'django_tables2/bootstrap4.html'
|
template_name = 'django_tables2/bootstrap4.html'
|
||||||
fields = ('last_name', 'first_name', 'username', 'email')
|
fields = ('last_name', 'first_name', 'username', 'email')
|
||||||
model = User
|
model = User
|
||||||
|
|
||||||
|
|
||||||
|
class MembershipTable(tables.Table):
|
||||||
|
roles = tables.Column(
|
||||||
|
attrs={
|
||||||
|
"td": {
|
||||||
|
"class": "text-truncate",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def render_fee(self, value):
|
||||||
|
return pretty_money(value)
|
||||||
|
|
||||||
|
def render_roles(self, record):
|
||||||
|
roles = record.roles.all()
|
||||||
|
s = ", ".join(str(role) for role in roles)
|
||||||
|
if PermissionBackend().has_perm(get_current_authenticated_user(), "member.change_membership_roles", record):
|
||||||
|
s = format_html("<a href='" + str(reverse_lazy("member:club_manage_roles", kwargs={"pk": record.pk}))
|
||||||
|
+ "'>" + s + "</a>")
|
||||||
|
return s
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
attrs = {
|
||||||
|
'class': 'table table-condensed table-striped table-hover',
|
||||||
|
'style': 'table-layout: fixed;'
|
||||||
|
}
|
||||||
|
template_name = 'django_tables2/bootstrap4.html'
|
||||||
|
fields = ('user', 'club', 'date_start', 'date_end', 'roles', 'fee', )
|
||||||
|
model = Membership
|
||||||
|
|
|
@ -12,15 +12,16 @@ urlpatterns = [
|
||||||
path('club/', views.ClubListView.as_view(), name="club_list"),
|
path('club/', views.ClubListView.as_view(), name="club_list"),
|
||||||
path('club/<int:pk>/', views.ClubDetailView.as_view(), name="club_detail"),
|
path('club/<int:pk>/', views.ClubDetailView.as_view(), name="club_detail"),
|
||||||
path('club/<int:pk>/add_member/', views.ClubAddMemberView.as_view(), name="club_add_member"),
|
path('club/<int:pk>/add_member/', views.ClubAddMemberView.as_view(), name="club_add_member"),
|
||||||
|
path('club/manage_roles/<int:pk>/', views.ClubManageRolesView.as_view(), name="club_manage_roles"),
|
||||||
path('club/create/', views.ClubCreateView.as_view(), name="club_create"),
|
path('club/create/', views.ClubCreateView.as_view(), name="club_create"),
|
||||||
path('club/<int:pk>/update/', views.ClubUpdateView.as_view(), name="club_update"),
|
path('club/<int:pk>/update/', views.ClubUpdateView.as_view(), name="club_update"),
|
||||||
path('club/<int:pk>/update_pic/', views.ClubPictureUpdateView.as_view(), name="club_update_pic"),
|
path('club/<int:pk>/update_pic/', views.ClubPictureUpdateView.as_view(), name="club_update_pic"),
|
||||||
path('club/<int:pk>/aliases/', views.ClubAliasView.as_view(), name="club_alias"),
|
path('club/<int:pk>/aliases/', views.ClubAliasView.as_view(), name="club_alias"),
|
||||||
|
|
||||||
path('user/', views.UserListView.as_view(), name="user_list"),
|
path('user/', views.UserListView.as_view(), name="user_list"),
|
||||||
path('user/<int:pk>', views.UserDetailView.as_view(), name="user_detail"),
|
path('user/<int:pk>/', views.UserDetailView.as_view(), name="user_detail"),
|
||||||
path('user/<int:pk>/update', views.UserUpdateView.as_view(), name="user_update_profile"),
|
path('user/<int:pk>/update/', views.UserUpdateView.as_view(), name="user_update_profile"),
|
||||||
path('user/<int:pk>/update_pic', views.ProfilePictureUpdateView.as_view(), name="user_update_pic"),
|
path('user/<int:pk>/update_pic/', views.ProfilePictureUpdateView.as_view(), name="user_update_pic"),
|
||||||
path('user/<int:pk>/aliases', views.ProfileAliasView.as_view(), name="user_alias"),
|
path('user/<int:pk>/aliases/', views.ProfileAliasView.as_view(), name="user_alias"),
|
||||||
path('manage-auth-token/', views.ManageAuthTokens.as_view(), name='auth_token'),
|
path('manage-auth-token/', views.ManageAuthTokens.as_view(), name='auth_token'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -10,6 +10,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.auth.views import LoginView
|
from django.contrib.auth.views import LoginView
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
from django.forms import HiddenInput
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
@ -27,7 +28,7 @@ from permission.views import ProtectQuerysetMixin
|
||||||
from .filters import UserFilter, UserFilterFormHelper
|
from .filters import UserFilter, UserFilterFormHelper
|
||||||
from .forms import SignUpForm, ProfileForm, ClubForm, MembershipForm, CustomAuthenticationForm
|
from .forms import SignUpForm, ProfileForm, ClubForm, MembershipForm, CustomAuthenticationForm
|
||||||
from .models import Club, Membership
|
from .models import Club, Membership
|
||||||
from .tables import ClubTable, UserTable
|
from .tables import ClubTable, UserTable, MembershipTable
|
||||||
|
|
||||||
|
|
||||||
class CustomLoginView(LoginView):
|
class CustomLoginView(LoginView):
|
||||||
|
@ -138,7 +139,7 @@ class UserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
|
||||||
context['history_list'] = HistoryTable(history_list)
|
context['history_list'] = HistoryTable(history_list)
|
||||||
club_list = Membership.objects.all().filter(user=user)\
|
club_list = Membership.objects.all().filter(user=user)\
|
||||||
.filter(PermissionBackend.filter_queryset(self.request.user, Membership, "view")).only("club")
|
.filter(PermissionBackend.filter_queryset(self.request.user, Membership, "view")).only("club")
|
||||||
context['club_list'] = ClubTable(club_list)
|
context['club_list'] = MembershipTable(data=club_list)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
@ -294,7 +295,19 @@ class ClubDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
|
||||||
date_start__lte=datetime.now().date(),
|
date_start__lte=datetime.now().date(),
|
||||||
date_end__gte=datetime.now().date(),
|
date_end__gte=datetime.now().date(),
|
||||||
).filter(PermissionBackend.filter_queryset(self.request.user, Membership, "view")).all()
|
).filter(PermissionBackend.filter_queryset(self.request.user, Membership, "view")).all()
|
||||||
context['member_list'] = club_member
|
|
||||||
|
context['member_list'] = MembershipTable(data=club_member)
|
||||||
|
|
||||||
|
empty_membership = Membership(
|
||||||
|
club=club,
|
||||||
|
user=User.objects.first(),
|
||||||
|
date_start=datetime.now().date(),
|
||||||
|
date_end=datetime.now().date(),
|
||||||
|
fee=0,
|
||||||
|
)
|
||||||
|
context["can_add_members"] = PermissionBackend()\
|
||||||
|
.has_perm(self.request.user, "member.add_membership", empty_membership)
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
@ -339,7 +352,6 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
|
||||||
.get(pk=self.kwargs["pk"])
|
.get(pk=self.kwargs["pk"])
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
context['club'] = club
|
context['club'] = club
|
||||||
context['no_cache'] = True
|
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
@ -347,6 +359,63 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
|
||||||
club = Club.objects.filter(PermissionBackend.filter_queryset(self.request.user, Club, "view"))\
|
club = Club.objects.filter(PermissionBackend.filter_queryset(self.request.user, Club, "view"))\
|
||||||
.get(pk=self.kwargs["pk"])
|
.get(pk=self.kwargs["pk"])
|
||||||
form.instance.club = club
|
form.instance.club = club
|
||||||
|
|
||||||
|
if club.parent_club is not None:
|
||||||
|
if not Membership.objects.filter(user=form.instance.user, club=club.parent_club).exists():
|
||||||
|
form.add_error('user', _('User is not a member of the parent club') + ' ' + club.parent_club.name)
|
||||||
|
return super().form_invalid(form)
|
||||||
|
|
||||||
|
if Membership.objects.filter(
|
||||||
|
user=form.instance.user,
|
||||||
|
club=club,
|
||||||
|
date_start__lte=datetime.now().date(),
|
||||||
|
date_end__gte=datetime.now().date(),
|
||||||
|
).exists():
|
||||||
|
form.add_error('user', _('User is already a member of the club'))
|
||||||
|
return super().form_invalid(form)
|
||||||
|
|
||||||
|
if form.instance.date_start < form.instance.club.membership_start:
|
||||||
|
form.add_error('user', _("The membership must start after {:%m-%d-%Y}.")
|
||||||
|
.format(form.instance.club.membership_start))
|
||||||
|
return super().form_invalid(form)
|
||||||
|
|
||||||
|
if form.instance.date_start > form.instance.club.membership_end:
|
||||||
|
form.add_error('user', _("The membership must end before {:%m-%d-%Y}.")
|
||||||
|
.format(form.instance.club.membership_start))
|
||||||
|
return super().form_invalid(form)
|
||||||
|
|
||||||
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return reverse_lazy('member:club_detail', kwargs={'pk': self.object.club.id})
|
||||||
|
|
||||||
|
|
||||||
|
class ClubManageRolesView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
|
||||||
|
model = Membership
|
||||||
|
form_class = MembershipForm
|
||||||
|
template_name = 'member/add_members.html'
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
club = self.object.club
|
||||||
|
context['club'] = club
|
||||||
|
form = context['form']
|
||||||
|
form.fields['user'].disabled = True
|
||||||
|
form.fields['date_start'].widget = HiddenInput()
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
if form.instance.date_start < form.instance.club.membership_start:
|
||||||
|
form.add_error('user', _("The membership must start after {:%m-%d-%Y}.")
|
||||||
|
.format(form.instance.club.membership_start))
|
||||||
|
return super().form_invalid(form)
|
||||||
|
|
||||||
|
if form.instance.date_start > form.instance.club.membership_end:
|
||||||
|
form.add_error('user', _("The membership must end before {:%m-%d-%Y}.")
|
||||||
|
.format(form.instance.club.membership_start))
|
||||||
|
return super().form_invalid(form)
|
||||||
|
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
|
|
|
@ -138,6 +138,13 @@ class TransactionAdmin(PolymorphicParentModelAdmin):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(MembershipTransaction)
|
||||||
|
class MembershipTransactionAdmin(PolymorphicChildModelAdmin):
|
||||||
|
"""
|
||||||
|
Admin customisation for Transaction
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
@admin.register(TransactionTemplate)
|
@admin.register(TransactionTemplate)
|
||||||
class TransactionTemplateAdmin(admin.ModelAdmin):
|
class TransactionTemplateAdmin(admin.ModelAdmin):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -140,6 +140,7 @@ class Transaction(PolymorphicModel):
|
||||||
max_length=255,
|
max_length=255,
|
||||||
default=None,
|
default=None,
|
||||||
null=True,
|
null=True,
|
||||||
|
blank=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# 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
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
|
||||||
from django.contrib.auth.backends import ModelBackend
|
from django.contrib.auth.backends import ModelBackend
|
||||||
from django.contrib.auth.models import User, AnonymousUser
|
from django.contrib.auth.models import User, AnonymousUser
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
@ -32,7 +34,8 @@ class PermissionBackend(ModelBackend):
|
||||||
for permission in Permission.objects.annotate(club=F("rolepermissions__role__membership__club")) \
|
for permission in Permission.objects.annotate(club=F("rolepermissions__role__membership__club")) \
|
||||||
.filter(
|
.filter(
|
||||||
rolepermissions__role__membership__user=user,
|
rolepermissions__role__membership__user=user,
|
||||||
rolepermissions__role__membership__valid=True,
|
rolepermissions__role__membership__date_start__lte=datetime.date.today(),
|
||||||
|
rolepermissions__role__membership__date_end__gte=datetime.date.today(),
|
||||||
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():
|
||||||
|
|
|
@ -45,11 +45,13 @@ class InstancedPermission:
|
||||||
else:
|
else:
|
||||||
oldpk = obj.pk
|
oldpk = obj.pk
|
||||||
# Ensure previous models are deleted
|
# Ensure previous models are deleted
|
||||||
self.model.model_class().objects.filter(pk=obj.pk).delete()
|
self.model.model_class().objects.filter(pk=obj.pk).annotate(_force_delete=F("pk") + 1).delete()
|
||||||
# Force insertion, no data verification, no trigger
|
# Force insertion, no data verification, no trigger
|
||||||
|
obj._force_save = True
|
||||||
Model.save(obj, force_insert=True)
|
Model.save(obj, force_insert=True)
|
||||||
ret = self.model.model_class().objects.filter(self.query & Q(pk=obj.pk)).exists()
|
ret = self.model.model_class().objects.filter(self.query & Q(pk=obj.pk)).exists()
|
||||||
# Delete testing object
|
# Delete testing object
|
||||||
|
obj._force_delete = True
|
||||||
Model.delete(obj)
|
Model.delete(obj)
|
||||||
|
|
||||||
# If the primary key was specified, we restore it
|
# If the primary key was specified, we restore it
|
||||||
|
|
|
@ -29,6 +29,9 @@ def pre_save_object(sender, instance, **kwargs):
|
||||||
if instance._meta.label_lower in EXCLUDED:
|
if instance._meta.label_lower in EXCLUDED:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if hasattr(instance, "_force_save"):
|
||||||
|
return
|
||||||
|
|
||||||
user = get_current_authenticated_user()
|
user = get_current_authenticated_user()
|
||||||
if user is None:
|
if user is None:
|
||||||
# Action performed on shell is always granted
|
# Action performed on shell is always granted
|
||||||
|
@ -58,32 +61,14 @@ def pre_save_object(sender, instance, **kwargs):
|
||||||
if not PermissionBackend().has_perm(user, app_label + ".change_" + model_name + "_" + field_name, instance):
|
if not PermissionBackend().has_perm(user, app_label + ".change_" + model_name + "_" + field_name, instance):
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
else:
|
else:
|
||||||
# We check if the user can add the model
|
|
||||||
|
|
||||||
# While checking permissions, the object will be inserted in the DB, then removed.
|
|
||||||
# We disable temporary the connectors
|
|
||||||
pre_save.disconnect(pre_save_object)
|
|
||||||
pre_delete.disconnect(pre_delete_object)
|
|
||||||
# We disable also logs connectors
|
|
||||||
pre_save.disconnect(logs_signals.pre_save_object)
|
|
||||||
post_save.disconnect(logs_signals.save_object)
|
|
||||||
post_delete.disconnect(logs_signals.delete_object)
|
|
||||||
|
|
||||||
# We check if the user has right to add the object
|
# We check if the user has right to add the object
|
||||||
has_perm = PermissionBackend().has_perm(user, app_label + ".add_" + model_name, instance)
|
has_perm = PermissionBackend().has_perm(user, app_label + ".add_" + model_name, instance)
|
||||||
|
|
||||||
# Then we reconnect all
|
|
||||||
pre_save.connect(pre_save_object)
|
|
||||||
pre_delete.connect(pre_delete_object)
|
|
||||||
pre_save.connect(logs_signals.pre_save_object)
|
|
||||||
post_save.connect(logs_signals.save_object)
|
|
||||||
post_delete.connect(logs_signals.delete_object)
|
|
||||||
|
|
||||||
if not has_perm:
|
if not has_perm:
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
|
|
||||||
|
|
||||||
def pre_delete_object(sender, instance, **kwargs):
|
def pre_delete_object(instance, **kwargs):
|
||||||
"""
|
"""
|
||||||
Before a model get deleted, we check the permissions
|
Before a model get deleted, we check the permissions
|
||||||
"""
|
"""
|
||||||
|
@ -91,6 +76,9 @@ def pre_delete_object(sender, instance, **kwargs):
|
||||||
if instance._meta.label_lower in EXCLUDED:
|
if instance._meta.label_lower in EXCLUDED:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if hasattr(instance, "_force_delete"):
|
||||||
|
return
|
||||||
|
|
||||||
user = get_current_authenticated_user()
|
user = get_current_authenticated_user()
|
||||||
if user is None:
|
if user is None:
|
||||||
# Action performed on shell is always granted
|
# Action performed on shell is always granted
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
import datetime
|
|
||||||
from json import dumps as json_dumps
|
from json import dumps as json_dumps
|
||||||
|
|
||||||
from django.forms.widgets import DateTimeBaseInput, NumberInput, TextInput
|
from django.forms.widgets import DateTimeBaseInput, NumberInput, TextInput
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% load i18n static pretty_money %}
|
{% load i18n static pretty_money perms %}
|
||||||
<div class="card bg-light shadow">
|
<div class="card bg-light shadow">
|
||||||
<div class="card-header text-center">
|
<div class="card-header text-center">
|
||||||
<h4> Club {{ club.name }} </h4>
|
<h4> Club {{ club.name }} </h4>
|
||||||
|
@ -40,9 +40,12 @@
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
<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_add_member' pk=club.pk %}"> {% trans "Add member" %}</a>
|
{% if can_add_members %}
|
||||||
<a class="btn btn-primary btn-sm my-1" href="{% url 'member:club_update' pk=club.pk %}"> {% trans "Edit" %}</a>
|
<a class="btn btn-primary btn-sm my-1" href="{% url 'member:club_add_member' pk=club.pk %}"> {% trans "Add member" %}</a>
|
||||||
<a class="btn btn-primary btn-sm my-1" href="{% url 'member:club_add_member' pk=club.pk %}"> {% trans "Add roles" %}</a>
|
{% endif %}
|
||||||
|
{% if ".change_"|has_perm:club %}
|
||||||
|
<a class="btn btn-primary btn-sm my-1" href="{% url 'member:club_update' pk=club.pk %}"> {% trans "Edit" %}</a>
|
||||||
|
{% endif %}
|
||||||
{% url 'member:club_detail' club.pk as club_detail_url %}
|
{% url 'member:club_detail' club.pk as club_detail_url %}
|
||||||
{%if request.get_full_path != club_detail_url %}
|
{%if request.get_full_path != club_detail_url %}
|
||||||
<a class="btn btn-primary btn-sm my-1" href="{{ club_detail_url }}">{% trans 'View Profile' %}</a>
|
<a class="btn btn-primary btn-sm my-1" href="{{ club_detail_url }}">{% trans 'View Profile' %}</a>
|
||||||
|
|
Loading…
Reference in New Issue