diff --git a/club/forms.py b/club/forms.py
index 5d6a3b10..a257dc50 100644
--- a/club/forms.py
+++ b/club/forms.py
@@ -30,8 +30,11 @@ from django.utils.translation import gettext_lazy as _
from club.models import Club, Mailing, MailingSubscription, Membership
from core.models import User
-from core.views.forms import SelectDate, SelectDateTime
-from core.views.widgets.ajax_select import AutoCompleteSelectMultipleUser
+from core.views.forms import SelectDateTime
+from core.views.widgets.ajax_select import (
+ AutoCompleteSelectMultipleUser,
+ AutoCompleteSelectUser,
+)
from counter.models import Counter, Selling
@@ -188,105 +191,73 @@ class SellingsForm(forms.Form):
)
-class ClubMemberForm(forms.Form):
+class ClubOldMemberForm(forms.Form):
+ members_old = forms.ModelMultipleChoiceField(
+ Membership.objects.none(),
+ label=_("Mark as old"),
+ widget=forms.CheckboxSelectMultiple,
+ required=False,
+ )
+
+ def __init__(self, *args, user: User, club: Club, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.fields["members_old"].queryset = (
+ Membership.objects.ongoing().filter(club=club).editable_by(user)
+ )
+
+
+class ClubMemberForm(forms.ModelForm):
"""Form handling the members of a club."""
error_css_class = "error"
required_css_class = "required"
- users = forms.ModelMultipleChoiceField(
- label=_("Users to add"),
- help_text=_("Search users to add (one or more)."),
- required=False,
- widget=AutoCompleteSelectMultipleUser,
- queryset=User.objects.all(),
- )
+ class Meta:
+ model = Membership
+ fields = ["user", "role", "description"]
+ widgets = {"user": AutoCompleteSelectUser}
- def __init__(self, *args, **kwargs):
- self.club = kwargs.pop("club")
- self.request_user = kwargs.pop("request_user")
- self.club_members = kwargs.pop("club_members", None)
- if not self.club_members:
- self.club_members = self.club.members.ongoing().order_by("-role").all()
+ def __init__(
+ self,
+ *args,
+ club: Club,
+ request_user: User,
+ **kwargs,
+ ):
+ self.club = club
+ self.request_user = request_user
self.request_user_membership = self.club.get_membership_for(self.request_user)
super().__init__(*args, **kwargs)
+ self.fields["role"].required = True
+ self.instance.club = club
- # Using a ModelForm binds too much the form with the model and we don't want that
- # We want the view to process the model creation since they are multiple users
- # We also want the form to handle bulk deletion
- self.fields.update(
- forms.fields_for_model(
- Membership,
- fields=("role", "start_date", "description"),
- widgets={"start_date": SelectDate},
- )
- )
-
- # Role is required only if users is specified
- self.fields["role"].required = False
-
- # Start date and description are never really required
- self.fields["start_date"].required = False
- self.fields["description"].required = False
-
- self.fields["users_old"] = forms.ModelMultipleChoiceField(
- User.objects.filter(
- id__in=[
- ms.user.id
- for ms in self.club_members
- if ms.can_be_edited_by(self.request_user)
- ]
- ).all(),
- label=_("Mark as old"),
- required=False,
- widget=forms.CheckboxSelectMultiple,
- )
- if not self.request_user.is_root:
- self.fields.pop("start_date")
-
- def clean_users(self):
- """Check that the user is not trying to add an user already in the club.
+ def clean_user(self):
+ """Check that the user is not trying to add a user already in the club.
Also check that the user is valid and has a valid subscription.
"""
- cleaned_data = super().clean()
- users = []
- for user in cleaned_data["users"]:
- if not user.is_subscribed:
- raise forms.ValidationError(
- _("User must be subscriber to take part to a club"), code="invalid"
- )
- if self.club.get_membership_for(user):
- raise forms.ValidationError(
- _("You can not add the same user twice"), code="invalid"
- )
- users.append(user)
- return users
+ user = self.cleaned_data["user"]
+ if not user.is_subscribed:
+ raise forms.ValidationError(
+ _("User must be subscriber to take part to a club"), code="invalid"
+ )
+ if self.club.get_membership_for(user):
+ raise forms.ValidationError(
+ _("You can not add the same user twice"), code="invalid"
+ )
+ return user
def clean(self):
"""Check user rights for adding an user."""
cleaned_data = super().clean()
-
- if "start_date" in cleaned_data and not cleaned_data["start_date"]:
- # Drop start_date if allowed to edition but not specified
- cleaned_data.pop("start_date")
-
- if not cleaned_data.get("users"):
- # No user to add equals no check needed
+ if "role" not in cleaned_data:
return cleaned_data
-
- if cleaned_data.get("role", "") == "":
- # Role is required if users exists
- self.add_error("role", _("You should specify a role"))
- return cleaned_data
-
request_user = self.request_user
membership = self.request_user_membership
if not (
cleaned_data["role"] <= settings.SITH_MAXIMUM_FREE_ROLE
or (membership is not None and membership.role >= cleaned_data["role"])
- or request_user.is_board_member
- or request_user.is_root
+ or request_user.has_perm("club.add_subscription")
):
raise forms.ValidationError(_("You do not have the permission to do that"))
return cleaned_data
diff --git a/club/models.py b/club/models.py
index 170187a2..67fe88ed 100644
--- a/club/models.py
+++ b/club/models.py
@@ -201,10 +201,6 @@ class Club(models.Model):
"""Method to see if that object can be edited by the given user."""
return self.has_rights_in_club(user)
- def can_be_viewed_by(self, user: User) -> bool:
- """Method to see if that object can be seen by the given user."""
- return user.was_subscribed
-
def get_membership_for(self, user: User) -> Membership | None:
"""Return the current membership the given user.
diff --git a/club/templates/club/club_members.jinja b/club/templates/club/club_members.jinja
index 0778b486..6f49fd65 100644
--- a/club/templates/club/club_members.jinja
+++ b/club/templates/club/club_members.jinja
@@ -1,15 +1,25 @@
{% extends "core/base.jinja" %}
{% from 'core/macros.jinja' import user_profile_link, select_all_checkbox %}
+{% block additional_js %}
+
+{% endblock %}
+{% block additional_css %}
+
+
+{% endblock %}
+
{% block content %}
{% trans %}Club members{% endtrans %}
+
+ {{ add_member_fragment }}
+
{% if members %}
-
{% endblock %}
diff --git a/club/templates/club/fragments/add_member.jinja b/club/templates/club/fragments/add_member.jinja
new file mode 100644
index 00000000..e59efda1
--- /dev/null
+++ b/club/templates/club/fragments/add_member.jinja
@@ -0,0 +1,27 @@
+
{% trans %}Add a new member{% endtrans %}
+
diff --git a/club/tests/base.py b/club/tests/base.py
index 8ae8f3f4..ca4fc6cf 100644
--- a/club/tests/base.py
+++ b/club/tests/base.py
@@ -43,6 +43,9 @@ class TestClub(TestCase):
cls.ae = Club.objects.get(pk=settings.SITH_MAIN_CLUB_ID)
cls.club = baker.make(Club)
+ cls.new_members_url = reverse(
+ "club:club_new_members", kwargs={"club_id": cls.club.id}
+ )
cls.members_url = reverse("club:club_members", kwargs={"club_id": cls.club.id})
a_month_ago = now() - timedelta(days=30)
yesterday = now() - timedelta(days=1)
diff --git a/club/tests/test_membership.py b/club/tests/test_membership.py
index 64d00a50..8a3e5737 100644
--- a/club/tests/test_membership.py
+++ b/club/tests/test_membership.py
@@ -7,6 +7,7 @@ from django.test import TestCase
from django.urls import reverse
from django.utils.timezone import localdate, localtime, now
from model_bakery import baker
+from pytest_django.asserts import assertRedirects
from club.forms import ClubMemberForm
from club.models import Club, Membership
@@ -185,7 +186,7 @@ class TestMembership(TestClub):
def assert_membership_ended_today(self, user: User):
"""Assert that the given user have a membership which ended today."""
- today = localtime(now()).date()
+ today = localdate()
assert user.memberships.filter(club=self.club, end_date=today).exists()
assert self.club.get_membership_for(user) is None
@@ -194,7 +195,9 @@ class TestMembership(TestClub):
cannot see the page.
"""
response = self.client.post(self.members_url)
- assert response.status_code == 403
+ assertRedirects(
+ response, reverse("core:login", query={"next": self.members_url})
+ )
self.client.force_login(self.public)
response = self.client.post(self.members_url)
@@ -205,7 +208,9 @@ class TestMembership(TestClub):
information are displayed.
"""
self.client.force_login(self.simple_board_member)
- response = self.client.get(self.members_url)
+ response = self.client.get(
+ reverse("club:club_members", kwargs={"club_id": self.club.id})
+ )
assert response.status_code == 200
soup = BeautifulSoup(response.text, "lxml")
table = soup.find("table", id="club_members_table")
@@ -231,59 +236,45 @@ class TestMembership(TestClub):
assert cols[2].text == membership.description
assert cols[3].text == str(membership.start_date)
- if membership.role <= 3: # 3 is the role of simple_board_member
+ if membership.role < 3 or membership.user_id == self.simple_board_member.id:
+ # 3 is the role of simple_board_member
form_input = cols[4].find("input")
expected_attrs = {
"type": "checkbox",
- "name": "users_old",
- "value": str(user.id),
+ "name": "members_old",
+ "value": str(membership.id),
}
assert form_input.attrs.items() >= expected_attrs.items()
else:
assert cols[4].find_all() == []
def test_root_add_one_club_member(self):
- """Test that root users can add members to clubs, one at a time."""
+ """Test that root users can add members to clubs"""
self.client.force_login(self.root)
response = self.client.post(
- self.members_url,
- {"users": [self.subscriber.id], "role": 3},
+ self.new_members_url, {"user": self.subscriber.id, "role": 3}
+ )
+ assert response.status_code == 200
+ assert response.headers.get("HX-Redirect", "") == reverse(
+ "club:club_members", kwargs={"club_id": self.club.id}
)
- self.assertRedirects(response, self.members_url)
self.subscriber.refresh_from_db()
self.assert_membership_started_today(self.subscriber, role=3)
- def test_root_add_multiple_club_member(self):
- """Test that root users can add multiple members at once to clubs."""
- self.client.force_login(self.root)
- response = self.client.post(
- self.members_url,
- {
- "users": (self.subscriber.id, self.krophil.id),
- "role": 3,
- },
- )
- self.assertRedirects(response, self.members_url)
- self.subscriber.refresh_from_db()
- self.assert_membership_started_today(self.subscriber, role=3)
- self.assert_membership_started_today(self.krophil, role=3)
-
def test_add_unauthorized_members(self):
"""Test that users who are not currently subscribed
cannot be members of clubs.
"""
for user in self.public, self.old_subscriber:
form = ClubMemberForm(
- data={"users": [user.id], "role": 1},
+ data={"user": user.id, "role": 1},
request_user=self.root,
club=self.club,
)
assert not form.is_valid()
assert form.errors == {
- "users": [
- "L'utilisateur doit être cotisant pour faire partie d'un club"
- ]
+ "user": ["L'utilisateur doit être cotisant pour faire partie d'un club"]
}
def test_add_members_already_members(self):
@@ -316,15 +307,15 @@ class TestMembership(TestClub):
max_id = User.objects.aggregate(id=Max("id"))["id"]
for members in [max_id + 1], [max_id + 1, self.subscriber.id]:
form = ClubMemberForm(
- data={"users": members, "role": 1},
+ data={"user": members, "role": 1},
request_user=self.root,
club=self.club,
)
assert not form.is_valid()
assert form.errors == {
- "users": [
+ "user": [
"Sélectionnez un choix valide. "
- f"{max_id + 1} n\u2019en fait pas partie."
+ "Ce choix ne fait pas partie de ceux disponibles."
]
}
self.club.refresh_from_db()
@@ -337,10 +328,12 @@ class TestMembership(TestClub):
nb_subscriber_memberships = self.subscriber.memberships.count()
self.client.force_login(president)
response = self.client.post(
- self.members_url,
- {"users": self.subscriber.id, "role": 9},
+ self.new_members_url, {"user": self.subscriber.id, "role": 9}
+ )
+ assert response.status_code == 200
+ assert response.headers.get("HX-Redirect", "") == reverse(
+ "club:club_members", kwargs={"club_id": self.club.id}
)
- self.assertRedirects(response, self.members_url)
self.club.refresh_from_db()
self.subscriber.refresh_from_db()
assert self.club.members.count() == nb_club_membership + 1
@@ -352,7 +345,7 @@ class TestMembership(TestClub):
a membership with a greater role than its own.
"""
form = ClubMemberForm(
- data={"users": [self.subscriber.id], "role": 10},
+ data={"user": self.subscriber.id, "role": 10},
request_user=self.simple_board_member,
club=self.club,
)
@@ -368,23 +361,18 @@ class TestMembership(TestClub):
def test_add_member_without_role(self):
"""Test that trying to add members without specifying their role fails."""
- self.client.force_login(self.root)
form = ClubMemberForm(
- data={"users": [self.subscriber.id]},
- request_user=self.simple_board_member,
- club=self.club,
+ data={"user": self.subscriber.id}, request_user=self.root, club=self.club
)
assert not form.is_valid()
- assert form.errors == {"role": ["Vous devez choisir un rôle"]}
+ assert form.errors == {"role": ["Ce champ est obligatoire."]}
def test_end_membership_self(self):
"""Test that a member can end its own membership."""
self.client.force_login(self.simple_board_member)
- self.client.post(
- self.members_url,
- {"users_old": self.simple_board_member.id},
- )
+ membership = self.club.members.get(end_date=None, user=self.simple_board_member)
+ self.client.post(self.members_url, {"members_old": [membership.id]})
self.simple_board_member.refresh_from_db()
self.assert_membership_ended_today(self.simple_board_member)
@@ -392,15 +380,13 @@ class TestMembership(TestClub):
"""Test that board members of the club can end memberships
of users with lower roles.
"""
- # remainder : simple_board_member has role 3, president has role 10, richard has role 1
+ # reminder : simple_board_member has role 3
self.client.force_login(self.simple_board_member)
- response = self.client.post(
- self.members_url,
- {"users_old": self.richard.id},
- )
+ membership = baker.make(Membership, club=self.club, role=2, end_date=None)
+ response = self.client.post(self.members_url, {"members_old": [membership.id]})
self.assertRedirects(response, self.members_url)
self.club.refresh_from_db()
- self.assert_membership_ended_today(self.richard)
+ self.assert_membership_ended_today(membership.user)
def test_end_membership_higher_role(self):
"""Test that board members of the club cannot end memberships
@@ -408,46 +394,30 @@ class TestMembership(TestClub):
"""
membership = self.president.memberships.filter(club=self.club).first()
self.client.force_login(self.simple_board_member)
- self.client.post(
- self.members_url,
- {"users_old": self.president.id},
- )
+ self.client.post(self.members_url, {"members_old": [membership.id]})
self.club.refresh_from_db()
new_membership = self.club.get_membership_for(self.president)
assert new_membership is not None
assert new_membership == membership
- membership = self.president.memberships.filter(club=self.club).first()
+ membership.refresh_from_db()
assert membership.end_date is None
- def test_end_membership_as_main_club_board(self):
- """Test that board members of the main club can end the membership
- of anyone.
- """
+ def test_end_membership_with_permission(self):
+ """Test that users with permission can end any membership."""
# make subscriber a board member
- subscriber = subscriber_user.make()
- Membership.objects.create(club=self.ae, user=subscriber, role=3)
-
nb_memberships = self.club.members.ongoing().count()
- self.client.force_login(subscriber)
+ self.client.force_login(
+ subscriber_user.make(
+ user_permissions=[Permission.objects.get(codename="change_membership")]
+ )
+ )
+ president_membership = self.club.president
response = self.client.post(
- self.members_url,
- {"users_old": self.president.id},
+ self.members_url, {"members_old": [president_membership.id]}
)
self.assertRedirects(response, self.members_url)
- self.assert_membership_ended_today(self.president)
- assert self.club.members.ongoing().count() == nb_memberships - 1
-
- def test_end_membership_as_root(self):
- """Test that root users can end the membership of anyone."""
- nb_memberships = self.club.members.ongoing().count()
- self.client.force_login(self.root)
- response = self.client.post(
- self.members_url,
- {"users_old": [self.president.id]},
- )
- self.assertRedirects(response, self.members_url)
- self.assert_membership_ended_today(self.president)
+ self.assert_membership_ended_today(president_membership.user)
assert self.club.members.ongoing().count() == nb_memberships - 1
def test_end_membership_as_foreigner(self):
@@ -455,14 +425,11 @@ class TestMembership(TestClub):
nb_memberships = self.club.members.count()
membership = self.richard.memberships.filter(club=self.club).first()
self.client.force_login(self.subscriber)
- self.client.post(
- self.members_url,
- {"users_old": [self.richard.id]},
- )
+ self.client.post(self.members_url, {"members_old": [self.richard.id]})
# nothing should have changed
- new_mem = self.club.get_membership_for(self.richard)
+ membership.refresh_from_db()
assert self.club.members.count() == nb_memberships
- assert membership == new_mem
+ assert membership.end_date is None
def test_remove_from_club_group(self):
"""Test that when a membership ends, the user is removed from club groups."""
diff --git a/club/urls.py b/club/urls.py
index 664d93a6..e33c2a26 100644
--- a/club/urls.py
+++ b/club/urls.py
@@ -25,6 +25,7 @@
from django.urls import path
from club.views import (
+ ClubAddMembersFragment,
ClubCreateView,
ClubEditView,
ClubListView,
@@ -60,6 +61,11 @@ urlpatterns = [
path("/edit/", ClubEditView.as_view(), name="club_edit"),
path("/edit/page/", ClubPageEditView.as_view(), name="club_edit_page"),
path("/members/", ClubMembersView.as_view(), name="club_members"),
+ path(
+ "fragment//members/",
+ ClubAddMembersFragment.as_view(),
+ name="club_new_members",
+ ),
path(
"/elderlies/",
ClubOldMembersView.as_view(),
diff --git a/club/views.py b/club/views.py
index 735e8291..fedc88ee 100644
--- a/club/views.py
+++ b/club/views.py
@@ -23,12 +23,13 @@
#
import csv
+from typing import Any
from django.conf import settings
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.exceptions import NON_FIELD_ERRORS, PermissionDenied, ValidationError
from django.core.paginator import InvalidPage, Paginator
-from django.db.models import Sum
+from django.db.models import Q, Sum
from django.http import (
Http404,
HttpResponseRedirect,
@@ -37,7 +38,8 @@ from django.http import (
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse, reverse_lazy
from django.utils import timezone
-from django.utils.functional import cached_property
+from django.utils.safestring import SafeString
+from django.utils.timezone import now
from django.utils.translation import gettext as _t
from django.utils.translation import gettext_lazy as _
from django.views.generic import DetailView, ListView, View
@@ -47,20 +49,26 @@ from club.forms import (
ClubAdminEditForm,
ClubEditForm,
ClubMemberForm,
+ ClubOldMemberForm,
MailingForm,
SellingsForm,
)
-from club.models import Club, Mailing, MailingSubscription, Membership
+from club.models import (
+ Club,
+ Mailing,
+ MailingSubscription,
+ Membership,
+)
from com.views import (
PosterCreateBaseView,
PosterDeleteBaseView,
PosterEditBaseView,
PosterListBaseView,
)
-from core.auth.mixins import CanCreateMixin, CanEditMixin, CanViewMixin
+from core.auth.mixins import CanCreateMixin, CanEditMixin
from core.models import PageRev
-from core.views import DetailFormView, PageEditViewBase
-from core.views.mixins import TabedViewMixin
+from core.views import DetailFormView, PageEditViewBase, UseFragmentsMixin
+from core.views.mixins import FragmentMixin, TabedViewMixin
from counter.models import Selling
@@ -79,7 +87,7 @@ class ClubTabsMixin(TabedViewMixin):
"name": _("Infos"),
}
]
- if self.request.user.can_view(self.object):
+ if self.request.user.has_perm("club.view_club"):
tab_list.extend(
[
{
@@ -98,16 +106,16 @@ class ClubTabsMixin(TabedViewMixin):
},
]
)
- if self.object.page:
- tab_list.append(
- {
- "url": reverse(
- "club:club_hist", kwargs={"club_id": self.object.id}
- ),
- "slug": "history",
- "name": _("History"),
- }
- )
+ if self.object.page:
+ tab_list.append(
+ {
+ "url": reverse(
+ "club:club_hist", kwargs={"club_id": self.object.id}
+ ),
+ "slug": "history",
+ "name": _("History"),
+ }
+ )
if self.request.user.can_edit(self.object):
tab_list.extend(
[
@@ -228,13 +236,14 @@ class ClubPageEditView(ClubTabsMixin, PageEditViewBase):
return reverse_lazy("club:club_view", kwargs={"club_id": self.club.id})
-class ClubPageHistView(ClubTabsMixin, CanViewMixin, DetailView):
+class ClubPageHistView(ClubTabsMixin, PermissionRequiredMixin, DetailView):
"""Modification hostory of the page."""
model = Club
pk_url_kwarg = "club_id"
template_name = "club/page_history.jinja"
current_tab = "history"
+ permission_required = "club.view_club"
class ClubToolsView(ClubTabsMixin, CanEditMixin, DetailView):
@@ -246,57 +255,92 @@ class ClubToolsView(ClubTabsMixin, CanEditMixin, DetailView):
current_tab = "tools"
-class ClubMembersView(ClubTabsMixin, CanViewMixin, DetailFormView):
+class ClubAddMembersFragment(FragmentMixin, PermissionRequiredMixin, CreateView):
+ template_name = "club/fragments/add_member.jinja"
+ form_class = ClubMemberForm
+ model = Membership
+ object = None
+ reload_on_redirect = True
+ permission_required = "club.view_club"
+
+ def dispatch(self, *args, **kwargs):
+ club_id = self.kwargs.get("club_id")
+ if not club_id:
+ raise Http404
+ self.club = get_object_or_404(Club, pk=kwargs.get("club_id"))
+ return super().dispatch(*args, **kwargs)
+
+ def get_form_kwargs(self):
+ return super().get_form_kwargs() | {
+ "request_user": self.request.user,
+ "club": self.club,
+ }
+
+ def render_fragment(self, request, **kwargs) -> SafeString:
+ self.club = kwargs.get("club")
+ return super().render_fragment(request, **kwargs)
+
+ def get_success_url(self):
+ return reverse("club:club_members", kwargs={"club_id": self.club.id})
+
+ def get_context_data(self, **kwargs):
+ return super().get_context_data(**kwargs) | {"club": self.club}
+
+
+class ClubMembersView(
+ ClubTabsMixin, UseFragmentsMixin, PermissionRequiredMixin, DetailFormView
+):
"""View of a club's members."""
model = Club
pk_url_kwarg = "club_id"
- form_class = ClubMemberForm
+ form_class = ClubOldMemberForm
template_name = "club/club_members.jinja"
current_tab = "members"
+ fragments = {"add_member_fragment": ClubAddMembersFragment}
+ permission_required = "club.view_club"
- @cached_property
- def members(self) -> list[Membership]:
- return list(self.object.members.ongoing().order_by("-role"))
+ def get_fragment_data(self) -> dict[str, Any]:
+ return {"add_member_fragment": {"club": self.object}}
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
- kwargs["request_user"] = self.request.user
+ kwargs["user"] = self.request.user
kwargs["club"] = self.object
- kwargs["club_members"] = self.members
return kwargs
def get_context_data(self, **kwargs):
kwargs = super().get_context_data(**kwargs)
- kwargs["members"] = self.members
+ editable = list(
+ kwargs["form"].fields["members_old"].queryset.values_list("id", flat=True)
+ )
+ kwargs["members"] = list(
+ self.object.members.ongoing()
+ .annotate(is_editable=Q(id__in=editable))
+ .order_by("-role")
+ .select_related("user")
+ )
+ kwargs["can_end_membership"] = len(editable) > 0
return kwargs
def form_valid(self, form):
- """Check user rights."""
- resp = super().form_valid(form)
-
- data = form.clean()
- users = data.pop("users", [])
- users_old = data.pop("users_old", [])
- for user in users:
- Membership(club=self.object, user=user, **data).save()
- for user in users_old:
- membership = self.object.get_membership_for(user)
- membership.end_date = timezone.now()
+ for membership in form.cleaned_data.get("members_old"):
+ membership.end_date = now()
membership.save()
- return resp
+ return super().form_valid(form)
def get_success_url(self, **kwargs):
return self.request.path
-class ClubOldMembersView(ClubTabsMixin, CanViewMixin, DetailView):
+class ClubOldMembersView(ClubTabsMixin, PermissionRequiredMixin, DetailView):
"""Old members of a club."""
model = Club
pk_url_kwarg = "club_id"
template_name = "club/club_old_members.jinja"
current_tab = "elderlies"
+ permission_required = "club.view_club"
class ClubSellingView(ClubTabsMixin, CanEditMixin, DetailFormView):
@@ -686,9 +730,11 @@ class MailingAutoGenerationView(View):
return redirect("club:mailing", club_id=club.id)
-class PosterListView(ClubTabsMixin, PosterListBaseView, CanViewMixin):
+class PosterListView(ClubTabsMixin, PermissionRequiredMixin, PosterListBaseView):
"""List communication posters."""
+ permission_required = "club.view_club"
+
def get_object(self):
return self.club
@@ -704,7 +750,7 @@ class PosterCreateView(PosterCreateBaseView, CanCreateMixin):
pk_url_kwarg = "club_id"
- def get_object(self):
+ def get_object(self, *args, **kwargs):
obj = super().get_object()
if not obj:
return self.club
diff --git a/eboutic/static/bundled/eboutic/eboutic-index.ts b/eboutic/static/bundled/eboutic/eboutic-index.ts
index 434d839a..d422431d 100644
--- a/eboutic/static/bundled/eboutic/eboutic-index.ts
+++ b/eboutic/static/bundled/eboutic/eboutic-index.ts
@@ -17,7 +17,8 @@ document.addEventListener("alpine:init", () => {
this.$watch("basket", () => {
this.saveBasket();
});
-
+ console.log(lastPurchaseTime);
+ console.log(localStorage.basketTimestamp);
// Invalidate basket if a purchase was made
if (lastPurchaseTime !== null && localStorage.basketTimestamp !== undefined) {
if (