From 32e1f09d469b92d320f0f47a6a6a26a9a99d11d6 Mon Sep 17 00:00:00 2001 From: imperosol Date: Sun, 16 Nov 2025 15:05:10 +0100 Subject: [PATCH] prevent csrf on `MembershipSetOldView` --- club/tests/test_membership.py | 31 +++++++++++++++++++++++++++- club/views.py | 29 +++++++------------------- core/templates/core/user_clubs.jinja | 19 ++++++++++++++--- 3 files changed, 53 insertions(+), 26 deletions(-) diff --git a/club/tests/test_membership.py b/club/tests/test_membership.py index a3c0be50..2420043d 100644 --- a/club/tests/test_membership.py +++ b/club/tests/test_membership.py @@ -7,7 +7,7 @@ from django.conf import settings from django.contrib.auth.models import Permission from django.core.cache import cache from django.db.models import Max -from django.test import TestCase +from django.test import Client, TestCase from django.urls import reverse from django.utils.timezone import localdate, localtime, now from model_bakery import baker @@ -532,6 +532,35 @@ class TestMembership(TestClub): assert new_board == initial_board +@pytest.mark.django_db +def test_membership_set_old(client: Client): + membership = baker.make(Membership, end_date=None, user=(subscriber_user.make())) + client.force_login(membership.user) + response = client.post( + reverse("club:membership_set_old", kwargs={"membership_id": membership.id}) + ) + assertRedirects( + response, reverse("core:user_clubs", kwargs={"user_id": membership.user_id}) + ) + membership.refresh_from_db() + assert membership.end_date == localdate() + + +@pytest.mark.django_db +def test_membership_delete(client: Client): + user = baker.make(User, is_superuser=True) + membership = baker.make(Membership) + client.force_login(user) + url = reverse("club:membership_delete", kwargs={"membership_id": membership.id}) + response = client.get(url) + assert response.status_code == 200 + response = client.post(url) + assertRedirects( + response, reverse("core:user_clubs", kwargs={"user_id": membership.user_id}) + ) + assert not Membership.objects.filter(id=membership.id).exists() + + @pytest.mark.django_db class TestJoinClub: @pytest.fixture(autouse=True) diff --git a/club/views.py b/club/views.py index 5a3535a6..9077d0d7 100644 --- a/club/views.py +++ b/club/views.py @@ -34,7 +34,7 @@ from django.contrib.messages.views import SuccessMessageMixin from django.core.exceptions import NON_FIELD_ERRORS, PermissionDenied, ValidationError from django.core.paginator import InvalidPage, Paginator from django.db.models import F, Q, Sum -from django.http import Http404, HttpResponseRedirect, StreamingHttpResponse +from django.http import Http404, StreamingHttpResponse from django.shortcuts import get_object_or_404, redirect from django.urls import reverse, reverse_lazy from django.utils import timezone @@ -43,6 +43,7 @@ from django.utils.timezone import now from django.utils.translation import gettext from django.utils.translation import gettext_lazy as _ from django.views.generic import DetailView, ListView, View +from django.views.generic.detail import SingleObjectMixin from django.views.generic.edit import CreateView, DeleteView, UpdateView from club.forms import ( @@ -544,33 +545,17 @@ class ClubCreateView(PermissionRequiredMixin, CreateView): permission_required = "club.add_club" -class MembershipSetOldView(CanEditMixin, DetailView): - """Set a membership as beeing old.""" +class MembershipSetOldView(CanEditMixin, SingleObjectMixin, View): + """Set a membership as being old.""" model = Membership pk_url_kwarg = "membership_id" - def get(self, request, *args, **kwargs): + def post(self, *_args, **_kwargs): self.object = self.get_object() self.object.end_date = timezone.now() self.object.save() - return HttpResponseRedirect( - reverse( - "club:club_members", - args=self.args, - kwargs={"club_id": self.object.club.id}, - ) - ) - - def post(self, request, *args, **kwargs): - self.object = self.get_object() - return HttpResponseRedirect( - reverse( - "club:club_members", - args=self.args, - kwargs={"club_id": self.object.club.id}, - ) - ) + return redirect("core:user_clubs", user_id=self.object.user_id) class MembershipDeleteView(PermissionRequiredMixin, DeleteView): @@ -582,7 +567,7 @@ class MembershipDeleteView(PermissionRequiredMixin, DeleteView): permission_required = "club.delete_membership" def get_success_url(self): - return reverse_lazy("core:user_clubs", kwargs={"user_id": self.object.user.id}) + return reverse_lazy("core:user_clubs", kwargs={"user_id": self.object.user_id}) class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView): diff --git a/core/templates/core/user_clubs.jinja b/core/templates/core/user_clubs.jinja index 51b6827f..bd365239 100644 --- a/core/templates/core/user_clubs.jinja +++ b/core/templates/core/user_clubs.jinja @@ -17,7 +17,9 @@ {% trans %}Description{% endtrans %} {% trans %}Since{% endtrans %} - + {% if user.has_perm("club.delete_membership") %} + + {% endif %} @@ -28,7 +30,16 @@ {{ m.description }} {{ m.start_date }} {% if m.can_be_edited_by(user) %} - {% trans %}Mark as old{% endtrans %} + +
+ {% csrf_token %} + +
+ {% endif %} {% if user.has_perm("club.delete_membership") %} {% trans %}Delete{% endtrans %} @@ -48,7 +59,9 @@ {% trans %}Description{% endtrans %} {% trans %}From{% endtrans %} {% trans %}To{% endtrans %} - + {% if user.has_perm("club.delete_membership") %} + + {% endif %}